-void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
- v3s16 dir, v3f scale, v3f posRelative_f,
- core::array<FastFace> &dest)
-{
- FastFace face;
-
- // Position is at the center of the cube.
- v3f pos = p * BS;
- posRelative_f *= BS;
-
- v3f vertex_pos[4];
- // If looking towards z+, this is the face that is behind
- // the center point, facing towards z+.
- vertex_pos[0] = v3f( BS/2,-BS/2,BS/2);
- vertex_pos[1] = v3f(-BS/2,-BS/2,BS/2);
- vertex_pos[2] = v3f(-BS/2, BS/2,BS/2);
- vertex_pos[3] = v3f( BS/2, BS/2,BS/2);
-
- if(dir == v3s16(0,0,1))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateXZBy(0);
- }
- else if(dir == v3s16(0,0,-1))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateXZBy(180);
- }
- else if(dir == v3s16(1,0,0))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateXZBy(-90);
- }
- else if(dir == v3s16(-1,0,0))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateXZBy(90);
- }
- else if(dir == v3s16(0,1,0))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateYZBy(-90);
- }
- else if(dir == v3s16(0,-1,0))
- {
- for(u16 i=0; i<4; i++)
- vertex_pos[i].rotateYZBy(90);
- }
-
- for(u16 i=0; i<4; i++)
- {
- vertex_pos[i].X *= scale.X;
- vertex_pos[i].Y *= scale.Y;
- vertex_pos[i].Z *= scale.Z;
- vertex_pos[i] += pos + posRelative_f;
- }
-
- f32 abs_scale = 1.;
- if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
- else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
- else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
-
- v3f zerovector = v3f(0,0,0);
-
- u8 li = decode_light(light);
- //u8 li = 150;
-
- u8 alpha = 255;
-
- if(tile.id == TILE_WATER)
- {
- alpha = 128;
- }
-
- video::SColor c = video::SColor(alpha,li,li,li);
-
- face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
- core::vector2d<f32>(0,1));
- face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
- core::vector2d<f32>(abs_scale,1));
- face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
- core::vector2d<f32>(abs_scale,0));
- face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
- core::vector2d<f32>(0,0));
-
- face.tile = tile;
- //DEBUG
- //f->tile = TILE_STONE;
-
- dest.push_back(face);
- //return f;
-}
-
-/*
- Gets node tile from any place relative to block.
- Returns TILE_NODE if doesn't exist or should not be drawn.
-*/
-TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
-{
- TileSpec spec;
-
- /*//DEBUG
- {
- spec.id = TILE_STONE;
- return spec;
- }*/
-
- spec.feature = TILEFEAT_NONE;
- //spec.id = TILE_STONE;
- spec.id = mn.getTile(face_dir);
-
- /*
- Check temporary modifications on this node
- */
- core::map<v3s16, NodeMod>::Node *n;
- n = m_temp_mods.find(p);
-
- // If modified
- if(n != NULL)
- {
- struct NodeMod mod = n->getValue();
- if(mod.type == NODEMOD_CHANGECONTENT)
- {
- spec.id = content_tile(mod.param, face_dir);
- }
- if(mod.type == NODEMOD_CRACK)
- {
- spec.feature = TILEFEAT_CRACK;
- spec.param.crack.progression = mod.param;
- }
- }
-
- return spec;
-}
-
-u8 MapBlock::getNodeContent(v3s16 p, MapNode mn)
-{
- /*
- Check temporary modifications on this node
- */
- core::map<v3s16, NodeMod>::Node *n;
- n = m_temp_mods.find(p);
-
- // If modified
- if(n != NULL)
- {
- struct NodeMod mod = n->getValue();
- if(mod.type == NODEMOD_CHANGECONTENT)
- {
- // Overrides content
- return mod.param;
- }
- if(mod.type == NODEMOD_CRACK)
- {
- /*
- Content doesn't change.
-
- face_contents works just like it should, because
- there should not be faces between differently cracked
- nodes.
-
- If a semi-transparent node is cracked in front an
- another one, it really doesn't matter whether there
- is a cracked face drawn in between or not.
- */
- }
- }
-
- return mn.d;
-}
-
-/*
- startpos:
- 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(
- u32 daynight_ratio,
- v3f posRelative_f,
- v3s16 startpos,
- u16 length,
- v3s16 translate_dir,
- v3f translate_dir_f,
- v3s16 face_dir,
- v3f face_dir_f,
- core::array<FastFace> &dest)
-{
- v3s16 p = startpos;
-
- u16 continuous_tiles_count = 0;
-
- MapNode n0 = getNodeParentNoEx(p);
- MapNode n1 = getNodeParentNoEx(p + face_dir);
-
- u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir);
-
- TileSpec tile0 = getNodeTile(n0, p, face_dir);
- TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir);
-
- for(u16 j=0; j<length; j++)
- {
- bool next_is_different = true;
-
- v3s16 p_next;
- MapNode n0_next;
- MapNode n1_next;
- TileSpec tile0_next;
- TileSpec tile1_next;
- u8 light_next = 0;
-
- if(j != length - 1)
- {
- p_next = p + translate_dir;
- n0_next = getNodeParentNoEx(p_next);
- n1_next = getNodeParentNoEx(p_next + face_dir);
- tile0_next = getNodeTile(n0_next, p_next, face_dir);
- tile1_next = getNodeTile(n1_next, p_next + face_dir, -face_dir);
- light_next = getFaceLight(daynight_ratio, n0_next, n1_next, face_dir);
-
- if(tile0_next == tile0
- && tile1_next == tile1
- && light_next == light)
- {
- next_is_different = false;
- }
- }
-
- continuous_tiles_count++;
-
- if(next_is_different)
- {
- /*
- Create a face if there should be one
- */
- //u8 mf = face_contents(tile0, tile1);
- // This is hackish
- u8 content0 = getNodeContent(p, n0);
- u8 content1 = getNodeContent(p + face_dir, n1);
- u8 mf = face_contents(content0, content1);
-
- if(mf != 0)
- {
- // Floating point conversion of the position vector
- v3f pf(p.X, p.Y, p.Z);
- // Center point of face (kind of)
- v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
- v3f scale(1,1,1);
- if(translate_dir.X != 0){
- scale.X = continuous_tiles_count;
- }
- if(translate_dir.Y != 0){
- scale.Y = continuous_tiles_count;
- }
- if(translate_dir.Z != 0){
- scale.Z = continuous_tiles_count;
- }
-
- //FastFace *f;
-
- // If node at sp (tile0) is more solid
- if(mf == 1)
- {
- makeFastFace(tile0, light,
- sp, face_dir, scale,
- posRelative_f, dest);
- }
- // If node at sp is less solid (mf == 2)
- else
- {
- makeFastFace(tile1, light,
- sp+face_dir_f, -face_dir, scale,
- posRelative_f, dest);
- }
- //dest.push_back(f);
- }
-
- continuous_tiles_count = 0;
- n0 = n0_next;
- n1 = n1_next;
- tile0 = tile0_next;
- tile1 = tile1_next;
- light = light_next;
- }
-
- p = p_next;
- }
-}
-
-/*
- 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;
-};
-