before daynight mesh cache

This commit is contained in:
Perttu Ahola 2010-12-18 17:46:00 +02:00
parent 15a43c5ed0
commit 240499dc2c
13 changed files with 442 additions and 216 deletions

View File

@ -81,7 +81,9 @@ Client::Client(IrrlichtDevice *device,
camera_direction(0,0,1),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_step_dtime(0.0),
m_inventory_updated(false)
m_inventory_updated(false),
m_time(0),
m_time_counter(0.0)
{
//m_fetchblock_mutex.Init();
m_incoming_queue_mutex.Init();
@ -142,6 +144,29 @@ void Client::step(float dtime)
if(dtime > 2.0)
dtime = 2.0;
/*
Day/night
*/
{
m_time_counter += dtime;
int seconds = (int)m_time_counter;
m_time_counter -= (float)seconds;
m_time += seconds;
if(seconds > 0)
{
dstream<<"m_time="<<m_time<<std::endl;
JMutexAutoLock envlock(m_env_mutex);
u32 dr = 500+500*sin((float)((m_time/10)%7)/7.*2.*PI);
if(dr != m_env.getDaylightRatio())
{
dstream<<"dr="<<dr<<std::endl;
m_env.setDaylightRatio(dr);
m_env.expireMeshes();
}
}
}
//dstream<<"Client steps "<<dtime<<std::endl;
{
@ -1755,4 +1780,9 @@ void Client::printDebugInfo(std::ostream &os)
<<std::endl;
}
float Client::getDaylightRatio()
{
JMutexAutoLock envlock(m_env_mutex);
return m_env.getDaylightRatio();
}

View File

@ -133,7 +133,7 @@ public:
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
m_env->getMap().updateMeshes(p);
m_env->updateMeshes(p);
}
m_blocks.clear();
}
@ -237,6 +237,8 @@ public:
// Prints a line or two of info
void printDebugInfo(std::ostream &os);
float getDaylightRatio();
private:
// Virtual methods from con::PeerHandler
@ -284,6 +286,10 @@ private:
core::map<v3s16, bool> m_active_blocks;
PacketCounter m_packetcounter;
// Access these only in main thread.
u32 m_time;
float m_time_counter;
};
#endif

View File

@ -24,6 +24,7 @@ Environment::Environment(Map *map, std::ostream &dout):
m_dout(dout)
{
m_map = map;
m_daylight_ratio = 0.2;
}
Environment::~Environment()
@ -152,7 +153,7 @@ void Environment::step(float dtime)
{
v3s16 p_blocks = getNodeBlockPos(bottompos);
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
b->updateMesh();
b->updateMesh(m_daylight_ratio);
}
}
}
@ -240,3 +241,23 @@ void Environment::printPlayers(std::ostream &o)
}
}
void Environment::updateMeshes(v3s16 blockpos)
{
m_map->updateMeshes(blockpos, m_daylight_ratio);
}
void Environment::expireMeshes()
{
m_map->expireMeshes();
}
void Environment::setDaylightRatio(u32 r)
{
m_daylight_ratio = r;
}
u32 Environment::getDaylightRatio()
{
return m_daylight_ratio;
}

View File

@ -49,6 +49,7 @@ public:
void step(f32 dtime);
Map & getMap();
/*
Environment deallocates players after use.
*/
@ -58,11 +59,18 @@ public:
Player * getPlayer(u16 peer_id);
core::list<Player*> getPlayers();
void printPlayers(std::ostream &o);
void updateMeshes(v3s16 blockpos);
void expireMeshes();
void setDaylightRatio(u32 r);
u32 getDaylightRatio();
private:
Map *m_map;
core::list<Player*> m_players;
// Debug output goes here
std::ostream &m_dout;
u32 m_daylight_ratio;
};
#endif

View File

@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "light.h"
// LIGHT_MAX is 15, 0-15 is 16 values
// LIGHT_MAX is 14, 0-14 is 15 values
/*u8 light_decode_table[LIGHT_MAX+1] =
{
0,

View File

@ -22,6 +22,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
/*
Lower level lighting stuff
*/
// This directly sets the range of light
#define LIGHT_MAX 14
// Light is stored as 4 bits, thus 15 is the maximum.

View File

