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"
29 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
31 m_daynight_ratio = daynight_ratio;
32 m_blockpos = block->getPos();
34 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
37 There is no harm not copying the TempMods of the neighbors
38 because they are already copied to this block
41 block->copyTempMods(m_temp_mods);
47 // Allocate this block + neighbors
49 m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
50 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
53 //TimeTaker timer("copy central block data");
57 block->copyTo(m_vmanip);
60 //TimeTaker timer("copy neighbor block data");
64 Copy neighbors. This is lightning fast.
65 Copying only the borders would be *very* slow.
69 Map *map = block->getParent();
71 for(u16 i=0; i<6; i++)
73 const v3s16 &dir = g_6dirs[i];
74 v3s16 bp = m_blockpos + dir;
75 MapBlock *b = map->getBlockNoCreateNoEx(bp);
85 void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
88 If looked from outside the node towards the face, the corners are:
94 if(dir == v3s16(0,0,1))
96 // If looking towards z+, this is the face that is behind
97 // the center point, facing towards z+.
98 vertex_dirs[0] = v3s16(-1,-1, 1);
99 vertex_dirs[1] = v3s16( 1,-1, 1);
100 vertex_dirs[2] = v3s16( 1, 1, 1);
101 vertex_dirs[3] = v3s16(-1, 1, 1);
103 else if(dir == v3s16(0,0,-1))
106 vertex_dirs[0] = v3s16( 1,-1,-1);
107 vertex_dirs[1] = v3s16(-1,-1,-1);
108 vertex_dirs[2] = v3s16(-1, 1,-1);
109 vertex_dirs[3] = v3s16( 1, 1,-1);
111 else if(dir == v3s16(1,0,0))
114 vertex_dirs[0] = v3s16( 1,-1, 1);
115 vertex_dirs[1] = v3s16( 1,-1,-1);
116 vertex_dirs[2] = v3s16( 1, 1,-1);
117 vertex_dirs[3] = v3s16( 1, 1, 1);
119 else if(dir == v3s16(-1,0,0))
122 vertex_dirs[0] = v3s16(-1,-1,-1);
123 vertex_dirs[1] = v3s16(-1,-1, 1);
124 vertex_dirs[2] = v3s16(-1, 1, 1);
125 vertex_dirs[3] = v3s16(-1, 1,-1);
127 else if(dir == v3s16(0,1,0))
129 // faces towards Y+ (assume Z- as "down" in texture)
130 vertex_dirs[0] = v3s16( 1, 1,-1);
131 vertex_dirs[1] = v3s16(-1, 1,-1);
132 vertex_dirs[2] = v3s16(-1, 1, 1);
133 vertex_dirs[3] = v3s16( 1, 1, 1);
135 else if(dir == v3s16(0,-1,0))
137 // faces towards Y- (assume Z+ as "down" in texture)
138 vertex_dirs[0] = v3s16( 1,-1, 1);
139 vertex_dirs[1] = v3s16(-1,-1, 1);
140 vertex_dirs[2] = v3s16(-1,-1,-1);
141 vertex_dirs[3] = v3s16( 1,-1,-1);
145 video::SColor MapBlock_LightColor(u8 alpha, u8 light)
148 return video::SColor(alpha,light,light,light);
150 //return video::SColor(alpha,light,light,MYMAX(0, (s16)light-25)+25);
151 /*return video::SColor(alpha,light,light,MYMAX(0,
152 pow((float)light/255.0, 0.8)*255.0));*/
154 // Emphase blue a bit in darker places
158 return video::SColor(alpha,light,light,light);
160 return video::SColor(alpha,light,light,MYMAX(0,
161 pow((float)light/lim, power)*lim));
168 video::S3DVertex vertices[4]; // Precalculated vertices
171 void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
172 v3s16 dir, v3f scale, v3f posRelative_f,
173 core::array<FastFace> &dest)
177 // Position is at the center of the cube.
182 v3s16 vertex_dirs[4];
183 getNodeVertexDirs(dir, vertex_dirs);
184 for(u16 i=0; i<4; i++)
187 BS/2*vertex_dirs[i].X,
188 BS/2*vertex_dirs[i].Y,
189 BS/2*vertex_dirs[i].Z
193 for(u16 i=0; i<4; i++)
195 vertex_pos[i].X *= scale.X;
196 vertex_pos[i].Y *= scale.Y;
197 vertex_pos[i].Z *= scale.Z;
198 vertex_pos[i] += pos + posRelative_f;
202 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
203 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
204 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
206 v3f zerovector = v3f(0,0,0);
208 u8 alpha = tile.alpha;
210 if(tile.id == TILE_WATER)
211 alpha = WATER_ALPHA;*/
213 float x0 = tile.texture.pos.X;
214 float y0 = tile.texture.pos.Y;
215 float w = tile.texture.size.X;
216 float h = tile.texture.size.Y;
218 /*video::SColor c = MapBlock_LightColor(alpha, li);
220 face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
221 core::vector2d<f32>(x0+w*abs_scale, y0+h));
222 face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
223 core::vector2d<f32>(x0, y0+h));
224 face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
225 core::vector2d<f32>(x0, y0));
226 face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
227 core::vector2d<f32>(x0+w*abs_scale, y0));*/
229 face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
230 MapBlock_LightColor(alpha, li0),
231 core::vector2d<f32>(x0+w*abs_scale, y0+h));
232 face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
233 MapBlock_LightColor(alpha, li1),
234 core::vector2d<f32>(x0, y0+h));
235 face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
236 MapBlock_LightColor(alpha, li2),
237 core::vector2d<f32>(x0, y0));
238 face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
239 MapBlock_LightColor(alpha, li3),
240 core::vector2d<f32>(x0+w*abs_scale, y0));
244 //f->tile = TILE_STONE;
246 dest.push_back(face);
250 Gets node tile from any place relative to block.
251 Returns TILE_NODE if doesn't exist or should not be drawn.
253 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
254 NodeModMap &temp_mods)
257 spec = mn.getTile(face_dir);
260 Check temporary modifications on this node
262 /*core::map<v3s16, NodeMod>::Node *n;
263 n = m_temp_mods.find(p);
267 struct NodeMod mod = n->getValue();*/
269 if(temp_mods.get(p, &mod))
271 if(mod.type == NODEMOD_CHANGECONTENT)
273 MapNode mn2(mod.param);
274 spec = mn2.getTile(face_dir);
276 if(mod.type == NODEMOD_CRACK)
279 Get texture id, translate it to name, append stuff to
283 // Get original texture name
284 u32 orig_id = spec.texture.id;
285 std::string orig_name = g_texturesource->getTextureName(orig_id);
287 // Create new texture name
288 std::ostringstream os;
289 os<<orig_name<<"^[crack"<<mod.param;
292 u32 new_id = g_texturesource->getTextureId(os.str());
294 /*dstream<<"MapBlock::getNodeTile(): Switching from "
295 <<orig_name<<" to "<<os.str()<<" ("
296 <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
298 spec.texture = g_texturesource->getTexture(new_id);
305 content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
308 Check temporary modifications on this node
310 /*core::map<v3s16, NodeMod>::Node *n;
311 n = m_temp_mods.find(p);
315 struct NodeMod mod = n->getValue();*/
317 if(temp_mods.get(p, &mod))
319 if(mod.type == NODEMOD_CHANGECONTENT)
324 if(mod.type == NODEMOD_CRACK)
327 Content doesn't change.
329 face_contents works just like it should, because
330 there should not be faces between differently cracked
333 If a semi-transparent node is cracked in front an
334 another one, it really doesn't matter whether there
335 is a cracked face drawn in between or not.
340 return mn.getContent();
354 // Calculate lighting at the XYZ- corner of p
355 u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
357 u16 ambient_occlusion = 0;
360 for(u32 i=0; i<8; i++)
362 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
363 if(content_features(n).param_type == CPT_LIGHT
364 // Fast-style leaves look better this way
365 && content_features(n).solidness != 2)
367 light += decode_light(n.getLightBlend(daynight_ratio));
372 if(n.getContent() != CONTENT_IGNORE)
380 light /= light_count;
382 if(ambient_occlusion > 4)
384 ambient_occlusion -= 4;
385 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
391 // Calculate lighting at the given corner of p
392 u8 getSmoothLight(v3s16 p, v3s16 corner,
393 VoxelManipulator &vmanip, u32 daynight_ratio)
395 if(corner.X == 1) p.X += 1;
396 else assert(corner.X == -1);
397 if(corner.Y == 1) p.Y += 1;
398 else assert(corner.Y == -1);
399 if(corner.Z == 1) p.Z += 1;
400 else assert(corner.Z == -1);
402 return getSmoothLight(p, vmanip, daynight_ratio);
407 v3s16 blockpos_nodes,
411 VoxelManipulator &vmanip,
412 NodeModMap &temp_mods,
413 bool smooth_lighting,
417 v3s16 &face_dir_corrected,
422 MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
423 MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
424 TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
425 TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
428 content_t content0 = getNodeContent(p, n0, temp_mods);
429 content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
430 u8 mf = face_contents(content0, content1);
444 face_dir_corrected = face_dir;
449 p_corrected = p + face_dir;
450 face_dir_corrected = -face_dir;
453 if(smooth_lighting == false)
455 lights[0] = lights[1] = lights[2] = lights[3] =
456 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
460 v3s16 vertex_dirs[4];
461 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
462 for(u16 i=0; i<4; i++)
464 lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
465 vertex_dirs[i], vmanip, daynight_ratio);
474 translate_dir: unit vector with only one of x, y or z
475 face_dir: unit vector with only one of x, y or z
477 void updateFastFaceRow(
486 core::array<FastFace> &dest,
487 NodeModMap &temp_mods,
488 VoxelManipulator &vmanip,
489 v3s16 blockpos_nodes,
490 bool smooth_lighting)
494 u16 continuous_tiles_count = 0;
496 bool makes_face = false;
498 v3s16 face_dir_corrected;
499 u8 lights[4] = {0,0,0,0};
501 getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
502 vmanip, temp_mods, smooth_lighting,
503 makes_face, p_corrected, face_dir_corrected, lights, tile);
505 for(u16 j=0; j<length; j++)
507 // If tiling can be done, this is set to false in the next step
508 bool next_is_different = true;
512 bool next_makes_face = false;
513 v3s16 next_p_corrected;
514 v3s16 next_face_dir_corrected;
515 u8 next_lights[4] = {0,0,0,0};
518 // If at last position, there is nothing to compare to and
519 // the face must be drawn anyway
522 p_next = p + translate_dir;
524 getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
525 vmanip, temp_mods, smooth_lighting,
526 next_makes_face, next_p_corrected,
527 next_face_dir_corrected, next_lights,
530 if(next_makes_face == makes_face
531 && next_p_corrected == p_corrected + translate_dir
532 && next_face_dir_corrected == face_dir_corrected
533 && next_lights[0] == lights[0]
534 && next_lights[1] == lights[1]
535 && next_lights[2] == lights[2]
536 && next_lights[3] == lights[3]
537 && next_tile == tile)
539 next_is_different = false;
543 g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
544 next_makes_face != makes_face ? 1 : 0);
545 g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
546 (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
547 g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
548 next_face_dir_corrected != face_dir_corrected ? 1 : 0);
549 g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
550 (next_lights[0] != lights[0] ||
551 next_lights[0] != lights[0] ||
552 next_lights[0] != lights[0] ||
553 next_lights[0] != lights[0]) ? 1 : 0);
554 g_profiler->add("Meshgen: diff: !(next_tile == tile)",
555 !(next_tile == tile) ? 1 : 0);
558 /*g_profiler->add("Meshgen: Total faces checked", 1);
560 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
563 g_profiler->add("Meshgen: diff: last position", 1);*/
566 continuous_tiles_count++;
568 // This is set to true if the texture doesn't allow more tiling
569 bool end_of_texture = false;
571 If there is no texture, it can be tiled infinitely.
572 If tiled==0, it means the texture can be tiled infinitely.
573 Otherwise check tiled agains continuous_tiles_count.
575 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
577 if(tile.texture.tiled <= continuous_tiles_count)
578 end_of_texture = true;
581 // Do this to disable tiling textures
582 //end_of_texture = true; //DEBUG
584 if(next_is_different || end_of_texture)
587 Create a face if there should be one
591 // Floating point conversion of the position vector
592 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
593 // Center point of face (kind of)
594 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
595 if(continuous_tiles_count != 1)
596 sp += translate_dir_f;
599 if(translate_dir.X != 0)
601 scale.X = continuous_tiles_count;
603 if(translate_dir.Y != 0)
605 scale.Y = continuous_tiles_count;
607 if(translate_dir.Z != 0)
609 scale.Z = continuous_tiles_count;
612 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
613 sp, face_dir_corrected, scale,
614 posRelative_f, dest);
616 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
617 for(int i=1; i<continuous_tiles_count; i++){
618 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
622 continuous_tiles_count = 0;
624 makes_face = next_makes_face;
625 p_corrected = next_p_corrected;
626 face_dir_corrected = next_face_dir_corrected;
627 lights[0] = next_lights[0];
628 lights[1] = next_lights[1];
629 lights[2] = next_lights[2];
630 lights[3] = next_lights[3];
638 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
640 // 4-21ms for MAP_BLOCKSIZE=16
641 // 24-155ms for MAP_BLOCKSIZE=32
642 //TimeTaker timer1("makeMapBlockMesh()");
644 core::array<FastFace> fastfaces_new;
646 v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
648 // floating point conversion
649 v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
654 //bool new_style_water = g_settings->getBool("new_style_water");
655 //bool new_style_leaves = g_settings->getBool("new_style_leaves");
656 bool smooth_lighting = g_settings->getBool("smooth_lighting");
659 We are including the faces of the trailing edges of the block.
660 This means that when something changes, the caller must
661 also update the meshes of the blocks at the leading edges.
663 NOTE: This is the slowest part of this method.
667 // 4-23ms for MAP_BLOCKSIZE=16
668 //TimeTaker timer2("updateMesh() collect");
671 Go through every y,z and get top(y+) faces in rows of x+
673 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
674 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
675 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
676 v3s16(0,y,z), MAP_BLOCKSIZE,
679 v3s16(0,1,0), //face dir
689 Go through every x,y and get right(x+) faces in rows of z+
691 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
692 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
693 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
694 v3s16(x,y,0), MAP_BLOCKSIZE,
707 Go through every y,z and get back(z+) faces in rows of x+
709 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
710 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
711 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
712 v3s16(0,y,z), MAP_BLOCKSIZE,
729 Convert FastFaces to SMesh
732 MeshCollector collector;
734 if(fastfaces_new.size() > 0)
736 // avg 0ms (100ms spikes when loading textures the first time)
737 //TimeTaker timer2("updateMesh() mesh building");
739 video::SMaterial material;
740 material.setFlag(video::EMF_LIGHTING, false);
741 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
742 material.setFlag(video::EMF_BILINEAR_FILTER, false);
743 material.setFlag(video::EMF_FOG_ENABLE, true);
744 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
745 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
746 material.MaterialType
747 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
749 for(u32 i=0; i<fastfaces_new.size(); i++)
751 FastFace &f = fastfaces_new[i];
753 const u16 indices[] = {0,1,2,2,3,0};
754 const u16 indices_alternate[] = {0,1,3,2,3,1};
756 video::ITexture *texture = f.tile.texture.atlas;
760 material.setTexture(0, texture);
762 f.tile.applyMaterialOptions(material);
764 const u16 *indices_p = indices;
767 Revert triangles for nicer looking gradient if vertices
768 1 and 3 have same color or 0 and 2 have different color.
770 if(f.vertices[0].Color != f.vertices[2].Color
771 || f.vertices[1].Color == f.vertices[3].Color)
772 indices_p = indices_alternate;
774 collector.append(material, f.vertices, 4, indices_p, 6);
779 Add special graphics:
786 mapblock_mesh_generate_special(data, collector);
789 Add stuff from collector to mesh
792 scene::SMesh *mesh_new = NULL;
793 mesh_new = new scene::SMesh();
795 collector.fillMesh(mesh_new);
798 Do some stuff to the mesh
801 mesh_new->recalculateBoundingBox();
804 Delete new mesh if it is empty
807 if(mesh_new->getMeshBufferCount() == 0)
816 // Usually 1-700 faces and 1-7 materials
817 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
818 <<"and uses "<<mesh_new->getMeshBufferCount()
819 <<" materials (meshbuffers)"<<std::endl;
822 // Use VBO for mesh (this just would set this for ever buffer)
823 // This will lead to infinite memory usage because or irrlicht.
824 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
827 NOTE: If that is enabled, some kind of a queue to the main
828 thread should be made which would call irrlicht to delete
829 the hardware buffer and then delete the mesh
835 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;