3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser 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"
28 #include "content_mapblock.h"
32 #include "util/directiontables.h"
33 #include <IMeshManipulator.h>
39 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
40 bool use_tangent_vertices):
42 m_blockpos(-1337,-1337,-1337),
43 m_crack_pos_relative(-1337, -1337, -1337),
44 m_smooth_lighting(false),
47 m_use_shaders(use_shaders),
48 m_use_tangent_vertices(use_tangent_vertices)
51 void MeshMakeData::fill(MapBlock *block)
53 m_blockpos = block->getPos();
55 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
61 // Allocate this block + neighbors
63 VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
64 blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
65 m_vmanip.addArea(voxel_area);
68 //TimeTaker timer("copy central block data");
72 block->copyTo(m_vmanip);
75 //TimeTaker timer("copy neighbor block data");
79 Copy neighbors. This is lightning fast.
80 Copying only the borders would be *very* slow.
84 Map *map = block->getParent();
86 for(u16 i=0; i<26; i++)
88 const v3s16 &dir = g_26dirs[i];
89 v3s16 bp = m_blockpos + dir;
90 MapBlock *b = map->getBlockNoCreateNoEx(bp);
97 void MeshMakeData::fillSingleNode(MapNode *node)
99 m_blockpos = v3s16(0,0,0);
101 v3s16 blockpos_nodes = v3s16(0,0,0);
102 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
103 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
104 s32 volume = area.getVolume();
105 s32 our_node_index = area.index(1,1,1);
107 // Allocate this block + neighbors
109 m_vmanip.addArea(area);
112 MapNode *data = new MapNode[volume];
113 for(s32 i = 0; i < volume; i++)
115 if(i == our_node_index)
121 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
124 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
128 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
131 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
134 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
136 m_smooth_lighting = smooth_lighting;
140 Light and vertex color functions
144 Calculate non-smooth lighting at interior of node.
147 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
148 INodeDefManager *ndef)
150 u8 light = n.getLight(bank, ndef);
154 light = undiminish_light(light);
159 light = diminish_light(light);
163 return decode_light(light);
167 Calculate non-smooth lighting at interior of node.
170 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
172 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
173 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
174 return day | (night << 8);
178 Calculate non-smooth lighting at face of node.
181 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
182 v3s16 face_dir, INodeDefManager *ndef)
185 u8 l1 = n.getLight(bank, ndef);
186 u8 l2 = n2.getLight(bank, ndef);
192 // Boost light level for light sources
193 u8 light_source = MYMAX(ndef->get(n).light_source,
194 ndef->get(n2).light_source);
195 if(light_source > light)
196 light = light_source;
198 return decode_light(light);
202 Calculate non-smooth lighting at face of node.
205 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
207 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
208 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
209 return day | (night << 8);
213 Calculate smooth lighting at the XYZ- corner of p.
216 static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
218 static const v3s16 dirs8[8] = {
229 INodeDefManager *ndef = data->m_client->ndef();
231 u16 ambient_occlusion = 0;
233 u8 light_source_max = 0;
237 for (u32 i = 0; i < 8; i++)
239 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dirs8[i]);
241 // if it's CONTENT_IGNORE we can't do any light calculations
242 if (n.getContent() == CONTENT_IGNORE) {
246 const ContentFeatures &f = ndef->get(n);
247 if (f.light_source > light_source_max)
248 light_source_max = f.light_source;
249 // Check f.solidness because fast-style leaves look better this way
250 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
251 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
252 light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
262 light_day /= light_count;
263 light_night /= light_count;
265 // Boost brightness around light sources
266 bool skip_ambient_occlusion_day = false;
267 if(decode_light(light_source_max) >= light_day) {
268 light_day = decode_light(light_source_max);
269 skip_ambient_occlusion_day = true;
272 bool skip_ambient_occlusion_night = false;
273 if(decode_light(light_source_max) >= light_night) {
274 light_night = decode_light(light_source_max);
275 skip_ambient_occlusion_night = true;
278 if (ambient_occlusion > 4)
280 static const float ao_gamma = rangelim(
281 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
283 // Table of gamma space multiply factors.
284 static const float light_amount[3] = {
285 powf(0.75, 1.0 / ao_gamma),
286 powf(0.5, 1.0 / ao_gamma),
287 powf(0.25, 1.0 / ao_gamma)
290 //calculate table index for gamma space multiplier
291 ambient_occlusion -= 5;
293 if (!skip_ambient_occlusion_day)
294 light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
295 if (!skip_ambient_occlusion_night)
296 light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
299 return light_day | (light_night << 8);
303 Calculate smooth lighting at the given corner of p.
306 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
308 if(corner.X == 1) p.X += 1;
309 // else corner.X == -1
310 if(corner.Y == 1) p.Y += 1;
311 // else corner.Y == -1
312 if(corner.Z == 1) p.Z += 1;
313 // else corner.Z == -1
315 return getSmoothLightCombined(p, data);
318 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
319 f32 rg = daynight_ratio / 1000.0f - 0.04f;
320 f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
326 void final_color_blend(video::SColor *result,
327 u16 light, u32 daynight_ratio)
329 video::SColorf dayLight;
330 get_sunlight_color(&dayLight, daynight_ratio);
331 final_color_blend(result,
332 encode_light_and_color(light, video::SColor(0xFFFFFFFF), 0), dayLight);
335 void final_color_blend(video::SColor *result,
336 const video::SColor &data, const video::SColorf &dayLight)
338 static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
340 video::SColorf c(data);
343 f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
344 f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
345 f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
347 // Emphase blue a bit in darker places
348 // Each entry of this array represents a range of 8 blue levels
349 static const u8 emphase_blue_when_dark[32] = {
350 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
354 b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
355 0, 255) / 8] / 255.0f;
357 result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
358 result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
359 result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
363 Mesh generation helpers
367 vertex_dirs: v3s16[4]
369 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
372 If looked from outside the node towards the face, the corners are:
378 if(dir == v3s16(0,0,1))
380 // If looking towards z+, this is the face that is behind
381 // the center point, facing towards z+.
382 vertex_dirs[0] = v3s16(-1,-1, 1);
383 vertex_dirs[1] = v3s16( 1,-1, 1);
384 vertex_dirs[2] = v3s16( 1, 1, 1);
385 vertex_dirs[3] = v3s16(-1, 1, 1);
387 else if(dir == v3s16(0,0,-1))
390 vertex_dirs[0] = v3s16( 1,-1,-1);
391 vertex_dirs[1] = v3s16(-1,-1,-1);
392 vertex_dirs[2] = v3s16(-1, 1,-1);
393 vertex_dirs[3] = v3s16( 1, 1,-1);
395 else if(dir == v3s16(1,0,0))
398 vertex_dirs[0] = v3s16( 1,-1, 1);
399 vertex_dirs[1] = v3s16( 1,-1,-1);
400 vertex_dirs[2] = v3s16( 1, 1,-1);
401 vertex_dirs[3] = v3s16( 1, 1, 1);
403 else if(dir == v3s16(-1,0,0))
406 vertex_dirs[0] = v3s16(-1,-1,-1);
407 vertex_dirs[1] = v3s16(-1,-1, 1);
408 vertex_dirs[2] = v3s16(-1, 1, 1);
409 vertex_dirs[3] = v3s16(-1, 1,-1);
411 else if(dir == v3s16(0,1,0))
413 // faces towards Y+ (assume Z- as "down" in texture)
414 vertex_dirs[0] = v3s16( 1, 1,-1);
415 vertex_dirs[1] = v3s16(-1, 1,-1);
416 vertex_dirs[2] = v3s16(-1, 1, 1);
417 vertex_dirs[3] = v3s16( 1, 1, 1);
419 else if(dir == v3s16(0,-1,0))
421 // faces towards Y- (assume Z+ as "down" in texture)
422 vertex_dirs[0] = v3s16( 1,-1, 1);
423 vertex_dirs[1] = v3s16(-1,-1, 1);
424 vertex_dirs[2] = v3s16(-1,-1,-1);
425 vertex_dirs[3] = v3s16( 1,-1,-1);
432 video::S3DVertex vertices[4]; // Precalculated vertices
435 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
436 v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
438 // Position is at the center of the cube.
447 v3s16 vertex_dirs[4];
448 getNodeVertexDirs(dir, vertex_dirs);
452 switch (tile.rotation)
458 vertex_dirs[0] = vertex_dirs[3];
459 vertex_dirs[3] = vertex_dirs[2];
460 vertex_dirs[2] = vertex_dirs[1];
470 vertex_dirs[0] = vertex_dirs[2];
473 vertex_dirs[1] = vertex_dirs[3];
484 vertex_dirs[0] = vertex_dirs[1];
485 vertex_dirs[1] = vertex_dirs[2];
486 vertex_dirs[2] = vertex_dirs[3];
496 vertex_dirs[0] = vertex_dirs[3];
497 vertex_dirs[3] = vertex_dirs[2];
498 vertex_dirs[2] = vertex_dirs[1];
510 vertex_dirs[0] = vertex_dirs[1];
511 vertex_dirs[1] = vertex_dirs[2];
512 vertex_dirs[2] = vertex_dirs[3];
524 vertex_dirs[0] = vertex_dirs[3];
525 vertex_dirs[3] = vertex_dirs[2];
526 vertex_dirs[2] = vertex_dirs[1];
538 vertex_dirs[0] = vertex_dirs[1];
539 vertex_dirs[1] = vertex_dirs[2];
540 vertex_dirs[2] = vertex_dirs[3];
562 for(u16 i=0; i<4; i++)
565 BS/2*vertex_dirs[i].X,
566 BS/2*vertex_dirs[i].Y,
567 BS/2*vertex_dirs[i].Z
571 for(u16 i=0; i<4; i++)
573 vertex_pos[i].X *= scale.X;
574 vertex_pos[i].Y *= scale.Y;
575 vertex_pos[i].Z *= scale.Z;
576 vertex_pos[i] += pos;
580 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
581 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
582 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
584 v3f normal(dir.X, dir.Y, dir.Z);
586 dest.push_back(FastFace());
588 FastFace& face = *dest.rbegin();
590 u16 li[4] = { li0, li1, li2, li3 };
592 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
593 core::vector2d<f32>(x0, y0 + h),
594 core::vector2d<f32>(x0, y0),
595 core::vector2d<f32>(x0 + w * abs_scale, y0) };
597 for (u8 i = 0; i < 4; i++) {
598 video::SColor c = encode_light_and_color(li[i], tile.color,
599 tile.emissive_light);
600 if (!tile.emissive_light)
601 applyFacesShading(c, normal);
603 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
610 Nodes make a face if contents differ and solidness differs.
613 1: Face uses m1's content
614 2: Face uses m2's content
615 equivalent: Whether the blocks share the same face (eg. water and glass)
617 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
619 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
620 INodeDefManager *ndef)
624 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
627 bool contents_differ = (m1 != m2);
629 const ContentFeatures &f1 = ndef->get(m1);
630 const ContentFeatures &f2 = ndef->get(m2);
632 // Contents don't differ for different forms of same liquid
633 if(f1.sameLiquid(f2))
634 contents_differ = false;
636 u8 c1 = f1.solidness;
637 u8 c2 = f2.solidness;
639 bool solidness_differs = (c1 != c2);
640 bool makes_face = contents_differ && solidness_differs;
642 if(makes_face == false)
646 c1 = f1.visual_solidness;
648 c2 = f2.visual_solidness;
652 // If same solidness, liquid takes precense
666 Gets nth node tile (0 <= n <= 5).
668 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
670 INodeDefManager *ndef = data->m_client->ndef();
671 const ContentFeatures &f = ndef->get(mn);
672 TileSpec spec = f.tiles[tileindex];
674 mn.getColor(f, &spec.color);
675 // Apply temporary crack
676 if (p == data->m_crack_pos_relative)
677 spec.material_flags |= MATERIAL_FLAG_CRACK;
682 Gets node tile given a face direction.
684 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
686 INodeDefManager *ndef = data->m_client->ndef();
688 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
689 // (0,0,1), (0,0,-1) or (0,0,0)
690 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
692 // Convert direction to single integer for table lookup
697 // 4 = invalid, treat as (0,0,0)
701 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
703 // Get rotation for things like chests
704 u8 facedir = mn.getFaceDir(ndef);
706 static const u16 dir_to_tile[24 * 16] =
708 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
709 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
710 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
711 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
712 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
714 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
715 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
716 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
717 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
719 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
720 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
721 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
722 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
724 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
725 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
726 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
727 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
729 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
730 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
731 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
732 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
734 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
735 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
736 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
737 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
740 u16 tile_index=facedir*16 + dir_i;
741 TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
742 spec.rotation=dir_to_tile[tile_index + 1];
743 spec.texture = data->m_client->tsrc()->getTexture(spec.texture_id);
747 static void getTileInfo(
751 const v3s16 &face_dir,
755 v3s16 &face_dir_corrected,
760 VoxelManipulator &vmanip = data->m_vmanip;
761 INodeDefManager *ndef = data->m_client->ndef();
762 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
764 MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
766 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
767 if (n0.getContent() == CONTENT_IGNORE) {
772 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(
773 blockpos_nodes + p + face_dir);
775 if (n1.getContent() == CONTENT_IGNORE) {
781 bool equivalent = false;
782 u8 mf = face_contents(n0.getContent(), n1.getContent(),
797 face_dir_corrected = face_dir;
800 p_corrected = p + face_dir;
801 face_dir_corrected = -face_dir;
803 tile = getNodeTile(n, p_corrected, face_dir_corrected, data);
804 const ContentFeatures &f = ndef->get(n);
805 tile.emissive_light = f.light_source;
807 // eg. water and glass
809 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
811 if (data->m_smooth_lighting == false)
813 lights[0] = lights[1] = lights[2] = lights[3] =
814 getFaceLight(n0, n1, face_dir, ndef);
818 v3s16 vertex_dirs[4];
819 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
820 for(u16 i=0; i<4; i++)
822 lights[i] = getSmoothLight(
823 blockpos_nodes + p_corrected,
824 vertex_dirs[i], data);
833 translate_dir: unit vector with only one of x, y or z
834 face_dir: unit vector with only one of x, y or z
836 static void updateFastFaceRow(
843 std::vector<FastFace> &dest)
847 u16 continuous_tiles_count = 1;
849 bool makes_face = false;
851 v3s16 face_dir_corrected;
852 u16 lights[4] = {0,0,0,0};
854 getTileInfo(data, p, face_dir,
855 makes_face, p_corrected, face_dir_corrected,
858 for(u16 j=0; j<MAP_BLOCKSIZE; j++)
860 // If tiling can be done, this is set to false in the next step
861 bool next_is_different = true;
865 bool next_makes_face = false;
866 v3s16 next_p_corrected;
867 v3s16 next_face_dir_corrected;
868 u16 next_lights[4] = {0,0,0,0};
871 // If at last position, there is nothing to compare to and
872 // the face must be drawn anyway
873 if(j != MAP_BLOCKSIZE - 1)
875 p_next = p + translate_dir;
877 getTileInfo(data, p_next, face_dir,
878 next_makes_face, next_p_corrected,
879 next_face_dir_corrected, next_lights,
882 if(next_makes_face == makes_face
883 && next_p_corrected == p_corrected + translate_dir
884 && next_face_dir_corrected == face_dir_corrected
885 && next_lights[0] == lights[0]
886 && next_lights[1] == lights[1]
887 && next_lights[2] == lights[2]
888 && next_lights[3] == lights[3]
890 && tile.rotation == 0
891 && (tile.material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
892 && (tile.material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)
893 && tile.color == next_tile.color
894 && tile.emissive_light == next_tile.emissive_light) {
895 next_is_different = false;
896 continuous_tiles_count++;
899 g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
900 next_makes_face != makes_face ? 1 : 0);
901 g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
902 (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
903 g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
904 next_face_dir_corrected != face_dir_corrected ? 1 : 0);
905 g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
906 (next_lights[0] != lights[0] ||
907 next_lights[0] != lights[0] ||
908 next_lights[0] != lights[0] ||
909 next_lights[0] != lights[0]) ? 1 : 0);
910 g_profiler->add("Meshgen: diff: !(next_tile == tile)",
911 !(next_tile == tile) ? 1 : 0);
914 /*g_profiler->add("Meshgen: Total faces checked", 1);
916 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
919 g_profiler->add("Meshgen: diff: last position", 1);*/
922 if(next_is_different)
925 Create a face if there should be one
929 // Floating point conversion of the position vector
930 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
931 // Center point of face (kind of)
932 v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
935 if(translate_dir.X != 0) {
936 scale.X = continuous_tiles_count;
938 if(translate_dir.Y != 0) {
939 scale.Y = continuous_tiles_count;
941 if(translate_dir.Z != 0) {
942 scale.Z = continuous_tiles_count;
945 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
946 sp, face_dir_corrected, scale, dest);
948 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
949 for(int i = 1; i < continuous_tiles_count; i++){
950 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
954 continuous_tiles_count = 1;
957 makes_face = next_makes_face;
958 p_corrected = next_p_corrected;
959 face_dir_corrected = next_face_dir_corrected;
960 lights[0] = next_lights[0];
961 lights[1] = next_lights[1];
962 lights[2] = next_lights[2];
963 lights[3] = next_lights[3];
969 static void updateAllFastFaceRows(MeshMakeData *data,
970 std::vector<FastFace> &dest)
973 Go through every y,z and get top(y+) faces in rows of x+
975 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
976 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
977 updateFastFaceRow(data,
981 v3s16(0,1,0), //face dir
988 Go through every x,y and get right(x+) faces in rows of z+
990 for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
991 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
992 updateFastFaceRow(data,
996 v3s16(1,0,0), //face dir
1003 Go through every y,z and get back(z+) faces in rows of x+
1005 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1006 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1007 updateFastFaceRow(data,
1011 v3s16(0,0,1), //face dir
1022 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1023 m_mesh(new scene::SMesh()),
1024 m_minimap_mapblock(NULL),
1025 m_client(data->m_client),
1026 m_driver(m_client->tsrc()->getDevice()->getVideoDriver()),
1027 m_tsrc(m_client->getTextureSource()),
1028 m_shdrsrc(m_client->getShaderSource()),
1029 m_animation_force_timer(0), // force initial animation
1031 m_crack_materials(),
1032 m_last_daynight_ratio((u32) -1),
1035 m_enable_shaders = data->m_use_shaders;
1036 m_use_tangent_vertices = data->m_use_tangent_vertices;
1037 m_enable_vbo = g_settings->getBool("enable_vbo");
1039 if (g_settings->getBool("enable_minimap")) {
1040 m_minimap_mapblock = new MinimapMapblock;
1041 m_minimap_mapblock->getMinimapNodes(
1042 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1045 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1046 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1047 //TimeTaker timer1("MapBlockMesh()");
1049 std::vector<FastFace> fastfaces_new;
1050 fastfaces_new.reserve(512);
1053 We are including the faces of the trailing edges of the block.
1054 This means that when something changes, the caller must
1055 also update the meshes of the blocks at the leading edges.
1057 NOTE: This is the slowest part of this method.
1060 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1061 //TimeTaker timer2("updateAllFastFaceRows()");
1062 updateAllFastFaceRows(data, fastfaces_new);
1067 Convert FastFaces to MeshCollector
1070 MeshCollector collector(m_use_tangent_vertices);
1073 // avg 0ms (100ms spikes when loading textures the first time)
1074 // (NOTE: probably outdated)
1075 //TimeTaker timer2("MeshCollector building");
1077 for (u32 i = 0; i < fastfaces_new.size(); i++) {
1078 FastFace &f = fastfaces_new[i];
1080 const u16 indices[] = {0,1,2,2,3,0};
1081 const u16 indices_alternate[] = {0,1,3,2,3,1};
1083 if(f.tile.texture == NULL)
1086 const u16 *indices_p = indices;
1089 Revert triangles for nicer looking gradient if the
1090 brightness of vertices 1 and 3 differ less than
1091 the brightness of vertices 0 and 2.
1093 if (fabs(f.vertices[0].Color.getLuminance()
1094 - f.vertices[2].Color.getLuminance())
1095 > fabs(f.vertices[1].Color.getLuminance()
1096 - f.vertices[3].Color.getLuminance()))
1097 indices_p = indices_alternate;
1099 collector.append(f.tile, f.vertices, 4, indices_p, 6);
1104 Add special graphics:
1112 MapblockMeshGenerator generator(data, &collector);
1113 generator.generate();
1117 Convert MeshCollector to SMesh
1120 for(u32 i = 0; i < collector.prebuffers.size(); i++)
1122 PreMeshBuffer &p = collector.prebuffers[i];
1124 // Generate animation data
1126 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1128 // Find the texture name plus ^[crack:N:
1129 std::ostringstream os(std::ios::binary);
1130 os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1131 if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1132 os<<"o"; // use ^[cracko
1133 os<<":"<<(u32)p.tile.animation_frame_count<<":";
1134 m_crack_materials.insert(std::make_pair(i, os.str()));
1135 // Replace tile texture with the cracked one
1136 p.tile.texture = m_tsrc->getTextureForMesh(
1138 &p.tile.texture_id);
1140 // - Texture animation
1141 if (p.tile.material_flags & MATERIAL_FLAG_ANIMATION) {
1142 // Add to MapBlockMesh in order to animate these tiles
1143 m_animation_tiles[i] = p.tile;
1144 m_animation_frames[i] = 0;
1145 if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1146 // Get starting position from noise
1147 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1148 data->m_blockpos.X, data->m_blockpos.Y,
1149 data->m_blockpos.Z, 0));
1151 // Play all synchronized
1152 m_animation_frame_offsets[i] = 0;
1154 // Replace tile texture with the first animation frame
1155 FrameSpec animation_frame = p.tile.frames[0];
1156 p.tile.texture = animation_frame.texture;
1159 if (!m_enable_shaders) {
1160 // Extract colors for day-night animation
1161 // Dummy sunlight to handle non-sunlit areas
1162 video::SColorf sunlight;
1163 get_sunlight_color(&sunlight, 0);
1165 m_use_tangent_vertices ?
1166 p.tangent_vertices.size() : p.vertices.size();
1167 for (u32 j = 0; j < vertex_count; j++) {
1169 if (m_use_tangent_vertices) {
1170 vc = &p.tangent_vertices[j].Color;
1172 vc = &p.vertices[j].Color;
1174 video::SColor copy(*vc);
1175 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1176 final_color_blend(vc, copy, sunlight); // Finalize color
1177 else // Record color to animate
1178 m_daynight_diffs[i][j] = copy;
1180 // The sunlight ratio has been stored,
1181 // delete alpha (for the final rendering).
1187 video::SMaterial material;
1188 material.setFlag(video::EMF_LIGHTING, false);
1189 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1190 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1191 material.setFlag(video::EMF_FOG_ENABLE, true);
1192 material.setTexture(0, p.tile.texture);
1194 if (m_enable_shaders) {
1195 material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
1196 p.tile.applyMaterialOptionsWithShaders(material);
1197 if (p.tile.normal_texture) {
1198 material.setTexture(1, p.tile.normal_texture);
1200 material.setTexture(2, p.tile.flags_texture);
1202 p.tile.applyMaterialOptions(material);
1205 scene::SMesh *mesh = (scene::SMesh *)m_mesh;
1207 // Create meshbuffer, add to mesh
1208 if (m_use_tangent_vertices) {
1209 scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1211 buf->Material = material;
1213 mesh->addMeshBuffer(buf);
1216 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1217 &p.indices[0], p.indices.size());
1219 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1221 buf->Material = material;
1223 mesh->addMeshBuffer(buf);
1226 buf->append(&p.vertices[0], p.vertices.size(),
1227 &p.indices[0], p.indices.size());
1232 Do some stuff to the mesh
1234 m_camera_offset = camera_offset;
1235 translateMesh(m_mesh,
1236 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1238 if (m_use_tangent_vertices) {
1239 scene::IMeshManipulator* meshmanip =
1240 m_client->getSceneManager()->getMeshManipulator();
1241 meshmanip->recalculateTangents(m_mesh, true, false, false);
1247 // Usually 1-700 faces and 1-7 materials
1248 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1249 <<"and uses "<<m_mesh->getMeshBufferCount()
1250 <<" materials (meshbuffers)"<<std::endl;
1253 // Use VBO for mesh (this just would set this for ever buffer)
1255 m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1259 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1261 // Check if animation is required for this mesh
1263 !m_crack_materials.empty() ||
1264 !m_daynight_diffs.empty() ||
1265 !m_animation_tiles.empty();
1268 MapBlockMesh::~MapBlockMesh()
1270 if (m_enable_vbo && m_mesh) {
1271 for (u32 i = 0; i < m_mesh->getMeshBufferCount(); i++) {
1272 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i);
1273 m_driver->removeHardwareBuffer(buf);
1278 delete m_minimap_mapblock;
1281 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1283 if(!m_has_animation)
1285 m_animation_force_timer = 100000;
1289 m_animation_force_timer = myrand_range(5, 100);
1292 if(crack != m_last_crack)
1294 for (UNORDERED_MAP<u32, std::string>::iterator i = m_crack_materials.begin();
1295 i != m_crack_materials.end(); ++i) {
1296 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1297 std::string basename = i->second;
1299 // Create new texture name from original
1300 std::ostringstream os;
1301 os<<basename<<crack;
1302 u32 new_texture_id = 0;
1303 video::ITexture *new_texture =
1304 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1305 buf->getMaterial().setTexture(0, new_texture);
1307 // If the current material is also animated,
1308 // update animation info
1309 UNORDERED_MAP<u32, TileSpec>::iterator anim_iter =
1310 m_animation_tiles.find(i->first);
1311 if (anim_iter != m_animation_tiles.end()){
1312 TileSpec &tile = anim_iter->second;
1313 tile.texture = new_texture;
1314 tile.texture_id = new_texture_id;
1315 // force animation update
1316 m_animation_frames[i->first] = -1;
1320 m_last_crack = crack;
1323 // Texture animation
1324 for (UNORDERED_MAP<u32, TileSpec>::iterator i = m_animation_tiles.begin();
1325 i != m_animation_tiles.end(); ++i) {
1326 const TileSpec &tile = i->second;
1327 // Figure out current frame
1328 int frameoffset = m_animation_frame_offsets[i->first];
1329 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1330 + frameoffset) % tile.animation_frame_count;
1331 // If frame doesn't change, skip
1332 if(frame == m_animation_frames[i->first])
1335 m_animation_frames[i->first] = frame;
1337 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1339 FrameSpec animation_frame = tile.frames[frame];
1340 buf->getMaterial().setTexture(0, animation_frame.texture);
1341 if (m_enable_shaders) {
1342 if (animation_frame.normal_texture) {
1343 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1345 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1349 // Day-night transition
1350 if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1352 // Force reload mesh to VBO
1356 video::SColorf day_color;
1357 get_sunlight_color(&day_color, daynight_ratio);
1358 for(std::map<u32, std::map<u32, video::SColor > >::iterator
1359 i = m_daynight_diffs.begin();
1360 i != m_daynight_diffs.end(); ++i)
1362 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1363 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1364 for(std::map<u32, video::SColor >::iterator
1365 j = i->second.begin();
1366 j != i->second.end(); ++j)
1368 final_color_blend(&(vertices[j->first].Color), j->second, day_color);
1371 m_last_daynight_ratio = daynight_ratio;
1377 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1379 if (camera_offset != m_camera_offset) {
1380 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1384 m_camera_offset = camera_offset;
1392 void MeshCollector::append(const TileSpec &tile,
1393 const video::S3DVertex *vertices, u32 numVertices,
1394 const u16 *indices, u32 numIndices)
1396 if (numIndices > 65535) {
1397 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1401 PreMeshBuffer *p = NULL;
1402 for (u32 i = 0; i < prebuffers.size(); i++) {
1403 PreMeshBuffer &pp = prebuffers[i];
1404 if (pp.tile != tile)
1406 if (pp.indices.size() + numIndices > 65535)
1416 prebuffers.push_back(pp);
1417 p = &prebuffers[prebuffers.size() - 1];
1421 if (m_use_tangent_vertices) {
1422 vertex_count = p->tangent_vertices.size();
1423 for (u32 i = 0; i < numVertices; i++) {
1424 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1425 vertices[i].Color, vertices[i].TCoords);
1426 p->tangent_vertices.push_back(vert);
1429 vertex_count = p->vertices.size();
1430 for (u32 i = 0; i < numVertices; i++) {
1431 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1432 vertices[i].Color, vertices[i].TCoords);
1433 p->vertices.push_back(vert);
1437 for (u32 i = 0; i < numIndices; i++) {
1438 u32 j = indices[i] + vertex_count;
1439 p->indices.push_back(j);
1444 MeshCollector - for meshnodes and converted drawtypes.
1447 void MeshCollector::append(const TileSpec &tile,
1448 const video::S3DVertex *vertices, u32 numVertices,
1449 const u16 *indices, u32 numIndices,
1450 v3f pos, video::SColor c, u8 light_source)
1452 if (numIndices > 65535) {
1453 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1457 PreMeshBuffer *p = NULL;
1458 for (u32 i = 0; i < prebuffers.size(); i++) {
1459 PreMeshBuffer &pp = prebuffers[i];
1462 if(pp.indices.size() + numIndices > 65535)
1472 prebuffers.push_back(pp);
1473 p = &prebuffers[prebuffers.size() - 1];
1476 video::SColor original_c = c;
1478 if (m_use_tangent_vertices) {
1479 vertex_count = p->tangent_vertices.size();
1480 for (u32 i = 0; i < numVertices; i++) {
1481 if (!light_source) {
1483 applyFacesShading(c, vertices[i].Normal);
1485 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1486 vertices[i].Normal, c, vertices[i].TCoords);
1487 p->tangent_vertices.push_back(vert);
1490 vertex_count = p->vertices.size();
1491 for (u32 i = 0; i < numVertices; i++) {
1492 if (!light_source) {
1494 applyFacesShading(c, vertices[i].Normal);
1496 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1497 vertices[i].TCoords);
1498 p->vertices.push_back(vert);
1502 for (u32 i = 0; i < numIndices; i++) {
1503 u32 j = indices[i] + vertex_count;
1504 p->indices.push_back(j);
1508 video::SColor encode_light_and_color(u16 light, const video::SColor &color,
1512 f32 day = (light & 0xff) / 255.0f;
1513 f32 night = (light >> 8) / 255.0f;
1514 // Add emissive light
1515 night += emissive_light * 0.01f;
1518 // Since we don't know if the day light is sunlight or
1519 // artificial light, assume it is artificial when the night
1520 // light bank is also lit.
1525 f32 sum = day + night;
1526 // Ratio of sunlight:
1533 float b = (day + night) / 2;
1534 return video::SColor(r * 255, b * color.getRed(), b * color.getGreen(),
1535 b * color.getBlue());