mirror of
https://github.com/minetest/minetest.git
synced 2024-08-21 14:04:13 +02:00
MapBlockMesh, mesh animation system, urgent mesh updates, athmospheric light, removed footprints
This commit is contained in:
parent
f9a66c5d46
commit
807a0d313b
224
src/client.cpp
224
src/client.cpp
@ -82,8 +82,9 @@ MeshUpdateQueue::~MeshUpdateQueue()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::list<QueuedMeshUpdate*>::Iterator i;
|
||||
for(i=m_queue.begin(); i!=m_queue.end(); i++)
|
||||
for(std::vector<QueuedMeshUpdate*>::iterator
|
||||
i = m_queue.begin();
|
||||
i != m_queue.end(); i++)
|
||||
{
|
||||
QueuedMeshUpdate *q = *i;
|
||||
delete q;
|
||||
@ -93,7 +94,7 @@ MeshUpdateQueue::~MeshUpdateQueue()
|
||||
/*
|
||||
peer_id=0 adds with nobody to send to
|
||||
*/
|
||||
void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
|
||||
void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
@ -101,12 +102,16 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se
|
||||
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
if(urgent)
|
||||
m_urgents.insert(p);
|
||||
|
||||
/*
|
||||
Find if block is already in queue.
|
||||
If it is, update the data and quit.
|
||||
*/
|
||||
core::list<QueuedMeshUpdate*>::Iterator i;
|
||||
for(i=m_queue.begin(); i!=m_queue.end(); i++)
|
||||
for(std::vector<QueuedMeshUpdate*>::iterator
|
||||
i = m_queue.begin();
|
||||
i != m_queue.end(); i++)
|
||||
{
|
||||
QueuedMeshUpdate *q = *i;
|
||||
if(q->p == p)
|
||||
@ -136,12 +141,19 @@ QueuedMeshUpdate * MeshUpdateQueue::pop()
|
||||
{
|
||||
JMutexAutoLock lock(m_mutex);
|
||||
|
||||
core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
|
||||
if(i == m_queue.end())
|
||||
return NULL;
|
||||
QueuedMeshUpdate *q = *i;
|
||||
m_queue.erase(i);
|
||||
return q;
|
||||
bool must_be_urgent = !m_urgents.empty();
|
||||
for(std::vector<QueuedMeshUpdate*>::iterator
|
||||
i = m_queue.begin();
|
||||
i != m_queue.end(); i++)
|
||||
{
|
||||
QueuedMeshUpdate *q = *i;
|
||||
if(must_be_urgent && m_urgents.count(q->p) == 0)
|
||||
continue;
|
||||
m_queue.erase(i);
|
||||
m_urgents.erase(q->p);
|
||||
return q;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -178,8 +190,12 @@ void * MeshUpdateThread::Thread()
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Client: Mesh making");
|
||||
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = makeMapBlockMesh(q->data, m_gamedef);
|
||||
MapBlockMesh *mesh_new = new MapBlockMesh(q->data);
|
||||
if(mesh_new->getMesh()->getMeshBufferCount() == 0)
|
||||
{
|
||||
delete mesh_new;
|
||||
mesh_new = NULL;
|
||||
}
|
||||
|
||||
MeshUpdateResult r;
|
||||
r.p = q->p;
|
||||
@ -227,6 +243,9 @@ Client::Client(
|
||||
m_inventory_updated(false),
|
||||
m_inventory_from_server(NULL),
|
||||
m_inventory_from_server_age(0.0),
|
||||
m_animation_time(0),
|
||||
m_crack_level(-1),
|
||||
m_crack_pos(0,0,0),
|
||||
m_time_of_day(0),
|
||||
m_map_seed(0),
|
||||
m_password(password),
|
||||
@ -309,6 +328,10 @@ void Client::step(float dtime)
|
||||
else
|
||||
m_ignore_damage_timer = 0.0;
|
||||
|
||||
m_animation_time += dtime;
|
||||
if(m_animation_time > 60.0)
|
||||
m_animation_time -= 60.0;
|
||||
|
||||
//infostream<<"Client steps "<<dtime<<std::endl;
|
||||
|
||||
{
|
||||
@ -635,7 +658,18 @@ void Client::step(float dtime)
|
||||
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
|
||||
if(block)
|
||||
{
|
||||
block->replaceMesh(r.mesh);
|
||||
//JMutexAutoLock lock(block->mesh_mutex);
|
||||
|
||||
// Delete the old mesh
|
||||
if(block->mesh != NULL)
|
||||
{
|
||||
// TODO: Remove hardware buffers of meshbuffers of block->mesh
|
||||
delete block->mesh;
|
||||
block->mesh = NULL;
|
||||
}
|
||||
|
||||
// Replace with the new mesh
|
||||
block->mesh = r.mesh;
|
||||
}
|
||||
if(r.ack_block_to_server)
|
||||
{
|
||||
@ -868,9 +902,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
|
||||
//TimeTaker t1("TOCLIENT_REMOVENODE");
|
||||
|
||||
// This will clear the cracking animation after digging
|
||||
((ClientMap&)m_env.getMap()).clearTempMod(p);
|
||||
|
||||
removeNode(p);
|
||||
}
|
||||
else if(command == TOCLIENT_ADDNODE)
|
||||
@ -960,13 +991,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
m_con.Send(PEER_ID_SERVER, 1, reply, true);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Update Mesh of this block and blocks at x-, y- and z-.
|
||||
Environment should not be locked as it interlocks with the
|
||||
main thread, from which is will want to retrieve textures.
|
||||
*/
|
||||
|
||||
//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
|
||||
/*
|
||||
Add it to mesh update queue and set it to be acknowledged after update.
|
||||
*/
|
||||
@ -1837,12 +1861,14 @@ void Client::removeNode(v3s16 p)
|
||||
{
|
||||
}
|
||||
|
||||
// add urgent task to update the modified node
|
||||
addUpdateMeshTaskForNode(p, false, true);
|
||||
|
||||
for(core::map<v3s16, MapBlock * >::Iterator
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
//m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
addUpdateMeshTaskWithEdge(p);
|
||||
}
|
||||
}
|
||||
@ -1863,14 +1889,13 @@ void Client::addNode(v3s16 p, MapNode n)
|
||||
catch(InvalidPositionException &e)
|
||||
{}
|
||||
|
||||
//TimeTaker timer2("Client::addNode(): updateMeshes");
|
||||
//TimeTaker timer2("Client::addNode(): addUpdateMeshTaskWithEdge");
|
||||
|
||||
for(core::map<v3s16, MapBlock * >::Iterator
|
||||
i = modified_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
v3s16 p = i.getNode()->getKey();
|
||||
//m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
|
||||
addUpdateMeshTaskWithEdge(p);
|
||||
}
|
||||
}
|
||||
@ -2051,6 +2076,36 @@ core::list<std::wstring> Client::getConnectedPlayerNames()
|
||||
return playerNames;
|
||||
}
|
||||
|
||||
float Client::getAnimationTime()
|
||||
{
|
||||
return m_animation_time;
|
||||
}
|
||||
|
||||
int Client::getCrackLevel()
|
||||
{
|
||||
return m_crack_level;
|
||||
}
|
||||
|
||||
void Client::setCrack(int level, v3s16 pos)
|
||||
{
|
||||
int old_crack_level = m_crack_level;
|
||||
v3s16 old_crack_pos = m_crack_pos;
|
||||
|
||||
m_crack_level = level;
|
||||
m_crack_pos = pos;
|
||||
|
||||
if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
|
||||
{
|
||||
// remove old crack
|
||||
addUpdateMeshTaskForNode(old_crack_pos, false, true);
|
||||
}
|
||||
if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
|
||||
{
|
||||
// add new crack
|
||||
addUpdateMeshTaskForNode(pos, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
u32 Client::getDayNightRatio()
|
||||
{
|
||||
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
|
||||
@ -2064,40 +2119,6 @@ u16 Client::getHP()
|
||||
return player->hp;
|
||||
}
|
||||
|
||||
void Client::setTempMod(v3s16 p, NodeMod mod)
|
||||
{
|
||||
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
|
||||
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||
|
||||
core::map<v3s16, MapBlock*> affected_blocks;
|
||||
((ClientMap&)m_env.getMap()).setTempMod(p, mod,
|
||||
&affected_blocks);
|
||||
|
||||
for(core::map<v3s16, MapBlock*>::Iterator
|
||||
i = affected_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
|
||||
}
|
||||
}
|
||||
|
||||
void Client::clearTempMod(v3s16 p)
|
||||
{
|
||||
//JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
|
||||
assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
|
||||
|
||||
core::map<v3s16, MapBlock*> affected_blocks;
|
||||
((ClientMap&)m_env.getMap()).clearTempMod(p,
|
||||
&affected_blocks);
|
||||
|
||||
for(core::map<v3s16, MapBlock*>::Iterator
|
||||
i = affected_blocks.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::getChatMessage(std::wstring &message)
|
||||
{
|
||||
if(m_chat_queue.size() == 0)
|
||||
@ -2131,10 +2152,12 @@ void Client::typeChatMessage(const std::wstring &message)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
|
||||
void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
|
||||
{
|
||||
/*infostream<<"Client::addUpdateMeshTask(): "
|
||||
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<" ack_to_server="<<ack_to_server
|
||||
<<" urgent="<<urgent
|
||||
<<std::endl;*/
|
||||
|
||||
MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
|
||||
@ -2145,45 +2168,29 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
|
||||
Create a task to update the mesh of the block
|
||||
*/
|
||||
|
||||
MeshMakeData *data = new MeshMakeData;
|
||||
MeshMakeData *data = new MeshMakeData(this);
|
||||
|
||||
{
|
||||
//TimeTaker timer("data fill");
|
||||
// Release: ~0ms
|
||||
// Debug: 1-6ms, avg=2ms
|
||||
data->fill(getDayNightRatio(), b);
|
||||
data->fill(b);
|
||||
data->setCrack(m_crack_level, m_crack_pos);
|
||||
data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
|
||||
}
|
||||
|
||||
// Debug wait
|
||||
//while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
|
||||
|
||||
// Add task to queue
|
||||
m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
|
||||
m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
|
||||
|
||||
/*infostream<<"Mesh update input queue size is "
|
||||
<<m_mesh_update_thread.m_queue_in.size()
|
||||
<<std::endl;*/
|
||||
|
||||
#if 0
|
||||
// Temporary test: make mesh directly in here
|
||||
{
|
||||
//TimeTaker timer("make mesh");
|
||||
// 10ms
|
||||
scene::SMesh *mesh_new = NULL;
|
||||
mesh_new = makeMapBlockMesh(data);
|
||||
b->replaceMesh(mesh_new);
|
||||
delete data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Mark mesh as non-expired at this point so that it can already
|
||||
be marked as expired again if the data changes
|
||||
*/
|
||||
b->setMeshExpired(false);
|
||||
}
|
||||
|
||||
void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
|
||||
void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
|
||||
{
|
||||
/*{
|
||||
v3s16 p = blockpos;
|
||||
@ -2195,27 +2202,68 @@ void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,0);
|
||||
//MapBlock *b = m_env.getMap().getBlockNoCreate(p);
|
||||
addUpdateMeshTask(p, ack_to_server);
|
||||
addUpdateMeshTask(p, ack_to_server, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
// Leading edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(-1,0,0);
|
||||
addUpdateMeshTask(p);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,-1,0);
|
||||
addUpdateMeshTask(p);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,-1);
|
||||
addUpdateMeshTask(p);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
}
|
||||
|
||||
void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
|
||||
{
|
||||
{
|
||||
v3s16 p = nodepos;
|
||||
infostream<<"Client::addUpdateMeshTaskForNode(): "
|
||||
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<std::endl;
|
||||
}
|
||||
|
||||
v3s16 blockpos = getNodeBlockPos(nodepos);
|
||||
v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
|
||||
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,0);
|
||||
addUpdateMeshTask(p, ack_to_server, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
// Leading edge
|
||||
if(nodepos.X == blockpos_relative.X){
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(-1,0,0);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
}
|
||||
if(nodepos.Y == blockpos_relative.Y){
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,-1,0);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
}
|
||||
if(nodepos.Z == blockpos_relative.Z){
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,-1);
|
||||
addUpdateMeshTask(p, false, urgent);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
}
|
||||
}
|
||||
|
||||
ClientEvent Client::getClientEvent()
|
||||
{
|
||||
if(m_client_event_queue.size() == 0)
|
||||
|
28
src/client.h
28
src/client.h
@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "common_irrlicht.h"
|
||||
#include "jmutex.h"
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "clientobject.h"
|
||||
#include "utility.h" // For IntervalLimiter
|
||||
#include "gamedef.h"
|
||||
@ -34,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "filesys.h"
|
||||
|
||||
struct MeshMakeData;
|
||||
class MapBlockMesh;
|
||||
class IGameDef;
|
||||
class IWritableTextureSource;
|
||||
class IWritableItemDefManager;
|
||||
@ -71,7 +74,8 @@ public:
|
||||
/*
|
||||
peer_id=0 adds with nobody to send to
|
||||
*/
|
||||
void addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server);
|
||||
void addBlock(v3s16 p, MeshMakeData *data,
|
||||
bool ack_block_to_server, bool urgent);
|
||||
|
||||
// Returned pointer must be deleted
|
||||
// Returns NULL if queue is empty
|
||||
@ -84,14 +88,15 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
core::list<QueuedMeshUpdate*> m_queue;
|
||||
std::vector<QueuedMeshUpdate*> m_queue;
|
||||
std::set<v3s16> m_urgents;
|
||||
JMutex m_mutex;
|
||||
};
|
||||
|
||||
struct MeshUpdateResult
|
||||
{
|
||||
v3s16 p;
|
||||
scene::SMesh *mesh;
|
||||
MapBlockMesh *mesh;
|
||||
bool ack_block_to_server;
|
||||
|
||||
MeshUpdateResult():
|
||||
@ -260,13 +265,15 @@ public:
|
||||
|
||||
core::list<std::wstring> getConnectedPlayerNames();
|
||||
|
||||
float getAnimationTime();
|
||||
|
||||
int getCrackLevel();
|
||||
void setCrack(int level, v3s16 pos);
|
||||
|
||||
u32 getDayNightRatio();
|
||||
|
||||
u16 getHP();
|
||||
|
||||
void setTempMod(v3s16 p, NodeMod mod);
|
||||
void clearTempMod(v3s16 p);
|
||||
|
||||
float getAvgRtt()
|
||||
{
|
||||
try{
|
||||
@ -281,9 +288,10 @@ public:
|
||||
|
||||
u64 getMapSeed(){ return m_map_seed; }
|
||||
|
||||
void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false);
|
||||
void addUpdateMeshTask(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
|
||||
// Including blocks at appropriate edges
|
||||
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false);
|
||||
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
|
||||
void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false);
|
||||
|
||||
// Get event from queue. CE_NONE is returned if queue is empty.
|
||||
ClientEvent getClientEvent();
|
||||
@ -352,6 +360,10 @@ private:
|
||||
float m_inventory_from_server_age;
|
||||
core::map<v3s16, bool> m_active_blocks;
|
||||
PacketCounter m_packetcounter;
|
||||
// Block mesh animation parameters
|
||||
float m_animation_time;
|
||||
int m_crack_level;
|
||||
v3s16 m_crack_pos;
|
||||
// Received from the server. 0-23999
|
||||
u32 m_time_of_day;
|
||||
// 0 <= m_daynight_i < DAYNIGHT_CACHE_COUNT
|
||||
|
@ -29,9 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// Create a cuboid.
|
||||
// collector - the MeshCollector for the resulting polygons
|
||||
// box - the position and size of the box
|
||||
// materials - the materials to use (for all 6 faces)
|
||||
// pa - texture atlas pointers for the materials
|
||||
// matcount - number of entries in "materials" and "pa", 1<=matcount<=6
|
||||
// tiles - the tiles (materials) to use (for all 6 faces)
|
||||
// tilecount - number of entries in tiles, 1<=tilecount<=6
|
||||
// c - vertex colour - used for all
|
||||
// txc - texture coordinates - this is a list of texture coordinates
|
||||
// for the opposite corners of each face - therefore, there
|
||||
@ -41,10 +40,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// (compatible with ContentFeatures). If you specified 0,0,1,1
|
||||
// for each face, that would be the same as passing NULL.
|
||||
void makeCuboid(MeshCollector *collector, const aabb3f &box,
|
||||
const video::SMaterial *materials, const AtlasPointer *pa, int matcount,
|
||||
const TileSpec *tiles, int tilecount,
|
||||
video::SColor &c, const f32* txc)
|
||||
{
|
||||
assert(matcount >= 1);
|
||||
assert(tilecount >= 1 && tilecount <= 6);
|
||||
|
||||
v3f min = box.MinEdge;
|
||||
v3f max = box.MaxEdge;
|
||||
@ -98,9 +97,9 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
|
||||
|
||||
for(s32 j=0; j<24; j++)
|
||||
{
|
||||
int matindex = MYMIN(j/4, matcount-1);
|
||||
vertices[j].TCoords *= pa[matindex].size;
|
||||
vertices[j].TCoords += pa[matindex].pos;
|
||||
int tileindex = MYMIN(j/4, tilecount-1);
|
||||
vertices[j].TCoords *= tiles[tileindex].texture.size;
|
||||
vertices[j].TCoords += tiles[tileindex].texture.pos;
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
@ -108,17 +107,16 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
|
||||
// Add to mesh collector
|
||||
for(s32 j=0; j<24; j+=4)
|
||||
{
|
||||
int matindex = MYMIN(j/4, matcount-1);
|
||||
collector->append(materials[matindex],
|
||||
int tileindex = MYMIN(j/4, tilecount-1);
|
||||
collector->append(tiles[tileindex],
|
||||
vertices+j, 4, indices, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
MeshCollector &collector, IGameDef *gamedef)
|
||||
MeshCollector &collector)
|
||||
{
|
||||
INodeDefManager *nodedef = gamedef->ndef();
|
||||
ITextureSource *tsrc = gamedef->getTextureSource();
|
||||
INodeDefManager *nodedef = data->m_gamedef->ndef();
|
||||
|
||||
// 0ms
|
||||
//TimeTaker timer("mapblock_mesh_generate_special()");
|
||||
@ -134,14 +132,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
|
||||
v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
/*// General ground material for special output
|
||||
// Texture is modified just before usage
|
||||
video::SMaterial material_general;
|
||||
material_general.setFlag(video::EMF_LIGHTING, false);
|
||||
material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_general.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;*/
|
||||
|
||||
for(s16 z=0; z<MAP_BLOCKSIZE; z++)
|
||||
for(s16 y=0; y<MAP_BLOCKSIZE; y++)
|
||||
for(s16 x=0; x<MAP_BLOCKSIZE; x++)
|
||||
@ -167,16 +157,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
/*
|
||||
Add water sources to mesh if using new style
|
||||
*/
|
||||
assert(nodedef->get(n).special_materials[0]);
|
||||
//assert(nodedef->get(n).special_materials[1]);
|
||||
assert(nodedef->get(n).special_aps[0]);
|
||||
|
||||
video::SMaterial &liquid_material =
|
||||
*nodedef->get(n).special_materials[0];
|
||||
/*video::SMaterial &liquid_material_bfculled =
|
||||
*nodedef->get(n).special_materials[1];*/
|
||||
AtlasPointer &pa_liquid1 =
|
||||
*nodedef->get(n).special_aps[0];
|
||||
TileSpec tile_liquid = f.special_tiles[0];
|
||||
AtlasPointer &pa_liquid = tile_liquid.texture;
|
||||
|
||||
bool top_is_air = false;
|
||||
MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
|
||||
@ -186,64 +168,55 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
if(top_is_air == false)
|
||||
continue;
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
|
||||
video::SColor c = MapBlock_LightColor(
|
||||
nodedef->get(n).alpha, l);
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l);
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
pa_liquid.x0(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y1()),
|
||||
pa_liquid.x1(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y0()),
|
||||
pa_liquid.x1(), pa_liquid.y0()),
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y0()),
|
||||
pa_liquid.x0(), pa_liquid.y0()),
|
||||
};
|
||||
|
||||
v3f offset(p.X, p.Y + (-0.5+node_liquid_level)*BS, p.Z);
|
||||
for(s32 i=0; i<4; i++)
|
||||
{
|
||||
vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS;
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += offset;
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(liquid_material, vertices, 4, indices, 6);
|
||||
collector.append(tile_liquid, vertices, 4, indices, 6);
|
||||
break;}
|
||||
case NDT_FLOWINGLIQUID:
|
||||
{
|
||||
/*
|
||||
Add flowing liquid to mesh
|
||||
*/
|
||||
assert(nodedef->get(n).special_materials[0]);
|
||||
assert(nodedef->get(n).special_materials[1]);
|
||||
assert(nodedef->get(n).special_aps[0]);
|
||||
|
||||
video::SMaterial &liquid_material =
|
||||
*nodedef->get(n).special_materials[0];
|
||||
video::SMaterial &liquid_material_bfculled =
|
||||
*nodedef->get(n).special_materials[1];
|
||||
AtlasPointer &pa_liquid1 =
|
||||
*nodedef->get(n).special_aps[0];
|
||||
TileSpec tile_liquid = f.special_tiles[0];
|
||||
TileSpec tile_liquid_bfculled = f.special_tiles[1];
|
||||
AtlasPointer &pa_liquid = tile_liquid.texture;
|
||||
|
||||
bool top_is_same_liquid = false;
|
||||
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
|
||||
content_t c_flowing = nodedef->getId(nodedef->get(n).liquid_alternative_flowing);
|
||||
content_t c_source = nodedef->getId(nodedef->get(n).liquid_alternative_source);
|
||||
content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
|
||||
content_t c_source = nodedef->getId(f.liquid_alternative_source);
|
||||
if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
|
||||
top_is_same_liquid = true;
|
||||
|
||||
u8 l = 0;
|
||||
u16 l = 0;
|
||||
// Use the light of the node on top if possible
|
||||
if(nodedef->get(ntop).param_type == CPT_LIGHT)
|
||||
l = decode_light(ntop.getLightBlend(data->m_daynight_ratio, nodedef));
|
||||
l = getInteriorLight(ntop, 0, data);
|
||||
// Otherwise use the light of this node (the liquid)
|
||||
else
|
||||
l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
|
||||
video::SColor c = MapBlock_LightColor(
|
||||
nodedef->get(n).alpha, l);
|
||||
l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(f.alpha, l);
|
||||
|
||||
// Neighbor liquid levels (key = relative position)
|
||||
// Includes current node
|
||||
@ -393,20 +366,20 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
|
||||
// Use backface culled material if neighbor doesn't have a
|
||||
// solidness of 0
|
||||
video::SMaterial *current_material = &liquid_material;
|
||||
const TileSpec *current_tile = &tile_liquid;
|
||||
if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
|
||||
current_material = &liquid_material_bfculled;
|
||||
current_tile = &tile_liquid_bfculled;
|
||||
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
pa_liquid.x0(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y1()),
|
||||
pa_liquid.x1(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y0()),
|
||||
pa_liquid.x1(), pa_liquid.y0()),
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y0()),
|
||||
pa_liquid.x0(), pa_liquid.y0()),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -464,12 +437,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
vertices[j].Pos.Z *= 0.98;
|
||||
}*/
|
||||
|
||||
vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[j].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(*current_material, vertices, 4, indices, 6);
|
||||
collector.append(*current_tile, vertices, 4, indices, 6);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -481,13 +454,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y1()),
|
||||
pa_liquid.x0(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y1()),
|
||||
pa_liquid.x1(), pa_liquid.y1()),
|
||||
video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_liquid1.x1(), pa_liquid1.y0()),
|
||||
pa_liquid.x1(), pa_liquid.y0()),
|
||||
video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
|
||||
pa_liquid1.x0(), pa_liquid1.y0()),
|
||||
pa_liquid.x0(), pa_liquid.y0()),
|
||||
};
|
||||
|
||||
// This fixes a strange bug
|
||||
@ -499,27 +472,20 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
|
||||
s32 j = corner_resolve[i];
|
||||
vertices[i].Pos.Y += corner_levels[j];
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(liquid_material, vertices, 4, indices, 6);
|
||||
collector.append(tile_liquid, vertices, 4, indices, 6);
|
||||
}
|
||||
break;}
|
||||
case NDT_GLASSLIKE:
|
||||
{
|
||||
video::SMaterial material_glass;
|
||||
material_glass.setFlag(video::EMF_LIGHTING, false);
|
||||
material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_glass.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
TileSpec tile_glass = getNodeTile(n, p, v3s16(0,0,0),
|
||||
&data->m_temp_mods, tsrc, nodedef);
|
||||
AtlasPointer pa_glass = tile_glass.texture;
|
||||
material_glass.setTexture(0, pa_glass.atlas);
|
||||
TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
for(u32 j=0; j<6; j++)
|
||||
@ -535,13 +501,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
pa_glass.x0(), pa_glass.y1()),
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
|
||||
pa_glass.x1(), pa_glass.y1()),
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
|
||||
pa_glass.x1(), pa_glass.y0()),
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
|
||||
pa_glass.x0(), pa_glass.y0()),
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
// Rotations in the g_6dirs format
|
||||
@ -565,36 +531,28 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
vertices[i].Pos.rotateXZBy(90);
|
||||
|
||||
for(u16 i=0; i<4; i++){
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material_glass, vertices, 4, indices, 6);
|
||||
collector.append(tile, vertices, 4, indices, 6);
|
||||
}
|
||||
break;}
|
||||
case NDT_ALLFACES:
|
||||
{
|
||||
video::SMaterial material_leaves1;
|
||||
material_leaves1.setFlag(video::EMF_LIGHTING, false);
|
||||
material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
TileSpec tile_leaves1 = getNodeTile(n, p, v3s16(0,0,0),
|
||||
&data->m_temp_mods, tsrc, nodedef);
|
||||
AtlasPointer pa_leaves1 = tile_leaves1.texture;
|
||||
material_leaves1.setTexture(0, pa_leaves1.atlas);
|
||||
TileSpec tile_leaves = getNodeTile(n, p,
|
||||
v3s16(0,0,0), data);
|
||||
AtlasPointer pa_leaves = tile_leaves.texture;
|
||||
|
||||
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
v3f pos = intToFloat(p+blockpos_nodes, BS);
|
||||
v3f pos = intToFloat(p, BS);
|
||||
aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
|
||||
box.MinEdge += pos;
|
||||
box.MaxEdge += pos;
|
||||
makeCuboid(&collector, box,
|
||||
&material_leaves1, &pa_leaves1, 1,
|
||||
c, NULL);
|
||||
makeCuboid(&collector, box, &tile_leaves, 1, c, NULL);
|
||||
break;}
|
||||
case NDT_ALLFACES_OPTIONAL:
|
||||
// This is always pre-converted to something else
|
||||
@ -604,28 +562,23 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
{
|
||||
v3s16 dir = n.getWallMountedDir(nodedef);
|
||||
|
||||
AtlasPointer ap(0);
|
||||
u8 tileindex = 0;
|
||||
if(dir == v3s16(0,-1,0)){
|
||||
ap = f.tiles[0].texture; // floor
|
||||
tileindex = 0; // floor
|
||||
} else if(dir == v3s16(0,1,0)){
|
||||
ap = f.tiles[1].texture; // ceiling
|
||||
tileindex = 1; // ceiling
|
||||
// For backwards compatibility
|
||||
} else if(dir == v3s16(0,0,0)){
|
||||
ap = f.tiles[0].texture; // floor
|
||||
tileindex = 0; // floor
|
||||
} else {
|
||||
ap = f.tiles[2].texture; // side
|
||||
tileindex = 2; // side
|
||||
}
|
||||
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material.setTexture(0, ap.atlas);
|
||||
TileSpec tile = getNodeTileN(n, p, tileindex, data);
|
||||
tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
|
||||
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
video::SColor c(255,255,255,255);
|
||||
|
||||
@ -657,27 +610,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
if(dir == v3s16(0,1,0))
|
||||
vertices[i].Pos.rotateXZBy(-45);
|
||||
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material, vertices, 4, indices, 6);
|
||||
collector.append(tile, vertices, 4, indices, 6);
|
||||
break;}
|
||||
case NDT_SIGNLIKE:
|
||||
{
|
||||
// Set material
|
||||
video::SMaterial material;
|
||||
material.setFlag(video::EMF_LIGHTING, false);
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
AtlasPointer ap = f.tiles[0].texture;
|
||||
material.setTexture(0, ap.atlas);
|
||||
TileSpec tile = getNodeTileN(n, p, 0, data);
|
||||
tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
float d = (float)BS/16;
|
||||
@ -711,24 +658,20 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
if(dir == v3s16(0,1,0))
|
||||
vertices[i].Pos.rotateXYBy(90);
|
||||
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material, vertices, 4, indices, 6);
|
||||
collector.append(tile, vertices, 4, indices, 6);
|
||||
break;}
|
||||
case NDT_PLANTLIKE:
|
||||
{
|
||||
video::SMaterial material_papyrus;
|
||||
material_papyrus.setFlag(video::EMF_LIGHTING, false);
|
||||
material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_papyrus.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
AtlasPointer pa_papyrus = f.tiles[0].texture;
|
||||
material_papyrus.setTexture(0, pa_papyrus.atlas);
|
||||
TileSpec tile = getNodeTileN(n, p, 0, data);
|
||||
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
for(u32 j=0; j<4; j++)
|
||||
@ -736,15 +679,15 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
video::S3DVertex vertices[4] =
|
||||
{
|
||||
video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
|
||||
pa_papyrus.x0(), pa_papyrus.y1()),
|
||||
ap.x0(), ap.y1()),
|
||||
video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
|
||||
pa_papyrus.x1(), pa_papyrus.y1()),
|
||||
ap.x1(), ap.y1()),
|
||||
video::S3DVertex( BS/2*f.visual_scale,
|
||||
-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
|
||||
pa_papyrus.x1(), pa_papyrus.y0()),
|
||||
ap.x1(), ap.y0()),
|
||||
video::S3DVertex(-BS/2*f.visual_scale,
|
||||
-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
|
||||
pa_papyrus.x0(), pa_papyrus.y0()),
|
||||
ap.x0(), ap.y0()),
|
||||
};
|
||||
|
||||
if(j == 0)
|
||||
@ -771,45 +714,28 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
for(u16 i=0; i<4; i++)
|
||||
{
|
||||
vertices[i].Pos *= f.visual_scale;
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
// Add to mesh collector
|
||||
collector.append(material_papyrus, vertices, 4, indices, 6);
|
||||
collector.append(tile, vertices, 4, indices, 6);
|
||||
}
|
||||
break;}
|
||||
case NDT_FENCELIKE:
|
||||
{
|
||||
video::SMaterial material_wood;
|
||||
material_wood.setFlag(video::EMF_LIGHTING, false);
|
||||
material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_wood.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
TileSpec tile_wood = getNodeTile(n, p, v3s16(0,0,0),
|
||||
&data->m_temp_mods, tsrc, nodedef);
|
||||
AtlasPointer pa_wood = tile_wood.texture;
|
||||
material_wood.setTexture(0, pa_wood.atlas);
|
||||
TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
|
||||
TileSpec tile_nocrack = tile;
|
||||
tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;
|
||||
|
||||
video::SMaterial material_wood_nomod;
|
||||
material_wood_nomod.setFlag(video::EMF_LIGHTING, false);
|
||||
material_wood_nomod.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_wood_nomod.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_wood_nomod.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
|
||||
TileSpec tile_wood_nomod = getNodeTile(n, p, v3s16(0,0,0),
|
||||
NULL, tsrc, nodedef);
|
||||
AtlasPointer pa_wood_nomod = tile_wood_nomod.texture;
|
||||
material_wood_nomod.setTexture(0, pa_wood_nomod.atlas);
|
||||
|
||||
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
|
||||
u16 l = getInteriorLight(n, 1, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
const f32 post_rad=(f32)BS/10;
|
||||
const f32 bar_rad=(f32)BS/20;
|
||||
const f32 bar_len=(f32)(BS/2)-post_rad;
|
||||
|
||||
v3f pos = intToFloat(p+blockpos_nodes, BS);
|
||||
v3f pos = intToFloat(p, BS);
|
||||
|
||||
// The post - always present
|
||||
aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
|
||||
@ -822,8 +748,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
0.35,0,0.65,1,
|
||||
0.35,0,0.65,1,
|
||||
0.35,0,0.65,1};
|
||||
makeCuboid(&collector, post, &material_wood,
|
||||
&pa_wood, 1, c, postuv);
|
||||
makeCuboid(&collector, post, &tile, 1, c, postuv);
|
||||
|
||||
// Now a section of fence, +X, if there's a post there
|
||||
v3s16 p2 = p;
|
||||
@ -843,12 +768,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
0,0.4,1,0.6,
|
||||
0,0.4,1,0.6,
|
||||
0,0.4,1,0.6};
|
||||
makeCuboid(&collector, bar, &material_wood_nomod,
|
||||
&pa_wood_nomod, 1, c, xrailuv);
|
||||
makeCuboid(&collector, bar, &tile_nocrack, 1,
|
||||
c, xrailuv);
|
||||
bar.MinEdge.Y -= BS/2;
|
||||
bar.MaxEdge.Y -= BS/2;
|
||||
makeCuboid(&collector, bar, &material_wood_nomod,
|
||||
&pa_wood_nomod, 1, c, xrailuv);
|
||||
// TODO: no crack
|
||||
makeCuboid(&collector, bar, &tile_nocrack, 1,
|
||||
c, xrailuv);
|
||||
}
|
||||
|
||||
// Now a section of fence, +Z, if there's a post there
|
||||
@ -870,12 +796,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
0,0.4,1,0.6,
|
||||
0,0.4,1,0.6};
|
||||
|
||||
makeCuboid(&collector, bar, &material_wood_nomod,
|
||||
&pa_wood_nomod, 1, c, zrailuv);
|
||||
makeCuboid(&collector, bar, &tile_nocrack, 1,
|
||||
c, zrailuv);
|
||||
bar.MinEdge.Y -= BS/2;
|
||||
bar.MaxEdge.Y -= BS/2;
|
||||
makeCuboid(&collector, bar, &material_wood_nomod,
|
||||
&pa_wood_nomod, 1, c, zrailuv);
|
||||
makeCuboid(&collector, bar, &tile_nocrack, 1,
|
||||
c, zrailuv);
|
||||
}
|
||||
break;}
|
||||
case NDT_RAILLIKE:
|
||||
@ -948,31 +874,28 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
}
|
||||
|
||||
// Assign textures
|
||||
AtlasPointer ap = f.tiles[0].texture; // straight
|
||||
u8 tileindex = 0; // straight
|
||||
if(adjacencies < 2)
|
||||
ap = f.tiles[0].texture; // straight
|
||||
tileindex = 0; // straight
|
||||
else if(adjacencies == 2)
|
||||
{
|
||||
if(is_straight)
|
||||
ap = f.tiles[0].texture; // straight
|
||||
tileindex = 0; // straight
|
||||
else
|
||||
ap = f.tiles[1].texture; // curved
|
||||
tileindex = 1; // curved
|
||||
}
|
||||
else if(adjacencies == 3)
|
||||
ap = f.tiles[2].texture; // t-junction
|
||||
tileindex = 2; // t-junction
|
||||
else if(adjacencies == 4)
|
||||
ap = f.tiles[3].texture; // crossing
|
||||
|
||||
video::SMaterial material_rail;
|
||||
material_rail.setFlag(video::EMF_LIGHTING, false);
|
||||
material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
material_rail.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
material_rail.MaterialType
|
||||
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||
material_rail.setTexture(0, ap.atlas);
|
||||
tileindex = 3; // crossing
|
||||
|
||||
u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
|
||||
TileSpec tile = getNodeTileN(n, p, tileindex, data);
|
||||
tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
|
||||
|
||||
AtlasPointer ap = tile.texture;
|
||||
|
||||
u16 l = getInteriorLight(n, 0, data);
|
||||
video::SColor c = MapBlock_LightColor(255, l);
|
||||
|
||||
float d = (float)BS/64;
|
||||
@ -1048,11 +971,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
|
||||
for(s32 i=0; i<4; i++)
|
||||
{
|
||||
vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
|
||||
vertices[i].Pos += intToFloat(p, BS);
|
||||
}
|
||||
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
collector.append(material_rail, vertices, 4, indices, 6);
|
||||
collector.append(tile, vertices, 4, indices, 6);
|
||||
break;}
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#ifndef CONTENT_MAPBLOCK_HEADER
|
||||
#define CONTENT_MAPBLOCK_HEADER
|
||||
|
||||
#ifndef SERVER
|
||||
#include "mapblock_mesh.h"
|
||||
#include "utility.h"
|
||||
class IGameDef;
|
||||
struct MeshMakeData;
|
||||
struct MeshCollector;
|
||||
void mapblock_mesh_generate_special(MeshMakeData *data,
|
||||
MeshCollector &collector, IGameDef *gamedef);
|
||||
#endif
|
||||
MeshCollector &collector);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -890,9 +890,6 @@ void ServerEnvironment::step(float dtime)
|
||||
|
||||
//TimeTaker timer("ServerEnv step");
|
||||
|
||||
// Get some settings
|
||||
bool footprints = g_settings->getBool("footprints");
|
||||
|
||||
/*
|
||||
Increment game time
|
||||
*/
|
||||
@ -921,26 +918,6 @@ void ServerEnvironment::step(float dtime)
|
||||
|
||||
// Move
|
||||
player->move(dtime, *m_map, 100*BS);
|
||||
|
||||
/*
|
||||
Add footsteps to grass
|
||||
*/
|
||||
if(footprints)
|
||||
{
|
||||
// Get node that is at BS/4 under player
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
|
||||
try{
|
||||
MapNode n = m_map->getNode(bottompos);
|
||||
if(n.getContent() == LEGN(m_gamedef->ndef(), "CONTENT_GRASS"))
|
||||
{
|
||||
n.setContent(LEGN(m_gamedef->ndef(), "CONTENT_GRASS_FOOTSTEPS"));
|
||||
m_map->setNode(bottompos, n);
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1873,7 +1850,6 @@ void ClientEnvironment::step(float dtime)
|
||||
|
||||
// Get some settings
|
||||
bool free_move = g_settings->getBool("free_move");
|
||||
bool footprints = g_settings->getBool("footprints");
|
||||
|
||||
// Get local player
|
||||
LocalPlayer *lplayer = getLocalPlayer();
|
||||
@ -2058,34 +2034,6 @@ void ClientEnvironment::step(float dtime)
|
||||
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
|
||||
}
|
||||
player->updateLight(light);
|
||||
|
||||
/*
|
||||
Add footsteps to grass
|
||||
*/
|
||||
if(footprints)
|
||||
{
|
||||
// Get node that is at BS/4 under player
|
||||
v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
|
||||
try{
|
||||
MapNode n = m_map->getNode(bottompos);
|
||||
if(n.getContent() == LEGN(m_gamedef->ndef(), "CONTENT_GRASS"))
|
||||
{
|
||||
n.setContent(LEGN(m_gamedef->ndef(), "CONTENT_GRASS_FOOTSTEPS"));
|
||||
m_map->setNode(bottompos, n);
|
||||
// Update mesh on client
|
||||
if(m_map->mapType() == MAPTYPE_CLIENT)
|
||||
{
|
||||
v3s16 p_blocks = getNodeBlockPos(bottompos);
|
||||
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
|
||||
//b->updateMesh(getDayNightRatio());
|
||||
b->setMeshExpired(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2133,16 +2081,6 @@ void ClientEnvironment::step(float dtime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientEnvironment::updateMeshes(v3s16 blockpos)
|
||||
{
|
||||
m_map->updateMeshes(blockpos, getDayNightRatio());
|
||||
}
|
||||
|
||||
void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
|
||||
{
|
||||
m_map->expireMeshes(only_daynight_diffed);
|
||||
}
|
||||
|
||||
void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
|
||||
{
|
||||
|
@ -407,24 +407,6 @@ public:
|
||||
virtual void addPlayer(Player *player);
|
||||
LocalPlayer * getLocalPlayer();
|
||||
|
||||
// Slightly deprecated
|
||||
void updateMeshes(v3s16 blockpos);
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
void setTimeOfDay(u32 time)
|
||||
{
|
||||
u32 old_dr = getDayNightRatio();
|
||||
|
||||
Environment::setTimeOfDay(time);
|
||||
|
||||
if(getDayNightRatio() != old_dr)
|
||||
{
|
||||
/*infostream<<"ClientEnvironment: DayNightRatio changed"
|
||||
<<" -> expiring meshes"<<std::endl;*/
|
||||
expireMeshes(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ClientSimpleObjects
|
||||
*/
|
||||
|
20
src/game.cpp
20
src/game.cpp
@ -1038,8 +1038,6 @@ void the_game(
|
||||
float object_hit_delay_timer = 0.0;
|
||||
float time_from_last_punch = 10;
|
||||
|
||||
float crack_update_timer = 0.0;
|
||||
|
||||
bool invert_mouse = g_settings->getBool("invert_mouse");
|
||||
|
||||
bool respawn_menu_active = false;
|
||||
@ -1185,7 +1183,6 @@ void the_game(
|
||||
if(object_hit_delay_timer >= 0)
|
||||
object_hit_delay_timer -= dtime;
|
||||
time_from_last_punch += dtime;
|
||||
crack_update_timer += dtime;
|
||||
|
||||
g_profiler->add("Elapsed time", dtime);
|
||||
g_profiler->avg("FPS", 1./dtime);
|
||||
@ -1908,7 +1905,7 @@ void the_game(
|
||||
if(!digging)
|
||||
{
|
||||
client.interact(1, pointed_old);
|
||||
client.clearTempMod(pointed_old.node_undersurface);
|
||||
client.setCrack(-1, v3s16(0,0,0));
|
||||
dig_time = 0.0;
|
||||
}
|
||||
}
|
||||
@ -2003,20 +2000,15 @@ void the_game(
|
||||
}
|
||||
else if(dig_index < CRACK_ANIMATION_LENGTH)
|
||||
{
|
||||
// Limit crack update speed
|
||||
if(crack_update_timer >= 0.1){
|
||||
crack_update_timer = 0.0;
|
||||
//infostream<<"dig_index="<<dig_index<<std::endl;
|
||||
//TimeTaker timer("client.setTempMod");
|
||||
client.setTempMod(nodepos,
|
||||
NodeMod(NODEMOD_CRACK, dig_index));
|
||||
}
|
||||
//TimeTaker timer("client.setTempMod");
|
||||
//infostream<<"dig_index="<<dig_index<<std::endl;
|
||||
client.setCrack(dig_index, nodepos);
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Digging completed"<<std::endl;
|
||||
client.interact(2, pointed);
|
||||
client.clearTempMod(nodepos);
|
||||
client.setCrack(-1, v3s16(0,0,0));
|
||||
client.removeNode(nodepos);
|
||||
|
||||
dig_time = 0;
|
||||
@ -2171,8 +2163,6 @@ void the_game(
|
||||
u32 daynight_ratio = client.getDayNightRatio();
|
||||
u8 light8 = decode_light((daynight_ratio * LIGHT_SUN) / 1000);
|
||||
brightness = (float)light8/255.0;
|
||||
// Make night look good
|
||||
brightness = brightness * 1.15 - 0.15;
|
||||
video::SColor bgcolor;
|
||||
if(brightness >= 0.2 && brightness < 0.7)
|
||||
bgcolor = video::SColor(
|
||||
|
@ -381,17 +381,20 @@ public:
|
||||
content_t id = nodedef->getId(def->name);
|
||||
const ContentFeatures &f = nodedef->get(id);
|
||||
|
||||
u8 param1 = 0;
|
||||
if(f.param_type == CPT_LIGHT)
|
||||
param1 = 0xee;
|
||||
|
||||
/*
|
||||
Make a mesh from the node
|
||||
*/
|
||||
MeshMakeData mesh_make_data;
|
||||
MapNode mesh_make_node(
|
||||
id,
|
||||
(f.param_type == CPT_LIGHT) ? 0xee : 0,
|
||||
0);
|
||||
mesh_make_data.fillSingleNode(1000, &mesh_make_node);
|
||||
scene::IMesh *node_mesh =
|
||||
makeMapBlockMesh(&mesh_make_data, gamedef);
|
||||
MeshMakeData mesh_make_data(gamedef);
|
||||
MapNode mesh_make_node(id, param1, 0);
|
||||
mesh_make_data.fillSingleNode(&mesh_make_node);
|
||||
MapBlockMesh mapblock_mesh(&mesh_make_data);
|
||||
|
||||
scene::IMesh *node_mesh = mapblock_mesh.getMesh();
|
||||
assert(node_mesh);
|
||||
setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));
|
||||
|
||||
/*
|
||||
@ -404,7 +407,7 @@ public:
|
||||
/*
|
||||
Draw node mesh into a render target texture
|
||||
*/
|
||||
if(def->inventory_texture == NULL && node_mesh != NULL)
|
||||
if(def->inventory_texture == NULL)
|
||||
{
|
||||
core::dimension2d<u32> dim(64,64);
|
||||
std::string rtt_texture_name = "INVENTORY_"
|
||||
@ -443,7 +446,7 @@ public:
|
||||
/*
|
||||
Use the node mesh as the wield mesh
|
||||
*/
|
||||
if(def->wield_mesh == NULL && node_mesh != NULL)
|
||||
if(def->wield_mesh == NULL)
|
||||
{
|
||||
// Scale to proper wield mesh proportions
|
||||
scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
|
||||
@ -452,9 +455,7 @@ public:
|
||||
def->wield_mesh->grab();
|
||||
}
|
||||
|
||||
|
||||
if(node_mesh != NULL)
|
||||
node_mesh->drop();
|
||||
// falling outside of here deletes node_mesh
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
321
src/map.cpp
321
src/map.cpp
@ -21,23 +21,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "mapsector.h"
|
||||
#include "mapblock.h"
|
||||
#include "main.h"
|
||||
#ifndef SERVER
|
||||
#include "client.h"
|
||||
#endif
|
||||
#include "filesys.h"
|
||||
#include "utility.h"
|
||||
#include "voxel.h"
|
||||
#include "porting.h"
|
||||
#include "mapgen.h"
|
||||
#include "nodemetadata.h"
|
||||
#ifndef SERVER
|
||||
#include <IMaterialRenderer.h>
|
||||
#endif
|
||||
#include "settings.h"
|
||||
#include "log.h"
|
||||
#include "profiler.h"
|
||||
#include "nodedef.h"
|
||||
#include "gamedef.h"
|
||||
#ifndef SERVER
|
||||
#include "client.h"
|
||||
#include "mapblock_mesh.h"
|
||||
#include <IMaterialRenderer.h>
|
||||
#endif
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@ -3676,7 +3675,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
*/
|
||||
int time1 = time(0);
|
||||
|
||||
//u32 daynight_ratio = m_client->getDayNightRatio();
|
||||
/*
|
||||
Get animation parameters
|
||||
*/
|
||||
float animation_time = m_client->getAnimationTime();
|
||||
int crack = m_client->getCrackLevel();
|
||||
u32 daynight_ratio = m_client->getDayNightRatio();
|
||||
|
||||
m_camera_mutex.Lock();
|
||||
v3f camera_position = m_camera_position;
|
||||
@ -3709,8 +3713,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
u32 vertex_count = 0;
|
||||
u32 meshbuffer_count = 0;
|
||||
|
||||
// For limiting number of mesh updates per frame
|
||||
u32 mesh_update_count = 0;
|
||||
// For limiting number of mesh animations per frame
|
||||
u32 mesh_animate_count = 0;
|
||||
u32 mesh_animate_count_far = 0;
|
||||
|
||||
// Number of blocks in rendering range
|
||||
u32 blocks_in_range = 0;
|
||||
@ -3791,57 +3796,18 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
|
||||
blocks_in_range++;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
Update expired mesh (used for day/night change)
|
||||
|
||||
It doesn't work exactly like it should now with the
|
||||
tasked mesh update but whatever.
|
||||
Ignore if mesh doesn't exist
|
||||
*/
|
||||
|
||||
bool mesh_expired = false;
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
//JMutexAutoLock lock(block->mesh_mutex);
|
||||
|
||||
mesh_expired = block->getMeshExpired();
|
||||
|
||||
// Mesh has not been expired and there is no mesh:
|
||||
// block has no content
|
||||
if(block->mesh == NULL && mesh_expired == false){
|
||||
if(block->mesh == NULL){
|
||||
blocks_in_range_without_mesh++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
f32 faraway = BS*50;
|
||||
//f32 faraway = m_control.wanted_range * BS;
|
||||
|
||||
/*
|
||||
This has to be done with the mesh_mutex unlocked
|
||||
*/
|
||||
// Pretty random but this should work somewhat nicely
|
||||
if(mesh_expired && (
|
||||
(mesh_update_count < 3
|
||||
&& (d < faraway || mesh_update_count < 2)
|
||||
)
|
||||
||
|
||||
(m_control.range_all && mesh_update_count < 20)
|
||||
)
|
||||
)
|
||||
/*if(mesh_expired && mesh_update_count < 6
|
||||
&& (d < faraway || mesh_update_count < 3))*/
|
||||
{
|
||||
mesh_update_count++;
|
||||
|
||||
// Mesh has been expired: generate new mesh
|
||||
//block->updateMesh(daynight_ratio);
|
||||
m_client->addUpdateMeshTask(block->getPos());
|
||||
|
||||
mesh_expired = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Occlusion culling
|
||||
*/
|
||||
@ -3883,27 +3849,40 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
// This block is in range. Reset usage timer.
|
||||
block->resetUsageTimer();
|
||||
|
||||
/*
|
||||
Ignore if mesh doesn't exist
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
|
||||
scene::SMesh *mesh = block->mesh;
|
||||
|
||||
if(mesh == NULL){
|
||||
blocks_in_range_without_mesh++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Limit block count in case of a sudden increase
|
||||
blocks_would_have_drawn++;
|
||||
if(blocks_drawn >= m_control.wanted_max_blocks
|
||||
&& m_control.range_all == false
|
||||
&& d > m_control.wanted_min_range * BS)
|
||||
continue;
|
||||
|
||||
|
||||
// Mesh animation
|
||||
{
|
||||
//JMutexAutoLock lock(block->mesh_mutex);
|
||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||
// Pretty random but this should work somewhat nicely
|
||||
bool faraway = d >= BS*50;
|
||||
//bool faraway = d >= m_control.wanted_range * BS;
|
||||
if(mapBlockMesh->isAnimationForced() ||
|
||||
!faraway ||
|
||||
mesh_animate_count_far < (m_control.range_all ? 200 : 50))
|
||||
{
|
||||
bool animated = mapBlockMesh->animate(
|
||||
faraway,
|
||||
animation_time,
|
||||
crack,
|
||||
daynight_ratio);
|
||||
if(animated)
|
||||
mesh_animate_count++;
|
||||
if(animated && faraway)
|
||||
mesh_animate_count_far++;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapBlockMesh->decreaseAnimationForceTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Add to set
|
||||
drawset[block->getPos()] = block;
|
||||
|
||||
@ -3951,11 +3930,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
Draw the faces of the block
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
//JMutexAutoLock lock(block->mesh_mutex);
|
||||
|
||||
scene::SMesh *mesh = block->mesh;
|
||||
MapBlockMesh *mapBlockMesh = block->mesh;
|
||||
assert(mapBlockMesh);
|
||||
|
||||
scene::SMesh *mesh = mapBlockMesh->getMesh();
|
||||
assert(mesh);
|
||||
|
||||
|
||||
u32 c = mesh->getMeshBufferCount();
|
||||
bool stuff_actually_drawn = false;
|
||||
for(u32 i=0; i<c; i++)
|
||||
@ -3999,6 +3981,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
||||
g_profiler->avg("CM: blocks in range without mesh (frac)",
|
||||
(float)blocks_in_range_without_mesh/blocks_in_range);
|
||||
g_profiler->avg("CM: blocks drawn", blocks_drawn);
|
||||
g_profiler->avg("CM: animated meshes", mesh_animate_count);
|
||||
g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
|
||||
}
|
||||
|
||||
g_profiler->avg(prefix+"vertices drawn", vertex_count);
|
||||
@ -4047,205 +4031,6 @@ void ClientMap::renderPostFx()
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
|
||||
core::map<v3s16, MapBlock*> *affected_blocks)
|
||||
{
|
||||
bool changed = false;
|
||||
/*
|
||||
Add it to all blocks touching it
|
||||
*/
|
||||
v3s16 dirs[7] = {
|
||||
v3s16(0,0,0), // this
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(0,-1,0), // bottom
|
||||
v3s16(-1,0,0), // left
|
||||
};
|
||||
for(u16 i=0; i<7; i++)
|
||||
{
|
||||
v3s16 p2 = p + dirs[i];
|
||||
// Block position of neighbor (or requested) node
|
||||
v3s16 blockpos = getNodeBlockPos(p2);
|
||||
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||
if(blockref == NULL)
|
||||
continue;
|
||||
// Relative position of requested node
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
if(blockref->setTempMod(relpos, mod))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed && affected_blocks!=NULL)
|
||||
{
|
||||
for(u16 i=0; i<7; i++)
|
||||
{
|
||||
v3s16 p2 = p + dirs[i];
|
||||
// Block position of neighbor (or requested) node
|
||||
v3s16 blockpos = getNodeBlockPos(p2);
|
||||
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||
if(blockref == NULL)
|
||||
continue;
|
||||
affected_blocks->insert(blockpos, blockref);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool ClientMap::clearTempMod(v3s16 p,
|
||||
core::map<v3s16, MapBlock*> *affected_blocks)
|
||||
{
|
||||
bool changed = false;
|
||||
v3s16 dirs[7] = {
|
||||
v3s16(0,0,0), // this
|
||||
v3s16(0,0,1), // back
|
||||
v3s16(0,1,0), // top
|
||||
v3s16(1,0,0), // right
|
||||
v3s16(0,0,-1), // front
|
||||
v3s16(0,-1,0), // bottom
|
||||
v3s16(-1,0,0), // left
|
||||
};
|
||||
for(u16 i=0; i<7; i++)
|
||||
{
|
||||
v3s16 p2 = p + dirs[i];
|
||||
// Block position of neighbor (or requested) node
|
||||
v3s16 blockpos = getNodeBlockPos(p2);
|
||||
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||
if(blockref == NULL)
|
||||
continue;
|
||||
// Relative position of requested node
|
||||
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
|
||||
if(blockref->clearTempMod(relpos))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if(changed && affected_blocks!=NULL)
|
||||
{
|
||||
for(u16 i=0; i<7; i++)
|
||||
{
|
||||
v3s16 p2 = p + dirs[i];
|
||||
// Block position of neighbor (or requested) node
|
||||
v3s16 blockpos = getNodeBlockPos(p2);
|
||||
MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
|
||||
if(blockref == NULL)
|
||||
continue;
|
||||
affected_blocks->insert(blockpos, blockref);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void ClientMap::expireMeshes(bool only_daynight_diffed)
|
||||
{
|
||||
TimeTaker timer("expireMeshes()");
|
||||
|
||||
core::map<v2s16, MapSector*>::Iterator si;
|
||||
si = m_sectors.getIterator();
|
||||
for(; si.atEnd() == false; si++)
|
||||
{
|
||||
MapSector *sector = si.getNode()->getValue();
|
||||
|
||||
core::list< MapBlock * > sectorblocks;
|
||||
sector->getBlocks(sectorblocks);
|
||||
|
||||
core::list< MapBlock * >::Iterator i;
|
||||
for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
|
||||
{
|
||||
MapBlock *block = *i;
|
||||
|
||||
if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
JMutexAutoLock lock(block->mesh_mutex);
|
||||
if(block->mesh != NULL)
|
||||
{
|
||||
/*block->mesh->drop();
|
||||
block->mesh = NULL;*/
|
||||
block->setMeshExpired(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
|
||||
{
|
||||
assert(mapType() == MAPTYPE_CLIENT);
|
||||
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
//b->setMeshExpired(true);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
// Leading edge
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(-1,0,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
//b->setMeshExpired(true);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,-1,0);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
//b->setMeshExpired(true);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
try{
|
||||
v3s16 p = blockpos + v3s16(0,0,-1);
|
||||
MapBlock *b = getBlockNoCreate(p);
|
||||
b->updateMesh(daynight_ratio);
|
||||
//b->setMeshExpired(true);
|
||||
}
|
||||
catch(InvalidPositionException &e){}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Update mesh of block in which the node is, and if the node is at the
|
||||
leading edge, update the appropriate leading blocks too.
|
||||
*/
|
||||
void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
|
||||
{
|
||||
v3s16 dirs[4] = {
|
||||
v3s16(0,0,0),
|
||||
v3s16(-1,0,0),
|
||||
v3s16(0,-1,0),
|
||||
v3s16(0,0,-1),
|
||||
};
|
||||
v3s16 blockposes[4];
|
||||
for(u32 i=0; i<4; i++)
|
||||
{
|
||||
v3s16 np = nodepos + dirs[i];
|
||||
blockposes[i] = getNodeBlockPos(np);
|
||||
// Don't update mesh of block if it has been done already
|
||||
bool already_updated = false;
|
||||
for(u32 j=0; j<i; j++)
|
||||
{
|
||||
if(blockposes[j] == blockposes[i])
|
||||
{
|
||||
already_updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(already_updated)
|
||||
continue;
|
||||
// Update mesh
|
||||
MapBlock *b = getBlockNoCreate(blockposes[i]);
|
||||
b->updateMesh(daynight_ratio);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ClientMap::PrintInfo(std::ostream &out)
|
||||
{
|
||||
out<<"ClientMap: ";
|
||||
|
28
src/map.h
28
src/map.h
@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapnode.h"
|
||||
#include "mapblock_nodemod.h"
|
||||
#include "constants.h"
|
||||
#include "voxel.h"
|
||||
#include "utility.h" // Needed for UniqueQueue, a member of Map
|
||||
@ -570,33 +569,6 @@ public:
|
||||
|
||||
void renderPostFx();
|
||||
|
||||
/*
|
||||
Methods for setting temporary modifications to nodes for
|
||||
drawing.
|
||||
|
||||
Returns true if something changed.
|
||||
|
||||
All blocks whose mesh could have been changed are inserted
|
||||
to affected_blocks.
|
||||
*/
|
||||
bool setTempMod(v3s16 p, NodeMod mod,
|
||||
core::map<v3s16, MapBlock*> *affected_blocks=NULL);
|
||||
bool clearTempMod(v3s16 p,
|
||||
core::map<v3s16, MapBlock*> *affected_blocks=NULL);
|
||||
// Efficient implementation needs a cache of TempMods
|
||||
//void clearTempMods();
|
||||
|
||||
void expireMeshes(bool only_daynight_diffed);
|
||||
|
||||
/*
|
||||
Update the faces of the given block and blocks on the
|
||||
leading edge, without threading. Rarely used.
|
||||
*/
|
||||
void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
|
||||
|
||||
// Update meshes that touch the node
|
||||
//void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
|
||||
|
||||
// For debug printing
|
||||
virtual void PrintInfo(std::ostream &out);
|
||||
|
||||
|
@ -59,10 +59,8 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
|
||||
reallocate();
|
||||
|
||||
#ifndef SERVER
|
||||
m_mesh_expired = false;
|
||||
mesh_mutex.Init();
|
||||
//mesh_mutex.Init();
|
||||
mesh = NULL;
|
||||
m_temp_mods_mutex.Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -70,11 +68,11 @@ MapBlock::~MapBlock()
|
||||
{
|
||||
#ifndef SERVER
|
||||
{
|
||||
JMutexAutoLock lock(mesh_mutex);
|
||||
//JMutexAutoLock lock(mesh_mutex);
|
||||
|
||||
if(mesh)
|
||||
{
|
||||
mesh->drop();
|
||||
delete mesh;
|
||||
mesh = NULL;
|
||||
}
|
||||
}
|
||||
@ -147,78 +145,6 @@ MapNode MapBlock::getNodeParentNoEx(v3s16 p)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
#if 1
|
||||
void MapBlock::updateMesh(u32 daynight_ratio)
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
DEBUG: If mesh has been generated, don't generate it again
|
||||
*/
|
||||
{
|
||||
JMutexAutoLock meshlock(mesh_mutex);
|
||||
if(mesh != NULL)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
MeshMakeData data;
|
||||
data.fill(daynight_ratio, this);
|
||||
|
||||
scene::SMesh *mesh_new = makeMapBlockMesh(&data, m_gamedef);
|
||||
|
||||
/*
|
||||
Replace the mesh
|
||||
*/
|
||||
|
||||
replaceMesh(mesh_new);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void MapBlock::replaceMesh(scene::SMesh *mesh_new)
|
||||
{
|
||||
mesh_mutex.Lock();
|
||||
|
||||
//scene::SMesh *mesh_old = mesh[daynight_i];
|
||||
//mesh[daynight_i] = mesh_new;
|
||||
|
||||
scene::SMesh *mesh_old = mesh;
|
||||
mesh = mesh_new;
|
||||
setMeshExpired(false);
|
||||
|
||||
if(mesh_old != NULL)
|
||||
{
|
||||
// Remove hardware buffers of meshbuffers of mesh
|
||||
// NOTE: No way, this runs in a different thread and everything
|
||||
/*u32 c = mesh_old->getMeshBufferCount();
|
||||
for(u32 i=0; i<c; i++)
|
||||
{
|
||||
IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
|
||||
}*/
|
||||
|
||||
/*infostream<<"mesh_old->getReferenceCount()="
|
||||
<<mesh_old->getReferenceCount()<<std::endl;
|
||||
u32 c = mesh_old->getMeshBufferCount();
|
||||
for(u32 i=0; i<c; i++)
|
||||
{
|
||||
scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
|
||||
infostream<<"buf->getReferenceCount()="
|
||||
<<buf->getReferenceCount()<<std::endl;
|
||||
}*/
|
||||
|
||||
// Drop the mesh
|
||||
mesh_old->drop();
|
||||
|
||||
//delete mesh_old;
|
||||
}
|
||||
|
||||
mesh_mutex.Unlock();
|
||||
}
|
||||
|
||||
#endif // !SERVER
|
||||
|
||||
/*
|
||||
Propagates sunlight down through the block.
|
||||
Doesn't modify nodes that are not affected by sunlight.
|
||||
@ -1232,13 +1158,6 @@ std::string analyze_block(MapBlock *block)
|
||||
else
|
||||
desc<<"is_ug [ ], ";
|
||||
|
||||
#ifndef SERVER
|
||||
if(block->getMeshExpired())
|
||||
desc<<"mesh_exp [X], ";
|
||||
else
|
||||
desc<<"mesh_exp [ ], ";
|
||||
#endif
|
||||
|
||||
if(block->getLightingExpired())
|
||||
desc<<"lighting_exp [X], ";
|
||||
else
|
||||
|
109
src/mapblock.h
109
src/mapblock.h
@ -31,13 +31,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "constants.h"
|
||||
#include "voxel.h"
|
||||
#include "staticobject.h"
|
||||
#include "mapblock_nodemod.h"
|
||||
#include "modifiedstate.h"
|
||||
|
||||
class Map;
|
||||
class NodeMetadataList;
|
||||
class IGameDef;
|
||||
class IWritableNodeDefManager;
|
||||
class MapBlockMesh;
|
||||
|
||||
#define BLOCK_TIMESTAMP_UNDEFINED 0xffffffff
|
||||
|
||||
@ -193,18 +192,6 @@ public:
|
||||
raiseModified(MOD_STATE_WRITE_NEEDED, "setIsUnderground");
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
void setMeshExpired(bool expired)
|
||||
{
|
||||
m_mesh_expired = expired;
|
||||
}
|
||||
|
||||
bool getMeshExpired()
|
||||
{
|
||||
return m_mesh_expired;
|
||||
}
|
||||
#endif
|
||||
|
||||
void setLightingExpired(bool expired)
|
||||
{
|
||||
if(expired != m_lighting_expired){
|
||||
@ -359,33 +346,6 @@ public:
|
||||
setNode(x0+x, y0+y, z0+z, node);
|
||||
}
|
||||
|
||||
/*
|
||||
Graphics-related methods
|
||||
*/
|
||||
|
||||
#ifndef SERVER // Only on client
|
||||
|
||||
u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir,
|
||||
INodeDefManager *nodemgr)
|
||||
{
|
||||
return getFaceLight(daynight_ratio,
|
||||
getNodeParentNoEx(p),
|
||||
getNodeParentNoEx(p + face_dir),
|
||||
face_dir, nodemgr);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/*
|
||||
Thread-safely updates the whole mesh of the mapblock.
|
||||
NOTE: Prefer generating the mesh separately and then using
|
||||
replaceMesh().
|
||||
*/
|
||||
void updateMesh(u32 daynight_ratio);
|
||||
#endif
|
||||
// Replace the mesh with a new one
|
||||
void replaceMesh(scene::SMesh *mesh_new);
|
||||
#endif
|
||||
|
||||
// See comments in mapblock.cpp
|
||||
bool propagateSunlight(core::map<v3s16, bool> & light_sources,
|
||||
bool remove_light=false, bool *black_air_left=NULL);
|
||||
@ -395,59 +355,10 @@ public:
|
||||
// Copies data from VoxelManipulator getPosRelative()
|
||||
void copyFrom(VoxelManipulator &dst);
|
||||
|
||||
#ifndef SERVER // Only on client
|
||||
/*
|
||||
Methods for setting temporary modifications to nodes for
|
||||
drawing
|
||||
|
||||
returns true if the mod was different last time
|
||||
*/
|
||||
bool setTempMod(v3s16 p, const NodeMod &mod)
|
||||
{
|
||||
/*dstream<<"setTempMod called on block"
|
||||
<<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
|
||||
<<", mod.type="<<mod.type
|
||||
<<", mod.param="<<mod.param
|
||||
<<std::endl;*/
|
||||
JMutexAutoLock lock(m_temp_mods_mutex);
|
||||
|
||||
return m_temp_mods.set(p, mod);
|
||||
}
|
||||
// Returns true if there was one
|
||||
bool getTempMod(v3s16 p, NodeMod *mod)
|
||||
{
|
||||
JMutexAutoLock lock(m_temp_mods_mutex);
|
||||
|
||||
return m_temp_mods.get(p, mod);
|
||||
}
|
||||
bool clearTempMod(v3s16 p)
|
||||
{
|
||||
JMutexAutoLock lock(m_temp_mods_mutex);
|
||||
|
||||
return m_temp_mods.clear(p);
|
||||
}
|
||||
bool clearTempMods()
|
||||
{
|
||||
JMutexAutoLock lock(m_temp_mods_mutex);
|
||||
|
||||
return m_temp_mods.clear();
|
||||
}
|
||||
void copyTempMods(NodeModMap &dst)
|
||||
{
|
||||
JMutexAutoLock lock(m_temp_mods_mutex);
|
||||
m_temp_mods.copy(dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Update day-night lighting difference flag.
|
||||
|
||||
Sets m_day_night_differs to appropriate value.
|
||||
|
||||
These methods don't care about neighboring blocks.
|
||||
It means that to know if a block really doesn't need a mesh
|
||||
update between day and night, the neighboring blocks have
|
||||
to be taken into account. Use Map::dayNightDiffed().
|
||||
*/
|
||||
void updateDayNightDiff();
|
||||
|
||||
@ -551,8 +462,8 @@ public:
|
||||
*/
|
||||
|
||||
#ifndef SERVER // Only on client
|
||||
scene::SMesh *mesh;
|
||||
JMutex mesh_mutex;
|
||||
MapBlockMesh *mesh;
|
||||
//JMutex mesh_mutex;
|
||||
#endif
|
||||
|
||||
NodeMetadataList *m_node_metadata;
|
||||
@ -609,20 +520,6 @@ private:
|
||||
|
||||
bool m_generated;
|
||||
|
||||
#ifndef SERVER // Only on client
|
||||
/*
|
||||
Set to true if the mesh has been ordered to be updated
|
||||
sometime in the background.
|
||||
In practice this is set when the day/night lighting switches.
|
||||
*/
|
||||
bool m_mesh_expired;
|
||||
|
||||
// Temporary modifications to nodes
|
||||
// These are only used when drawing
|
||||
NodeModMap m_temp_mods;
|
||||
JMutex m_temp_mods_mutex;
|
||||
#endif
|
||||
|
||||
/*
|
||||
When block is removed from active blocks, this is set to gametime.
|
||||
Value BLOCK_TIMESTAMP_UNDEFINED=0xffffffff means there is no timestamp.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,9 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define MAPBLOCK_MESH_HEADER
|
||||
|
||||
#include "common_irrlicht.h"
|
||||
#include "mapblock_nodemod.h"
|
||||
#include "tile.h"
|
||||
#include "voxel.h"
|
||||
#include <map>
|
||||
|
||||
class IGameDef;
|
||||
|
||||
@ -31,127 +31,143 @@ class IGameDef;
|
||||
Mesh making stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
This is used because CMeshBuffer::append() is very slow
|
||||
*/
|
||||
struct PreMeshBuffer
|
||||
{
|
||||
video::SMaterial material;
|
||||
core::array<u16> indices;
|
||||
core::array<video::S3DVertex> vertices;
|
||||
};
|
||||
|
||||
class MeshCollector
|
||||
{
|
||||
public:
|
||||
void append(
|
||||
video::SMaterial material,
|
||||
const video::S3DVertex* const vertices,
|
||||
u32 numVertices,
|
||||
const u16* const indices,
|
||||
u32 numIndices
|
||||
)
|
||||
{
|
||||
PreMeshBuffer *p = NULL;
|
||||
for(u32 i=0; i<m_prebuffers.size(); i++)
|
||||
{
|
||||
PreMeshBuffer &pp = m_prebuffers[i];
|
||||
if(pp.material != material)
|
||||
continue;
|
||||
|
||||
p = &pp;
|
||||
break;
|
||||
}
|
||||
|
||||
if(p == NULL)
|
||||
{
|
||||
PreMeshBuffer pp;
|
||||
pp.material = material;
|
||||
m_prebuffers.push_back(pp);
|
||||
p = &m_prebuffers[m_prebuffers.size()-1];
|
||||
}
|
||||
|
||||
u32 vertex_count = p->vertices.size();
|
||||
for(u32 i=0; i<numIndices; i++)
|
||||
{
|
||||
u32 j = indices[i] + vertex_count;
|
||||
if(j > 65535)
|
||||
{
|
||||
dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
|
||||
// NOTE: Fix is to just add an another MeshBuffer
|
||||
}
|
||||
p->indices.push_back(j);
|
||||
}
|
||||
for(u32 i=0; i<numVertices; i++)
|
||||
{
|
||||
p->vertices.push_back(vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void fillMesh(scene::SMesh *mesh)
|
||||
{
|
||||
/*dstream<<"Filling mesh with "<<m_prebuffers.size()
|
||||
<<" meshbuffers"<<std::endl;*/
|
||||
for(u32 i=0; i<m_prebuffers.size(); i++)
|
||||
{
|
||||
PreMeshBuffer &p = m_prebuffers[i];
|
||||
|
||||
/*dstream<<"p.vertices.size()="<<p.vertices.size()
|
||||
<<", p.indices.size()="<<p.indices.size()
|
||||
<<std::endl;*/
|
||||
|
||||
// Create meshbuffer
|
||||
|
||||
// This is a "Standard MeshBuffer",
|
||||
// it's a typedeffed CMeshBuffer<video::S3DVertex>
|
||||
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
// Set material
|
||||
buf->Material = p.material;
|
||||
//((scene::SMeshBuffer*)buf)->Material = p.material;
|
||||
// Use VBO
|
||||
//buf->setHardwareMappingHint(scene::EHM_STATIC);
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
// Mesh grabbed it
|
||||
buf->drop();
|
||||
|
||||
buf->append(p.vertices.pointer(), p.vertices.size(),
|
||||
p.indices.pointer(), p.indices.size());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
core::array<PreMeshBuffer> m_prebuffers;
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
video::SColor MapBlock_LightColor(u8 alpha, u8 light);
|
||||
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
|
||||
NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef);
|
||||
|
||||
class MapBlock;
|
||||
|
||||
struct MeshMakeData
|
||||
{
|
||||
u32 m_daynight_ratio;
|
||||
NodeModMap m_temp_mods;
|
||||
VoxelManipulator m_vmanip;
|
||||
v3s16 m_blockpos;
|
||||
|
||||
v3s16 m_crack_pos_relative;
|
||||
bool m_smooth_lighting;
|
||||
IGameDef *m_gamedef;
|
||||
|
||||
MeshMakeData(IGameDef *gamedef);
|
||||
|
||||
/*
|
||||
Copy central data directly from block, and other data from
|
||||
parent of block.
|
||||
*/
|
||||
void fill(u32 daynight_ratio, MapBlock *block);
|
||||
void fill(MapBlock *block);
|
||||
|
||||
/*
|
||||
Set up with only a single node at (1,1,1)
|
||||
*/
|
||||
void fillSingleNode(u32 daynight_ratio, MapNode *node);
|
||||
void fillSingleNode(MapNode *node);
|
||||
|
||||
/*
|
||||
Set the (node) position of a crack
|
||||
*/
|
||||
void setCrack(int crack_level, v3s16 crack_pos);
|
||||
|
||||
/*
|
||||
Enable or disable smooth lighting
|
||||
*/
|
||||
void setSmoothLighting(bool smooth_lighting);
|
||||
};
|
||||
|
||||
// This is the highest-level function in here
|
||||
scene::SMesh* makeMapBlockMesh(MeshMakeData *data, IGameDef *gamedef);
|
||||
/*
|
||||
Holds a mesh for a mapblock.
|
||||
|
||||
Besides the SMesh*, this contains information used for animating
|
||||
the vertex positions, colors and texture coordinates of the mesh.
|
||||
For example:
|
||||
- cracks [implemented]
|
||||
- day/night transitions [implemented]
|
||||
- animated flowing liquids [not implemented]
|
||||
- animating vertex positions for e.g. axles [not implemented]
|
||||
*/
|
||||
class MapBlockMesh
|
||||
{
|
||||
public:
|
||||
// Builds the mesh given
|
||||
MapBlockMesh(MeshMakeData *data);
|
||||
~MapBlockMesh();
|
||||
|
||||
// Main animation function, parameters:
|
||||
// faraway: whether the block is far away from the camera (~50 nodes)
|
||||
// time: the global animation time, 0 .. 60 (repeats every minute)
|
||||
// daynight_ratio: 0 .. 1000
|
||||
// crack: -1 .. CRACK_ANIMATION_LENGTH-1 (-1 for off)
|
||||
// Returns true if anything has been changed.
|
||||
bool animate(bool faraway, float time, int crack, u32 daynight_ratio);
|
||||
|
||||
scene::SMesh* getMesh()
|
||||
{
|
||||
return m_mesh;
|
||||
}
|
||||
|
||||
bool isAnimationForced() const
|
||||
{
|
||||
return m_animation_force_timer == 0;
|
||||
}
|
||||
|
||||
void decreaseAnimationForceTimer()
|
||||
{
|
||||
if(m_animation_force_timer > 0)
|
||||
m_animation_force_timer--;
|
||||
}
|
||||
|
||||
private:
|
||||
scene::SMesh *m_mesh;
|
||||
IGameDef *m_gamedef;
|
||||
|
||||
// Must animate() be called before rendering?
|
||||
bool m_has_animation;
|
||||
int m_animation_force_timer;
|
||||
|
||||
// Animation info: cracks
|
||||
// Last crack value passed to animate()
|
||||
int m_last_crack;
|
||||
// Maps mesh buffer (i.e. material) indices to base texture names
|
||||
std::map<u32, std::string> m_crack_materials;
|
||||
|
||||
// Animation info: day/night transitions
|
||||
// Last daynight_ratio value passed to animate()
|
||||
u32 m_last_daynight_ratio;
|
||||
// For each meshbuffer, maps vertex indices to (day,night) pairs
|
||||
std::map<u32, std::map<u32, std::pair<u8, u8> > > m_daynight_diffs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
This is used because CMeshBuffer::append() is very slow
|
||||
*/
|
||||
struct PreMeshBuffer
|
||||
{
|
||||
TileSpec tile;
|
||||
core::array<u16> indices;
|
||||
core::array<video::S3DVertex> vertices;
|
||||
};
|
||||
|
||||
struct MeshCollector
|
||||
{
|
||||
core::array<PreMeshBuffer> prebuffers;
|
||||
|
||||
void append(const TileSpec &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices);
|
||||
};
|
||||
|
||||
// This encodes
|
||||
// alpha in the A channel of the returned SColor
|
||||
// day light (0-255) in the R channel of the returned SColor
|
||||
// night light (0-255) in the G channel of the returned SColor
|
||||
inline video::SColor MapBlock_LightColor(u8 alpha, u16 light)
|
||||
{
|
||||
return video::SColor(alpha, (light & 0xff), (light >> 8), 0);
|
||||
}
|
||||
|
||||
// Compute light at node
|
||||
u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data);
|
||||
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data);
|
||||
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
|
||||
|
||||
// Retrieves the TileSpec of a face of a node
|
||||
// Adds MATERIAL_FLAG_CRACK if the node is cracked
|
||||
TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data);
|
||||
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
Minetest-c55
|
||||
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MAPBLOCK_NODEMOD_HEADER
|
||||
#define MAPBLOCK_NODEMOD_HEADER
|
||||
|
||||
enum NodeModType
|
||||
{
|
||||
NODEMOD_NONE,
|
||||
NODEMOD_CHANGECONTENT, //param is content id
|
||||
NODEMOD_CRACK // param is crack progression
|
||||
};
|
||||
|
||||
struct NodeMod
|
||||
{
|
||||
NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
|
||||
{
|
||||
type = a_type;
|
||||
param = a_param;
|
||||
}
|
||||
bool operator==(const NodeMod &other)
|
||||
{
|
||||
return (type == other.type && param == other.param);
|
||||
}
|
||||
enum NodeModType type;
|
||||
u16 param;
|
||||
};
|
||||
|
||||
class NodeModMap
|
||||
{
|
||||
public:
|
||||
/*
|
||||
returns true if the mod was different last time
|
||||
*/
|
||||
bool set(v3s16 p, const NodeMod &mod)
|
||||
{
|
||||
// See if old is different, cancel if it is not different.
|
||||
core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
|
||||
if(n)
|
||||
{
|
||||
NodeMod old = n->getValue();
|
||||
if(old == mod)
|
||||
return false;
|
||||
|
||||
n->setValue(mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mods.insert(p, mod);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Returns true if there was one
|
||||
bool get(v3s16 p, NodeMod *mod)
|
||||
{
|
||||
core::map<v3s16, NodeMod>::Node *n;
|
||||
n = m_mods.find(p);
|
||||
if(n == NULL)
|
||||
return false;
|
||||
if(mod)
|
||||
*mod = n->getValue();
|
||||
return true;
|
||||
}
|
||||
bool clear(v3s16 p)
|
||||
{
|
||||
if(m_mods.find(p))
|
||||
{
|
||||
m_mods.remove(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool clear()
|
||||
{
|
||||
if(m_mods.size() == 0)
|
||||
return false;
|
||||
m_mods.clear();
|
||||
return true;
|
||||
}
|
||||
void copy(NodeModMap &dest)
|
||||
{
|
||||
dest.m_mods.clear();
|
||||
|
||||
for(core::map<v3s16, NodeMod>::Iterator
|
||||
i = m_mods.getIterator();
|
||||
i.atEnd() == false; i++)
|
||||
{
|
||||
dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
core::map<v3s16, NodeMod> m_mods;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
112
src/mapnode.cpp
112
src/mapnode.cpp
@ -353,115 +353,3 @@ void MapNode::deSerialize_pre22(u8 *source, u8 version)
|
||||
// Translate to our known version
|
||||
*this = mapnode_translate_to_internal(*this, version);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
/*
|
||||
Nodes make a face if contents differ and solidness differs.
|
||||
Return value:
|
||||
0: No face
|
||||
1: Face uses m1's content
|
||||
2: Face uses m2's content
|
||||
equivalent: Whether the blocks share the same face (eg. water and glass)
|
||||
|
||||
TODO: Add 3: Both faces drawn with backface culling, remove equivalent
|
||||
*/
|
||||
u8 face_contents(content_t m1, content_t m2, bool *equivalent,
|
||||
INodeDefManager *nodemgr)
|
||||
{
|
||||
*equivalent = false;
|
||||
|
||||
if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
|
||||
return 0;
|
||||
|
||||
bool contents_differ = (m1 != m2);
|
||||
|
||||
const ContentFeatures &f1 = nodemgr->get(m1);
|
||||
const ContentFeatures &f2 = nodemgr->get(m2);
|
||||
|
||||
// Contents don't differ for different forms of same liquid
|
||||
if(f1.sameLiquid(f2))
|
||||
contents_differ = false;
|
||||
|
||||
u8 c1 = f1.solidness;
|
||||
u8 c2 = f2.solidness;
|
||||
|
||||
bool solidness_differs = (c1 != c2);
|
||||
bool makes_face = contents_differ && solidness_differs;
|
||||
|
||||
if(makes_face == false)
|
||||
return 0;
|
||||
|
||||
if(c1 == 0)
|
||||
c1 = f1.visual_solidness;
|
||||
if(c2 == 0)
|
||||
c2 = f2.visual_solidness;
|
||||
|
||||
if(c1 == c2){
|
||||
*equivalent = true;
|
||||
// If same solidness, liquid takes precense
|
||||
if(f1.isLiquid())
|
||||
return 1;
|
||||
if(f2.isLiquid())
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(c1 > c2)
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
Gets lighting value at face of node
|
||||
|
||||
Parameters must consist of air and !air.
|
||||
Order doesn't matter.
|
||||
|
||||
If either of the nodes doesn't exist, light is 0.
|
||||
|
||||
parameters:
|
||||
daynight_ratio: 0...1000
|
||||
n: getNode(p) (uses only the lighting value)
|
||||
n2: getNode(p + face_dir) (uses only the lighting value)
|
||||
face_dir: axis oriented unit vector from p to p2
|
||||
|
||||
returns encoded light value.
|
||||
*/
|
||||
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
|
||||
v3s16 face_dir, INodeDefManager *nodemgr)
|
||||
{
|
||||
try{
|
||||
u8 light;
|
||||
u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
|
||||
u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
|
||||
if(l1 > l2)
|
||||
light = l1;
|
||||
else
|
||||
light = l2;
|
||||
|
||||
// Make some nice difference to different sides
|
||||
|
||||
// This makes light come from a corner
|
||||
/*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
|
||||
light = diminish_light(diminish_light(light));
|
||||
else if(face_dir.X == -1 || face_dir.Z == -1)
|
||||
light = diminish_light(light);*/
|
||||
|
||||
// All neighboring faces have different shade (like in minecraft)
|
||||
if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
|
||||
light = diminish_light(diminish_light(light));
|
||||
else if(face_dir.Z == 1 || face_dir.Z == -1)
|
||||
light = diminish_light(light);
|
||||
|
||||
return light;
|
||||
}
|
||||
catch(InvalidPositionException &e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -223,45 +223,5 @@ private:
|
||||
void deSerialize_pre22(u8 *source, u8 version);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
MapNode helpers for mesh making stuff
|
||||
*/
|
||||
|
||||
#ifndef SERVER
|
||||
|
||||
/*
|
||||
Nodes make a face if contents differ and solidness differs.
|
||||
Return value:
|
||||
0: No face
|
||||
1: Face uses m1's content
|
||||
2: Face uses m2's content
|
||||
equivalent: Whether the blocks share the same face (eg. water and glass)
|
||||
*/
|
||||
u8 face_contents(content_t m1, content_t m2, bool *equivalent,
|
||||
INodeDefManager *nodemgr);
|
||||
|
||||
/*
|
||||
Gets lighting value at face of node
|
||||
|
||||
Parameters must consist of air and !air.
|
||||
Order doesn't matter.
|
||||
|
||||
If either of the nodes doesn't exist, light is 0.
|
||||
|
||||
parameters:
|
||||
daynight_ratio: 0...1000
|
||||
n: getNode(p) (uses only the lighting value)
|
||||
n2: getNode(p + face_dir) (uses only the lighting value)
|
||||
face_dir: axis oriented unit vector from p to p2
|
||||
|
||||
returns encoded light value.
|
||||
*/
|
||||
u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
|
||||
v3s16 face_dir, INodeDefManager *nodemgr);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -89,12 +89,6 @@ ContentFeatures::ContentFeatures()
|
||||
|
||||
ContentFeatures::~ContentFeatures()
|
||||
{
|
||||
#ifndef SERVER
|
||||
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
|
||||
delete special_materials[j];
|
||||
delete special_aps[j];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ContentFeatures::reset()
|
||||
@ -103,10 +97,6 @@ void ContentFeatures::reset()
|
||||
Cached stuff
|
||||
*/
|
||||
#ifndef SERVER
|
||||
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
|
||||
special_materials[j] = NULL;
|
||||
special_aps[j] = NULL;
|
||||
}
|
||||
solidness = 2;
|
||||
visual_solidness = 0;
|
||||
backface_culling = true;
|
||||
@ -526,38 +516,21 @@ public:
|
||||
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
else
|
||||
f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
f->tiles[j].material_flags = 0;
|
||||
if(f->backface_culling)
|
||||
f->tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
else
|
||||
f->tiles[j].material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
}
|
||||
// Special textures
|
||||
// Special tiles
|
||||
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
|
||||
// Remove all stuff
|
||||
if(f->special_aps[j]){
|
||||
delete f->special_aps[j];
|
||||
f->special_aps[j] = NULL;
|
||||
}
|
||||
if(f->special_materials[j]){
|
||||
delete f->special_materials[j];
|
||||
f->special_materials[j] = NULL;
|
||||
}
|
||||
// Skip if should not exist
|
||||
if(f->mspec_special[j].tname == "")
|
||||
continue;
|
||||
// Create all stuff
|
||||
f->special_aps[j] = new AtlasPointer(
|
||||
tsrc->getTexture(f->mspec_special[j].tname));
|
||||
f->special_materials[j] = new video::SMaterial;
|
||||
f->special_materials[j]->setFlag(video::EMF_LIGHTING, false);
|
||||
f->special_materials[j]->setFlag(video::EMF_BACK_FACE_CULLING,
|
||||
f->mspec_special[j].backface_culling);
|
||||
f->special_materials[j]->setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
f->special_materials[j]->setFlag(video::EMF_FOG_ENABLE, true);
|
||||
f->special_materials[j]->setTexture(0, f->special_aps[j]->atlas);
|
||||
if(f->alpha != 255)
|
||||
f->special_materials[j]->MaterialType =
|
||||
video::EMT_TRANSPARENT_VERTEX_ALPHA;
|
||||
f->special_tiles[j].texture = tsrc->getTexture(f->mspec_special[j].tname);
|
||||
f->special_tiles[j].alpha = f->alpha;
|
||||
if(f->alpha == 255)
|
||||
f->special_tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
|
||||
else
|
||||
f->special_tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
|
||||
f->special_tiles[j].material_flags = 0;
|
||||
if(f->mspec_special[j].backface_culling)
|
||||
f->special_tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -135,10 +135,9 @@ struct ContentFeatures
|
||||
// 0 1 2 3 4 5
|
||||
// up down right left back front
|
||||
TileSpec tiles[6];
|
||||
// Special material/texture
|
||||
// Special tiles
|
||||
// - Currently used for flowing liquids
|
||||
video::SMaterial *special_materials[CF_SPECIAL_COUNT];
|
||||
AtlasPointer *special_aps[CF_SPECIAL_COUNT];
|
||||
TileSpec special_tiles[CF_SPECIAL_COUNT];
|
||||
u8 solidness; // Used when choosing which face is drawn
|
||||
u8 visual_solidness; // When solidness=0, this tells how it looks like
|
||||
bool backface_culling;
|
||||
|
152
src/tile.cpp
152
src/tile.cpp
@ -279,12 +279,14 @@ public:
|
||||
Example case #2:
|
||||
- Assume a texture with the id 1 exists, and has the name
|
||||
"stone.png^mineral1" and is specified as a part of some atlas.
|
||||
- Now MapBlock::getNodeTile() stumbles upon a node which uses
|
||||
texture id 1, and finds out that NODEMOD_CRACK must be applied
|
||||
with progression=0
|
||||
- It finds out the name of the texture with getTextureName(1),
|
||||
- Now getNodeTile() stumbles upon a node which uses
|
||||
texture id 1, and determines that MATERIAL_FLAG_CRACK
|
||||
must be applied to the tile
|
||||
- MapBlockMesh::animate() finds the MATERIAL_FLAG_CRACK and
|
||||
has received the current crack level 0 from the client. It
|
||||
finds out the name of the texture with getTextureName(1),
|
||||
appends "^crack0" to it and gets a new texture id with
|
||||
getTextureId("stone.png^mineral1^crack0")
|
||||
getTextureId("stone.png^mineral1^crack0").
|
||||
|
||||
*/
|
||||
|
||||
@ -337,6 +339,12 @@ public:
|
||||
return ap.atlas;
|
||||
}
|
||||
|
||||
// Gets a separate texture atlas pointer
|
||||
AtlasPointer getTextureRawAP(const AtlasPointer &ap)
|
||||
{
|
||||
return getTexture(getTextureName(ap.id) + "^[forcesingle");
|
||||
}
|
||||
|
||||
// Returns a pointer to the irrlicht device
|
||||
virtual IrrlichtDevice* getDevice()
|
||||
{
|
||||
@ -475,6 +483,9 @@ u32 TextureSource::getTextureId(const std::string &name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Overlay image on top of another image (used for cracks)
|
||||
void overlay(video::IImage *image, video::IImage *overlay);
|
||||
|
||||
// Brighten image
|
||||
void brighten(video::IImage *image);
|
||||
|
||||
@ -1183,8 +1194,19 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Crack image number
|
||||
u16 progression = stoi(part_of_name.substr(6));
|
||||
// Crack image number and overlay option
|
||||
s32 progression = 0;
|
||||
bool use_overlay = false;
|
||||
if(part_of_name.substr(6,1) == "o")
|
||||
{
|
||||
progression = stoi(part_of_name.substr(7));
|
||||
use_overlay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
progression = stoi(part_of_name.substr(6));
|
||||
use_overlay = false;
|
||||
}
|
||||
|
||||
// Size of the base image
|
||||
core::dimension2d<u32> dim_base = baseimg->getDimension();
|
||||
@ -1197,65 +1219,56 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
*/
|
||||
video::IImage *img_crack = sourcecache->getOrLoad("crack.png", device);
|
||||
|
||||
if(img_crack)
|
||||
if(img_crack && progression >= 0)
|
||||
{
|
||||
// Dimension of original image
|
||||
core::dimension2d<u32> dim_crack
|
||||
= img_crack->getDimension();
|
||||
// Count of crack stages
|
||||
u32 crack_count = dim_crack.Height / dim_crack.Width;
|
||||
s32 crack_count = dim_crack.Height / dim_crack.Width;
|
||||
// Limit progression
|
||||
if(progression > crack_count-1)
|
||||
progression = crack_count-1;
|
||||
// Dimension of a single scaled crack stage
|
||||
core::dimension2d<u32> dim_crack_scaled_single(
|
||||
dim_base.Width,
|
||||
dim_base.Height
|
||||
// Dimension of a single crack stage
|
||||
core::dimension2d<u32> dim_crack_cropped(
|
||||
dim_crack.Width,
|
||||
dim_crack.Width
|
||||
);
|
||||
// Dimension of scaled size
|
||||
core::dimension2d<u32> dim_crack_scaled(
|
||||
dim_crack_scaled_single.Width,
|
||||
dim_crack_scaled_single.Height * crack_count
|
||||
);
|
||||
// Create scaled crack image
|
||||
// Create cropped and scaled crack images
|
||||
video::IImage *img_crack_cropped = driver->createImage(
|
||||
video::ECF_A8R8G8B8, dim_crack_cropped);
|
||||
video::IImage *img_crack_scaled = driver->createImage(
|
||||
video::ECF_A8R8G8B8, dim_crack_scaled);
|
||||
if(img_crack_scaled)
|
||||
{
|
||||
// Scale crack image by copying
|
||||
img_crack->copyToScaling(img_crack_scaled);
|
||||
|
||||
// Position to copy the crack from
|
||||
core::position2d<s32> pos_crack_scaled(
|
||||
0,
|
||||
dim_crack_scaled_single.Height * progression
|
||||
);
|
||||
|
||||
// This tiling does nothing currently but is useful
|
||||
for(u32 y0=0; y0<dim_base.Height
|
||||
/ dim_crack_scaled_single.Height; y0++)
|
||||
for(u32 x0=0; x0<dim_base.Width
|
||||
/ dim_crack_scaled_single.Width; x0++)
|
||||
{
|
||||
// Position to copy the crack to in the base image
|
||||
core::position2d<s32> pos_base(
|
||||
x0*dim_crack_scaled_single.Width,
|
||||
y0*dim_crack_scaled_single.Height
|
||||
);
|
||||
// Rectangle to copy the crack from on the scaled image
|
||||
core::rect<s32> rect_crack_scaled(
|
||||
pos_crack_scaled,
|
||||
dim_crack_scaled_single
|
||||
);
|
||||
// Copy it
|
||||
img_crack_scaled->copyToWithAlpha(baseimg, pos_base,
|
||||
rect_crack_scaled,
|
||||
video::SColor(255,255,255,255),
|
||||
NULL);
|
||||
}
|
||||
video::ECF_A8R8G8B8, dim_base);
|
||||
|
||||
img_crack_scaled->drop();
|
||||
if(img_crack_cropped && img_crack_scaled)
|
||||
{
|
||||
// Crop crack image
|
||||
v2s32 pos_crack(0, progression*dim_crack.Width);
|
||||
img_crack->copyTo(img_crack_cropped,
|
||||
v2s32(0,0),
|
||||
core::rect<s32>(pos_crack, dim_crack_cropped));
|
||||
// Scale crack image by copying
|
||||
img_crack_cropped->copyToScaling(img_crack_scaled);
|
||||
// Copy or overlay crack image
|
||||
if(use_overlay)
|
||||
{
|
||||
overlay(baseimg, img_crack_scaled);
|
||||
}
|
||||
else
|
||||
{
|
||||
img_crack_scaled->copyToWithAlpha(
|
||||
baseimg,
|
||||
v2s32(0,0),
|
||||
core::rect<s32>(v2s32(0,0), dim_base),
|
||||
video::SColor(255,255,255,255));
|
||||
}
|
||||
}
|
||||
|
||||
if(img_crack_scaled)
|
||||
img_crack_scaled->drop();
|
||||
|
||||
if(img_crack_cropped)
|
||||
img_crack_cropped->drop();
|
||||
|
||||
img_crack->drop();
|
||||
}
|
||||
@ -1511,6 +1524,37 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
|
||||
return true;
|
||||
}
|
||||
|
||||
void overlay(video::IImage *image, video::IImage *overlay)
|
||||
{
|
||||
/*
|
||||
Copy overlay to image, taking alpha into account.
|
||||
Where image is transparent, don't copy from overlay.
|
||||
Images sizes must be identical.
|
||||
*/
|
||||
if(image == NULL || overlay == NULL)
|
||||
return;
|
||||
|
||||
core::dimension2d<u32> dim = image->getDimension();
|
||||
core::dimension2d<u32> dim_overlay = overlay->getDimension();
|
||||
assert(dim == dim_overlay);
|
||||
|
||||
for(u32 y=0; y<dim.Height; y++)
|
||||
for(u32 x=0; x<dim.Width; x++)
|
||||
{
|
||||
video::SColor c1 = image->getPixel(x,y);
|
||||
video::SColor c2 = overlay->getPixel(x,y);
|
||||
u32 a1 = c1.getAlpha();
|
||||
u32 a2 = c2.getAlpha();
|
||||
if(a1 == 255 && a2 != 0)
|
||||
{
|
||||
c1.setRed((c1.getRed()*(255-a2) + c2.getRed()*a2)/255);
|
||||
c1.setGreen((c1.getGreen()*(255-a2) + c2.getGreen()*a2)/255);
|
||||
c1.setBlue((c1.getBlue()*(255-a2) + c2.getBlue()*a2)/255);
|
||||
}
|
||||
image->setPixel(x,y,c1);
|
||||
}
|
||||
}
|
||||
|
||||
void brighten(video::IImage *image)
|
||||
{
|
||||
if(image == NULL)
|
||||
|
22
src/tile.h
22
src/tile.h
@ -73,7 +73,7 @@ struct AtlasPointer
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const AtlasPointer &other)
|
||||
bool operator==(const AtlasPointer &other) const
|
||||
{
|
||||
return (
|
||||
id == other.id
|
||||
@ -87,6 +87,11 @@ struct AtlasPointer
|
||||
);*/
|
||||
}
|
||||
|
||||
bool operator!=(const AtlasPointer &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
float x0(){ return pos.X; }
|
||||
float x1(){ return pos.X + size.X; }
|
||||
float y0(){ return pos.Y; }
|
||||
@ -110,6 +115,8 @@ public:
|
||||
{return AtlasPointer(0);}
|
||||
virtual video::ITexture* getTextureRaw(const std::string &name)
|
||||
{return NULL;}
|
||||
virtual AtlasPointer getTextureRawAP(const AtlasPointer &ap)
|
||||
{return AtlasPointer(0);}
|
||||
virtual IrrlichtDevice* getDevice()
|
||||
{return NULL;}
|
||||
virtual void updateAP(AtlasPointer &ap){};
|
||||
@ -148,7 +155,13 @@ enum MaterialType{
|
||||
};
|
||||
|
||||
// Material flags
|
||||
// Should backface culling be enabled?
|
||||
#define MATERIAL_FLAG_BACKFACE_CULLING 0x01
|
||||
// Should a crack be drawn?
|
||||
#define MATERIAL_FLAG_CRACK 0x02
|
||||
// Should the crack be drawn on transparent pixels (unset) or not (set)?
|
||||
// Ignored if MATERIAL_FLAG_CRACK is not set.
|
||||
#define MATERIAL_FLAG_CRACK_OVERLAY 0x04
|
||||
|
||||
/*
|
||||
This fully defines the looks of a tile.
|
||||
@ -169,7 +182,7 @@ struct TileSpec
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(TileSpec &other)
|
||||
bool operator==(const TileSpec &other) const
|
||||
{
|
||||
return (
|
||||
texture == other.texture &&
|
||||
@ -178,6 +191,11 @@ struct TileSpec
|
||||
material_flags == other.material_flags
|
||||
);
|
||||
}
|
||||
|
||||
bool operator!=(const TileSpec &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// Sets everything else except the texture in the material
|
||||
void applyMaterialOptions(video::SMaterial &material) const
|
||||
|
@ -1753,18 +1753,17 @@ std::string deSerializeJsonString(std::istream &is);
|
||||
|
||||
inline u32 time_to_daynight_ratio(u32 time_of_day)
|
||||
{
|
||||
const s32 daylength = 16;
|
||||
const s32 nightlength = 6;
|
||||
const s32 daytimelength = 8;
|
||||
s32 d = daylength;
|
||||
s32 t = (((time_of_day)%24000)/(24000/d));
|
||||
if(t < nightlength/2 || t >= d - nightlength/2)
|
||||
//return 300;
|
||||
s32 t = time_of_day%24000;
|
||||
if(t < 4500 || t >= 19500)
|
||||
return 150;
|
||||
else if(t < 5000 || t >= 19000)
|
||||
return 350;
|
||||
else if(t >= d/2 - daytimelength/2 && t < d/2 + daytimelength/2)
|
||||
return 1000;
|
||||
else
|
||||
else if(t < 5500 || t >= 18500)
|
||||
return 500;
|
||||
else if(t < 6000 || t >= 18000)
|
||||
return 750;
|
||||
else
|
||||
return 1000;
|
||||
}
|
||||
|
||||
// Random helper. Usually d=BS
|
||||
|
Loading…
Reference in New Issue
Block a user