@ -210,7 +210,8 @@ bool Map::isNodeUnderground(v3s16 p)
values of from_nodes are lighting values.
*/
void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
void Map::unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
core::map<v3s16, bool> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks)
{
@ -310,19 +311,19 @@ void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
If the neighbor is dimmer than what was specified
as oldlight (the light of the previous node)
*/
if(n2.getLight() < oldlight)
if(n2.getLight(bank) < oldlight)
{
/*
And the neighbor is transparent and it has some light
*/
if(n2.light_propagates() && n2.getLight() != 0)
if(n2.light_propagates() && n2.getLight(bank) != 0)
{
/*
Set light to 0 and add to queue
*/
u8 current_light = n2.getLight();
n2.setLight(0);
u8 current_light = n2.getLight(bank);
n2.setLight(bank, 0);
block->setNode(relpos, n2);
unlighted_nodes.insert(n2pos, current_light);
@ -371,27 +372,29 @@ void Map::unspreadLight(core::map<v3s16, u8> & from_nodes,
<<std::endl;*/
if(unlighted_nodes.size() > 0)
unspreadLight(unlighted_nodes, light_sources, modified_blocks);
unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
}
/*
A single-node wrapper of the above
*/
void Map::unLightNeighbors(v3s16 pos, u8 lightwas,
void Map::unLightNeighbors(enum LightBank bank,
v3s16 pos, u8 lightwas,
core::map<v3s16, bool> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks)
{
core::map<v3s16, u8> from_nodes;
from_nodes.insert(pos, lightwas);
unspreadLight(from_nodes, light_sources, modified_blocks);
unspreadLight(bank, from_nodes, light_sources, modified_blocks);
}
/*
Lights neighbors of from_nodes, collects all them and then
goes on recursively.
*/
void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
void Map::spreadLight(enum LightBank bank,
core::map<v3s16, bool> & from_nodes,
core::map<v3s16, MapBlock*> & modified_blocks)
{
const v3s16 dirs[6] = {
@ -452,7 +455,7 @@ void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
// Get node straight from the block
MapNode n = block->getNode(relpos);
u8 oldlight = n.getLight();
u8 oldlight = n.getLight(bank);
u8 newlight = diminish_light(oldlight);
// Loop through 6 neighbors
@ -490,7 +493,7 @@ void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
If the neighbor is brighter than the current node,
add to list (it will light up this node on its turn)
*/
if(n2.getLight() > undiminish_light(oldlight))
if(n2.getLight(bank) > undiminish_light(oldlight))
{
lighted_nodes.insert(n2pos, true);
//lighted_nodes.push_back(n2pos);
@ -500,11 +503,11 @@ void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
If the neighbor is dimmer than how much light this node
would spread on it, add to list
*/
if(n2.getLight() < newlight)
if(n2.getLight(bank) < newlight)
{
if(n2.light_propagates())
{
n2.setLight(newlight);
n2.setLight(bank, newlight);
block->setNode(relpos, n2);
lighted_nodes.insert(n2pos, true);
//lighted_nodes.push_back(n2pos);
@ -536,21 +539,22 @@ void Map::spreadLight(core::map<v3s16, bool> & from_nodes,
<<std::endl;*/
if(lighted_nodes.size() > 0)
spreadLight(lighted_nodes, modified_blocks);
spreadLight(bank, lighted_nodes, modified_blocks);
}
/*
A single-node source variation of the above.
*/
void Map::lightNeighbors(v3s16 pos,
void Map::lightNeighbors(enum LightBank bank,
v3s16 pos,
core::map<v3s16, MapBlock*> & modified_blocks)
{
core::map<v3s16, bool> from_nodes;
from_nodes.insert(pos, true);
spreadLight(from_nodes, modified_blocks);
spreadLight(bank, from_nodes, modified_blocks);
}
v3s16 Map::getBrightestNeighbour(v3s16 p)
v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
{
v3s16 dirs[6] = {
v3s16(0,0,1), // back
@ -577,8 +581,8 @@ v3s16 Map::getBrightestNeighbour(v3s16 p)
{
continue;
}
if(n2.getLight() > brightest_light || found_something == false){
brightest_light = n2.getLight();
if(n2.getLight(bank) > brightest_light || found_something == false){
brightest_light = n2.getLight(bank);
brightest_pos = n2pos;
found_something = true;
}
@ -619,7 +623,7 @@ s16 Map::propagateSunlight(v3s16 start,
if(n.sunlight_propagates())
{
n.setLight(LIGHT_SUN);
n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
block->setNode(relpos, n);
modified_blocks.insert(blockpos, block);
@ -631,7 +635,8 @@ s16 Map::propagateSunlight(v3s16 start,
return y + 1;
}
void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
void Map::updateLighting(enum LightBank bank,
core::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks)
{
/*m_dout<<DTIME<<"Map::updateLighting(): "
@ -671,8 +676,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
try{
v3s16 p(x,y,z);
MapNode n = block->getNode(v3s16(x,y,z));
u8 oldlight = n.getLight();
n.setLight(0);
u8 oldlight = n.getLight(bank);
n.setLight(bank, 0);
block->setNode(v3s16(x,y,z), n);
// Collect borders for unlighting
@ -699,11 +704,22 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
}
}
if(bank == LIGHTBANK_DAY)
{
bool bottom_valid = block->propagateSunlight(light_sources);
// If bottom is valid, we're done.
if(bottom_valid)
break;
}
else if(bank == LIGHTBANK_NIGHT)
{
break;
}
else
{
assert(0);
}
/*dstream<<"Bottom for sunlight-propagated block ("
<<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
@ -725,7 +741,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
{
//TimeTaker timer("unspreadLight", g_device);
unspreadLight(unlight_from, light_sources, modified_blocks);
unspreadLight(bank, unlight_from, light_sources, modified_blocks);
}
if(debug)
@ -744,7 +760,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
{
//TimeTaker timer("spreadLight", g_device);
spreadLight(light_sources, modified_blocks);
spreadLight(bank, light_sources, modified_blocks);
}
if(debug)
@ -757,6 +773,13 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
//m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
}
void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks)
{
updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
}
/*
This is called after changing a node from transparent to opaque.
The lighting value of the node should be left as-is after changing
@ -771,12 +794,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
m_dout<<DTIME<<"Map::nodeAddedUpdate(): p=("
<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
u8 lightwas = getNode(p).getLight();
//core::list<v3s16> light_sources;
core::map<v3s16, bool> light_sources;
//MapNode n = getNode(p);
/*
From this node to nodes underneath:
If lighting is sunlight (1.0), unlight neighbours and
@ -784,10 +801,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
Else discontinue.
*/
bool node_under_sunlight = true;
v3s16 toppos = p + v3s16(0,1,0);
bool node_under_sunlight = true;
core::map<v3s16, bool> light_sources;
/*
If there is a node at top and it doesn't have sunlight,
there has not been any sunlight going down.
@ -797,13 +815,24 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
try{
MapNode topnode = getNode(toppos);
if(topnode.getLight() != LIGHT_SUN)
if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
node_under_sunlight = false;
}
catch(InvalidPositionException &e)
{
}
enum LightBank banks[] =
{
LIGHTBANK_DAY,
LIGHTBANK_NIGHT
};
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
u8 lightwas = getNode(p).getLight(bank);
// Add the block of the added node to modified_blocks
v3s16 blockpos = getNodeBlockPos(p);
MapBlock * block = getBlockNoCreate(blockpos);
@ -818,15 +847,19 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
// to 0.
// This also collects the nodes at the border which will spread
// light again into this.
unLightNeighbors(p, lightwas, light_sources, modified_blocks);
unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
n.setLight(bank, 0);
}
n.setLight(0);
setNode(p, n);
/*
If node is under sunlight, take all sunlighted nodes under
it and clear light from them and from where the light has
been spread.
TODO: This could be optimized by mass-unlighting instead
of looping
*/
if(node_under_sunlight)
{
@ -844,11 +877,13 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
break;
}
if(n2.getLight() == LIGHT_SUN)
if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
{
//m_dout<<DTIME<<"doing"<<std::endl;
unLightNeighbors(n2pos, n2.getLight(), light_sources, modified_blocks);
n2.setLight(0);
unLightNeighbors(LIGHTBANK_DAY,
n2pos, n2.getLight(LIGHTBANK_DAY),
light_sources, modified_blocks);
n2.setLight(LIGHTBANK_DAY, 0);
setNode(n2pos, n2);
}
else
@ -856,11 +891,16 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
}
}
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
/*
Spread light from all nodes that might be capable of doing so
TODO: Convert to spreadLight
*/
spreadLight(light_sources, modified_blocks);
spreadLight(bank, light_sources, modified_blocks);
}
}
/*
@ -879,67 +919,6 @@ void Map::removeNodeAndUpdate(v3s16 p,
// Node will be replaced with this
u8 replace_material = CONTENT_AIR;
// NOTE: Water is now managed elsewhere
#if 0
{
/*
Find out with what material the node will be replaced.
It will be replaced with the mostly seen buildable_to.
*/
v3s16 dirs[6] = {
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
};
core::map<u8, u16> neighbor_rankings;
for(u32 i=0; i<sizeof(dirs)/sizeof(dirs[0]); i++)
{
try{
MapNode n2 = getNode(p + dirs[i]);
if(material_buildable_to(n2.d))
{
if(neighbor_rankings.find(n2.d) == NULL)
neighbor_rankings[n2.d] = 1;
else
neighbor_rankings[n2.d]
= neighbor_rankings[n2.d] + 1;
}
}
catch(InvalidPositionException &e)
{
}
}
u16 highest_ranking = 0;
for(core::map<u8, u16>::Iterator
i = neighbor_rankings.getIterator();
i.atEnd() == false; i++)
{
u8 m = i.getNode()->getKey();
u8 c = i.getNode()->getValue();
if(
c > highest_ranking ||
// Prefer something else than air
(c >= highest_ranking && m != CONTENT_AIR)
)
{
replace_material = m;
highest_ranking = c;
}
}
}
#endif
/*
If there is a node at top and it doesn't have sunlight,
there will be no sunlight going down.
@ -947,33 +926,50 @@ void Map::removeNodeAndUpdate(v3s16 p,
try{
MapNode topnode = getNode(toppos);
if(topnode.getLight() != LIGHT_SUN)
if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
node_under_sunlight = false;
}
catch(InvalidPositionException &e)
{
}
core::map<v3s16, bool> light_sources;
enum LightBank banks[] =
{
LIGHTBANK_DAY,
LIGHTBANK_NIGHT
};
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
/*
Unlight neighbors (in case the node is a light source)
*/
//core::list<v3s16> light_sources;
core::map<v3s16, bool> light_sources;
unLightNeighbors(p, getNode(p).getLight(),
unLightNeighbors(bank, p,
getNode(p).getLight(bank),
light_sources, modified_blocks);
}
/*
Remove the node
Remove the node.
This also clears the lighting.
*/
MapNode n;
n.d = replace_material;
n.setLight(0);
setNode(p, n);
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
/*
Recalculate lighting
*/
spreadLight(light_sources, modified_blocks);
spreadLight(bank, light_sources, modified_blocks);
}
// Add the block of the removed node to modified_blocks
v3s16 blockpos = getNodeBlockPos(p);
@ -999,15 +995,16 @@ void Map::removeNodeAndUpdate(v3s16 p,
/*m_dout<<DTIME<<"lighting neighbors of node ("
<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
<<std::endl;*/
lightNeighbors(p2, modified_blocks);
lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
}
}
else
{
// Set the lighting of this node to 0
// TODO: Is this needed? Lighting is cleared up there already.
try{
MapNode n = getNode(p);
n.setLight(0);
n.setLight(LIGHTBANK_DAY, 0);
setNode(p, n);
}
catch(InvalidPositionException &e)
@ -1016,43 +1013,78 @@ void Map::removeNodeAndUpdate(v3s16 p,
}
}
for(s32 i=0; i<2; i++)
{
enum LightBank bank = banks[i];
// Get the brightest neighbour node and propagate light from it
v3s16 n2p = getBrightestNeighbour(p);
v3s16 n2p = getBrightestNeighbour(bank, p);
try{
MapNode n2 = getNode(n2p);
lightNeighbors(n2p, modified_blocks);
lightNeighbors(bank, n2p, modified_blocks);
}
catch(InvalidPositionException &e)
{
}
}
}
void Map::updateMeshes(v3s16 blockpos)
void Map::expireMeshes()
{
TimeTaker timer("expireMeshes()", g_device);
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;
{
JMutexAutoLock lock(block->mesh_mutex);
if(block->mesh != NULL)
{
//block->mesh->drop();
//block->mesh = NULL;
block->setMeshExpired(true);
}
}
}
}
}
void Map::updateMeshes(v3s16 blockpos, u32 daylight_factor)
{
assert(mapType() == MAPTYPE_CLIENT);
try{
v3s16 p = blockpos + v3s16(0,0,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh();
b->updateMesh(daylight_factor);
}
catch(InvalidPositionException &e){}
try{
v3s16 p = blockpos + v3s16(-1,0,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh();
b->updateMesh(daylight_factor);
}
catch(InvalidPositionException &e){}
try{
v3s16 p = blockpos + v3s16(0,-1,0);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh();
b->updateMesh(daylight_factor);
}
catch(InvalidPositionException &e){}
try{
v3s16 p = blockpos + v3s16(0,0,-1);
MapBlock *b = getBlockNoCreate(p);
b->updateMesh();
b->updateMesh(daylight_factor);
}
catch(InvalidPositionException &e){}
}
@ -1691,7 +1723,7 @@ MapBlock * ServerMap::emergeBlock(
newly created block, they won't be taken into account.
*/
if(real_y > surface_y)
n.setLight(LIGHT_SUN);
n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
/*
Calculate material
@ -1751,7 +1783,8 @@ MapBlock * ServerMap::emergeBlock(
if(real_y < WATER_LEVEL)
{
n.d = water_material;
n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
n.setLight(LIGHTBANK_DAY,
diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
}
// else air
else
@ -2732,11 +2765,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
u32 vertex_count = 0;
core::map<v2s16, MapSector*>::Iterator si;
// For limiting number of mesh updates per frame
u32 mesh_update_count = 0;
//NOTE: The sectors map should be locked but we're not doing it
// because it'd cause too much delays
core::map<v2s16, MapSector*>::Iterator si;
si = m_sectors.getIterator();
for(; si.atEnd() == false; si++)
{
@ -2838,10 +2873,33 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
Draw the faces of the block
*/
bool mesh_expired = false;
{
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)
continue;
}
/*
This has to be done with the mesh_mutex unlocked
*/
if(mesh_expired && mesh_update_count < 1)
{
mesh_update_count++;
// Mesh has been expired: generate new mesh
block->updateMesh(m_client->getDaylightRatio());
}
{
JMutexAutoLock lock(block->mesh_mutex);
// Cancel if block has no mesh
if(block->mesh == NULL)
continue;

View File

@ -333,25 +333,33 @@ public:
blockref->setNode(relpos, n);
}*/
void unspreadLight(core::map<v3s16, u8> & from_nodes,
void unspreadLight(enum LightBank bank,
core::map<v3s16, u8> & from_nodes,
core::map<v3s16, bool> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks);
void unLightNeighbors(v3s16 pos, u8 lightwas,
void unLightNeighbors(enum LightBank bank,
v3s16 pos, u8 lightwas,
core::map<v3s16, bool> & light_sources,
core::map<v3s16, MapBlock*> & modified_blocks);
void spreadLight(core::map<v3s16, bool> & from_nodes,
void spreadLight(enum LightBank bank,
core::map<v3s16, bool> & from_nodes,
core::map<v3s16, MapBlock*> & modified_blocks);
void lightNeighbors(v3s16 pos,
void lightNeighbors(enum LightBank bank,
v3s16 pos,
core::map<v3s16, MapBlock*> & modified_blocks);
v3s16 getBrightestNeighbour(v3s16 p);
v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p);
s16 propagateSunlight(v3s16 start,
core::map<v3s16, MapBlock*> & modified_blocks);
void updateLighting(enum LightBank bank,
core::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks);
void updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
core::map<v3s16, MapBlock*> & modified_blocks);
@ -367,7 +375,9 @@ public:
Updates the faces of the given block and blocks on the
leading edge.
*/
void updateMeshes(v3s16 blockpos);
void updateMeshes(v3s16 blockpos, u32 daylight_factor);
void expireMeshes();
//core::aabbox3d<s16> getDisplayedBlockArea();

View File

@ -147,20 +147,18 @@ FastFace * MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
If either of the nodes doesn't exist, light is 0.
*/
u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir)
u8 MapBlock::getFaceLight(u32 daylight_factor, v3s16 p, v3s16 face_dir)
{
try{
MapNode n = getNodeParent(p);
MapNode n2 = getNodeParent(p + face_dir);
u8 light;
/*if(n.solidness() < n2.solidness())
light = n.getLight();
u8 l1 = n.getLightBlend(daylight_factor);
u8 l2 = n2.getLightBlend(daylight_factor);
if(l1 > l2)
light = l1;
else
light = n2.getLight();*/
if(n.getLight() > n2.getLight())
light = n.getLight();
else
light = n2.getLight();
light = l2;
// Make some nice difference to different sides
@ -272,7 +270,9 @@ u8 MapBlock::getNodeContent(v3s16 p)
translate_dir: unit vector with only one of x, y or z
face_dir: unit vector with only one of x, y or z
*/
void MapBlock::updateFastFaceRow(v3s16 startpos,
void MapBlock::updateFastFaceRow(
u32 daylight_factor,
v3s16 startpos,
u16 length,
v3s16 translate_dir,
v3s16 face_dir,
@ -292,7 +292,7 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
/*
Get face light at starting position
*/
u8 light = getFaceLight(p, face_dir);
u8 light = getFaceLight(daylight_factor, p, face_dir);
u16 continuous_tiles_count = 0;
@ -312,7 +312,7 @@ void MapBlock::updateFastFaceRow(v3s16 startpos,
p_next = p + translate_dir;
tile0_next = getNodeTile(p_next, face_dir);
tile1_next = getNodeTile(p_next + face_dir, -face_dir);
light_next = getFaceLight(p_next, face_dir);
light_next = getFaceLight(daylight_factor, p_next, face_dir);
if(tile0_next == tile0
&& tile1_next == tile1
@ -474,12 +474,13 @@ private:
core::array<PreMeshBuffer> m_prebuffers;
};
void MapBlock::updateMesh()
void MapBlock::updateMesh(u32 daylight_factor)
{
/*v3s16 p = getPosRelative();
std::cout<<"MapBlock("<<p.X<<","<<p.Y<<","<<p.Z<<")"
<<"::updateMesh(): ";*/
//<<"::updateMesh()"<<std::endl;
TimeTaker timer1("updateMesh()", g_device);
/*
TODO: Change this to directly generate the mesh (and get rid
@ -492,6 +493,9 @@ void MapBlock::updateMesh()
We are including the faces of the trailing edges of the block.
This means that when something changes, the caller must
also update the meshes of the blocks at the leading edges.
NOTE: This is the slowest part of this method. The other parts
take around 0ms, this takes around 15-70ms.
*/
/*
@ -500,7 +504,8 @@ void MapBlock::updateMesh()
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
//for(s16 y=-1; y<MAP_BLOCKSIZE; y++){
for(s16 z=0; z<MAP_BLOCKSIZE; z++){
updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
updateFastFaceRow(daylight_factor,
v3s16(0,y,z), MAP_BLOCKSIZE,
v3s16(1,0,0),
v3s16(0,1,0),
*fastfaces_new);
@ -512,7 +517,8 @@ void MapBlock::updateMesh()
for(s16 x=0; x<MAP_BLOCKSIZE; x++){
//for(s16 x=-1; x<MAP_BLOCKSIZE; x++){
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
updateFastFaceRow(v3s16(x,y,0), MAP_BLOCKSIZE,
updateFastFaceRow(daylight_factor,
v3s16(x,y,0), MAP_BLOCKSIZE,
v3s16(0,0,1),
v3s16(1,0,0),
*fastfaces_new);
@ -524,7 +530,8 @@ void MapBlock::updateMesh()
for(s16 z=0; z<MAP_BLOCKSIZE; z++){
//for(s16 z=-1; z<MAP_BLOCKSIZE; z++){
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE,
updateFastFaceRow(daylight_factor,
v3s16(0,y,z), MAP_BLOCKSIZE,
v3s16(1,0,0),
v3s16(0,0,1),
*fastfaces_new);
@ -693,6 +700,7 @@ void MapBlock::updateMesh()
scene::SMesh *mesh_old = mesh;
mesh = mesh_new;
setMeshExpired(false);
if(mesh_old != NULL)
{
@ -743,7 +751,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
// Check if node above block has sunlight
try{
MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
if(n.getLight() != LIGHT_SUN)
if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
{
/*if(is_underground)
{
@ -789,7 +797,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
if(n.sunlight_propagates())
{
n.setLight(LIGHT_SUN);
n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
light_sources.insert(pos_relative + pos, true);
}
@ -809,7 +817,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
if(n.light_propagates())
{
n.setLight(0);
n.setLight(LIGHTBANK_DAY, 0);
}
else{
break;
@ -831,10 +839,10 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
MapNode n = getNodeParent(v3s16(x, -1, z));
if(n.light_propagates())
{
if(n.getLight() == LIGHT_SUN
if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
&& sunlight_should_go_down == false)
block_below_is_valid = false;
else if(n.getLight() != LIGHT_SUN
else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
&& sunlight_should_go_down == true)
block_below_is_valid = false;
}

View File

@ -108,6 +108,7 @@ public:
m_pos(pos),
changed(true),
is_underground(false),
m_mesh_expired(false),
m_objects(this)
//is_incomplete(false)
{
@ -170,6 +171,16 @@ public:
changed = true;
}
void setMeshExpired(bool expired)
{
m_mesh_expired = expired;
}
bool getMeshExpired()
{
return m_mesh_expired;
}
v3s16 getPos()
{
return m_pos;
@ -303,7 +314,7 @@ public:
static FastFace * makeFastFace(TileSpec tile, u8 light, v3f p,
v3s16 dir, v3f scale, v3f posRelative_f);
u8 getFaceLight(v3s16 p, v3s16 face_dir);
u8 getFaceLight(u32 daylight_factor, v3s16 p, v3s16 face_dir);
TileSpec getNodeTile(v3s16 p, v3s16 face_dir);
u8 getNodeContent(v3s16 p);
@ -313,13 +324,15 @@ public:
translate_dir: unit vector with only one of x, y or z
face_dir: unit vector with only one of x, y or z
*/
void updateFastFaceRow(v3s16 startpos,
void updateFastFaceRow(
u32 daylight_factor,
v3s16 startpos,
u16 length,
v3s16 translate_dir,
v3s16 face_dir,
core::list<FastFace*> &dest);
void updateMesh();
void updateMesh(u32 daylight_factor);
bool propagateSunlight(core::map<v3s16, bool> & light_sources);
@ -465,6 +478,8 @@ private:
*/
bool is_underground;
bool m_mesh_expired;
MapBlockObjectList m_objects;
// Temporary modifications to nodes

View File

@ -280,6 +280,12 @@ inline u16 content_tile(u8 c, v3s16 dir)
return g_content_tiles[c][dir_i];
}
enum LightBank
{
LIGHTBANK_DAY,
LIGHTBANK_NIGHT
};
struct MapNode
{
// Content
@ -352,24 +358,77 @@ struct MapNode
return 0;
}
u8 getLight()
u8 getLightBanksWithSource()
{
// Select the brightest of [light source, propagated light]
u8 lightday = 0;
u8 lightnight = 0;
if(light_propagates())
{
lightday = param & 0x0f;
lightnight = (param>>4)&0x0f;
}
if(light_source() > lightday)
lightday = light_source();
if(light_source() > lightnight)
lightnight = light_source();
return (lightday&0x0f) | ((lightnight<<4)&0xf0);
}
void setLightBanks(u8 a_light)
{
param = a_light;
}
u8 getLight(enum LightBank bank)
{
// Select the brightest of [light source, propagated light]
u8 light = 0;
if(light_propagates())
{
if(bank == LIGHTBANK_DAY)
light = param & 0x0f;
else if(bank == LIGHTBANK_NIGHT)
light = (param>>4)&0x0f;
else
assert(0);
}
if(light_source() > light)
light = light_source();
return light;
}
void setLight(u8 a_light)
// 0 <= daylight_factor <= 1000
u8 getLightBlend(u32 daylight_factor)
{
u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
+ (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
)/1000;
u8 max = LIGHT_MAX;
if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
max = LIGHT_SUN;
if(l > max)
l = max;
return l;
}
void setLight(enum LightBank bank, u8 a_light)
{
// If not transparent, can't set light
if(light_propagates() == false)
return;
if(bank == LIGHTBANK_DAY)
{
param &= 0xf0;
param |= a_light;
param |= a_light & 0x0f;
}
else if(bank == LIGHTBANK_NIGHT)
{
param &= 0x0f;
param |= (a_light & 0x0f)<<4;
}
else
assert(0);
}
u16 getTile(v3s16 dir)

View File

@ -194,7 +194,8 @@ struct TestMapNode
// Default values
assert(n.d == CONTENT_AIR);
assert(n.getLight() == 0);
assert(n.getLight(LIGHTBANK_DAY) == 0);
assert(n.getLight(LIGHTBANK_NIGHT) == 0);
// Transparency
n.d = CONTENT_AIR;
@ -432,9 +433,11 @@ struct TestMapBlock
// .d=CONTENT_AIR and .getLight() = 0
for(u16 z=0; z<MAP_BLOCKSIZE; z++)
for(u16 y=0; y<MAP_BLOCKSIZE; y++)
for(u16 x=0; x<MAP_BLOCKSIZE; x++){
for(u16 x=0; x<MAP_BLOCKSIZE; x++)
{
assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
assert(b.getNode(v3s16(x,y,z)).getLight() == 0);
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0);
assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
}
/*
@ -496,7 +499,8 @@ struct TestMapBlock
for(u16 y=0; y<MAP_BLOCKSIZE; y++){
for(u16 x=0; x<MAP_BLOCKSIZE; x++){
MapNode n = b.getNode(v3s16(x,y,z));
n.setLight(0);
n.setLight(LIGHTBANK_DAY, 0);
n.setLight(LIGHTBANK_NIGHT, 0);
b.setNode(v3s16(x,y,z), n);
}
}
@ -508,22 +512,25 @@ struct TestMapBlock
parent.position_valid = true;
b.setIsUnderground(false);
parent.node.d = CONTENT_AIR;
parent.node.setLight(LIGHT_SUN);
parent.node.setLight(LIGHTBANK_DAY, LIGHT_SUN);
parent.node.setLight(LIGHTBANK_NIGHT, 0);
core::map<v3s16, bool> light_sources;
// The bottom block is invalid, because we have a shadowing node
assert(b.propagateSunlight(light_sources) == false);
assert(b.getNode(v3s16(1,4,0)).getLight() == LIGHT_SUN);
assert(b.getNode(v3s16(1,3,0)).getLight() == LIGHT_SUN);
assert(b.getNode(v3s16(1,2,0)).getLight() == 0);
assert(b.getNode(v3s16(1,1,0)).getLight() == 0);
assert(b.getNode(v3s16(1,0,0)).getLight() == 0);
assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN);
assert(b.getFaceLight(p, v3s16(0,1,0)) == LIGHT_SUN);
assert(b.getFaceLight(p, v3s16(0,-1,0)) == 0);
assert(b.getNode(v3s16(1,4,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
assert(b.getNode(v3s16(1,3,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
assert(b.getNode(v3s16(1,2,0)).getLight(LIGHTBANK_DAY) == 0);
assert(b.getNode(v3s16(1,1,0)).getLight(LIGHTBANK_DAY) == 0);
assert(b.getNode(v3s16(1,0,0)).getLight(LIGHTBANK_DAY) == 0);
assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
assert(b.getFaceLight(1000, p, v3s16(0,1,0)) == LIGHT_SUN);
assert(b.getFaceLight(1000, p, v3s16(0,-1,0)) == 0);
assert(b.getFaceLight(0, p, v3s16(0,-1,0)) == 0);
// According to MapBlock::getFaceLight,
// The face on the z+ side should have double-diminished light
//assert(b.getFaceLight(p, v3s16(0,0,1)) == diminish_light(diminish_light(LIGHT_MAX)));
assert(b.getFaceLight(p, v3s16(0,0,1)) == diminish_light(LIGHT_MAX));
// The face on the z+ side should have diminished light
assert(b.getFaceLight(1000, p, v3s16(0,0,1)) == diminish_light(LIGHT_MAX));
}
/*
Check how the block handles being in between blocks with some non-sunlight
@ -533,7 +540,7 @@ struct TestMapBlock
// Make neighbours to exist and set some non-sunlight to them
parent.position_valid = true;
b.setIsUnderground(true);
parent.node.setLight(LIGHT_MAX/2);
parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2);
core::map<v3s16, bool> light_sources;
// The block below should be valid because there shouldn't be
// sunlight in there either
@ -541,7 +548,7 @@ struct TestMapBlock
// Should not touch nodes that are not affected (that is, all of them)
//assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN);
// Should set light of non-sunlighted blocks to 0.
assert(b.getNode(v3s16(1,2,3)).getLight() == 0);
assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == 0);
}
/*
Set up a situation where:
@ -560,7 +567,7 @@ struct TestMapBlock
for(u16 x=0; x<MAP_BLOCKSIZE; x++){
MapNode n;
n.d = CONTENT_AIR;
n.setLight(0);
n.setLight(LIGHTBANK_DAY, 0);
b.setNode(v3s16(x,y,z), n);
}
}
@ -574,7 +581,7 @@ struct TestMapBlock
parent.validity_exceptions.push_back(v3s16(MAP_BLOCKSIZE+x, MAP_BLOCKSIZE-1, MAP_BLOCKSIZE+z));
}
// Lighting value for the valid nodes
parent.node.setLight(LIGHT_MAX/2);
parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2);
core::map<v3s16, bool> light_sources;
// Bottom block is not valid
assert(b.propagateSunlight(light_sources) == false);

View File

@ -734,12 +734,12 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
correctly. Otherwise unspreadLight will fuck up when water
has replaced a light source.
*/
u8 light = m_data[m_area.index(removed_pos)].getLight();
u8 light = m_data[m_area.index(removed_pos)].getLightBanksWithSource();
m_data[m_area.index(removed_pos)].d = m;
m_flags[m_area.index(removed_pos)] = f;
m_data[m_area.index(removed_pos)].setLight(light);
m_data[m_area.index(removed_pos)].setLightBanks(light);
/*// NOTE: HACK: This has to be set to LIGHT_MAX so that
// unspreadLight will clear all light that came from this node.