3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "mapblock_mesh.h"
24 #include "main.h" // For g_settings and g_texturesource
25 #include "content_mapblock.h"
27 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
29 m_daynight_ratio = daynight_ratio;
30 m_blockpos = block->getPos();
32 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
35 There is no harm not copying the TempMods of the neighbors
36 because they are already copied to this block
39 block->copyTempMods(m_temp_mods);
45 // Allocate this block + neighbors
47 m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
48 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
51 //TimeTaker timer("copy central block data");
55 block->copyTo(m_vmanip);
58 //TimeTaker timer("copy neighbor block data");
62 Copy neighbors. This is lightning fast.
63 Copying only the borders would be *very* slow.
67 NodeContainer *parentcontainer = block->getParent();
68 // This will only work if the parent is the map
69 assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP);
70 // OK, we have the map!
71 Map *map = (Map*)parentcontainer;
73 for(u16 i=0; i<6; i++)
75 const v3s16 &dir = g_6dirs[i];
76 v3s16 bp = m_blockpos + dir;
77 MapBlock *b = map->getBlockNoCreateNoEx(bp);
87 void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
90 If looked from outside the node towards the face, the corners are:
96 if(dir == v3s16(0,0,1))
98 // If looking towards z+, this is the face that is behind
99 // the center point, facing towards z+.
100 vertex_dirs[0] = v3s16(-1,-1, 1);
101 vertex_dirs[1] = v3s16( 1,-1, 1);
102 vertex_dirs[2] = v3s16( 1, 1, 1);
103 vertex_dirs[3] = v3s16(-1, 1, 1);
105 else if(dir == v3s16(0,0,-1))
108 vertex_dirs[0] = v3s16( 1,-1,-1);
109 vertex_dirs[1] = v3s16(-1,-1,-1);
110 vertex_dirs[2] = v3s16(-1, 1,-1);
111 vertex_dirs[3] = v3s16( 1, 1,-1);
113 else if(dir == v3s16(1,0,0))
116 vertex_dirs[0] = v3s16( 1,-1, 1);
117 vertex_dirs[1] = v3s16( 1,-1,-1);
118 vertex_dirs[2] = v3s16( 1, 1,-1);
119 vertex_dirs[3] = v3s16( 1, 1, 1);
121 else if(dir == v3s16(-1,0,0))
124 vertex_dirs[0] = v3s16(-1,-1,-1);
125 vertex_dirs[1] = v3s16(-1,-1, 1);
126 vertex_dirs[2] = v3s16(-1, 1, 1);
127 vertex_dirs[3] = v3s16(-1, 1,-1);
129 else if(dir == v3s16(0,1,0))
131 // faces towards Y+ (assume Z- as "down" in texture)
132 vertex_dirs[0] = v3s16( 1, 1,-1);
133 vertex_dirs[1] = v3s16(-1, 1,-1);
134 vertex_dirs[2] = v3s16(-1, 1, 1);
135 vertex_dirs[3] = v3s16( 1, 1, 1);
137 else if(dir == v3s16(0,-1,0))
139 // faces towards Y- (assume Z+ as "down" in texture)
140 vertex_dirs[0] = v3s16( 1,-1, 1);
141 vertex_dirs[1] = v3s16(-1,-1, 1);
142 vertex_dirs[2] = v3s16(-1,-1,-1);
143 vertex_dirs[3] = v3s16( 1,-1,-1);
147 inline video::SColor lightColor(u8 alpha, u8 light)
149 return video::SColor(alpha,light,light,light);
155 video::S3DVertex vertices[4]; // Precalculated vertices
158 void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
159 v3s16 dir, v3f scale, v3f posRelative_f,
160 core::array<FastFace> &dest)
164 // Position is at the center of the cube.
169 v3s16 vertex_dirs[4];
170 getNodeVertexDirs(dir, vertex_dirs);
171 for(u16 i=0; i<4; i++)
174 BS/2*vertex_dirs[i].X,
175 BS/2*vertex_dirs[i].Y,
176 BS/2*vertex_dirs[i].Z
180 for(u16 i=0; i<4; i++)
182 vertex_pos[i].X *= scale.X;
183 vertex_pos[i].Y *= scale.Y;
184 vertex_pos[i].Z *= scale.Z;
185 vertex_pos[i] += pos + posRelative_f;
189 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
190 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
191 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
193 v3f zerovector = v3f(0,0,0);
195 u8 alpha = tile.alpha;
197 if(tile.id == TILE_WATER)
198 alpha = WATER_ALPHA;*/
200 float x0 = tile.texture.pos.X;
201 float y0 = tile.texture.pos.Y;
202 float w = tile.texture.size.X;
203 float h = tile.texture.size.Y;
205 /*video::SColor c = lightColor(alpha, li);
207 face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
208 core::vector2d<f32>(x0+w*abs_scale, y0+h));
209 face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
210 core::vector2d<f32>(x0, y0+h));
211 face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
212 core::vector2d<f32>(x0, y0));
213 face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
214 core::vector2d<f32>(x0+w*abs_scale, y0));*/
216 face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
217 lightColor(alpha, li0),
218 core::vector2d<f32>(x0+w*abs_scale, y0+h));
219 face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
220 lightColor(alpha, li1),
221 core::vector2d<f32>(x0, y0+h));
222 face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
223 lightColor(alpha, li2),
224 core::vector2d<f32>(x0, y0));
225 face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
226 lightColor(alpha, li3),
227 core::vector2d<f32>(x0+w*abs_scale, y0));
231 //f->tile = TILE_STONE;
233 dest.push_back(face);
237 Gets node tile from any place relative to block.
238 Returns TILE_NODE if doesn't exist or should not be drawn.
240 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
241 NodeModMap &temp_mods)
244 spec = mn.getTile(face_dir);
247 Check temporary modifications on this node
249 /*core::map<v3s16, NodeMod>::Node *n;
250 n = m_temp_mods.find(p);
254 struct NodeMod mod = n->getValue();*/
256 if(temp_mods.get(p, &mod))
258 if(mod.type == NODEMOD_CHANGECONTENT)
260 MapNode mn2(mod.param);
261 spec = mn2.getTile(face_dir);
263 if(mod.type == NODEMOD_CRACK)
266 Get texture id, translate it to name, append stuff to
270 // Get original texture name
271 u32 orig_id = spec.texture.id;
272 std::string orig_name = g_texturesource->getTextureName(orig_id);
274 // Create new texture name
275 std::ostringstream os;
276 os<<orig_name<<"^[crack"<<mod.param;
279 u32 new_id = g_texturesource->getTextureId(os.str());
281 /*dstream<<"MapBlock::getNodeTile(): Switching from "
282 <<orig_name<<" to "<<os.str()<<" ("
283 <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
285 spec.texture = g_texturesource->getTexture(new_id);
292 u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
295 Check temporary modifications on this node
297 /*core::map<v3s16, NodeMod>::Node *n;
298 n = m_temp_mods.find(p);
302 struct NodeMod mod = n->getValue();*/
304 if(temp_mods.get(p, &mod))
306 if(mod.type == NODEMOD_CHANGECONTENT)
311 if(mod.type == NODEMOD_CRACK)
314 Content doesn't change.
316 face_contents works just like it should, because
317 there should not be faces between differently cracked
320 If a semi-transparent node is cracked in front an
321 another one, it really doesn't matter whether there
322 is a cracked face drawn in between or not.
341 // Calculate lighting at the XYZ- corner of p
342 u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
344 u16 ambient_occlusion = 0;
347 for(u32 i=0; i<8; i++)
349 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
350 if(content_features(n.d).param_type == CPT_LIGHT
351 // Fast-style leaves look better this way
352 && content_features(n.d).solidness != 2)
354 light += decode_light(n.getLightBlend(daynight_ratio));
359 if(n.d != CONTENT_IGNORE)
367 light /= light_count;
369 if(ambient_occlusion > 4)
371 ambient_occlusion -= 4;
372 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
378 // Calculate lighting at the given corner of p
379 u8 getSmoothLight(v3s16 p, v3s16 corner,
380 VoxelManipulator &vmanip, u32 daynight_ratio)
382 if(corner.X == 1) p.X += 1;
383 else assert(corner.X == -1);
384 if(corner.Y == 1) p.Y += 1;
385 else assert(corner.Y == -1);
386 if(corner.Z == 1) p.Z += 1;
387 else assert(corner.Z == -1);
389 return getSmoothLight(p, vmanip, daynight_ratio);
394 v3s16 blockpos_nodes,
398 VoxelManipulator &vmanip,
399 NodeModMap &temp_mods,
400 bool smooth_lighting,
404 v3s16 &face_dir_corrected,
409 MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
410 MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
411 TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
412 TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
415 u8 content0 = getNodeContent(p, n0, temp_mods);
416 u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
417 u8 mf = face_contents(content0, content1);
431 face_dir_corrected = face_dir;
436 p_corrected = p + face_dir;
437 face_dir_corrected = -face_dir;
440 if(smooth_lighting == false)
442 lights[0] = lights[1] = lights[2] = lights[3] =
443 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
447 v3s16 vertex_dirs[4];
448 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
449 for(u16 i=0; i<4; i++)
451 lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
452 vertex_dirs[i], vmanip, daynight_ratio);
461 translate_dir: unit vector with only one of x, y or z
462 face_dir: unit vector with only one of x, y or z
464 void updateFastFaceRow(
473 core::array<FastFace> &dest,
474 NodeModMap &temp_mods,
475 VoxelManipulator &vmanip,
476 v3s16 blockpos_nodes,
477 bool smooth_lighting)
481 u16 continuous_tiles_count = 0;
485 v3s16 face_dir_corrected;
488 getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
489 vmanip, temp_mods, smooth_lighting,
490 makes_face, p_corrected, face_dir_corrected, lights, tile);
492 for(u16 j=0; j<length; j++)
494 // If tiling can be done, this is set to false in the next step
495 bool next_is_different = true;
499 bool next_makes_face = false;
500 v3s16 next_p_corrected;
501 v3s16 next_face_dir_corrected;
502 u8 next_lights[4] = {0,0,0,0};
505 // If at last position, there is nothing to compare to and
506 // the face must be drawn anyway
509 p_next = p + translate_dir;
511 getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
512 vmanip, temp_mods, smooth_lighting,
513 next_makes_face, next_p_corrected,
514 next_face_dir_corrected, next_lights,
517 if(next_makes_face == makes_face
518 && next_p_corrected == p_corrected
519 && next_face_dir_corrected == face_dir_corrected
520 && next_lights[0] == lights[0]
521 && next_lights[1] == lights[1]
522 && next_lights[2] == lights[2]
523 && next_lights[3] == lights[3]
524 && next_tile == tile)
526 next_is_different = false;
530 continuous_tiles_count++;
532 // This is set to true if the texture doesn't allow more tiling
533 bool end_of_texture = false;
535 If there is no texture, it can be tiled infinitely.
536 If tiled==0, it means the texture can be tiled infinitely.
537 Otherwise check tiled agains continuous_tiles_count.
539 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
541 if(tile.texture.tiled <= continuous_tiles_count)
542 end_of_texture = true;
545 // Do this to disable tiling textures
546 //end_of_texture = true; //DEBUG
548 if(next_is_different || end_of_texture)
551 Create a face if there should be one
555 // Floating point conversion of the position vector
556 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
557 // Center point of face (kind of)
558 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
561 if(translate_dir.X != 0)
563 scale.X = continuous_tiles_count;
565 if(translate_dir.Y != 0)
567 scale.Y = continuous_tiles_count;
569 if(translate_dir.Z != 0)
571 scale.Z = continuous_tiles_count;
574 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
575 sp, face_dir_corrected, scale,
576 posRelative_f, dest);
579 continuous_tiles_count = 0;
581 makes_face = next_makes_face;
582 p_corrected = next_p_corrected;
583 face_dir_corrected = next_face_dir_corrected;
584 lights[0] = next_lights[0];
585 lights[1] = next_lights[1];
586 lights[2] = next_lights[2];
587 lights[3] = next_lights[3];
595 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
597 // 4-21ms for MAP_BLOCKSIZE=16
598 // 24-155ms for MAP_BLOCKSIZE=32
599 //TimeTaker timer1("makeMapBlockMesh()");
601 core::array<FastFace> fastfaces_new;
603 v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
605 // floating point conversion
606 v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
611 //bool new_style_water = g_settings.getBool("new_style_water");
612 //bool new_style_leaves = g_settings.getBool("new_style_leaves");
613 bool smooth_lighting = g_settings.getBool("smooth_lighting");
616 We are including the faces of the trailing edges of the block.
617 This means that when something changes, the caller must
618 also update the meshes of the blocks at the leading edges.
620 NOTE: This is the slowest part of this method.
624 // 4-23ms for MAP_BLOCKSIZE=16
625 //TimeTaker timer2("updateMesh() collect");
628 Go through every y,z and get top(y+) faces in rows of x+
630 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
631 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
632 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
633 v3s16(0,y,z), MAP_BLOCKSIZE,
636 v3s16(0,1,0), //face dir
646 Go through every x,y and get right(x+) faces in rows of z+
648 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
649 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
650 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
651 v3s16(x,y,0), MAP_BLOCKSIZE,
664 Go through every y,z and get back(z+) faces in rows of x+
666 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
667 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
668 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
669 v3s16(0,y,z), MAP_BLOCKSIZE,
686 Convert FastFaces to SMesh
689 MeshCollector collector;
691 if(fastfaces_new.size() > 0)
693 // avg 0ms (100ms spikes when loading textures the first time)
694 //TimeTaker timer2("updateMesh() mesh building");
696 video::SMaterial material;
697 material.setFlag(video::EMF_LIGHTING, false);
698 material.setFlag(video::EMF_BILINEAR_FILTER, false);
699 material.setFlag(video::EMF_FOG_ENABLE, true);
700 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
701 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
703 for(u32 i=0; i<fastfaces_new.size(); i++)
705 FastFace &f = fastfaces_new[i];
707 const u16 indices[] = {0,1,2,2,3,0};
708 const u16 indices_alternate[] = {0,1,3,2,3,1};
710 video::ITexture *texture = f.tile.texture.atlas;
714 material.setTexture(0, texture);
716 f.tile.applyMaterialOptions(material);
718 const u16 *indices_p = indices;
721 Revert triangles for nicer looking gradient if vertices
722 1 and 3 have same color or 0 and 2 have different color.
724 if(f.vertices[0].Color != f.vertices[2].Color
725 || f.vertices[1].Color == f.vertices[3].Color)
726 indices_p = indices_alternate;
728 collector.append(material, f.vertices, 4, indices_p, 6);
733 Add special graphics:
740 mapblock_mesh_generate_special(data, collector);
743 Add stuff from collector to mesh
746 scene::SMesh *mesh_new = NULL;
747 mesh_new = new scene::SMesh();
749 collector.fillMesh(mesh_new);
752 Do some stuff to the mesh
755 mesh_new->recalculateBoundingBox();
758 Delete new mesh if it is empty
761 if(mesh_new->getMeshBufferCount() == 0)
770 // Usually 1-700 faces and 1-7 materials
771 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
772 <<"and uses "<<mesh_new->getMeshBufferCount()
773 <<" materials (meshbuffers)"<<std::endl;
776 // Use VBO for mesh (this just would set this for ever buffer)
777 // This will lead to infinite memory usage because or irrlicht.
778 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
781 NOTE: If that is enabled, some kind of a queue to the main
782 thread should be made which would call irrlicht to delete
783 the hardware buffer and then delete the mesh
789 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;