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)
103 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
105 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
109 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
111 if (crack_level >= 0)
112 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
115 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
117 m_smooth_lighting = smooth_lighting;
121 Light and vertex color functions
125 Calculate non-smooth lighting at interior of node.
128 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
129 INodeDefManager *ndef)
131 u8 light = n.getLight(bank, ndef);
135 light = undiminish_light(light);
140 light = diminish_light(light);
144 return decode_light(light);
148 Calculate non-smooth lighting at interior of node.
151 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
153 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
154 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
155 return day | (night << 8);
159 Calculate non-smooth lighting at face of node.
162 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
163 v3s16 face_dir, INodeDefManager *ndef)
166 u8 l1 = n.getLight(bank, ndef);
167 u8 l2 = n2.getLight(bank, ndef);
173 // Boost light level for light sources
174 u8 light_source = MYMAX(ndef->get(n).light_source,
175 ndef->get(n2).light_source);
176 if(light_source > light)
177 light = light_source;
179 return decode_light(light);
183 Calculate non-smooth lighting at face of node.
186 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
188 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
189 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
190 return day | (night << 8);
194 Calculate smooth lighting at the XYZ- corner of p.
197 static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
199 static const v3s16 dirs8[8] = {
210 INodeDefManager *ndef = data->m_client->ndef();
212 u16 ambient_occlusion = 0;
214 u8 light_source_max = 0;
218 for (const v3s16 &dir : dirs8) {
219 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dir);
221 // if it's CONTENT_IGNORE we can't do any light calculations
222 if (n.getContent() == CONTENT_IGNORE)
225 const ContentFeatures &f = ndef->get(n);
226 if (f.light_source > light_source_max)
227 light_source_max = f.light_source;
228 // Check f.solidness because fast-style leaves look better this way
229 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
230 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
231 light_night += decode_light(
232 n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
242 light_day /= light_count;
243 light_night /= light_count;
245 // Boost brightness around light sources
246 bool skip_ambient_occlusion_day = false;
247 if (decode_light(light_source_max) >= light_day) {
248 light_day = decode_light(light_source_max);
249 skip_ambient_occlusion_day = true;
252 bool skip_ambient_occlusion_night = false;
253 if(decode_light(light_source_max) >= light_night) {
254 light_night = decode_light(light_source_max);
255 skip_ambient_occlusion_night = true;
258 if (ambient_occlusion > 4) {
259 static thread_local const float ao_gamma = rangelim(
260 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
262 // Table of gamma space multiply factors.
263 static const float light_amount[3] = {
264 powf(0.75, 1.0 / ao_gamma),
265 powf(0.5, 1.0 / ao_gamma),
266 powf(0.25, 1.0 / ao_gamma)
269 //calculate table index for gamma space multiplier
270 ambient_occlusion -= 5;
272 if (!skip_ambient_occlusion_day)
273 light_day = rangelim(core::round32(
274 light_day * light_amount[ambient_occlusion]), 0, 255);
275 if (!skip_ambient_occlusion_night)
276 light_night = rangelim(core::round32(
277 light_night * light_amount[ambient_occlusion]), 0, 255);
280 return light_day | (light_night << 8);
284 Calculate smooth lighting at the given corner of p.
287 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
291 // else corner.X == -1
294 // else corner.Y == -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)) {
363 // If looking towards z+, this is the face that is behind
364 // the center point, facing towards z+.
365 vertex_dirs[0] = v3s16(-1,-1, 1);
366 vertex_dirs[1] = v3s16( 1,-1, 1);
367 vertex_dirs[2] = v3s16( 1, 1, 1);
368 vertex_dirs[3] = v3s16(-1, 1, 1);
369 } else if (dir == v3s16(0, 0, -1)) {
371 vertex_dirs[0] = v3s16( 1,-1,-1);
372 vertex_dirs[1] = v3s16(-1,-1,-1);
373 vertex_dirs[2] = v3s16(-1, 1,-1);
374 vertex_dirs[3] = v3s16( 1, 1,-1);
375 } else if (dir == v3s16(1, 0, 0)) {
377 vertex_dirs[0] = v3s16( 1,-1, 1);
378 vertex_dirs[1] = v3s16( 1,-1,-1);
379 vertex_dirs[2] = v3s16( 1, 1,-1);
380 vertex_dirs[3] = v3s16( 1, 1, 1);
381 } else if (dir == v3s16(-1, 0, 0)) {
383 vertex_dirs[0] = v3s16(-1,-1,-1);
384 vertex_dirs[1] = v3s16(-1,-1, 1);
385 vertex_dirs[2] = v3s16(-1, 1, 1);
386 vertex_dirs[3] = v3s16(-1, 1,-1);
387 } else if (dir == v3s16(0, 1, 0)) {
388 // faces towards Y+ (assume Z- as "down" in texture)
389 vertex_dirs[0] = v3s16( 1, 1,-1);
390 vertex_dirs[1] = v3s16(-1, 1,-1);
391 vertex_dirs[2] = v3s16(-1, 1, 1);
392 vertex_dirs[3] = v3s16( 1, 1, 1);
393 } else if (dir == v3s16(0, -1, 0)) {
394 // faces towards Y- (assume Z+ as "down" in texture)
395 vertex_dirs[0] = v3s16( 1,-1, 1);
396 vertex_dirs[1] = v3s16(-1,-1, 1);
397 vertex_dirs[2] = v3s16(-1,-1,-1);
398 vertex_dirs[3] = v3s16( 1,-1,-1);
405 video::S3DVertex vertices[4]; // Precalculated vertices
407 * The face is divided into two triangles. If this is true,
408 * vertices 0 and 2 are connected, othervise vertices 1 and 3
411 bool vertex_0_2_connected;
415 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
416 const v3f &p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
418 // Position is at the center of the cube.
427 v3s16 vertex_dirs[4];
428 getNodeVertexDirs(dir, vertex_dirs);
432 switch (tile.rotation) {
437 vertex_dirs[0] = vertex_dirs[3];
438 vertex_dirs[3] = vertex_dirs[2];
439 vertex_dirs[2] = vertex_dirs[1];
449 vertex_dirs[0] = vertex_dirs[2];
452 vertex_dirs[1] = vertex_dirs[3];
463 vertex_dirs[0] = vertex_dirs[1];
464 vertex_dirs[1] = vertex_dirs[2];
465 vertex_dirs[2] = vertex_dirs[3];
475 vertex_dirs[0] = vertex_dirs[3];
476 vertex_dirs[3] = vertex_dirs[2];
477 vertex_dirs[2] = vertex_dirs[1];
489 vertex_dirs[0] = vertex_dirs[1];
490 vertex_dirs[1] = vertex_dirs[2];
491 vertex_dirs[2] = vertex_dirs[3];
503 vertex_dirs[0] = vertex_dirs[3];
504 vertex_dirs[3] = vertex_dirs[2];
505 vertex_dirs[2] = vertex_dirs[1];
517 vertex_dirs[0] = vertex_dirs[1];
518 vertex_dirs[1] = vertex_dirs[2];
519 vertex_dirs[2] = vertex_dirs[3];
541 for (u16 i = 0; i < 4; i++) {
543 BS / 2 * vertex_dirs[i].X,
544 BS / 2 * vertex_dirs[i].Y,
545 BS / 2 * vertex_dirs[i].Z
549 for (v3f &vpos : vertex_pos) {
556 f32 abs_scale = 1.0f;
557 if (scale.X < 0.999f || scale.X > 1.001f) abs_scale = scale.X;
558 else if (scale.Y < 0.999f || scale.Y > 1.001f) abs_scale = scale.Y;
559 else if (scale.Z < 0.999f || scale.Z > 1.001f) abs_scale = scale.Z;
561 v3f normal(dir.X, dir.Y, dir.Z);
563 u16 li[4] = { li0, li1, li2, li3 };
567 for (u8 i = 0; i < 4; i++) {
569 night[i] = li[i] & 0xFF;
572 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
573 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
576 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
577 core::vector2d<f32>(x0, y0 + h),
578 core::vector2d<f32>(x0, y0),
579 core::vector2d<f32>(x0 + w * abs_scale, y0) };
581 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
582 const TileLayer *layer = &tile.layers[layernum];
583 if (layer->texture_id == 0)
586 // equivalent to dest.push_back(FastFace()) but faster
588 FastFace& face = *dest.rbegin();
590 for (u8 i = 0; i < 4; i++) {
591 video::SColor c = encode_light(li[i], tile.emissive_light);
592 if (!tile.emissive_light)
593 applyFacesShading(c, normal);
595 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
599 Revert triangles for nicer looking gradient if the
600 brightness of vertices 1 and 3 differ less than
601 the brightness of vertices 0 and 2.
603 face.vertex_0_2_connected = vertex_0_2_connected;
606 face.layernum = layernum;
611 Nodes make a face if contents differ and solidness differs.
614 1: Face uses m1's content
615 2: Face uses m2's content
616 equivalent: Whether the blocks share the same face (eg. water and glass)
618 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
620 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
621 INodeDefManager *ndef)
625 if (m1 == m2 || m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
628 const ContentFeatures &f1 = ndef->get(m1);
629 const ContentFeatures &f2 = ndef->get(m2);
631 // Contents don't differ for different forms of same liquid
632 if (f1.sameLiquid(f2))
635 u8 c1 = f1.solidness;
636 u8 c2 = f2.solidness;
642 c1 = f1.visual_solidness;
644 c2 = f2.visual_solidness;
648 // If same solidness, liquid takes precense
662 Gets nth node tile (0 <= n <= 5).
664 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
666 INodeDefManager *ndef = data->m_client->ndef();
667 const ContentFeatures &f = ndef->get(mn);
668 tile = f.tiles[tileindex];
669 bool has_crack = p == data->m_crack_pos_relative;
670 for (TileLayer &layer : tile.layers) {
671 if (layer.texture_id == 0)
673 if (!layer.has_color)
674 mn.getColor(f, &(layer.color));
675 // Apply temporary crack
677 layer.material_flags |= MATERIAL_FLAG_CRACK;
682 Gets node tile given a face direction.
684 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
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 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
742 tile.rotation = dir_to_tile[tile_index + 1];
745 static void getTileInfo(
749 const v3s16 &face_dir,
753 v3s16 &face_dir_corrected,
758 VoxelManipulator &vmanip = data->m_vmanip;
759 INodeDefManager *ndef = data->m_client->ndef();
760 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
762 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
764 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
765 if (n0.getContent() == CONTENT_IGNORE) {
770 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
772 if (n1.getContent() == CONTENT_IGNORE) {
778 bool equivalent = false;
779 u8 mf = face_contents(n0.getContent(), n1.getContent(),
793 face_dir_corrected = face_dir;
796 p_corrected = p + face_dir;
797 face_dir_corrected = -face_dir;
800 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
801 const ContentFeatures &f = ndef->get(n);
802 tile.emissive_light = f.light_source;
804 // eg. water and glass
806 for (TileLayer &layer : tile.layers)
807 layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
810 if (!data->m_smooth_lighting) {
811 lights[0] = lights[1] = lights[2] = lights[3] =
812 getFaceLight(n0, n1, face_dir, ndef);
814 v3s16 vertex_dirs[4];
815 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
817 v3s16 light_p = blockpos_nodes + p_corrected;
818 for (u16 i = 0; i < 4; i++)
819 lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
825 translate_dir: unit vector with only one of x, y or z
826 face_dir: unit vector with only one of x, y or z
828 static void updateFastFaceRow(
830 const v3s16 &&startpos,
832 const v3f &&translate_dir_f,
833 const v3s16 &&face_dir,
834 std::vector<FastFace> &dest)
838 u16 continuous_tiles_count = 1;
840 bool makes_face = false;
842 v3s16 face_dir_corrected;
843 u16 lights[4] = {0, 0, 0, 0};
845 getTileInfo(data, p, face_dir,
846 makes_face, p_corrected, face_dir_corrected,
849 // Unroll this variable which has a significant build cost
851 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
852 // If tiling can be done, this is set to false in the next step
853 bool next_is_different = true;
857 bool next_makes_face = false;
858 v3s16 next_p_corrected;
859 v3s16 next_face_dir_corrected;
860 u16 next_lights[4] = {0, 0, 0, 0};
862 // If at last position, there is nothing to compare to and
863 // the face must be drawn anyway
864 if (j != MAP_BLOCKSIZE - 1) {
865 p_next = p + translate_dir;
867 getTileInfo(data, p_next, face_dir,
868 next_makes_face, next_p_corrected,
869 next_face_dir_corrected, next_lights,
872 if (next_makes_face == makes_face
873 && next_p_corrected == p_corrected + translate_dir
874 && next_face_dir_corrected == face_dir_corrected
875 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
876 && next_tile.isTileable(tile)) {
877 next_is_different = false;
878 continuous_tiles_count++;
881 if (next_is_different) {
883 Create a face if there should be one
886 // Floating point conversion of the position vector
887 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
888 // Center point of face (kind of)
889 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
893 if (translate_dir.X != 0)
894 scale.X = continuous_tiles_count;
895 if (translate_dir.Y != 0)
896 scale.Y = continuous_tiles_count;
897 if (translate_dir.Z != 0)
898 scale.Z = continuous_tiles_count;
900 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
901 sp, face_dir_corrected, scale, dest);
903 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
904 for (int i = 1; i < continuous_tiles_count; i++)
905 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
908 continuous_tiles_count = 1;
911 makes_face = next_makes_face;
912 p_corrected = next_p_corrected;
913 face_dir_corrected = next_face_dir_corrected;
914 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
915 if (next_is_different)
921 static void updateAllFastFaceRows(MeshMakeData *data,
922 std::vector<FastFace> &dest)
925 Go through every y,z and get top(y+) faces in rows of x+
927 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
928 for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
929 updateFastFaceRow(data,
931 v3s16(1, 0, 0), //dir
933 v3s16(0, 1, 0), //face dir
937 Go through every x,y and get right(x+) faces in rows of z+
939 for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
940 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
941 updateFastFaceRow(data,
943 v3s16(0, 0, 1), //dir
945 v3s16(1, 0, 0), //face dir
949 Go through every y,z and get back(z+) faces in rows of x+
951 for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
952 for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
953 updateFastFaceRow(data,
955 v3s16(1, 0, 0), //dir
957 v3s16(0, 0, 1), //face dir
965 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
966 m_minimap_mapblock(NULL),
967 m_tsrc(data->m_client->getTextureSource()),
968 m_shdrsrc(data->m_client->getShaderSource()),
969 m_animation_force_timer(0), // force initial animation
971 m_last_daynight_ratio((u32) -1)
973 for (auto &m : m_mesh)
974 m = new scene::SMesh();
975 m_enable_shaders = data->m_use_shaders;
976 m_use_tangent_vertices = data->m_use_tangent_vertices;
977 m_enable_vbo = g_settings->getBool("enable_vbo");
979 if (g_settings->getBool("enable_minimap")) {
980 m_minimap_mapblock = new MinimapMapblock;
981 m_minimap_mapblock->getMinimapNodes(
982 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
985 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
986 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
987 //TimeTaker timer1("MapBlockMesh()");
989 std::vector<FastFace> fastfaces_new;
990 fastfaces_new.reserve(512);
993 We are including the faces of the trailing edges of the block.
994 This means that when something changes, the caller must
995 also update the meshes of the blocks at the leading edges.
997 NOTE: This is the slowest part of this method.
1000 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1001 //TimeTaker timer2("updateAllFastFaceRows()");
1002 updateAllFastFaceRows(data, fastfaces_new);
1007 Convert FastFaces to MeshCollector
1010 MeshCollector collector(m_use_tangent_vertices);
1013 // avg 0ms (100ms spikes when loading textures the first time)
1014 // (NOTE: probably outdated)
1015 //TimeTaker timer2("MeshCollector building");
1017 for (const FastFace &f : fastfaces_new) {
1018 static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1019 static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1021 if (!f.layer.texture)
1024 const u16 *indices_p =
1025 f.vertex_0_2_connected ? indices : indices_alternate;
1027 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1033 Add special graphics:
1041 MapblockMeshGenerator generator(data, &collector);
1042 generator.generate();
1045 collector.applyTileColors();
1048 Convert MeshCollector to SMesh
1051 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1052 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1054 PreMeshBuffer &p = collector.prebuffers[layer][i];
1056 // Generate animation data
1058 if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1059 // Find the texture name plus ^[crack:N:
1060 std::ostringstream os(std::ios::binary);
1061 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1062 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1063 os << "o"; // use ^[cracko
1064 os << ":" << (u32)p.layer.animation_frame_count << ":";
1065 m_crack_materials.insert(std::make_pair(
1066 std::pair<u8, u32>(layer, i), os.str()));
1067 // Replace tile texture with the cracked one
1068 p.layer.texture = m_tsrc->getTextureForMesh(
1070 &p.layer.texture_id);
1072 // - Texture animation
1073 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1074 // Add to MapBlockMesh in order to animate these tiles
1075 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1076 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1077 if (g_settings->getBool(
1078 "desynchronize_mapblock_texture_animation")) {
1079 // Get starting position from noise
1080 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1081 100000 * (2.0 + noise3d(
1082 data->m_blockpos.X, data->m_blockpos.Y,
1083 data->m_blockpos.Z, 0));
1085 // Play all synchronized
1086 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1088 // Replace tile texture with the first animation frame
1089 p.layer.texture = (*p.layer.frames)[0].texture;
1092 if (!m_enable_shaders) {
1093 // Extract colors for day-night animation
1094 // Dummy sunlight to handle non-sunlit areas
1095 video::SColorf sunlight;
1096 get_sunlight_color(&sunlight, 0);
1097 u32 vertex_count = m_use_tangent_vertices ?
1098 p.tangent_vertices.size() : p.vertices.size();
1099 for (u32 j = 0; j < vertex_count; j++) {
1101 if (m_use_tangent_vertices) {
1102 vc = &p.tangent_vertices[j].Color;
1104 vc = &p.vertices[j].Color;
1106 video::SColor copy(*vc);
1107 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1108 final_color_blend(vc, copy, sunlight); // Finalize color
1109 else // Record color to animate
1110 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1112 // The sunlight ratio has been stored,
1113 // delete alpha (for the final rendering).
1119 video::SMaterial material;
1120 material.setFlag(video::EMF_LIGHTING, false);
1121 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1122 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1123 material.setFlag(video::EMF_FOG_ENABLE, true);
1124 material.setTexture(0, p.layer.texture);
1126 if (m_enable_shaders) {
1127 material.MaterialType = m_shdrsrc->getShaderInfo(
1128 p.layer.shader_id).material;
1129 p.layer.applyMaterialOptionsWithShaders(material);
1130 if (p.layer.normal_texture)
1131 material.setTexture(1, p.layer.normal_texture);
1132 material.setTexture(2, p.layer.flags_texture);
1134 p.layer.applyMaterialOptions(material);
1137 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1139 // Create meshbuffer, add to mesh
1140 if (m_use_tangent_vertices) {
1141 scene::SMeshBufferTangents *buf =
1142 new scene::SMeshBufferTangents();
1144 buf->Material = material;
1146 mesh->addMeshBuffer(buf);
1149 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1150 &p.indices[0], p.indices.size());
1152 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1154 buf->Material = material;
1156 mesh->addMeshBuffer(buf);
1159 buf->append(&p.vertices[0], p.vertices.size(),
1160 &p.indices[0], p.indices.size());
1165 Do some stuff to the mesh
1167 m_camera_offset = camera_offset;
1168 translateMesh(m_mesh[layer],
1169 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1171 if (m_use_tangent_vertices) {
1172 scene::IMeshManipulator* meshmanip =
1173 RenderingEngine::get_scene_manager()->getMeshManipulator();
1174 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1177 if (m_mesh[layer]) {
1179 // Usually 1-700 faces and 1-7 materials
1180 std::cout << "Updated MapBlock has " << fastfaces_new.size()
1181 << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1182 << " materials (meshbuffers)" << std::endl;
1185 // Use VBO for mesh (this just would set this for ever buffer)
1187 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1191 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1193 // Check if animation is required for this mesh
1195 !m_crack_materials.empty() ||
1196 !m_daynight_diffs.empty() ||
1197 !m_animation_tiles.empty();
1200 MapBlockMesh::~MapBlockMesh()
1202 for (scene::IMesh *m : m_mesh) {
1203 if (m_enable_vbo && m)
1204 for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1205 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1206 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1211 delete m_minimap_mapblock;
1214 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1217 if (!m_has_animation) {
1218 m_animation_force_timer = 100000;
1222 m_animation_force_timer = myrand_range(5, 100);
1225 if (crack != m_last_crack) {
1226 for (auto &crack_material : m_crack_materials) {
1227 scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1228 getMeshBuffer(crack_material.first.second);
1229 std::string basename = crack_material.second;
1231 // Create new texture name from original
1232 std::ostringstream os;
1233 os << basename << crack;
1234 u32 new_texture_id = 0;
1235 video::ITexture *new_texture =
1236 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1237 buf->getMaterial().setTexture(0, new_texture);
1239 // If the current material is also animated,
1240 // update animation info
1241 auto anim_iter = m_animation_tiles.find(crack_material.first);
1242 if (anim_iter != m_animation_tiles.end()) {
1243 TileLayer &tile = anim_iter->second;
1244 tile.texture = new_texture;
1245 tile.texture_id = new_texture_id;
1246 // force animation update
1247 m_animation_frames[crack_material.first] = -1;
1251 m_last_crack = crack;
1254 // Texture animation
1255 for (auto &animation_tile : m_animation_tiles) {
1256 const TileLayer &tile = animation_tile.second;
1257 // Figure out current frame
1258 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1259 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1260 + frameoffset) % tile.animation_frame_count;
1261 // If frame doesn't change, skip
1262 if (frame == m_animation_frames[animation_tile.first])
1265 m_animation_frames[animation_tile.first] = frame;
1267 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1268 getMeshBuffer(animation_tile.first.second);
1270 const FrameSpec &animation_frame = (*tile.frames)[frame];
1271 buf->getMaterial().setTexture(0, animation_frame.texture);
1272 if (m_enable_shaders) {
1273 if (animation_frame.normal_texture)
1274 buf->getMaterial().setTexture(1,
1275 animation_frame.normal_texture);
1276 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1280 // Day-night transition
1281 if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1282 // Force reload mesh to VBO
1284 for (scene::IMesh *m : m_mesh)
1286 video::SColorf day_color;
1287 get_sunlight_color(&day_color, daynight_ratio);
1289 for (auto &daynight_diff : m_daynight_diffs) {
1290 scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1291 getMeshBuffer(daynight_diff.first.second);
1292 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1293 for (const auto &j : daynight_diff.second)
1294 final_color_blend(&(vertices[j.first].Color), j.second,
1297 m_last_daynight_ratio = daynight_ratio;
1303 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1305 if (camera_offset != m_camera_offset) {
1306 for (scene::IMesh *layer : m_mesh) {
1307 translateMesh(layer,
1308 intToFloat(m_camera_offset - camera_offset, BS));
1312 m_camera_offset = camera_offset;
1320 void MeshCollector::append(const TileSpec &tile,
1321 const video::S3DVertex *vertices, u32 numVertices,
1322 const u16 *indices, u32 numIndices)
1324 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1325 const TileLayer *layer = &tile.layers[layernum];
1326 if (layer->texture_id == 0)
1328 append(*layer, vertices, numVertices, indices, numIndices, layernum);
1332 void MeshCollector::append(const TileLayer &layer,
1333 const video::S3DVertex *vertices, u32 numVertices,
1334 const u16 *indices, u32 numIndices, u8 layernum)
1336 if (numIndices > 65535) {
1337 dstream << "FIXME: MeshCollector::append() called with numIndices="
1338 << numIndices << " (limit 65535)" << std::endl;
1341 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1343 PreMeshBuffer *p = NULL;
1344 for (PreMeshBuffer &pp : *buffers) {
1345 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1354 buffers->push_back(pp);
1355 p = &(*buffers)[buffers->size() - 1];
1359 if (m_use_tangent_vertices) {
1360 vertex_count = p->tangent_vertices.size();
1361 for (u32 i = 0; i < numVertices; i++) {
1363 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1364 vertices[i].Color, vertices[i].TCoords);
1365 p->tangent_vertices.push_back(vert);
1368 vertex_count = p->vertices.size();
1369 for (u32 i = 0; i < numVertices; i++) {
1370 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1371 vertices[i].Color, vertices[i].TCoords);
1373 p->vertices.push_back(vert);
1377 for (u32 i = 0; i < numIndices; i++) {
1378 u32 j = indices[i] + vertex_count;
1379 p->indices.push_back(j);
1384 MeshCollector - for meshnodes and converted drawtypes.
1387 void MeshCollector::append(const TileSpec &tile,
1388 const video::S3DVertex *vertices, u32 numVertices,
1389 const u16 *indices, u32 numIndices,
1390 v3f pos, video::SColor c, u8 light_source)
1392 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1393 const TileLayer *layer = &tile.layers[layernum];
1394 if (layer->texture_id == 0)
1396 append(*layer, vertices, numVertices, indices, numIndices, pos,
1397 c, light_source, layernum);
1401 void MeshCollector::append(const TileLayer &layer,
1402 const video::S3DVertex *vertices, u32 numVertices,
1403 const u16 *indices, u32 numIndices,
1404 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1406 if (numIndices > 65535) {
1407 dstream << "FIXME: MeshCollector::append() called with numIndices="
1408 << numIndices << " (limit 65535)" << std::endl;
1411 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1413 PreMeshBuffer *p = NULL;
1414 for (PreMeshBuffer &pp : *buffers) {
1415 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1424 buffers->push_back(pp);
1425 p = &(*buffers)[buffers->size() - 1];
1428 video::SColor original_c = c;
1430 if (m_use_tangent_vertices) {
1431 vertex_count = p->tangent_vertices.size();
1432 for (u32 i = 0; i < numVertices; i++) {
1433 if (!light_source) {
1435 applyFacesShading(c, vertices[i].Normal);
1437 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1438 vertices[i].Normal, c, vertices[i].TCoords);
1439 p->tangent_vertices.push_back(vert);
1442 vertex_count = p->vertices.size();
1443 for (u32 i = 0; i < numVertices; i++) {
1444 if (!light_source) {
1446 applyFacesShading(c, vertices[i].Normal);
1448 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1449 vertices[i].TCoords);
1450 p->vertices.push_back(vert);
1454 for (u32 i = 0; i < numIndices; i++) {
1455 u32 j = indices[i] + vertex_count;
1456 p->indices.push_back(j);
1460 void MeshCollector::applyTileColors()
1462 if (m_use_tangent_vertices)
1463 for (auto &prebuffer : prebuffers) {
1464 for (PreMeshBuffer &pmb : prebuffer) {
1465 video::SColor tc = pmb.layer.color;
1466 if (tc == video::SColor(0xFFFFFFFF))
1468 for (video::S3DVertexTangents &tangent_vertex : pmb.tangent_vertices) {
1469 video::SColor *c = &tangent_vertex.Color;
1470 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1471 c->getGreen() * tc.getGreen() / 255,
1472 c->getBlue() * tc.getBlue() / 255);
1477 for (auto &prebuffer : prebuffers) {
1478 for (PreMeshBuffer &pmb : prebuffer) {
1479 video::SColor tc = pmb.layer.color;
1480 if (tc == video::SColor(0xFFFFFFFF))
1482 for (video::S3DVertex &vertex : pmb.vertices) {
1483 video::SColor *c = &vertex.Color;
1484 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1485 c->getGreen() * tc.getGreen() / 255,
1486 c->getBlue() * tc.getBlue() / 255);
1492 video::SColor encode_light(u16 light, u8 emissive_light)
1495 u32 day = (light & 0xff);
1496 u32 night = (light >> 8);
1497 // Add emissive light
1498 night += emissive_light * 2.5f;
1501 // Since we don't know if the day light is sunlight or
1502 // artificial light, assume it is artificial when the night
1503 // light bank is also lit.
1508 u32 sum = day + night;
1509 // Ratio of sunlight:
1512 r = day * 255 / sum;
1516 float b = (day + night) / 2;
1517 return video::SColor(r, b, b, b);