Viscous fluids

This commit is contained in:
Giuseppe Bilotta 2011-08-16 19:56:57 +02:00
parent 56e9f97294
commit 1eb14c7743
3 changed files with 41 additions and 6 deletions

@ -26,6 +26,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define WATER_ALPHA 160 #define WATER_ALPHA 160
#define WATER_VISC 1
#define LAVA_VISC 7
// TODO: Get rid of these and set up some attributes like toughness, // TODO: Get rid of these and set up some attributes like toughness,
// fluffyness, and a funciton to calculate time and durability loss // fluffyness, and a funciton to calculate time and durability loss
// (and sound? and whatever else) from them // (and sound? and whatever else) from them
@ -374,6 +377,7 @@ void content_mapnode_init()
f->liquid_type = LIQUID_FLOWING; f->liquid_type = LIQUID_FLOWING;
f->liquid_alternative_flowing = CONTENT_WATER; f->liquid_alternative_flowing = CONTENT_WATER;
f->liquid_alternative_source = CONTENT_WATERSOURCE; f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA; f->vertex_alpha = WATER_ALPHA;
if(f->special_material == NULL && g_texturesource) if(f->special_material == NULL && g_texturesource)
{ {
@ -421,6 +425,7 @@ void content_mapnode_init()
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->liquid_alternative_flowing = CONTENT_WATER; f->liquid_alternative_flowing = CONTENT_WATER;
f->liquid_alternative_source = CONTENT_WATERSOURCE; f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA; f->vertex_alpha = WATER_ALPHA;
if(f->special_material == NULL && g_texturesource) if(f->special_material == NULL && g_texturesource)
{ {
@ -451,6 +456,7 @@ void content_mapnode_init()
f->liquid_type = LIQUID_FLOWING; f->liquid_type = LIQUID_FLOWING;
f->liquid_alternative_flowing = CONTENT_LAVA; f->liquid_alternative_flowing = CONTENT_LAVA;
f->liquid_alternative_source = CONTENT_LAVASOURCE; f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2; f->damage_per_second = 4*2;
if(f->special_material == NULL && g_texturesource) if(f->special_material == NULL && g_texturesource)
{ {
@ -499,6 +505,7 @@ void content_mapnode_init()
f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
f->liquid_alternative_flowing = CONTENT_LAVA; f->liquid_alternative_flowing = CONTENT_LAVA;
f->liquid_alternative_source = CONTENT_LAVASOURCE; f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2; f->damage_per_second = 4*2;
if(f->special_material == NULL && g_texturesource) if(f->special_material == NULL && g_texturesource)
{ {

@ -1562,6 +1562,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
/*if(initial_size != 0) /*if(initial_size != 0)
dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/ dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
// list of nodes that due to viscosity have not reached their max level height
UniqueQueue<v3s16> must_reflow;
while(m_transforming_liquid.size() != 0) while(m_transforming_liquid.size() != 0)
{ {
// This should be done here so that it is done when continue is used // This should be done here so that it is done when continue is used
@ -1672,6 +1675,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
*/ */
content_t new_node_content; content_t new_node_content;
s8 new_node_level = -1; s8 new_node_level = -1;
s8 max_node_level = -1;
if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) { if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
// liquid_kind will be set to either the flowing alternative of the node (if it's a liquid) // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
// or the flowing alternative of the first of the surrounding sources (if it's air), so // or the flowing alternative of the first of the surrounding sources (if it's air), so
@ -1680,34 +1684,51 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
} else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) { } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
// liquid_kind is set properly, see above // liquid_kind is set properly, see above
new_node_content = liquid_kind; new_node_content = liquid_kind;
new_node_level = LIQUID_LEVEL_MAX; max_node_level = new_node_level = LIQUID_LEVEL_MAX;
} else { } else {
// no surrounding sources, so get the maximum level that can flow into this node // no surrounding sources, so get the maximum level that can flow into this node
for (u16 i = 0; i < num_flows; i++) { for (u16 i = 0; i < num_flows; i++) {
u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
switch (flows[i].t) { switch (flows[i].t) {
case NEIGHBOR_UPPER: case NEIGHBOR_UPPER:
if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) { if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
new_node_level = LIQUID_LEVEL_MAX; max_node_level = LIQUID_LEVEL_MAX;
if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX) if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
new_node_level = nb_liquid_level + WATER_DROP_BOOST; max_node_level = nb_liquid_level + WATER_DROP_BOOST;
} }
break; break;
case NEIGHBOR_LOWER: case NEIGHBOR_LOWER:
break; break;
case NEIGHBOR_SAME_LEVEL: case NEIGHBOR_SAME_LEVEL:
if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) { nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
new_node_level = nb_liquid_level - 1; max_node_level = nb_liquid_level - 1;
} }
break; break;
} }
} }
if (max_node_level != liquid_level) {
// amount to gain, limited by viscosity
// must be at least 1 in absolute value
s8 level_inc = max_node_level - liquid_level;
u8 viscosity = content_features(liquid_kind).liquid_viscosity;
if (level_inc < -viscosity || level_inc > viscosity)
new_node_level = liquid_level + level_inc/viscosity;
else if (level_inc < 0)
new_node_level = liquid_level - 1;
else if (level_inc > 0)
new_node_level = liquid_level + 1;
if (new_node_level != max_node_level)
must_reflow.push_back(p0);
} else
new_node_level = max_node_level;
if (new_node_level >= 0) if (new_node_level >= 0)
new_node_content = liquid_kind; new_node_content = liquid_kind;
else else
new_node_content = CONTENT_AIR; new_node_content = CONTENT_AIR;
} }
/* /*
@ -1760,6 +1781,8 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
} }
} }
//dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl; //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
while (must_reflow.size() > 0)
m_transforming_liquid.push_back(must_reflow.pop_front());
} }
NodeMetadata* Map::getNodeMetadata(v3s16 p) NodeMetadata* Map::getNodeMetadata(v3s16 p)

@ -153,6 +153,10 @@ struct ContentFeatures
content_t liquid_alternative_flowing; content_t liquid_alternative_flowing;
// If the content is liquid, this is the source version of the liquid. // If the content is liquid, this is the source version of the liquid.
content_t liquid_alternative_source; content_t liquid_alternative_source;
// Viscosity for fluid flow, ranging from 1 to 7, with
// 1 giving almost instantaneous propagation and 7 being
// the slowest possible
u8 liquid_viscosity;
// Used currently for flowing liquids // Used currently for flowing liquids
u8 vertex_alpha; u8 vertex_alpha;
// Special irrlicht material, used sometimes // Special irrlicht material, used sometimes
@ -189,6 +193,7 @@ struct ContentFeatures
initial_metadata = NULL; initial_metadata = NULL;
liquid_alternative_flowing = CONTENT_IGNORE; liquid_alternative_flowing = CONTENT_IGNORE;
liquid_alternative_source = CONTENT_IGNORE; liquid_alternative_source = CONTENT_IGNORE;
liquid_viscosity = 0;
vertex_alpha = 255; vertex_alpha = 255;
special_material = NULL; special_material = NULL;
special_atlas = NULL; special_atlas = NULL;