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();
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;
{
<<std::endl;
}
+float Client::getDaylightRatio()
+{
+ JMutexAutoLock envlock(m_env_mutex);
+ return m_env.getDaylightRatio();
+}
i.atEnd() == false; i++)
{
v3s16 p = i.getNode()->getKey();
- m_env->getMap().updateMeshes(p);
+ m_env->updateMeshes(p);
}
m_blocks.clear();
}
// Prints a line or two of info
void printDebugInfo(std::ostream &os);
+
+ float getDaylightRatio();
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
m_dout(dout)
{
m_map = map;
+ m_daylight_ratio = 0.2;
}
Environment::~Environment()
{
v3s16 p_blocks = getNodeBlockPos(bottompos);
MapBlock *b = m_map->getBlockNoCreate(p_blocks);
- b->updateMesh();
+ b->updateMesh(m_daylight_ratio);
}
}
}
}
}
+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;
+}
+
void step(f32 dtime);
Map & getMap();
+
/*
Environment deallocates players after use.
*/
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
#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,
#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.
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)
{
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);
<<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] = {
// 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
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);
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);
<<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
{
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;
}
if(n.sunlight_propagates())
{
- n.setLight(LIGHT_SUN);
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
block->setNode(relpos, n);
modified_blocks.insert(blockpos, block);
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(): "
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
}
}
- bool bottom_valid = block->propagateSunlight(light_sources);
+ if(bank == LIGHTBANK_DAY)
+ {
+ bool bottom_valid = block->propagateSunlight(light_sources);
- // If bottom is valid, we're done.
- if(bottom_valid)
+ // 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"
{
//TimeTaker timer("unspreadLight", g_device);
- unspreadLight(unlight_from, light_sources, modified_blocks);
+ unspreadLight(bank, unlight_from, light_sources, modified_blocks);
}
if(debug)
{
//TimeTaker timer("spreadLight", g_device);
- spreadLight(light_sources, modified_blocks);
+ spreadLight(bank, light_sources, modified_blocks);
}
if(debug)
//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
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
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.
try{
MapNode topnode = getNode(toppos);
- if(topnode.getLight() != LIGHT_SUN)
+ if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
node_under_sunlight = false;
}
catch(InvalidPositionException &e)
{
}
- // Add the block of the added node to modified_blocks
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * block = getBlockNoCreate(blockpos);
- assert(block != NULL);
- modified_blocks.insert(blockpos, block);
-
- if(isValidPosition(p) == false)
- throw;
+ 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);
+ assert(block != NULL);
+ modified_blocks.insert(blockpos, block);
- // Unlight neighbours of node.
- // This means setting light of all consequent dimmer nodes
- // to 0.
- // This also collects the nodes at the border which will spread
- // light again into this.
- unLightNeighbors(p, lightwas, light_sources, modified_blocks);
-
- n.setLight(0);
+ if(isValidPosition(p) == false)
+ throw;
+
+ // Unlight neighbours of node.
+ // This means setting light of all consequent dimmer nodes
+ // to 0.
+ // This also collects the nodes at the border which will spread
+ // light again into this.
+ unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
+
+ n.setLight(bank, 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)
{
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
}
}
- /*
- Spread light from all nodes that might be capable of doing so
- TODO: Convert to spreadLight
- */
- spreadLight(light_sources, modified_blocks);
+ 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(bank, light_sources, modified_blocks);
+ }
}
/*
// 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.
try{
MapNode topnode = getNode(toppos);
- if(topnode.getLight() != LIGHT_SUN)
+ if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
node_under_sunlight = false;
}
catch(InvalidPositionException &e)
{
}
- /*
- 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(),
- light_sources, modified_blocks);
+
+ 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)
+ */
+ 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);
- /*
- Recalculate lighting
- */
- spreadLight(light_sources, modified_blocks);
+ for(s32 i=0; i<2; i++)
+ {
+ enum LightBank bank = banks[i];
+
+ /*
+ Recalculate lighting
+ */
+ spreadLight(bank, light_sources, modified_blocks);
+ }
// Add the block of the removed node to modified_blocks
v3s16 blockpos = getNodeBlockPos(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)
}
}
- // Get the brightest neighbour node and propagate light from it
- v3s16 n2p = getBrightestNeighbour(p);
- try{
- MapNode n2 = getNode(n2p);
- lightNeighbors(n2p, modified_blocks);
+ 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(bank, p);
+ try{
+ MapNode n2 = getNode(n2p);
+ lightNeighbors(bank, n2p, modified_blocks);
+ }
+ catch(InvalidPositionException &e)
+ {
+ }
}
- catch(InvalidPositionException &e)
+}
+
+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)
+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){}
}
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
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
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++)
{
/*
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;
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);
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();
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
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,
/*
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;
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
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
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.
*/
/*
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);
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);
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);
<<"and uses "<<mesh_new->getMeshBufferCount()
<<" materials (meshbuffers)"<<std::endl;*/
}
-
+
/*
Clear temporary FastFaces
*/
buf->drop();
}
}
-
+
/*
Do some stuff to the mesh
*/
scene::SMesh *mesh_old = mesh;
mesh = mesh_new;
+ setMeshExpired(false);
if(mesh_old != NULL)
{
// 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)
{
if(n.sunlight_propagates())
{
- n.setLight(LIGHT_SUN);
+ n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
light_sources.insert(pos_relative + pos, true);
}
if(n.light_propagates())
{
- n.setLight(0);
+ n.setLight(LIGHTBANK_DAY, 0);
}
else{
break;
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;
}
m_pos(pos),
changed(true),
is_underground(false),
+ m_mesh_expired(false),
m_objects(this)
//is_incomplete(false)
{
changed = true;
}
+ void setMeshExpired(bool expired)
+ {
+ m_mesh_expired = expired;
+ }
+
+ bool getMeshExpired()
+ {
+ return m_mesh_expired;
+ }
+
v3s16 getPos()
{
return m_pos;
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);
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);
At least /has been/ used. 8)
*/
bool is_underground;
+
+ bool m_mesh_expired;
MapBlockObjectList m_objects;
return g_content_tiles[c][dir_i];
}
+enum LightBank
+{
+ LIGHTBANK_DAY,
+ LIGHTBANK_NIGHT
+};
+
struct MapNode
{
// Content
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())
- light = param & 0x0f;
+ {
+ 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;
}
+
+ // 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(u8 a_light)
+ void setLight(enum LightBank bank, u8 a_light)
{
// If not transparent, can't set light
if(light_propagates() == false)
return;
- param &= 0xf0;
- param |= a_light;
+ if(bank == LIGHTBANK_DAY)
+ {
+ param &= 0xf0;
+ param |= a_light & 0x0f;
+ }
+ else if(bank == LIGHTBANK_NIGHT)
+ {
+ param &= 0x0f;
+ param |= (a_light & 0x0f)<<4;
+ }
+ else
+ assert(0);
}
u16 getTile(v3s16 dir)
// 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;
// All nodes should have been set to
// .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++){
- assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
- assert(b.getNode(v3s16(x,y,z)).getLight() == 0);
- }
+ for(u16 y=0; y<MAP_BLOCKSIZE; y++)
+ 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(LIGHTBANK_DAY) == 0);
+ assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
+ }
/*
Parent fetch functions
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);
}
}
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
// 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
// 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:
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);
}
}
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);
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.