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"
29 #include "util/directiontables.h"
30 #include "client/renderingengine.h"
36 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
37 bool use_tangent_vertices):
39 m_use_shaders(use_shaders),
40 m_use_tangent_vertices(use_tangent_vertices)
43 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
45 m_blockpos = blockpos;
47 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
50 VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
51 blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
52 m_vmanip.addArea(voxel_area);
55 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
57 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
58 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
60 v3s16 bp = m_blockpos + block_offset;
61 v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
62 m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
65 void MeshMakeData::fill(MapBlock *block)
67 fillBlockDataBegin(block->getPos());
69 fillBlockData(v3s16(0,0,0), block->getData());
71 // Get map for reading neigbhor blocks
72 Map *map = block->getParent();
74 for (const v3s16 &dir : g_26dirs) {
75 v3s16 bp = m_blockpos + dir;
76 MapBlock *b = map->getBlockNoCreateNoEx(bp);
78 fillBlockData(dir, b->getData());
82 void MeshMakeData::fillSingleNode(MapNode *node)
84 m_blockpos = v3s16(0,0,0);
86 v3s16 blockpos_nodes = v3s16(0,0,0);
87 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
88 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
89 s32 volume = area.getVolume();
90 s32 our_node_index = area.index(1,1,1);
92 // Allocate this block + neighbors
94 m_vmanip.addArea(area);
97 MapNode *data = new MapNode[volume];
98 for(s32 i = 0; i < volume; i++)
100 if(i == our_node_index)
106 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
109 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
113 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
116 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
119 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
121 m_smooth_lighting = smooth_lighting;
125 Light and vertex color functions
129 Calculate non-smooth lighting at interior of node.
132 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
133 INodeDefManager *ndef)
135 u8 light = n.getLight(bank, ndef);
139 light = undiminish_light(light);
144 light = diminish_light(light);
148 return decode_light(light);
152 Calculate non-smooth lighting at interior of node.
155 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
157 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
158 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
159 return day | (night << 8);
163 Calculate non-smooth lighting at face of node.
166 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
167 v3s16 face_dir, INodeDefManager *ndef)
170 u8 l1 = n.getLight(bank, ndef);
171 u8 l2 = n2.getLight(bank, ndef);
177 // Boost light level for light sources
178 u8 light_source = MYMAX(ndef->get(n).light_source,
179 ndef->get(n2).light_source);
180 if(light_source > light)
181 light = light_source;
183 return decode_light(light);
187 Calculate non-smooth lighting at face of node.
190 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
192 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
193 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
194 return day | (night << 8);
198 Calculate smooth lighting at the XYZ- corner of p.
201 static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
203 static const v3s16 dirs8[8] = {
214 INodeDefManager *ndef = data->m_client->ndef();
216 u16 ambient_occlusion = 0;
218 u8 light_source_max = 0;
222 for (const v3s16 &dir : dirs8) {
223 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dir);
225 // if it's CONTENT_IGNORE we can't do any light calculations
226 if (n.getContent() == CONTENT_IGNORE) {
230 const ContentFeatures &f = ndef->get(n);
231 if (f.light_source > light_source_max)
232 light_source_max = f.light_source;
233 // Check f.solidness because fast-style leaves look better this way
234 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
235 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
236 light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
246 light_day /= light_count;
247 light_night /= light_count;
249 // Boost brightness around light sources
250 bool skip_ambient_occlusion_day = false;
251 if(decode_light(light_source_max) >= light_day) {
252 light_day = decode_light(light_source_max);
253 skip_ambient_occlusion_day = true;
256 bool skip_ambient_occlusion_night = false;
257 if(decode_light(light_source_max) >= light_night) {
258 light_night = decode_light(light_source_max);
259 skip_ambient_occlusion_night = true;
262 if (ambient_occlusion > 4)
264 static thread_local const float ao_gamma = rangelim(
265 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
267 // Table of gamma space multiply factors.
268 static const float light_amount[3] = {
269 powf(0.75, 1.0 / ao_gamma),
270 powf(0.5, 1.0 / ao_gamma),
271 powf(0.25, 1.0 / ao_gamma)
274 //calculate table index for gamma space multiplier
275 ambient_occlusion -= 5;
277 if (!skip_ambient_occlusion_day)
278 light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
279 if (!skip_ambient_occlusion_night)
280 light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
283 return light_day | (light_night << 8);
287 Calculate smooth lighting at the given corner of p.
290 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
292 if(corner.X == 1) p.X += 1;
293 // else corner.X == -1
294 if(corner.Y == 1) p.Y += 1;
295 // else corner.Y == -1
296 if(corner.Z == 1) p.Z += 1;
297 // else corner.Z == -1
299 return getSmoothLightCombined(p, data);
302 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
303 f32 rg = daynight_ratio / 1000.0f - 0.04f;
304 f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
310 void final_color_blend(video::SColor *result,
311 u16 light, u32 daynight_ratio)
313 video::SColorf dayLight;
314 get_sunlight_color(&dayLight, daynight_ratio);
315 final_color_blend(result,
316 encode_light(light, 0), dayLight);
319 void final_color_blend(video::SColor *result,
320 const video::SColor &data, const video::SColorf &dayLight)
322 static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
324 video::SColorf c(data);
327 f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
328 f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
329 f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
331 // Emphase blue a bit in darker places
332 // Each entry of this array represents a range of 8 blue levels
333 static const u8 emphase_blue_when_dark[32] = {
334 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
338 b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
339 0, 255) / 8] / 255.0f;
341 result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
342 result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
343 result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
347 Mesh generation helpers
351 vertex_dirs: v3s16[4]
353 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
356 If looked from outside the node towards the face, the corners are:
362 if(dir == v3s16(0,0,1))
364 // If looking towards z+, this is the face that is behind
365 // the center point, facing towards z+.
366 vertex_dirs[0] = v3s16(-1,-1, 1);
367 vertex_dirs[1] = v3s16( 1,-1, 1);
368 vertex_dirs[2] = v3s16( 1, 1, 1);
369 vertex_dirs[3] = v3s16(-1, 1, 1);
371 else if(dir == v3s16(0,0,-1))
374 vertex_dirs[0] = v3s16( 1,-1,-1);
375 vertex_dirs[1] = v3s16(-1,-1,-1);
376 vertex_dirs[2] = v3s16(-1, 1,-1);
377 vertex_dirs[3] = v3s16( 1, 1,-1);
379 else if(dir == v3s16(1,0,0))
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(-1,0,0))
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(0,1,0))
397 // faces towards Y+ (assume Z- as "down" in texture)
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(0,-1,0))
405 // faces towards Y- (assume Z+ as "down" in texture)
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);
416 video::S3DVertex vertices[4]; // Precalculated vertices
418 * The face is divided into two triangles. If this is true,
419 * vertices 0 and 2 are connected, othervise vertices 1 and 3
422 bool vertex_0_2_connected;
426 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
427 const v3f &p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
429 // Position is at the center of the cube.
438 v3s16 vertex_dirs[4];
439 getNodeVertexDirs(dir, vertex_dirs);
443 switch (tile.rotation)
449 vertex_dirs[0] = vertex_dirs[3];
450 vertex_dirs[3] = vertex_dirs[2];
451 vertex_dirs[2] = vertex_dirs[1];
461 vertex_dirs[0] = vertex_dirs[2];
464 vertex_dirs[1] = vertex_dirs[3];
475 vertex_dirs[0] = vertex_dirs[1];
476 vertex_dirs[1] = vertex_dirs[2];
477 vertex_dirs[2] = vertex_dirs[3];
487 vertex_dirs[0] = vertex_dirs[3];
488 vertex_dirs[3] = vertex_dirs[2];
489 vertex_dirs[2] = vertex_dirs[1];
501 vertex_dirs[0] = vertex_dirs[1];
502 vertex_dirs[1] = vertex_dirs[2];
503 vertex_dirs[2] = vertex_dirs[3];
515 vertex_dirs[0] = vertex_dirs[3];
516 vertex_dirs[3] = vertex_dirs[2];
517 vertex_dirs[2] = vertex_dirs[1];
529 vertex_dirs[0] = vertex_dirs[1];
530 vertex_dirs[1] = vertex_dirs[2];
531 vertex_dirs[2] = vertex_dirs[3];
553 for(u16 i=0; i<4; i++)
556 BS/2*vertex_dirs[i].X,
557 BS/2*vertex_dirs[i].Y,
558 BS/2*vertex_dirs[i].Z
562 for (v3f &vpos : vertex_pos) {
570 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
571 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
572 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
574 v3f normal(dir.X, dir.Y, dir.Z);
576 u16 li[4] = { li0, li1, li2, li3 };
580 for (u8 i = 0; i < 4; i++) {
582 night[i] = li[i] & 0xFF;
585 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
586 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
589 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
590 core::vector2d<f32>(x0, y0 + h),
591 core::vector2d<f32>(x0, y0),
592 core::vector2d<f32>(x0 + w * abs_scale, y0) };
594 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
595 const TileLayer *layer = &tile.layers[layernum];
596 if (layer->texture_id == 0)
599 // equivalent to dest.push_back(FastFace()) but faster
601 FastFace& face = *dest.rbegin();
603 for (u8 i = 0; i < 4; i++) {
604 video::SColor c = encode_light(li[i], tile.emissive_light);
605 if (!tile.emissive_light)
606 applyFacesShading(c, normal);
608 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
612 Revert triangles for nicer looking gradient if the
613 brightness of vertices 1 and 3 differ less than
614 the brightness of vertices 0 and 2.
616 face.vertex_0_2_connected = vertex_0_2_connected;
619 face.layernum = layernum;
624 Nodes make a face if contents differ and solidness differs.
627 1: Face uses m1's content
628 2: Face uses m2's content
629 equivalent: Whether the blocks share the same face (eg. water and glass)
631 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
633 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
634 INodeDefManager *ndef)
638 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
641 bool contents_differ = (m1 != m2);
643 const ContentFeatures &f1 = ndef->get(m1);
644 const ContentFeatures &f2 = ndef->get(m2);
646 // Contents don't differ for different forms of same liquid
647 if(f1.sameLiquid(f2))
648 contents_differ = false;
650 u8 c1 = f1.solidness;
651 u8 c2 = f2.solidness;
653 bool solidness_differs = (c1 != c2);
654 bool makes_face = contents_differ && solidness_differs;
660 c1 = f1.visual_solidness;
662 c2 = f2.visual_solidness;
666 // If same solidness, liquid takes precense
680 Gets nth node tile (0 <= n <= 5).
682 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
684 INodeDefManager *ndef = data->m_client->ndef();
685 const ContentFeatures &f = ndef->get(mn);
686 tile = f.tiles[tileindex];
687 TileLayer *top_layer = NULL;
688 for (TileLayer &layer : tile.layers) {
689 if (layer.texture_id == 0)
692 if (!layer.has_color)
693 mn.getColor(f, &(layer.color));
695 // Apply temporary crack
696 if (p == data->m_crack_pos_relative)
697 top_layer->material_flags |= MATERIAL_FLAG_CRACK;
701 Gets node tile given a face direction.
703 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
705 INodeDefManager *ndef = data->m_client->ndef();
707 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
708 // (0,0,1), (0,0,-1) or (0,0,0)
709 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
711 // Convert direction to single integer for table lookup
716 // 4 = invalid, treat as (0,0,0)
720 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
722 // Get rotation for things like chests
723 u8 facedir = mn.getFaceDir(ndef);
725 static const u16 dir_to_tile[24 * 16] =
727 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
728 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
729 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
730 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
731 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
733 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
734 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
735 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
736 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
738 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
739 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
740 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
741 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
743 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
744 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
745 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
746 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
748 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
749 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
750 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
751 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
753 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
754 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
755 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
756 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
759 u16 tile_index=facedir*16 + dir_i;
760 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
761 tile.rotation = dir_to_tile[tile_index + 1];
764 static void getTileInfo(
768 const v3s16 &face_dir,
772 v3s16 &face_dir_corrected,
777 VoxelManipulator &vmanip = data->m_vmanip;
778 INodeDefManager *ndef = data->m_client->ndef();
779 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
781 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
783 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
784 if (n0.getContent() == CONTENT_IGNORE) {
789 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
791 if (n1.getContent() == CONTENT_IGNORE) {
797 bool equivalent = false;
798 u8 mf = face_contents(n0.getContent(), n1.getContent(),
812 face_dir_corrected = face_dir;
815 p_corrected = p + face_dir;
816 face_dir_corrected = -face_dir;
819 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
820 const ContentFeatures &f = ndef->get(n);
821 tile.emissive_light = f.light_source;
823 // eg. water and glass
825 for (TileLayer &layer : tile.layers)
826 layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
829 if (!data->m_smooth_lighting) {
830 lights[0] = lights[1] = lights[2] = lights[3] =
831 getFaceLight(n0, n1, face_dir, ndef);
834 v3s16 vertex_dirs[4];
835 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
837 v3s16 light_p = blockpos_nodes + p_corrected;
838 for (u16 i = 0; i < 4; i++) {
839 lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
846 translate_dir: unit vector with only one of x, y or z
847 face_dir: unit vector with only one of x, y or z
849 static void updateFastFaceRow(
851 const v3s16 &&startpos,
853 const v3f &&translate_dir_f,
854 const v3s16 &&face_dir,
855 std::vector<FastFace> &dest)
859 u16 continuous_tiles_count = 1;
861 bool makes_face = false;
863 v3s16 face_dir_corrected;
864 u16 lights[4] = {0,0,0,0};
866 getTileInfo(data, p, face_dir,
867 makes_face, p_corrected, face_dir_corrected,
870 // Unroll this variable which has a significant build cost
872 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
873 // If tiling can be done, this is set to false in the next step
874 bool next_is_different = true;
878 bool next_makes_face = false;
879 v3s16 next_p_corrected;
880 v3s16 next_face_dir_corrected;
881 u16 next_lights[4] = {0,0,0,0};
884 // If at last position, there is nothing to compare to and
885 // the face must be drawn anyway
886 if (j != MAP_BLOCKSIZE - 1) {
887 p_next = p + translate_dir;
889 getTileInfo(data, p_next, face_dir,
890 next_makes_face, next_p_corrected,
891 next_face_dir_corrected, next_lights,
894 if (next_makes_face == makes_face
895 && next_p_corrected == p_corrected + translate_dir
896 && next_face_dir_corrected == face_dir_corrected
897 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
898 && next_tile.isTileable(tile)) {
899 next_is_different = false;
900 continuous_tiles_count++;
904 if (next_is_different) {
906 Create a face if there should be one
909 // Floating point conversion of the position vector
910 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
911 // Center point of face (kind of)
913 ((f32)continuous_tiles_count / 2.0f - 0.5f) * translate_dir_f;
916 if(translate_dir.X != 0) {
917 scale.X = continuous_tiles_count;
919 if(translate_dir.Y != 0) {
920 scale.Y = continuous_tiles_count;
922 if(translate_dir.Z != 0) {
923 scale.Z = continuous_tiles_count;
926 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
927 sp, face_dir_corrected, scale, dest);
929 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
930 for(int i = 1; i < continuous_tiles_count; i++){
931 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
935 continuous_tiles_count = 1;
938 makes_face = next_makes_face;
939 p_corrected = next_p_corrected;
940 face_dir_corrected = next_face_dir_corrected;
941 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
942 if (next_is_different)
948 static void updateAllFastFaceRows(MeshMakeData *data,
949 std::vector<FastFace> &dest)
952 Go through every y,z and get top(y+) faces in rows of x+
954 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
955 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
956 updateFastFaceRow(data,
960 v3s16(0,1,0), //face dir
966 Go through every x,y and get right(x+) faces in rows of z+
968 for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
969 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
970 updateFastFaceRow(data,
974 v3s16(1,0,0), //face dir
980 Go through every y,z and get back(z+) faces in rows of x+
982 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
983 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
984 updateFastFaceRow(data,
988 v3s16(0,0,1), //face dir
998 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
999 m_minimap_mapblock(NULL),
1000 m_tsrc(data->m_client->getTextureSource()),
1001 m_shdrsrc(data->m_client->getShaderSource()),
1002 m_animation_force_timer(0), // force initial animation
1004 m_last_daynight_ratio((u32) -1)
1006 for (auto &m : m_mesh)
1007 m = new scene::SMesh();
1008 m_enable_shaders = data->m_use_shaders;
1009 m_use_tangent_vertices = data->m_use_tangent_vertices;
1010 m_enable_vbo = g_settings->getBool("enable_vbo");
1012 if (g_settings->getBool("enable_minimap")) {
1013 m_minimap_mapblock = new MinimapMapblock;
1014 m_minimap_mapblock->getMinimapNodes(
1015 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1018 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1019 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1020 //TimeTaker timer1("MapBlockMesh()");
1022 std::vector<FastFace> fastfaces_new;
1023 fastfaces_new.reserve(512);
1026 We are including the faces of the trailing edges of the block.
1027 This means that when something changes, the caller must
1028 also update the meshes of the blocks at the leading edges.
1030 NOTE: This is the slowest part of this method.
1033 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1034 //TimeTaker timer2("updateAllFastFaceRows()");
1035 updateAllFastFaceRows(data, fastfaces_new);
1040 Convert FastFaces to MeshCollector
1043 MeshCollector collector(m_use_tangent_vertices);
1046 // avg 0ms (100ms spikes when loading textures the first time)
1047 // (NOTE: probably outdated)
1048 //TimeTaker timer2("MeshCollector building");
1050 for (const FastFace &f : fastfaces_new) {
1051 const u16 indices[] = {0,1,2,2,3,0};
1052 const u16 indices_alternate[] = {0,1,3,2,3,1};
1054 if (!f.layer.texture)
1057 const u16 *indices_p =
1058 f.vertex_0_2_connected ? indices : indices_alternate;
1060 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1066 Add special graphics:
1074 MapblockMeshGenerator generator(data, &collector);
1075 generator.generate();
1078 collector.applyTileColors();
1081 Convert MeshCollector to SMesh
1084 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1085 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1087 PreMeshBuffer &p = collector.prebuffers[layer][i];
1089 // Generate animation data
1091 if(p.layer.material_flags & MATERIAL_FLAG_CRACK)
1093 // Find the texture name plus ^[crack:N:
1094 std::ostringstream os(std::ios::binary);
1095 os<<m_tsrc->getTextureName(p.layer.texture_id)<<"^[crack";
1096 if(p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1097 os<<"o"; // use ^[cracko
1098 os<<":"<<(u32)p.layer.animation_frame_count<<":";
1099 m_crack_materials.insert(std::make_pair(std::pair<u8, u32>(layer, i), os.str()));
1100 // Replace tile texture with the cracked one
1101 p.layer.texture = m_tsrc->getTextureForMesh(
1103 &p.layer.texture_id);
1105 // - Texture animation
1106 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1107 // Add to MapBlockMesh in order to animate these tiles
1108 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1109 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1110 if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1111 // Get starting position from noise
1112 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 100000 * (2.0 + noise3d(
1113 data->m_blockpos.X, data->m_blockpos.Y,
1114 data->m_blockpos.Z, 0));
1116 // Play all synchronized
1117 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1119 // Replace tile texture with the first animation frame
1120 p.layer.texture = (*p.layer.frames)[0].texture;
1123 if (!m_enable_shaders) {
1124 // Extract colors for day-night animation
1125 // Dummy sunlight to handle non-sunlit areas
1126 video::SColorf sunlight;
1127 get_sunlight_color(&sunlight, 0);
1129 m_use_tangent_vertices ?
1130 p.tangent_vertices.size() : p.vertices.size();
1131 for (u32 j = 0; j < vertex_count; j++) {
1133 if (m_use_tangent_vertices) {
1134 vc = &p.tangent_vertices[j].Color;
1136 vc = &p.vertices[j].Color;
1138 video::SColor copy(*vc);
1139 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1140 final_color_blend(vc, copy, sunlight); // Finalize color
1141 else // Record color to animate
1142 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1144 // The sunlight ratio has been stored,
1145 // delete alpha (for the final rendering).
1151 video::SMaterial material;
1152 material.setFlag(video::EMF_LIGHTING, false);
1153 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1154 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1155 material.setFlag(video::EMF_FOG_ENABLE, true);
1156 material.setTexture(0, p.layer.texture);
1158 if (m_enable_shaders) {
1159 material.MaterialType = m_shdrsrc->getShaderInfo(p.layer.shader_id).material;
1160 p.layer.applyMaterialOptionsWithShaders(material);
1161 if (p.layer.normal_texture) {
1162 material.setTexture(1, p.layer.normal_texture);
1164 material.setTexture(2, p.layer.flags_texture);
1166 p.layer.applyMaterialOptions(material);
1169 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1171 // Create meshbuffer, add to mesh
1172 if (m_use_tangent_vertices) {
1173 scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1175 buf->Material = material;
1177 mesh->addMeshBuffer(buf);
1180 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1181 &p.indices[0], p.indices.size());
1183 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1185 buf->Material = material;
1187 mesh->addMeshBuffer(buf);
1190 buf->append(&p.vertices[0], p.vertices.size(),
1191 &p.indices[0], p.indices.size());
1197 Do some stuff to the mesh
1199 m_camera_offset = camera_offset;
1200 translateMesh(m_mesh[layer],
1201 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1203 if (m_use_tangent_vertices) {
1204 scene::IMeshManipulator* meshmanip =
1205 RenderingEngine::get_scene_manager()->getMeshManipulator();
1206 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1212 // Usually 1-700 faces and 1-7 materials
1213 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1214 <<"and uses "<<m_mesh[layer]->getMeshBufferCount()
1215 <<" materials (meshbuffers)"<<std::endl;
1218 // Use VBO for mesh (this just would set this for ever buffer)
1220 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1225 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1227 // Check if animation is required for this mesh
1229 !m_crack_materials.empty() ||
1230 !m_daynight_diffs.empty() ||
1231 !m_animation_tiles.empty();
1234 MapBlockMesh::~MapBlockMesh()
1236 for (scene::IMesh *m : m_mesh) {
1237 if (m_enable_vbo && m)
1238 for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1239 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1240 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1245 delete m_minimap_mapblock;
1248 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1250 if(!m_has_animation)
1252 m_animation_force_timer = 100000;
1256 m_animation_force_timer = myrand_range(5, 100);
1259 if (crack != m_last_crack) {
1260 for (auto &crack_material : m_crack_materials) {
1261 scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1262 getMeshBuffer(crack_material.first.second);
1263 std::string basename = crack_material.second;
1265 // Create new texture name from original
1266 std::ostringstream os;
1267 os<<basename<<crack;
1268 u32 new_texture_id = 0;
1269 video::ITexture *new_texture =
1270 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1271 buf->getMaterial().setTexture(0, new_texture);
1273 // If the current material is also animated,
1274 // update animation info
1275 auto anim_iter = m_animation_tiles.find(crack_material.first);
1276 if (anim_iter != m_animation_tiles.end()){
1277 TileLayer &tile = anim_iter->second;
1278 tile.texture = new_texture;
1279 tile.texture_id = new_texture_id;
1280 // force animation update
1281 m_animation_frames[crack_material.first] = -1;
1285 m_last_crack = crack;
1288 // Texture animation
1289 for (auto &animation_tile : m_animation_tiles) {
1290 const TileLayer &tile = animation_tile.second;
1291 // Figure out current frame
1292 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1293 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1294 + frameoffset) % tile.animation_frame_count;
1295 // If frame doesn't change, skip
1296 if(frame == m_animation_frames[animation_tile.first])
1299 m_animation_frames[animation_tile.first] = frame;
1301 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1302 getMeshBuffer(animation_tile.first.second);
1304 const FrameSpec &animation_frame = (*tile.frames)[frame];
1305 buf->getMaterial().setTexture(0, animation_frame.texture);
1306 if (m_enable_shaders) {
1307 if (animation_frame.normal_texture) {
1308 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1310 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1314 // Day-night transition
1315 if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1317 // Force reload mesh to VBO
1319 for (scene::IMesh *m : m_mesh)
1321 video::SColorf day_color;
1322 get_sunlight_color(&day_color, daynight_ratio);
1324 for (auto &daynight_diff : m_daynight_diffs) {
1325 scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1326 getMeshBuffer(daynight_diff.first.second);
1327 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1328 for (const auto &j : daynight_diff.second) {
1329 final_color_blend(&(vertices[j.first].Color), j.second, day_color);
1332 m_last_daynight_ratio = daynight_ratio;
1338 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1340 if (camera_offset != m_camera_offset) {
1341 for (scene::IMesh *layer : m_mesh) {
1342 translateMesh(layer,
1343 intToFloat(m_camera_offset - camera_offset, BS));
1348 m_camera_offset = camera_offset;
1356 void MeshCollector::append(const TileSpec &tile,
1357 const video::S3DVertex *vertices, u32 numVertices,
1358 const u16 *indices, u32 numIndices)
1360 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1361 const TileLayer *layer = &tile.layers[layernum];
1362 if (layer->texture_id == 0)
1364 append(*layer, vertices, numVertices, indices, numIndices,
1369 void MeshCollector::append(const TileLayer &layer,
1370 const video::S3DVertex *vertices, u32 numVertices,
1371 const u16 *indices, u32 numIndices, u8 layernum)
1373 if (numIndices > 65535) {
1374 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1377 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1379 PreMeshBuffer *p = NULL;
1380 for (PreMeshBuffer &pp : *buffers) {
1381 if (pp.layer != layer)
1383 if (pp.indices.size() + numIndices > 65535)
1393 buffers->push_back(pp);
1394 p = &(*buffers)[buffers->size() - 1];
1398 if (m_use_tangent_vertices) {
1399 vertex_count = p->tangent_vertices.size();
1400 for (u32 i = 0; i < numVertices; i++) {
1401 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1402 vertices[i].Color, vertices[i].TCoords);
1403 p->tangent_vertices.push_back(vert);
1406 vertex_count = p->vertices.size();
1407 for (u32 i = 0; i < numVertices; i++) {
1408 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1409 vertices[i].Color, vertices[i].TCoords);
1410 p->vertices.push_back(vert);
1414 for (u32 i = 0; i < numIndices; i++) {
1415 u32 j = indices[i] + vertex_count;
1416 p->indices.push_back(j);
1421 MeshCollector - for meshnodes and converted drawtypes.
1424 void MeshCollector::append(const TileSpec &tile,
1425 const video::S3DVertex *vertices, u32 numVertices,
1426 const u16 *indices, u32 numIndices,
1427 v3f pos, video::SColor c, u8 light_source)
1429 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1430 const TileLayer *layer = &tile.layers[layernum];
1431 if (layer->texture_id == 0)
1433 append(*layer, vertices, numVertices, indices, numIndices, pos,
1434 c, light_source, layernum);
1438 void MeshCollector::append(const TileLayer &layer,
1439 const video::S3DVertex *vertices, u32 numVertices,
1440 const u16 *indices, u32 numIndices,
1441 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1443 if (numIndices > 65535) {
1444 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1447 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1449 PreMeshBuffer *p = NULL;
1450 for (PreMeshBuffer &pp : *buffers) {
1451 if(pp.layer != layer)
1453 if(pp.indices.size() + numIndices > 65535)
1463 buffers->push_back(pp);
1464 p = &(*buffers)[buffers->size() - 1];
1467 video::SColor original_c = c;
1469 if (m_use_tangent_vertices) {
1470 vertex_count = p->tangent_vertices.size();
1471 for (u32 i = 0; i < numVertices; i++) {
1472 if (!light_source) {
1474 applyFacesShading(c, vertices[i].Normal);
1476 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1477 vertices[i].Normal, c, vertices[i].TCoords);
1478 p->tangent_vertices.push_back(vert);
1481 vertex_count = p->vertices.size();
1482 for (u32 i = 0; i < numVertices; i++) {
1483 if (!light_source) {
1485 applyFacesShading(c, vertices[i].Normal);
1487 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1488 vertices[i].TCoords);
1489 p->vertices.push_back(vert);
1493 for (u32 i = 0; i < numIndices; i++) {
1494 u32 j = indices[i] + vertex_count;
1495 p->indices.push_back(j);
1499 void MeshCollector::applyTileColors()
1501 if (m_use_tangent_vertices)
1502 for (auto &prebuffer : prebuffers) {
1503 for (PreMeshBuffer &pmb : prebuffer) {
1504 video::SColor tc = pmb.layer.color;
1505 if (tc == video::SColor(0xFFFFFFFF))
1507 for (video::S3DVertexTangents &tangent_vertex : pmb.tangent_vertices) {
1508 video::SColor *c = &tangent_vertex.Color;
1509 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1510 c->getGreen() * tc.getGreen() / 255,
1511 c->getBlue() * tc.getBlue() / 255);
1516 for (auto &prebuffer : prebuffers) {
1517 for (PreMeshBuffer &pmb : prebuffer) {
1518 video::SColor tc = pmb.layer.color;
1519 if (tc == video::SColor(0xFFFFFFFF))
1521 for (video::S3DVertex &vertex : pmb.vertices) {
1522 video::SColor *c = &vertex.Color;
1523 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1524 c->getGreen() * tc.getGreen() / 255,
1525 c->getBlue() * tc.getBlue() / 255);
1531 video::SColor encode_light(u16 light, u8 emissive_light)
1534 u32 day = (light & 0xff);
1535 u32 night = (light >> 8);
1536 // Add emissive light
1537 night += emissive_light * 2.5f;
1540 // Since we don't know if the day light is sunlight or
1541 // artificial light, assume it is artificial when the night
1542 // light bank is also lit.
1547 u32 sum = day + night;
1548 // Ratio of sunlight:
1551 r = day * 255 / sum;
1555 float b = (day + night) / 2;
1556 return video::SColor(r, b, b, b);