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"
37 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
38 bool use_tangent_vertices):
40 m_use_shaders(use_shaders),
41 m_use_tangent_vertices(use_tangent_vertices)
44 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
46 m_blockpos = blockpos;
48 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
51 VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
52 blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
53 m_vmanip.addArea(voxel_area);
56 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
58 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
59 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
61 v3s16 bp = m_blockpos + block_offset;
62 v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
63 m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
66 void MeshMakeData::fill(MapBlock *block)
68 fillBlockDataBegin(block->getPos());
70 fillBlockData(v3s16(0,0,0), block->getData());
72 // Get map for reading neighbor blocks
73 Map *map = block->getParent();
75 for (const v3s16 &dir : g_26dirs) {
76 v3s16 bp = m_blockpos + dir;
77 MapBlock *b = map->getBlockNoCreateNoEx(bp);
79 fillBlockData(dir, b->getData());
83 void MeshMakeData::fillSingleNode(MapNode *node)
85 m_blockpos = v3s16(0,0,0);
87 v3s16 blockpos_nodes = v3s16(0,0,0);
88 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
89 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
90 s32 volume = area.getVolume();
91 s32 our_node_index = area.index(1,1,1);
93 // Allocate this block + neighbors
95 m_vmanip.addArea(area);
98 MapNode *data = new MapNode[volume];
99 for(s32 i = 0; i < volume; i++)
101 if (i == our_node_index)
104 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
106 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
110 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
112 if (crack_level >= 0)
113 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
116 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
118 m_smooth_lighting = smooth_lighting;
122 Light and vertex color functions
126 Calculate non-smooth lighting at interior of node.
129 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
130 INodeDefManager *ndef)
132 u8 light = n.getLight(bank, ndef);
136 light = undiminish_light(light);
141 light = diminish_light(light);
145 return decode_light(light);
149 Calculate non-smooth lighting at interior of node.
152 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
154 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
155 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
156 return day | (night << 8);
160 Calculate non-smooth lighting at face of node.
163 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
164 v3s16 face_dir, INodeDefManager *ndef)
167 u8 l1 = n.getLight(bank, ndef);
168 u8 l2 = n2.getLight(bank, ndef);
174 // Boost light level for light sources
175 u8 light_source = MYMAX(ndef->get(n).light_source,
176 ndef->get(n2).light_source);
177 if(light_source > light)
178 light = light_source;
180 return decode_light(light);
184 Calculate non-smooth lighting at face of node.
187 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
189 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
190 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
191 return day | (night << 8);
195 Calculate smooth lighting at the XYZ- corner of p.
198 static u16 getSmoothLightCombined(const v3s16 &p,
199 const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
201 INodeDefManager *ndef = data->m_client->ndef();
203 u16 ambient_occlusion = 0;
205 u8 light_source_max = 0;
209 auto add_node = [&] (int i) -> const ContentFeatures& {
210 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
211 const ContentFeatures &f = ndef->get(n);
212 if (f.light_source > light_source_max)
213 light_source_max = f.light_source;
214 // Check f.solidness because fast-style leaves look better this way
215 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
216 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
217 light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
226 ambient_occlusion = 3;
227 bool corner_obstructed = true;
228 for (int i = 0; i < 2; ++i) {
229 if (add_node(i).light_propagates)
230 corner_obstructed = false;
234 if (corner_obstructed)
239 std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
241 bool opaque1 = !add_node(1).light_propagates;
242 bool opaque2 = !add_node(2).light_propagates;
243 bool opaque3 = !add_node(3).light_propagates;
244 obstructed[0] = opaque1 && opaque2;
245 obstructed[1] = opaque1 && opaque3;
246 obstructed[2] = opaque2 && opaque3;
247 for (int k = 0; k < 4; ++k) {
250 else if (add_node(k + 4).light_propagates)
251 obstructed[3] = false;
255 if (light_count == 0) {
256 light_day = light_night = 0;
258 light_day /= light_count;
259 light_night /= light_count;
262 // Boost brightness around light sources
263 bool skip_ambient_occlusion_day = false;
264 if (decode_light(light_source_max) >= light_day) {
265 light_day = decode_light(light_source_max);
266 skip_ambient_occlusion_day = true;
269 bool skip_ambient_occlusion_night = false;
270 if(decode_light(light_source_max) >= light_night) {
271 light_night = decode_light(light_source_max);
272 skip_ambient_occlusion_night = true;
275 if (ambient_occlusion > 4) {
276 static thread_local const float ao_gamma = rangelim(
277 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
279 // Table of gamma space multiply factors.
280 static const float light_amount[3] = {
281 powf(0.75, 1.0 / ao_gamma),
282 powf(0.5, 1.0 / ao_gamma),
283 powf(0.25, 1.0 / ao_gamma)
286 //calculate table index for gamma space multiplier
287 ambient_occlusion -= 5;
289 if (!skip_ambient_occlusion_day)
290 light_day = rangelim(core::round32(
291 light_day * light_amount[ambient_occlusion]), 0, 255);
292 if (!skip_ambient_occlusion_night)
293 light_night = rangelim(core::round32(
294 light_night * light_amount[ambient_occlusion]), 0, 255);
297 return light_day | (light_night << 8);
301 Calculate smooth lighting at the given corner of p.
303 Node at p is solid, and thus the lighting is face-dependent.
305 u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
307 v3s16 neighbor_offset1, neighbor_offset2;
310 * face_dir, neighbor_offset1 and neighbor_offset2 define an
311 * orthonormal basis which is used to define the offsets of the 8
312 * surrounding nodes and to differentiate the "distance" (by going only
313 * along directly neighboring nodes) relative to the node at p.
314 * Apart from the node at p, only the 4 nodes which contain face_dir
315 * can contribute light.
317 if (face_dir.X != 0) {
318 neighbor_offset1 = v3s16(0, corner.Y, 0);
319 neighbor_offset2 = v3s16(0, 0, corner.Z);
320 } else if (face_dir.Y != 0) {
321 neighbor_offset1 = v3s16(0, 0, corner.Z);
322 neighbor_offset2 = v3s16(corner.X, 0, 0);
323 } else if (face_dir.Z != 0) {
324 neighbor_offset1 = v3s16(corner.X,0,0);
325 neighbor_offset2 = v3s16(0,corner.Y,0);
328 const std::array<v3s16,8> dirs = {{
329 // Always shine light
330 neighbor_offset1 + face_dir,
331 neighbor_offset2 + face_dir,
336 neighbor_offset1 + neighbor_offset2 + face_dir,
338 // Do not shine light, only for ambient occlusion
341 neighbor_offset1 + neighbor_offset2
343 return getSmoothLightCombined(p, dirs, data, true);
347 Calculate smooth lighting at the given corner of p.
349 Node at p is not solid, and the lighting is not face-dependent.
351 u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
353 const std::array<v3s16,8> dirs = {{
354 // Always shine light
361 v3s16(corner.X,corner.Y,0),
362 v3s16(corner.X,0,corner.Z),
363 v3s16(0,corner.Y,corner.Z),
364 v3s16(corner.X,corner.Y,corner.Z)
366 return getSmoothLightCombined(p, dirs, data, false);
369 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
370 f32 rg = daynight_ratio / 1000.0f - 0.04f;
371 f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
377 void final_color_blend(video::SColor *result,
378 u16 light, u32 daynight_ratio)
380 video::SColorf dayLight;
381 get_sunlight_color(&dayLight, daynight_ratio);
382 final_color_blend(result,
383 encode_light(light, 0), dayLight);
386 void final_color_blend(video::SColor *result,
387 const video::SColor &data, const video::SColorf &dayLight)
389 static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
391 video::SColorf c(data);
394 f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
395 f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
396 f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
398 // Emphase blue a bit in darker places
399 // Each entry of this array represents a range of 8 blue levels
400 static const u8 emphase_blue_when_dark[32] = {
401 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
405 b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
406 0, 255) / 8] / 255.0f;
408 result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
409 result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
410 result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
414 Mesh generation helpers
418 vertex_dirs: v3s16[4]
420 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
423 If looked from outside the node towards the face, the corners are:
429 if (dir == v3s16(0, 0, 1)) {
430 // If looking towards z+, this is the face that is behind
431 // the center point, facing towards z+.
432 vertex_dirs[0] = v3s16(-1,-1, 1);
433 vertex_dirs[1] = v3s16( 1,-1, 1);
434 vertex_dirs[2] = v3s16( 1, 1, 1);
435 vertex_dirs[3] = v3s16(-1, 1, 1);
436 } else if (dir == v3s16(0, 0, -1)) {
438 vertex_dirs[0] = v3s16( 1,-1,-1);
439 vertex_dirs[1] = v3s16(-1,-1,-1);
440 vertex_dirs[2] = v3s16(-1, 1,-1);
441 vertex_dirs[3] = v3s16( 1, 1,-1);
442 } else if (dir == v3s16(1, 0, 0)) {
444 vertex_dirs[0] = v3s16( 1,-1, 1);
445 vertex_dirs[1] = v3s16( 1,-1,-1);
446 vertex_dirs[2] = v3s16( 1, 1,-1);
447 vertex_dirs[3] = v3s16( 1, 1, 1);
448 } else if (dir == v3s16(-1, 0, 0)) {
450 vertex_dirs[0] = v3s16(-1,-1,-1);
451 vertex_dirs[1] = v3s16(-1,-1, 1);
452 vertex_dirs[2] = v3s16(-1, 1, 1);
453 vertex_dirs[3] = v3s16(-1, 1,-1);
454 } else if (dir == v3s16(0, 1, 0)) {
455 // faces towards Y+ (assume Z- as "down" in texture)
456 vertex_dirs[0] = v3s16( 1, 1,-1);
457 vertex_dirs[1] = v3s16(-1, 1,-1);
458 vertex_dirs[2] = v3s16(-1, 1, 1);
459 vertex_dirs[3] = v3s16( 1, 1, 1);
460 } else if (dir == v3s16(0, -1, 0)) {
461 // faces towards Y- (assume Z+ as "down" in texture)
462 vertex_dirs[0] = v3s16( 1,-1, 1);
463 vertex_dirs[1] = v3s16(-1,-1, 1);
464 vertex_dirs[2] = v3s16(-1,-1,-1);
465 vertex_dirs[3] = v3s16( 1,-1,-1);
472 video::S3DVertex vertices[4]; // Precalculated vertices
474 * The face is divided into two triangles. If this is true,
475 * vertices 0 and 2 are connected, othervise vertices 1 and 3
478 bool vertex_0_2_connected;
482 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
483 const v3f &p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
485 // Position is at the center of the cube.
494 v3s16 vertex_dirs[4];
495 getNodeVertexDirs(dir, vertex_dirs);
499 switch (tile.rotation) {
504 vertex_dirs[0] = vertex_dirs[3];
505 vertex_dirs[3] = vertex_dirs[2];
506 vertex_dirs[2] = vertex_dirs[1];
516 vertex_dirs[0] = vertex_dirs[2];
519 vertex_dirs[1] = vertex_dirs[3];
530 vertex_dirs[0] = vertex_dirs[1];
531 vertex_dirs[1] = vertex_dirs[2];
532 vertex_dirs[2] = vertex_dirs[3];
542 vertex_dirs[0] = vertex_dirs[3];
543 vertex_dirs[3] = vertex_dirs[2];
544 vertex_dirs[2] = vertex_dirs[1];
556 vertex_dirs[0] = vertex_dirs[1];
557 vertex_dirs[1] = vertex_dirs[2];
558 vertex_dirs[2] = vertex_dirs[3];
570 vertex_dirs[0] = vertex_dirs[3];
571 vertex_dirs[3] = vertex_dirs[2];
572 vertex_dirs[2] = vertex_dirs[1];
584 vertex_dirs[0] = vertex_dirs[1];
585 vertex_dirs[1] = vertex_dirs[2];
586 vertex_dirs[2] = vertex_dirs[3];
608 for (u16 i = 0; i < 4; i++) {
610 BS / 2 * vertex_dirs[i].X,
611 BS / 2 * vertex_dirs[i].Y,
612 BS / 2 * vertex_dirs[i].Z
616 for (v3f &vpos : vertex_pos) {
623 f32 abs_scale = 1.0f;
624 if (scale.X < 0.999f || scale.X > 1.001f) abs_scale = scale.X;
625 else if (scale.Y < 0.999f || scale.Y > 1.001f) abs_scale = scale.Y;
626 else if (scale.Z < 0.999f || scale.Z > 1.001f) abs_scale = scale.Z;
628 v3f normal(dir.X, dir.Y, dir.Z);
630 u16 li[4] = { li0, li1, li2, li3 };
634 for (u8 i = 0; i < 4; i++) {
636 night[i] = li[i] & 0xFF;
639 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
640 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
643 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
644 core::vector2d<f32>(x0, y0 + h),
645 core::vector2d<f32>(x0, y0),
646 core::vector2d<f32>(x0 + w * abs_scale, y0) };
648 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
649 const TileLayer *layer = &tile.layers[layernum];
650 if (layer->texture_id == 0)
653 // equivalent to dest.push_back(FastFace()) but faster
655 FastFace& face = *dest.rbegin();
657 for (u8 i = 0; i < 4; i++) {
658 video::SColor c = encode_light(li[i], tile.emissive_light);
659 if (!tile.emissive_light)
660 applyFacesShading(c, normal);
662 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
666 Revert triangles for nicer looking gradient if the
667 brightness of vertices 1 and 3 differ less than
668 the brightness of vertices 0 and 2.
670 face.vertex_0_2_connected = vertex_0_2_connected;
673 face.layernum = layernum;
678 Nodes make a face if contents differ and solidness differs.
681 1: Face uses m1's content
682 2: Face uses m2's content
683 equivalent: Whether the blocks share the same face (eg. water and glass)
685 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
687 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
688 INodeDefManager *ndef)
692 if (m1 == m2 || m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
695 const ContentFeatures &f1 = ndef->get(m1);
696 const ContentFeatures &f2 = ndef->get(m2);
698 // Contents don't differ for different forms of same liquid
699 if (f1.sameLiquid(f2))
702 u8 c1 = f1.solidness;
703 u8 c2 = f2.solidness;
709 c1 = f1.visual_solidness;
711 c2 = f2.visual_solidness;
715 // If same solidness, liquid takes precense
729 Gets nth node tile (0 <= n <= 5).
731 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
733 INodeDefManager *ndef = data->m_client->ndef();
734 const ContentFeatures &f = ndef->get(mn);
735 tile = f.tiles[tileindex];
736 bool has_crack = p == data->m_crack_pos_relative;
737 for (TileLayer &layer : tile.layers) {
738 if (layer.texture_id == 0)
740 if (!layer.has_color)
741 mn.getColor(f, &(layer.color));
742 // Apply temporary crack
744 layer.material_flags |= MATERIAL_FLAG_CRACK;
749 Gets node tile given a face direction.
751 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
753 INodeDefManager *ndef = data->m_client->ndef();
755 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
756 // (0,0,1), (0,0,-1) or (0,0,0)
757 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
759 // Convert direction to single integer for table lookup
764 // 4 = invalid, treat as (0,0,0)
768 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7) * 2;
770 // Get rotation for things like chests
771 u8 facedir = mn.getFaceDir(ndef);
773 static const u16 dir_to_tile[24 * 16] =
775 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
776 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
777 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
778 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
779 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
781 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
782 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
783 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
784 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
786 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
787 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
788 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
789 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
791 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
792 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
793 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
794 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
796 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
797 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
798 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
799 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
801 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
802 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
803 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
804 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
807 u16 tile_index = facedir * 16 + dir_i;
808 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
809 tile.rotation = dir_to_tile[tile_index + 1];
812 static void getTileInfo(
816 const v3s16 &face_dir,
820 v3s16 &face_dir_corrected,
825 VoxelManipulator &vmanip = data->m_vmanip;
826 INodeDefManager *ndef = data->m_client->ndef();
827 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
829 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
831 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
832 if (n0.getContent() == CONTENT_IGNORE) {
837 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
839 if (n1.getContent() == CONTENT_IGNORE) {
845 bool equivalent = false;
846 u8 mf = face_contents(n0.getContent(), n1.getContent(),
860 face_dir_corrected = face_dir;
863 p_corrected = p + face_dir;
864 face_dir_corrected = -face_dir;
867 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
868 const ContentFeatures &f = ndef->get(n);
869 tile.emissive_light = f.light_source;
871 // eg. water and glass
873 for (TileLayer &layer : tile.layers)
874 layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
877 if (!data->m_smooth_lighting) {
878 lights[0] = lights[1] = lights[2] = lights[3] =
879 getFaceLight(n0, n1, face_dir, ndef);
881 v3s16 vertex_dirs[4];
882 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
884 v3s16 light_p = blockpos_nodes + p_corrected;
885 for (u16 i = 0; i < 4; i++)
886 lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
892 translate_dir: unit vector with only one of x, y or z
893 face_dir: unit vector with only one of x, y or z
895 static void updateFastFaceRow(
897 const v3s16 &&startpos,
899 const v3f &&translate_dir_f,
900 const v3s16 &&face_dir,
901 std::vector<FastFace> &dest)
905 u16 continuous_tiles_count = 1;
907 bool makes_face = false;
909 v3s16 face_dir_corrected;
910 u16 lights[4] = {0, 0, 0, 0};
912 getTileInfo(data, p, face_dir,
913 makes_face, p_corrected, face_dir_corrected,
916 // Unroll this variable which has a significant build cost
918 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
919 // If tiling can be done, this is set to false in the next step
920 bool next_is_different = true;
924 bool next_makes_face = false;
925 v3s16 next_p_corrected;
926 v3s16 next_face_dir_corrected;
927 u16 next_lights[4] = {0, 0, 0, 0};
929 // If at last position, there is nothing to compare to and
930 // the face must be drawn anyway
931 if (j != MAP_BLOCKSIZE - 1) {
932 p_next = p + translate_dir;
934 getTileInfo(data, p_next, face_dir,
935 next_makes_face, next_p_corrected,
936 next_face_dir_corrected, next_lights,
939 if (next_makes_face == makes_face
940 && next_p_corrected == p_corrected + translate_dir
941 && next_face_dir_corrected == face_dir_corrected
942 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
943 && next_tile.isTileable(tile)) {
944 next_is_different = false;
945 continuous_tiles_count++;
948 if (next_is_different) {
950 Create a face if there should be one
953 // Floating point conversion of the position vector
954 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
955 // Center point of face (kind of)
956 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
960 if (translate_dir.X != 0)
961 scale.X = continuous_tiles_count;
962 if (translate_dir.Y != 0)
963 scale.Y = continuous_tiles_count;
964 if (translate_dir.Z != 0)
965 scale.Z = continuous_tiles_count;
967 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
968 sp, face_dir_corrected, scale, dest);
970 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
971 for (int i = 1; i < continuous_tiles_count; i++)
972 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
975 continuous_tiles_count = 1;
978 makes_face = next_makes_face;
979 p_corrected = next_p_corrected;
980 face_dir_corrected = next_face_dir_corrected;
981 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
982 if (next_is_different)
988 static void updateAllFastFaceRows(MeshMakeData *data,
989 std::vector<FastFace> &dest)
992 Go through every y,z and get top(y+) faces in rows of x+
994 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
995 for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
996 updateFastFaceRow(data,
998 v3s16(1, 0, 0), //dir
1000 v3s16(0, 1, 0), //face dir
1004 Go through every x,y and get right(x+) faces in rows of z+
1006 for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
1007 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1008 updateFastFaceRow(data,
1010 v3s16(0, 0, 1), //dir
1012 v3s16(1, 0, 0), //face dir
1016 Go through every y,z and get back(z+) faces in rows of x+
1018 for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1019 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1020 updateFastFaceRow(data,
1022 v3s16(1, 0, 0), //dir
1024 v3s16(0, 0, 1), //face dir
1032 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1033 m_minimap_mapblock(NULL),
1034 m_tsrc(data->m_client->getTextureSource()),
1035 m_shdrsrc(data->m_client->getShaderSource()),
1036 m_animation_force_timer(0), // force initial animation
1038 m_last_daynight_ratio((u32) -1)
1040 for (auto &m : m_mesh)
1041 m = new scene::SMesh();
1042 m_enable_shaders = data->m_use_shaders;
1043 m_use_tangent_vertices = data->m_use_tangent_vertices;
1044 m_enable_vbo = g_settings->getBool("enable_vbo");
1046 if (g_settings->getBool("enable_minimap")) {
1047 m_minimap_mapblock = new MinimapMapblock;
1048 m_minimap_mapblock->getMinimapNodes(
1049 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1052 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1053 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1054 //TimeTaker timer1("MapBlockMesh()");
1056 std::vector<FastFace> fastfaces_new;
1057 fastfaces_new.reserve(512);
1060 We are including the faces of the trailing edges of the block.
1061 This means that when something changes, the caller must
1062 also update the meshes of the blocks at the leading edges.
1064 NOTE: This is the slowest part of this method.
1067 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1068 //TimeTaker timer2("updateAllFastFaceRows()");
1069 updateAllFastFaceRows(data, fastfaces_new);
1074 Convert FastFaces to MeshCollector
1077 MeshCollector collector(m_use_tangent_vertices);
1080 // avg 0ms (100ms spikes when loading textures the first time)
1081 // (NOTE: probably outdated)
1082 //TimeTaker timer2("MeshCollector building");
1084 for (const FastFace &f : fastfaces_new) {
1085 static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1086 static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1088 if (!f.layer.texture)
1091 const u16 *indices_p =
1092 f.vertex_0_2_connected ? indices : indices_alternate;
1094 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1100 Add special graphics:
1108 MapblockMeshGenerator generator(data, &collector);
1109 generator.generate();
1112 collector.applyTileColors();
1115 Convert MeshCollector to SMesh
1118 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1119 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1121 PreMeshBuffer &p = collector.prebuffers[layer][i];
1123 // Generate animation data
1125 if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1126 // Find the texture name plus ^[crack:N:
1127 std::ostringstream os(std::ios::binary);
1128 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1129 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1130 os << "o"; // use ^[cracko
1131 os << ":" << (u32)p.layer.animation_frame_count << ":";
1132 m_crack_materials.insert(std::make_pair(
1133 std::pair<u8, u32>(layer, i), os.str()));
1134 // Replace tile texture with the cracked one
1135 p.layer.texture = m_tsrc->getTextureForMesh(
1137 &p.layer.texture_id);
1139 // - Texture animation
1140 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1141 // Add to MapBlockMesh in order to animate these tiles
1142 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1143 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1144 if (g_settings->getBool(
1145 "desynchronize_mapblock_texture_animation")) {
1146 // Get starting position from noise
1147 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1148 100000 * (2.0 + noise3d(
1149 data->m_blockpos.X, data->m_blockpos.Y,
1150 data->m_blockpos.Z, 0));
1152 // Play all synchronized
1153 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1155 // Replace tile texture with the first animation frame
1156 p.layer.texture = (*p.layer.frames)[0].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);
1164 u32 vertex_count = m_use_tangent_vertices ?
1165 p.tangent_vertices.size() : p.vertices.size();
1166 for (u32 j = 0; j < vertex_count; j++) {
1168 if (m_use_tangent_vertices) {
1169 vc = &p.tangent_vertices[j].Color;
1171 vc = &p.vertices[j].Color;
1173 video::SColor copy(*vc);
1174 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1175 final_color_blend(vc, copy, sunlight); // Finalize color
1176 else // Record color to animate
1177 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1179 // The sunlight ratio has been stored,
1180 // delete alpha (for the final rendering).
1186 video::SMaterial material;
1187 material.setFlag(video::EMF_LIGHTING, false);
1188 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1189 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1190 material.setFlag(video::EMF_FOG_ENABLE, true);
1191 material.setTexture(0, p.layer.texture);
1193 if (m_enable_shaders) {
1194 material.MaterialType = m_shdrsrc->getShaderInfo(
1195 p.layer.shader_id).material;
1196 p.layer.applyMaterialOptionsWithShaders(material);
1197 if (p.layer.normal_texture)
1198 material.setTexture(1, p.layer.normal_texture);
1199 material.setTexture(2, p.layer.flags_texture);
1201 p.layer.applyMaterialOptions(material);
1204 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1206 // Create meshbuffer, add to mesh
1207 if (m_use_tangent_vertices) {
1208 scene::SMeshBufferTangents *buf =
1209 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[layer],
1236 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1238 if (m_use_tangent_vertices) {
1239 scene::IMeshManipulator* meshmanip =
1240 RenderingEngine::get_scene_manager()->getMeshManipulator();
1241 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1244 if (m_mesh[layer]) {
1246 // Usually 1-700 faces and 1-7 materials
1247 std::cout << "Updated MapBlock has " << fastfaces_new.size()
1248 << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1249 << " materials (meshbuffers)" << std::endl;
1252 // Use VBO for mesh (this just would set this for ever buffer)
1254 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1258 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1260 // Check if animation is required for this mesh
1262 !m_crack_materials.empty() ||
1263 !m_daynight_diffs.empty() ||
1264 !m_animation_tiles.empty();
1267 MapBlockMesh::~MapBlockMesh()
1269 for (scene::IMesh *m : m_mesh) {
1270 if (m_enable_vbo && m)
1271 for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1272 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1273 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1278 delete m_minimap_mapblock;
1281 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1284 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) {
1293 for (auto &crack_material : m_crack_materials) {
1294 scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1295 getMeshBuffer(crack_material.first.second);
1296 std::string basename = crack_material.second;
1298 // Create new texture name from original
1299 std::ostringstream os;
1300 os << basename << crack;
1301 u32 new_texture_id = 0;
1302 video::ITexture *new_texture =
1303 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1304 buf->getMaterial().setTexture(0, new_texture);
1306 // If the current material is also animated,
1307 // update animation info
1308 auto anim_iter = m_animation_tiles.find(crack_material.first);
1309 if (anim_iter != m_animation_tiles.end()) {
1310 TileLayer &tile = anim_iter->second;
1311 tile.texture = new_texture;
1312 tile.texture_id = new_texture_id;
1313 // force animation update
1314 m_animation_frames[crack_material.first] = -1;
1318 m_last_crack = crack;
1321 // Texture animation
1322 for (auto &animation_tile : m_animation_tiles) {
1323 const TileLayer &tile = animation_tile.second;
1324 // Figure out current frame
1325 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1326 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1327 + frameoffset) % tile.animation_frame_count;
1328 // If frame doesn't change, skip
1329 if (frame == m_animation_frames[animation_tile.first])
1332 m_animation_frames[animation_tile.first] = frame;
1334 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1335 getMeshBuffer(animation_tile.first.second);
1337 const FrameSpec &animation_frame = (*tile.frames)[frame];
1338 buf->getMaterial().setTexture(0, animation_frame.texture);
1339 if (m_enable_shaders) {
1340 if (animation_frame.normal_texture)
1341 buf->getMaterial().setTexture(1,
1342 animation_frame.normal_texture);
1343 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1347 // Day-night transition
1348 if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1349 // Force reload mesh to VBO
1351 for (scene::IMesh *m : m_mesh)
1353 video::SColorf day_color;
1354 get_sunlight_color(&day_color, daynight_ratio);
1356 for (auto &daynight_diff : m_daynight_diffs) {
1357 scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1358 getMeshBuffer(daynight_diff.first.second);
1359 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1360 for (const auto &j : daynight_diff.second)
1361 final_color_blend(&(vertices[j.first].Color), j.second,
1364 m_last_daynight_ratio = daynight_ratio;
1370 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1372 if (camera_offset != m_camera_offset) {
1373 for (scene::IMesh *layer : m_mesh) {
1374 translateMesh(layer,
1375 intToFloat(m_camera_offset - camera_offset, BS));
1379 m_camera_offset = camera_offset;
1387 void MeshCollector::append(const TileSpec &tile,
1388 const video::S3DVertex *vertices, u32 numVertices,
1389 const u16 *indices, u32 numIndices)
1391 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1392 const TileLayer *layer = &tile.layers[layernum];
1393 if (layer->texture_id == 0)
1395 append(*layer, vertices, numVertices, indices, numIndices, layernum);
1399 void MeshCollector::append(const TileLayer &layer,
1400 const video::S3DVertex *vertices, u32 numVertices,
1401 const u16 *indices, u32 numIndices, u8 layernum)
1403 if (numIndices > 65535) {
1404 dstream << "FIXME: MeshCollector::append() called with numIndices="
1405 << numIndices << " (limit 65535)" << std::endl;
1408 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1410 PreMeshBuffer *p = NULL;
1411 for (PreMeshBuffer &pp : *buffers) {
1412 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1421 buffers->push_back(pp);
1422 p = &(*buffers)[buffers->size() - 1];
1426 if (m_use_tangent_vertices) {
1427 vertex_count = p->tangent_vertices.size();
1428 for (u32 i = 0; i < numVertices; i++) {
1430 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1431 vertices[i].Color, vertices[i].TCoords);
1432 p->tangent_vertices.push_back(vert);
1435 vertex_count = p->vertices.size();
1436 for (u32 i = 0; i < numVertices; i++) {
1437 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1438 vertices[i].Color, vertices[i].TCoords);
1440 p->vertices.push_back(vert);
1444 for (u32 i = 0; i < numIndices; i++) {
1445 u32 j = indices[i] + vertex_count;
1446 p->indices.push_back(j);
1451 MeshCollector - for meshnodes and converted drawtypes.
1454 void MeshCollector::append(const TileSpec &tile,
1455 const video::S3DVertex *vertices, u32 numVertices,
1456 const u16 *indices, u32 numIndices,
1457 v3f pos, video::SColor c, u8 light_source)
1459 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1460 const TileLayer *layer = &tile.layers[layernum];
1461 if (layer->texture_id == 0)
1463 append(*layer, vertices, numVertices, indices, numIndices, pos,
1464 c, light_source, layernum);
1468 void MeshCollector::append(const TileLayer &layer,
1469 const video::S3DVertex *vertices, u32 numVertices,
1470 const u16 *indices, u32 numIndices,
1471 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1473 if (numIndices > 65535) {
1474 dstream << "FIXME: MeshCollector::append() called with numIndices="
1475 << numIndices << " (limit 65535)" << std::endl;
1478 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1480 PreMeshBuffer *p = NULL;
1481 for (PreMeshBuffer &pp : *buffers) {
1482 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1491 buffers->push_back(pp);
1492 p = &(*buffers)[buffers->size() - 1];
1495 video::SColor original_c = c;
1497 if (m_use_tangent_vertices) {
1498 vertex_count = p->tangent_vertices.size();
1499 for (u32 i = 0; i < numVertices; i++) {
1500 if (!light_source) {
1502 applyFacesShading(c, vertices[i].Normal);
1504 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1505 vertices[i].Normal, c, vertices[i].TCoords);
1506 p->tangent_vertices.push_back(vert);
1509 vertex_count = p->vertices.size();
1510 for (u32 i = 0; i < numVertices; i++) {
1511 if (!light_source) {
1513 applyFacesShading(c, vertices[i].Normal);
1515 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1516 vertices[i].TCoords);
1517 p->vertices.push_back(vert);
1521 for (u32 i = 0; i < numIndices; i++) {
1522 u32 j = indices[i] + vertex_count;
1523 p->indices.push_back(j);
1527 void MeshCollector::applyTileColors()
1529 if (m_use_tangent_vertices)
1530 for (auto &prebuffer : prebuffers) {
1531 for (PreMeshBuffer &pmb : prebuffer) {
1532 video::SColor tc = pmb.layer.color;
1533 if (tc == video::SColor(0xFFFFFFFF))
1535 for (video::S3DVertexTangents &tangent_vertex : pmb.tangent_vertices) {
1536 video::SColor *c = &tangent_vertex.Color;
1537 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1538 c->getGreen() * tc.getGreen() / 255,
1539 c->getBlue() * tc.getBlue() / 255);
1544 for (auto &prebuffer : prebuffers) {
1545 for (PreMeshBuffer &pmb : prebuffer) {
1546 video::SColor tc = pmb.layer.color;
1547 if (tc == video::SColor(0xFFFFFFFF))
1549 for (video::S3DVertex &vertex : pmb.vertices) {
1550 video::SColor *c = &vertex.Color;
1551 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1552 c->getGreen() * tc.getGreen() / 255,
1553 c->getBlue() * tc.getBlue() / 255);
1559 video::SColor encode_light(u16 light, u8 emissive_light)
1562 u32 day = (light & 0xff);
1563 u32 night = (light >> 8);
1564 // Add emissive light
1565 night += emissive_light * 2.5f;
1568 // Since we don't know if the day light is sunlight or
1569 // artificial light, assume it is artificial when the night
1570 // light bank is also lit.
1575 u32 sum = day + night;
1576 // Ratio of sunlight:
1579 r = day * 255 / sum;
1583 float b = (day + night) / 2;
1584 return video::SColor(r, b, b, b);