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 // Make some nice difference to different sides
188 // This makes light come from a corner
189 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
190 light = diminish_light(diminish_light(light));
191 else if(face_dir.X == -1 || face_dir.Z == -1)
192 light = diminish_light(light);*/
194 // All neighboring faces have different shade (like in minecraft)
195 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
196 light = diminish_light(diminish_light(light));
197 else if(face_dir.Z == 1 || face_dir.Z == -1)
198 light = diminish_light(light);
200 return decode_light(light);
204 Calculate non-smooth lighting at face of node.
207 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data)
209 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data);
210 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data);
211 return day | (night << 8);
215 Calculate smooth lighting at the XYZ- corner of p.
218 static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
220 static v3s16 dirs8[8] = {
231 INodeDefManager *ndef = data->m_gamedef->ndef();
233 u16 ambient_occlusion = 0;
236 for(u32 i=0; i<8; i++)
238 MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
239 const ContentFeatures &f = ndef->get(n);
240 // Check f.solidness because fast-style leaves look
242 if(f.param_type == CPT_LIGHT && f.solidness != 2)
244 light += decode_light(n.getLight(bank, ndef));
247 else if(n.getContent() != CONTENT_IGNORE)
256 light /= light_count;
258 if(ambient_occlusion > 4)
260 ambient_occlusion -= 4;
261 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
268 Calculate smooth lighting at the XYZ- corner of p.
271 static u16 getSmoothLight(v3s16 p, MeshMakeData *data)
273 u16 day = getSmoothLight(LIGHTBANK_DAY, p, data);
274 u16 night = getSmoothLight(LIGHTBANK_NIGHT, p, data);
275 return day | (night << 8);
279 Calculate smooth lighting at the given corner of p.
282 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
284 if(corner.X == 1) p.X += 1;
285 else assert(corner.X == -1);
286 if(corner.Y == 1) p.Y += 1;
287 else assert(corner.Y == -1);
288 if(corner.Z == 1) p.Z += 1;
289 else assert(corner.Z == -1);
291 return getSmoothLight(p, data);
295 Converts from day + night color values (0..255)
296 and a given daynight_ratio to the final SColor shown on screen.
298 static void finalColorBlend(video::SColor& result,
299 u8 day, u8 night, u32 daynight_ratio)
301 s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
305 b += (day - night) / 13;
306 rg -= (day - night) / 23;
308 // Emphase blue a bit in darker places
309 // Each entry of this array represents a range of 8 blue levels
310 static u8 emphase_blue_when_dark[32] = {
311 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
318 b += emphase_blue_when_dark[b / 8];
320 // Artificial light is yellow-ish
321 static u8 emphase_yellow_when_artificial[16] = {
322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
324 rg += emphase_yellow_when_artificial[night/16];
336 Mesh generation helpers
340 vertex_dirs: v3s16[4]
342 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
345 If looked from outside the node towards the face, the corners are:
351 if(dir == v3s16(0,0,1))
353 // If looking towards z+, this is the face that is behind
354 // the center point, facing towards z+.
355 vertex_dirs[0] = v3s16(-1,-1, 1);
356 vertex_dirs[1] = v3s16( 1,-1, 1);
357 vertex_dirs[2] = v3s16( 1, 1, 1);
358 vertex_dirs[3] = v3s16(-1, 1, 1);
360 else if(dir == v3s16(0,0,-1))
363 vertex_dirs[0] = v3s16( 1,-1,-1);
364 vertex_dirs[1] = v3s16(-1,-1,-1);
365 vertex_dirs[2] = v3s16(-1, 1,-1);
366 vertex_dirs[3] = v3s16( 1, 1,-1);
368 else if(dir == v3s16(1,0,0))
371 vertex_dirs[0] = v3s16( 1,-1, 1);
372 vertex_dirs[1] = v3s16( 1,-1,-1);
373 vertex_dirs[2] = v3s16( 1, 1,-1);
374 vertex_dirs[3] = v3s16( 1, 1, 1);
376 else if(dir == v3s16(-1,0,0))
379 vertex_dirs[0] = v3s16(-1,-1,-1);
380 vertex_dirs[1] = v3s16(-1,-1, 1);
381 vertex_dirs[2] = v3s16(-1, 1, 1);
382 vertex_dirs[3] = v3s16(-1, 1,-1);
384 else if(dir == v3s16(0,1,0))
386 // faces towards Y+ (assume Z- as "down" in texture)
387 vertex_dirs[0] = v3s16( 1, 1,-1);
388 vertex_dirs[1] = v3s16(-1, 1,-1);
389 vertex_dirs[2] = v3s16(-1, 1, 1);
390 vertex_dirs[3] = v3s16( 1, 1, 1);
392 else if(dir == v3s16(0,-1,0))
394 // faces towards Y- (assume Z+ as "down" in texture)
395 vertex_dirs[0] = v3s16( 1,-1, 1);
396 vertex_dirs[1] = v3s16(-1,-1, 1);
397 vertex_dirs[2] = v3s16(-1,-1,-1);
398 vertex_dirs[3] = v3s16( 1,-1,-1);
405 video::S3DVertex vertices[4]; // Precalculated vertices
408 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
409 v3f p, v3s16 dir, v3f scale, core::array<FastFace> &dest)
413 // Position is at the center of the cube.
417 v3s16 vertex_dirs[4];
418 getNodeVertexDirs(dir, vertex_dirs);
419 for(u16 i=0; i<4; i++)
422 BS/2*vertex_dirs[i].X,
423 BS/2*vertex_dirs[i].Y,
424 BS/2*vertex_dirs[i].Z
428 for(u16 i=0; i<4; i++)
430 vertex_pos[i].X *= scale.X;
431 vertex_pos[i].Y *= scale.Y;
432 vertex_pos[i].Z *= scale.Z;
433 vertex_pos[i] += pos;
437 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
438 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
439 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
441 v3f normal(dir.X, dir.Y, dir.Z);
443 u8 alpha = tile.alpha;
445 float x0 = tile.texture.pos.X;
446 float y0 = tile.texture.pos.Y;
447 float w = tile.texture.size.X;
448 float h = tile.texture.size.Y;
450 face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
451 MapBlock_LightColor(alpha, li0),
452 core::vector2d<f32>(x0+w*abs_scale, y0+h));
453 face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
454 MapBlock_LightColor(alpha, li1),
455 core::vector2d<f32>(x0, y0+h));
456 face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
457 MapBlock_LightColor(alpha, li2),
458 core::vector2d<f32>(x0, y0));
459 face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
460 MapBlock_LightColor(alpha, li3),
461 core::vector2d<f32>(x0+w*abs_scale, y0));
465 dest.push_back(face);
469 Nodes make a face if contents differ and solidness differs.
472 1: Face uses m1's content
473 2: Face uses m2's content
474 equivalent: Whether the blocks share the same face (eg. water and glass)
476 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
478 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
479 INodeDefManager *ndef)
483 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
486 bool contents_differ = (m1 != m2);
488 const ContentFeatures &f1 = ndef->get(m1);
489 const ContentFeatures &f2 = ndef->get(m2);
491 // Contents don't differ for different forms of same liquid
492 if(f1.sameLiquid(f2))
493 contents_differ = false;
495 u8 c1 = f1.solidness;
496 u8 c2 = f2.solidness;
498 bool solidness_differs = (c1 != c2);
499 bool makes_face = contents_differ && solidness_differs;
501 if(makes_face == false)
505 c1 = f1.visual_solidness;
507 c2 = f2.visual_solidness;
511 // If same solidness, liquid takes precense
525 Gets nth node tile (0 <= n <= 5).
527 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
529 INodeDefManager *ndef = data->m_gamedef->ndef();
530 TileSpec spec = ndef->get(mn).tiles[tileindex];
531 // Apply temporary crack
532 if(p == data->m_crack_pos_relative)
534 spec.material_flags |= MATERIAL_FLAG_CRACK;
535 spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
541 Gets node tile given a face direction.
543 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
545 INodeDefManager *ndef = data->m_gamedef->ndef();
547 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
548 // (0,0,1), (0,0,-1) or (0,0,0)
549 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
551 // Convert direction to single integer for table lookup
556 // 4 = invalid, treat as (0,0,0)
560 u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
562 // Get rotation for things like chests
563 u8 facedir = mn.getFaceDir(ndef);
564 assert(facedir <= 3);
566 static const u8 dir_to_tile[4 * 8] =
568 // 0 +X +Y +Z 0 -Z -Y -X
569 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0
570 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1
571 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2
572 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3
574 u8 tileindex = dir_to_tile[facedir*8 + dir_i];
575 return getNodeTileN(mn, p, tileindex, data);
578 static void getTileInfo(
586 v3s16 &face_dir_corrected,
591 VoxelManipulator &vmanip = data->m_vmanip;
592 INodeDefManager *ndef = data->m_gamedef->ndef();
593 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
595 MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
596 MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
597 TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
598 TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
601 bool equivalent = false;
602 u8 mf = face_contents(n0.getContent(), n1.getContent(),
617 face_dir_corrected = face_dir;
622 p_corrected = p + face_dir;
623 face_dir_corrected = -face_dir;
626 // eg. water and glass
628 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
630 if(data->m_smooth_lighting == false)
632 lights[0] = lights[1] = lights[2] = lights[3] =
633 getFaceLight(n0, n1, face_dir, data);
637 v3s16 vertex_dirs[4];
638 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
639 for(u16 i=0; i<4; i++)
641 lights[i] = getSmoothLight(
642 blockpos_nodes + p_corrected,
643 vertex_dirs[i], data);
652 translate_dir: unit vector with only one of x, y or z
653 face_dir: unit vector with only one of x, y or z
655 static void updateFastFaceRow(
662 core::array<FastFace> &dest)
666 u16 continuous_tiles_count = 0;
668 bool makes_face = false;
670 v3s16 face_dir_corrected;
671 u16 lights[4] = {0,0,0,0};
673 getTileInfo(data, p, face_dir,
674 makes_face, p_corrected, face_dir_corrected,
677 for(u16 j=0; j<MAP_BLOCKSIZE; j++)
679 // If tiling can be done, this is set to false in the next step
680 bool next_is_different = true;
684 bool next_makes_face = false;
685 v3s16 next_p_corrected;
686 v3s16 next_face_dir_corrected;
687 u16 next_lights[4] = {0,0,0,0};
690 // If at last position, there is nothing to compare to and
691 // the face must be drawn anyway
692 if(j != MAP_BLOCKSIZE - 1)
694 p_next = p + translate_dir;
696 getTileInfo(data, p_next, face_dir,
697 next_makes_face, next_p_corrected,
698 next_face_dir_corrected, next_lights,
701 if(next_makes_face == makes_face
702 && next_p_corrected == p_corrected + translate_dir
703 && next_face_dir_corrected == face_dir_corrected
704 && next_lights[0] == lights[0]
705 && next_lights[1] == lights[1]
706 && next_lights[2] == lights[2]
707 && next_lights[3] == lights[3]
708 && next_tile == tile)
710 next_is_different = false;
714 g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
715 next_makes_face != makes_face ? 1 : 0);
716 g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
717 (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
718 g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
719 next_face_dir_corrected != face_dir_corrected ? 1 : 0);
720 g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
721 (next_lights[0] != lights[0] ||
722 next_lights[0] != lights[0] ||
723 next_lights[0] != lights[0] ||
724 next_lights[0] != lights[0]) ? 1 : 0);
725 g_profiler->add("Meshgen: diff: !(next_tile == tile)",
726 !(next_tile == tile) ? 1 : 0);
729 /*g_profiler->add("Meshgen: Total faces checked", 1);
731 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
734 g_profiler->add("Meshgen: diff: last position", 1);*/
737 continuous_tiles_count++;
739 // This is set to true if the texture doesn't allow more tiling
740 bool end_of_texture = false;
742 If there is no texture, it can be tiled infinitely.
743 If tiled==0, it means the texture can be tiled infinitely.
744 Otherwise check tiled agains continuous_tiles_count.
746 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
748 if(tile.texture.tiled <= continuous_tiles_count)
749 end_of_texture = true;
752 // Do this to disable tiling textures
753 //end_of_texture = true; //DEBUG
755 if(next_is_different || end_of_texture)
758 Create a face if there should be one
762 // Floating point conversion of the position vector
763 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
764 // Center point of face (kind of)
765 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
766 if(continuous_tiles_count != 1)
767 sp += translate_dir_f;
770 if(translate_dir.X != 0)
772 scale.X = continuous_tiles_count;
774 if(translate_dir.Y != 0)
776 scale.Y = continuous_tiles_count;
778 if(translate_dir.Z != 0)
780 scale.Z = continuous_tiles_count;
783 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
784 sp, face_dir_corrected, scale,
787 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
788 for(int i=1; i<continuous_tiles_count; i++){
789 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
793 continuous_tiles_count = 0;
795 makes_face = next_makes_face;
796 p_corrected = next_p_corrected;
797 face_dir_corrected = next_face_dir_corrected;
798 lights[0] = next_lights[0];
799 lights[1] = next_lights[1];
800 lights[2] = next_lights[2];
801 lights[3] = next_lights[3];
809 static void updateAllFastFaceRows(MeshMakeData *data,
810 core::array<FastFace> &dest)
813 Go through every y,z and get top(y+) faces in rows of x+
815 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
816 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
817 updateFastFaceRow(data,
821 v3s16(0,1,0), //face dir
828 Go through every x,y and get right(x+) faces in rows of z+
830 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
831 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
832 updateFastFaceRow(data,
836 v3s16(1,0,0), //face dir
843 Go through every y,z and get back(z+) faces in rows of x+
845 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
846 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
847 updateFastFaceRow(data,
851 v3s16(0,0,1), //face dir
862 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
863 m_mesh(new scene::SMesh()),
864 m_gamedef(data->m_gamedef),
865 m_animation_force_timer(0), // force initial animation
868 m_last_daynight_ratio((u32) -1),
871 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
872 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
873 //TimeTaker timer1("MapBlockMesh()");
875 core::array<FastFace> fastfaces_new;
878 We are including the faces of the trailing edges of the block.
879 This means that when something changes, the caller must
880 also update the meshes of the blocks at the leading edges.
882 NOTE: This is the slowest part of this method.
885 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
886 //TimeTaker timer2("updateAllFastFaceRows()");
887 updateAllFastFaceRows(data, fastfaces_new);
892 Convert FastFaces to MeshCollector
895 MeshCollector collector;
898 // avg 0ms (100ms spikes when loading textures the first time)
899 // (NOTE: probably outdated)
900 //TimeTaker timer2("MeshCollector building");
902 for(u32 i=0; i<fastfaces_new.size(); i++)
904 FastFace &f = fastfaces_new[i];
906 const u16 indices[] = {0,1,2,2,3,0};
907 const u16 indices_alternate[] = {0,1,3,2,3,1};
909 if(f.tile.texture.atlas == NULL)
912 const u16 *indices_p = indices;
915 Revert triangles for nicer looking gradient if vertices
916 1 and 3 have same color or 0 and 2 have different color.
917 getRed() is the day color.
919 if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
920 || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
921 indices_p = indices_alternate;
923 collector.append(f.tile, f.vertices, 4, indices_p, 6);
928 Add special graphics:
935 mapblock_mesh_generate_special(data, collector);
939 Convert MeshCollector to SMesh
940 Also store animation info
942 for(u32 i = 0; i < collector.prebuffers.size(); i++)
944 PreMeshBuffer &p = collector.prebuffers[i];
945 /*dstream<<"p.vertices.size()="<<p.vertices.size()
946 <<", p.indices.size()="<<p.indices.size()
949 // Generate animation data
951 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
953 ITextureSource *tsrc = data->m_gamedef->tsrc();
954 std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
955 if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
956 crack_basename += "^[cracko";
958 crack_basename += "^[crack";
959 m_crack_materials.insert(std::make_pair(i, crack_basename));
962 for(u32 j = 0; j < p.vertices.size(); j++)
964 video::SColor &vc = p.vertices[j].Color;
965 u8 day = vc.getRed();
966 u8 night = vc.getGreen();
967 finalColorBlend(vc, day, night, 1000);
969 m_daynight_diffs[i][j] = std::make_pair(day, night);
974 video::SMaterial material;
975 material.setFlag(video::EMF_LIGHTING, false);
976 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
977 material.setFlag(video::EMF_BILINEAR_FILTER, false);
978 material.setFlag(video::EMF_FOG_ENABLE, true);
979 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
980 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
981 material.MaterialType
982 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
983 material.setTexture(0, p.tile.texture.atlas);
984 p.tile.applyMaterialOptions(material);
988 // This is a "Standard MeshBuffer",
989 // it's a typedeffed CMeshBuffer<video::S3DVertex>
990 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
992 buf->Material = material;
994 m_mesh->addMeshBuffer(buf);
997 buf->append(p.vertices.pointer(), p.vertices.size(),
998 p.indices.pointer(), p.indices.size());
1002 Do some stuff to the mesh
1005 translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1006 m_mesh->recalculateBoundingBox(); // translateMesh already does this
1011 // Usually 1-700 faces and 1-7 materials
1012 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1013 <<"and uses "<<m_mesh->getMeshBufferCount()
1014 <<" materials (meshbuffers)"<<std::endl;
1017 // Use VBO for mesh (this just would set this for ever buffer)
1018 // This will lead to infinite memory usage because or irrlicht.
1019 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1022 NOTE: If that is enabled, some kind of a queue to the main
1023 thread should be made which would call irrlicht to delete
1024 the hardware buffer and then delete the mesh
1028 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1030 // Check if animation is required for this mesh
1032 !m_crack_materials.empty() ||
1033 !m_daynight_diffs.empty();
1036 MapBlockMesh::~MapBlockMesh()
1042 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1044 if(!m_has_animation)
1046 m_animation_force_timer = 100000;
1050 m_animation_force_timer = myrand_range(5, 100);
1053 if(crack != m_last_crack)
1055 for(std::map<u32, std::string>::iterator
1056 i = m_crack_materials.begin();
1057 i != m_crack_materials.end(); i++)
1059 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1060 std::string basename = i->second;
1062 // Create new texture name from original
1063 ITextureSource *tsrc = m_gamedef->getTextureSource();
1064 std::ostringstream os;
1065 os<<basename<<crack;
1066 AtlasPointer ap = tsrc->getTexture(os.str());
1067 buf->getMaterial().setTexture(0, ap.atlas);
1070 m_last_crack = crack;
1073 // Day-night transition
1074 if(daynight_ratio != m_last_daynight_ratio)
1076 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1077 i = m_daynight_diffs.begin();
1078 i != m_daynight_diffs.end(); i++)
1080 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1081 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1082 for(std::map<u32, std::pair<u8, u8 > >::iterator
1083 j = i->second.begin();
1084 j != i->second.end(); j++)
1086 u32 vertexIndex = j->first;
1087 u8 day = j->second.first;
1088 u8 night = j->second.second;
1089 finalColorBlend(vertices[vertexIndex].Color,
1090 day, night, daynight_ratio);
1093 m_last_daynight_ratio = daynight_ratio;
1103 void MeshCollector::append(const TileSpec &tile,
1104 const video::S3DVertex *vertices, u32 numVertices,
1105 const u16 *indices, u32 numIndices)
1107 PreMeshBuffer *p = NULL;
1108 for(u32 i=0; i<prebuffers.size(); i++)
1110 PreMeshBuffer &pp = prebuffers[i];
1122 prebuffers.push_back(pp);
1123 p = &prebuffers[prebuffers.size()-1];
1126 u32 vertex_count = p->vertices.size();
1127 for(u32 i=0; i<numIndices; i++)
1129 u32 j = indices[i] + vertex_count;
1132 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
1133 // NOTE: Fix is to just add an another MeshBuffer
1135 p->indices.push_back(j);
1137 for(u32 i=0; i<numVertices; i++)
1139 p->vertices.push_back(vertices[i]);