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_profiler
29 #include "content_mapblock.h"
35 MeshMakeData::MeshMakeData(IGameDef *gamedef):
37 m_blockpos(-1337,-1337,-1337),
38 m_crack_pos_relative(-1337, -1337, -1337),
39 m_smooth_lighting(false),
43 void MeshMakeData::fill(MapBlock *block)
45 m_blockpos = block->getPos();
47 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
53 // Allocate this block + neighbors
55 m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
56 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
59 //TimeTaker timer("copy central block data");
63 block->copyTo(m_vmanip);
66 //TimeTaker timer("copy neighbor block data");
70 Copy neighbors. This is lightning fast.
71 Copying only the borders would be *very* slow.
75 Map *map = block->getParent();
77 for(u16 i=0; i<6; i++)
79 const v3s16 &dir = g_6dirs[i];
80 v3s16 bp = m_blockpos + dir;
81 MapBlock *b = map->getBlockNoCreateNoEx(bp);
88 void MeshMakeData::fillSingleNode(MapNode *node)
90 m_blockpos = v3s16(0,0,0);
92 v3s16 blockpos_nodes = v3s16(0,0,0);
93 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
94 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
95 s32 volume = area.getVolume();
96 s32 our_node_index = area.index(1,1,1);
98 // Allocate this block + neighbors
100 m_vmanip.addArea(area);
103 MapNode *data = new MapNode[volume];
104 for(s32 i = 0; i < volume; i++)
106 if(i == our_node_index)
112 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
115 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
119 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
122 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
125 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
127 m_smooth_lighting = smooth_lighting;
131 Light and vertex color functions
135 Calculate non-smooth lighting at interior of node.
138 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
141 INodeDefManager *ndef = data->m_gamedef->ndef();
142 u8 light = n.getLight(bank, ndef);
146 light = undiminish_light(light);
151 light = diminish_light(light);
155 return decode_light(light);
159 Calculate non-smooth lighting at interior of node.
162 u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data)
164 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, data);
165 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, data);
166 return day | (night << 8);
170 Calculate non-smooth lighting at face of node.
173 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
174 v3s16 face_dir, MeshMakeData *data)
176 INodeDefManager *ndef = data->m_gamedef->ndef();
179 u8 l1 = n.getLight(bank, ndef);
180 u8 l2 = n2.getLight(bank, ndef);
186 // Boost light level for light sources
187 u8 light_source = MYMAX(ndef->get(n).light_source,
188 ndef->get(n2).light_source);
189 //if(light_source >= light)
190 //return decode_light(undiminish_light(light_source));
191 if(light_source > light)
192 //return decode_light(light_source);
193 light = light_source;
195 // Make some nice difference to different sides
197 // This makes light come from a corner
198 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
199 light = diminish_light(diminish_light(light));
200 else if(face_dir.X == -1 || face_dir.Z == -1)
201 light = diminish_light(light);*/
203 // All neighboring faces have different shade (like in minecraft)
204 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
205 light = diminish_light(diminish_light(light));
206 else if(face_dir.Z == 1 || face_dir.Z == -1)
207 light = diminish_light(light);
209 return decode_light(light);
213 Calculate non-smooth lighting at face of node.
216 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data)
218 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data);
219 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data);
220 return day | (night << 8);
224 Calculate smooth lighting at the XYZ- corner of p.
227 static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
229 static v3s16 dirs8[8] = {
240 INodeDefManager *ndef = data->m_gamedef->ndef();
242 u16 ambient_occlusion = 0;
245 u8 light_source_max = 0;
246 for(u32 i=0; i<8; i++)
248 MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
249 const ContentFeatures &f = ndef->get(n);
250 if(f.light_source > light_source_max)
251 light_source_max = f.light_source;
252 // Check f.solidness because fast-style leaves look
254 if(f.param_type == CPT_LIGHT && f.solidness != 2)
256 light += decode_light(n.getLight(bank, ndef));
259 else if(n.getContent() != CONTENT_IGNORE)
268 light /= light_count;
270 // Boost brightness around light sources
271 if(decode_light(light_source_max) >= light)
272 //return decode_light(undiminish_light(light_source_max));
273 return decode_light(light_source_max);
275 if(ambient_occlusion > 4)
277 ambient_occlusion -= 4;
278 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
285 Calculate smooth lighting at the XYZ- corner of p.
288 static u16 getSmoothLight(v3s16 p, MeshMakeData *data)
290 u16 day = getSmoothLight(LIGHTBANK_DAY, p, data);
291 u16 night = getSmoothLight(LIGHTBANK_NIGHT, p, data);
292 return day | (night << 8);
296 Calculate smooth lighting at the given corner of p.
299 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
301 if(corner.X == 1) p.X += 1;
302 else assert(corner.X == -1);
303 if(corner.Y == 1) p.Y += 1;
304 else assert(corner.Y == -1);
305 if(corner.Z == 1) p.Z += 1;
306 else assert(corner.Z == -1);
308 return getSmoothLight(p, data);
312 Converts from day + night color values (0..255)
313 and a given daynight_ratio to the final SColor shown on screen.
315 static void finalColorBlend(video::SColor& result,
316 u8 day, u8 night, u32 daynight_ratio)
318 s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
322 b += (day - night) / 13;
323 rg -= (day - night) / 23;
325 // Emphase blue a bit in darker places
326 // Each entry of this array represents a range of 8 blue levels
327 static u8 emphase_blue_when_dark[32] = {
328 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
329 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335 b += emphase_blue_when_dark[b / 8];
337 // Artificial light is yellow-ish
338 static u8 emphase_yellow_when_artificial[16] = {
339 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
341 rg += emphase_yellow_when_artificial[night/16];
353 Mesh generation helpers
357 vertex_dirs: v3s16[4]
359 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
362 If looked from outside the node towards the face, the corners are:
368 if(dir == v3s16(0,0,1))
370 // If looking towards z+, this is the face that is behind
371 // the center point, facing towards z+.
372 vertex_dirs[0] = v3s16(-1,-1, 1);
373 vertex_dirs[1] = v3s16( 1,-1, 1);
374 vertex_dirs[2] = v3s16( 1, 1, 1);
375 vertex_dirs[3] = v3s16(-1, 1, 1);
377 else if(dir == v3s16(0,0,-1))
380 vertex_dirs[0] = v3s16( 1,-1,-1);
381 vertex_dirs[1] = v3s16(-1,-1,-1);
382 vertex_dirs[2] = v3s16(-1, 1,-1);
383 vertex_dirs[3] = v3s16( 1, 1,-1);
385 else if(dir == v3s16(1,0,0))
388 vertex_dirs[0] = v3s16( 1,-1, 1);
389 vertex_dirs[1] = v3s16( 1,-1,-1);
390 vertex_dirs[2] = v3s16( 1, 1,-1);
391 vertex_dirs[3] = v3s16( 1, 1, 1);
393 else if(dir == v3s16(-1,0,0))
396 vertex_dirs[0] = v3s16(-1,-1,-1);
397 vertex_dirs[1] = v3s16(-1,-1, 1);
398 vertex_dirs[2] = v3s16(-1, 1, 1);
399 vertex_dirs[3] = v3s16(-1, 1,-1);
401 else if(dir == v3s16(0,1,0))
403 // faces towards Y+ (assume Z- as "down" in texture)
404 vertex_dirs[0] = v3s16( 1, 1,-1);
405 vertex_dirs[1] = v3s16(-1, 1,-1);
406 vertex_dirs[2] = v3s16(-1, 1, 1);
407 vertex_dirs[3] = v3s16( 1, 1, 1);
409 else if(dir == v3s16(0,-1,0))
411 // faces towards Y- (assume Z+ as "down" in texture)
412 vertex_dirs[0] = v3s16( 1,-1, 1);
413 vertex_dirs[1] = v3s16(-1,-1, 1);
414 vertex_dirs[2] = v3s16(-1,-1,-1);
415 vertex_dirs[3] = v3s16( 1,-1,-1);
422 video::S3DVertex vertices[4]; // Precalculated vertices
425 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
426 v3f p, v3s16 dir, v3f scale, core::array<FastFace> &dest)
430 // Position is at the center of the cube.
434 v3s16 vertex_dirs[4];
435 getNodeVertexDirs(dir, vertex_dirs);
436 for(u16 i=0; i<4; i++)
439 BS/2*vertex_dirs[i].X,
440 BS/2*vertex_dirs[i].Y,
441 BS/2*vertex_dirs[i].Z
445 for(u16 i=0; i<4; i++)
447 vertex_pos[i].X *= scale.X;
448 vertex_pos[i].Y *= scale.Y;
449 vertex_pos[i].Z *= scale.Z;
450 vertex_pos[i] += pos;
454 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
455 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
456 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
458 v3f normal(dir.X, dir.Y, dir.Z);
460 u8 alpha = tile.alpha;
462 float x0 = tile.texture.pos.X;
463 float y0 = tile.texture.pos.Y;
464 float w = tile.texture.size.X;
465 float h = tile.texture.size.Y;
467 face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
468 MapBlock_LightColor(alpha, li0),
469 core::vector2d<f32>(x0+w*abs_scale, y0+h));
470 face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
471 MapBlock_LightColor(alpha, li1),
472 core::vector2d<f32>(x0, y0+h));
473 face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
474 MapBlock_LightColor(alpha, li2),
475 core::vector2d<f32>(x0, y0));
476 face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
477 MapBlock_LightColor(alpha, li3),
478 core::vector2d<f32>(x0+w*abs_scale, y0));
482 dest.push_back(face);
486 Nodes make a face if contents differ and solidness differs.
489 1: Face uses m1's content
490 2: Face uses m2's content
491 equivalent: Whether the blocks share the same face (eg. water and glass)
493 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
495 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
496 INodeDefManager *ndef)
500 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
503 bool contents_differ = (m1 != m2);
505 const ContentFeatures &f1 = ndef->get(m1);
506 const ContentFeatures &f2 = ndef->get(m2);
508 // Contents don't differ for different forms of same liquid
509 if(f1.sameLiquid(f2))
510 contents_differ = false;
512 u8 c1 = f1.solidness;
513 u8 c2 = f2.solidness;
515 bool solidness_differs = (c1 != c2);
516 bool makes_face = contents_differ && solidness_differs;
518 if(makes_face == false)
522 c1 = f1.visual_solidness;
524 c2 = f2.visual_solidness;
528 // If same solidness, liquid takes precense
542 Gets nth node tile (0 <= n <= 5).
544 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
546 INodeDefManager *ndef = data->m_gamedef->ndef();
547 TileSpec spec = ndef->get(mn).tiles[tileindex];
548 // Apply temporary crack
549 if(p == data->m_crack_pos_relative)
551 spec.material_flags |= MATERIAL_FLAG_CRACK;
552 spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
558 Gets node tile given a face direction.
560 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
562 INodeDefManager *ndef = data->m_gamedef->ndef();
564 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
565 // (0,0,1), (0,0,-1) or (0,0,0)
566 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
568 // Convert direction to single integer for table lookup
573 // 4 = invalid, treat as (0,0,0)
577 u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
579 // Get rotation for things like chests
580 u8 facedir = mn.getFaceDir(ndef);
581 assert(facedir <= 3);
583 static const u8 dir_to_tile[4 * 8] =
585 // 0 +X +Y +Z 0 -Z -Y -X
586 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
587 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
588 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
589 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
591 u8 tileindex = dir_to_tile[facedir*8 + dir_i];
592 return getNodeTileN(mn, p, tileindex, data);
595 static void getTileInfo(
603 v3s16 &face_dir_corrected,
608 VoxelManipulator &vmanip = data->m_vmanip;
609 INodeDefManager *ndef = data->m_gamedef->ndef();
610 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
612 MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
613 MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
614 TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
615 TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
618 bool equivalent = false;
619 u8 mf = face_contents(n0.getContent(), n1.getContent(),
634 face_dir_corrected = face_dir;
639 p_corrected = p + face_dir;
640 face_dir_corrected = -face_dir;
643 // eg. water and glass
645 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
647 if(data->m_smooth_lighting == false)
649 lights[0] = lights[1] = lights[2] = lights[3] =
650 getFaceLight(n0, n1, face_dir, data);
654 v3s16 vertex_dirs[4];
655 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
656 for(u16 i=0; i<4; i++)
658 lights[i] = getSmoothLight(
659 blockpos_nodes + p_corrected,
660 vertex_dirs[i], data);
669 translate_dir: unit vector with only one of x, y or z
670 face_dir: unit vector with only one of x, y or z
672 static void updateFastFaceRow(
679 core::array<FastFace> &dest)
683 u16 continuous_tiles_count = 0;
685 bool makes_face = false;
687 v3s16 face_dir_corrected;
688 u16 lights[4] = {0,0,0,0};
690 getTileInfo(data, p, face_dir,
691 makes_face, p_corrected, face_dir_corrected,
694 for(u16 j=0; j<MAP_BLOCKSIZE; j++)
696 // If tiling can be done, this is set to false in the next step
697 bool next_is_different = true;
701 bool next_makes_face = false;
702 v3s16 next_p_corrected;
703 v3s16 next_face_dir_corrected;
704 u16 next_lights[4] = {0,0,0,0};
707 // If at last position, there is nothing to compare to and
708 // the face must be drawn anyway
709 if(j != MAP_BLOCKSIZE - 1)
711 p_next = p + translate_dir;
713 getTileInfo(data, p_next, face_dir,
714 next_makes_face, next_p_corrected,
715 next_face_dir_corrected, next_lights,
718 if(next_makes_face == makes_face
719 && next_p_corrected == p_corrected + translate_dir
720 && next_face_dir_corrected == face_dir_corrected
721 && next_lights[0] == lights[0]
722 && next_lights[1] == lights[1]
723 && next_lights[2] == lights[2]
724 && next_lights[3] == lights[3]
725 && next_tile == tile)
727 next_is_different = false;
731 g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
732 next_makes_face != makes_face ? 1 : 0);
733 g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
734 (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
735 g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
736 next_face_dir_corrected != face_dir_corrected ? 1 : 0);
737 g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
738 (next_lights[0] != lights[0] ||
739 next_lights[0] != lights[0] ||
740 next_lights[0] != lights[0] ||
741 next_lights[0] != lights[0]) ? 1 : 0);
742 g_profiler->add("Meshgen: diff: !(next_tile == tile)",
743 !(next_tile == tile) ? 1 : 0);
746 /*g_profiler->add("Meshgen: Total faces checked", 1);
748 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
751 g_profiler->add("Meshgen: diff: last position", 1);*/
754 continuous_tiles_count++;
756 // This is set to true if the texture doesn't allow more tiling
757 bool end_of_texture = false;
759 If there is no texture, it can be tiled infinitely.
760 If tiled==0, it means the texture can be tiled infinitely.
761 Otherwise check tiled agains continuous_tiles_count.
763 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
765 if(tile.texture.tiled <= continuous_tiles_count)
766 end_of_texture = true;
769 // Do this to disable tiling textures
770 //end_of_texture = true; //DEBUG
772 if(next_is_different || end_of_texture)
775 Create a face if there should be one
779 // Floating point conversion of the position vector
780 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
781 // Center point of face (kind of)
782 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
783 if(continuous_tiles_count != 1)
784 sp += translate_dir_f;
787 if(translate_dir.X != 0)
789 scale.X = continuous_tiles_count;
791 if(translate_dir.Y != 0)
793 scale.Y = continuous_tiles_count;
795 if(translate_dir.Z != 0)
797 scale.Z = continuous_tiles_count;
800 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
801 sp, face_dir_corrected, scale,
804 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
805 for(int i=1; i<continuous_tiles_count; i++){
806 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
810 continuous_tiles_count = 0;
812 makes_face = next_makes_face;
813 p_corrected = next_p_corrected;
814 face_dir_corrected = next_face_dir_corrected;
815 lights[0] = next_lights[0];
816 lights[1] = next_lights[1];
817 lights[2] = next_lights[2];
818 lights[3] = next_lights[3];
826 static void updateAllFastFaceRows(MeshMakeData *data,
827 core::array<FastFace> &dest)
830 Go through every y,z and get top(y+) faces in rows of x+
832 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
833 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
834 updateFastFaceRow(data,
838 v3s16(0,1,0), //face dir
845 Go through every x,y and get right(x+) faces in rows of z+
847 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
848 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
849 updateFastFaceRow(data,
853 v3s16(1,0,0), //face dir
860 Go through every y,z and get back(z+) faces in rows of x+
862 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
863 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
864 updateFastFaceRow(data,
868 v3s16(0,0,1), //face dir
879 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
880 m_mesh(new scene::SMesh()),
881 m_gamedef(data->m_gamedef),
882 m_animation_force_timer(0), // force initial animation
885 m_last_daynight_ratio((u32) -1),
888 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
889 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
890 //TimeTaker timer1("MapBlockMesh()");
892 core::array<FastFace> fastfaces_new;
895 We are including the faces of the trailing edges of the block.
896 This means that when something changes, the caller must
897 also update the meshes of the blocks at the leading edges.
899 NOTE: This is the slowest part of this method.
902 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
903 //TimeTaker timer2("updateAllFastFaceRows()");
904 updateAllFastFaceRows(data, fastfaces_new);
909 Convert FastFaces to MeshCollector
912 MeshCollector collector;
915 // avg 0ms (100ms spikes when loading textures the first time)
916 // (NOTE: probably outdated)
917 //TimeTaker timer2("MeshCollector building");
919 for(u32 i=0; i<fastfaces_new.size(); i++)
921 FastFace &f = fastfaces_new[i];
923 const u16 indices[] = {0,1,2,2,3,0};
924 const u16 indices_alternate[] = {0,1,3,2,3,1};
926 if(f.tile.texture.atlas == NULL)
929 const u16 *indices_p = indices;
932 Revert triangles for nicer looking gradient if vertices
933 1 and 3 have same color or 0 and 2 have different color.
934 getRed() is the day color.
936 if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
937 || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
938 indices_p = indices_alternate;
940 collector.append(f.tile, f.vertices, 4, indices_p, 6);
945 Add special graphics:
952 mapblock_mesh_generate_special(data, collector);
956 Convert MeshCollector to SMesh
957 Also store animation info
959 for(u32 i = 0; i < collector.prebuffers.size(); i++)
961 PreMeshBuffer &p = collector.prebuffers[i];
962 /*dstream<<"p.vertices.size()="<<p.vertices.size()
963 <<", p.indices.size()="<<p.indices.size()
966 // Generate animation data
968 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
970 ITextureSource *tsrc = data->m_gamedef->tsrc();
971 std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
972 if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
973 crack_basename += "^[cracko";
975 crack_basename += "^[crack";
976 m_crack_materials.insert(std::make_pair(i, crack_basename));
979 for(u32 j = 0; j < p.vertices.size(); j++)
981 video::SColor &vc = p.vertices[j].Color;
982 u8 day = vc.getRed();
983 u8 night = vc.getGreen();
984 finalColorBlend(vc, day, night, 1000);
986 m_daynight_diffs[i][j] = std::make_pair(day, night);
991 video::SMaterial material;
992 material.setFlag(video::EMF_LIGHTING, false);
993 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
994 material.setFlag(video::EMF_BILINEAR_FILTER, false);
995 material.setFlag(video::EMF_FOG_ENABLE, true);
996 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
997 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
998 material.MaterialType
999 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1000 material.setTexture(0, p.tile.texture.atlas);
1001 p.tile.applyMaterialOptions(material);
1003 // Create meshbuffer
1005 // This is a "Standard MeshBuffer",
1006 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1007 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1009 buf->Material = material;
1011 m_mesh->addMeshBuffer(buf);
1014 buf->append(p.vertices.pointer(), p.vertices.size(),
1015 p.indices.pointer(), p.indices.size());
1019 Do some stuff to the mesh
1022 translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1023 m_mesh->recalculateBoundingBox(); // translateMesh already does this
1028 // Usually 1-700 faces and 1-7 materials
1029 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1030 <<"and uses "<<m_mesh->getMeshBufferCount()
1031 <<" materials (meshbuffers)"<<std::endl;
1034 // Use VBO for mesh (this just would set this for ever buffer)
1035 // This will lead to infinite memory usage because or irrlicht.
1036 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1039 NOTE: If that is enabled, some kind of a queue to the main
1040 thread should be made which would call irrlicht to delete
1041 the hardware buffer and then delete the mesh
1045 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1047 // Check if animation is required for this mesh
1049 !m_crack_materials.empty() ||
1050 !m_daynight_diffs.empty();
1053 MapBlockMesh::~MapBlockMesh()
1059 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1061 if(!m_has_animation)
1063 m_animation_force_timer = 100000;
1067 m_animation_force_timer = myrand_range(5, 100);
1070 if(crack != m_last_crack)
1072 for(std::map<u32, std::string>::iterator
1073 i = m_crack_materials.begin();
1074 i != m_crack_materials.end(); i++)
1076 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1077 std::string basename = i->second;
1079 // Create new texture name from original
1080 ITextureSource *tsrc = m_gamedef->getTextureSource();
1081 std::ostringstream os;
1082 os<<basename<<crack;
1083 AtlasPointer ap = tsrc->getTexture(os.str());
1084 buf->getMaterial().setTexture(0, ap.atlas);
1087 m_last_crack = crack;
1090 // Day-night transition
1091 if(daynight_ratio != m_last_daynight_ratio)
1093 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1094 i = m_daynight_diffs.begin();
1095 i != m_daynight_diffs.end(); i++)
1097 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1098 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1099 for(std::map<u32, std::pair<u8, u8 > >::iterator
1100 j = i->second.begin();
1101 j != i->second.end(); j++)
1103 u32 vertexIndex = j->first;
1104 u8 day = j->second.first;
1105 u8 night = j->second.second;
1106 finalColorBlend(vertices[vertexIndex].Color,
1107 day, night, daynight_ratio);
1110 m_last_daynight_ratio = daynight_ratio;
1120 void MeshCollector::append(const TileSpec &tile,
1121 const video::S3DVertex *vertices, u32 numVertices,
1122 const u16 *indices, u32 numIndices)
1124 PreMeshBuffer *p = NULL;
1125 for(u32 i=0; i<prebuffers.size(); i++)
1127 PreMeshBuffer &pp = prebuffers[i];
1139 prebuffers.push_back(pp);
1140 p = &prebuffers[prebuffers.size()-1];
1143 u32 vertex_count = p->vertices.size();
1144 for(u32 i=0; i<numIndices; i++)
1146 u32 j = indices[i] + vertex_count;
1149 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
1150 // NOTE: Fix is to just add an another MeshBuffer
1152 p->indices.push_back(j);
1154 for(u32 i=0; i<numVertices; i++)
1156 p->vertices.push_back(vertices[i]);