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"
26 #include "content_mapblock.h"
27 #include "util/directiontables.h"
28 #include "client/renderingengine.h"
34 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
35 bool use_tangent_vertices):
37 m_use_shaders(use_shaders),
38 m_use_tangent_vertices(use_tangent_vertices)
41 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
43 m_blockpos = blockpos;
45 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
48 VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
49 blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
50 m_vmanip.addArea(voxel_area);
53 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
55 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
56 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
58 v3s16 bp = m_blockpos + block_offset;
59 v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
60 m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
63 void MeshMakeData::fill(MapBlock *block)
65 fillBlockDataBegin(block->getPos());
67 fillBlockData(v3s16(0,0,0), block->getData());
69 // Get map for reading neigbhor blocks
70 Map *map = block->getParent();
72 for (u16 i=0; i<26; i++) {
73 const v3s16 &dir = g_26dirs[i];
74 v3s16 bp = m_blockpos + dir;
75 MapBlock *b = map->getBlockNoCreateNoEx(bp);
77 fillBlockData(dir, b->getData());
81 void MeshMakeData::fillSingleNode(MapNode *node)
83 m_blockpos = v3s16(0,0,0);
85 v3s16 blockpos_nodes = v3s16(0,0,0);
86 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
87 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
88 s32 volume = area.getVolume();
89 s32 our_node_index = area.index(1,1,1);
91 // Allocate this block + neighbors
93 m_vmanip.addArea(area);
96 MapNode *data = new MapNode[volume];
97 for(s32 i = 0; i < volume; i++)
99 if(i == our_node_index)
105 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
108 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
112 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
115 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
118 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
120 m_smooth_lighting = smooth_lighting;
124 Light and vertex color functions
128 Calculate non-smooth lighting at interior of node.
131 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
132 INodeDefManager *ndef)
134 u8 light = n.getLight(bank, ndef);
138 light = undiminish_light(light);
143 light = diminish_light(light);
147 return decode_light(light);
151 Calculate non-smooth lighting at interior of node.
154 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
156 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
157 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
158 return day | (night << 8);
162 Calculate non-smooth lighting at face of node.
165 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
166 v3s16 face_dir, INodeDefManager *ndef)
169 u8 l1 = n.getLight(bank, ndef);
170 u8 l2 = n2.getLight(bank, ndef);
176 // Boost light level for light sources
177 u8 light_source = MYMAX(ndef->get(n).light_source,
178 ndef->get(n2).light_source);
179 if(light_source > light)
180 light = light_source;
182 return decode_light(light);
186 Calculate non-smooth lighting at face of node.
189 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
191 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
192 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
193 return day | (night << 8);
197 Calculate smooth lighting at the XYZ- corner of p.
200 static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
202 static const v3s16 dirs8[8] = {
213 INodeDefManager *ndef = data->m_client->ndef();
215 u16 ambient_occlusion = 0;
217 u8 light_source_max = 0;
221 for (u32 i = 0; i < 8; i++)
223 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dirs8[i]);
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 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(u16 i=0; i<4; i++)
564 vertex_pos[i].X *= scale.X;
565 vertex_pos[i].Y *= scale.Y;
566 vertex_pos[i].Z *= scale.Z;
567 vertex_pos[i] += pos;
571 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
572 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
573 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
575 v3f normal(dir.X, dir.Y, dir.Z);
577 u16 li[4] = { li0, li1, li2, li3 };
581 for (u8 i = 0; i < 4; i++) {
583 night[i] = li[i] & 0xFF;
586 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
587 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
590 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
591 core::vector2d<f32>(x0, y0 + h),
592 core::vector2d<f32>(x0, y0),
593 core::vector2d<f32>(x0 + w * abs_scale, y0) };
595 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
596 const TileLayer *layer = &tile.layers[layernum];
597 if (layer->texture_id == 0)
600 // equivalent to dest.push_back(FastFace()) but faster
602 FastFace& face = *dest.rbegin();
604 for (u8 i = 0; i < 4; i++) {
605 video::SColor c = encode_light(li[i], tile.emissive_light);
606 if (!tile.emissive_light)
607 applyFacesShading(c, normal);
609 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
613 Revert triangles for nicer looking gradient if the
614 brightness of vertices 1 and 3 differ less than
615 the brightness of vertices 0 and 2.
617 face.vertex_0_2_connected = vertex_0_2_connected;
620 face.layernum = layernum;
625 Nodes make a face if contents differ and solidness differs.
628 1: Face uses m1's content
629 2: Face uses m2's content
630 equivalent: Whether the blocks share the same face (eg. water and glass)
632 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
634 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
635 INodeDefManager *ndef)
639 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
642 bool contents_differ = (m1 != m2);
644 const ContentFeatures &f1 = ndef->get(m1);
645 const ContentFeatures &f2 = ndef->get(m2);
647 // Contents don't differ for different forms of same liquid
648 if(f1.sameLiquid(f2))
649 contents_differ = false;
651 u8 c1 = f1.solidness;
652 u8 c2 = f2.solidness;
654 bool solidness_differs = (c1 != c2);
655 bool makes_face = contents_differ && solidness_differs;
657 if(makes_face == false)
661 c1 = f1.visual_solidness;
663 c2 = f2.visual_solidness;
667 // If same solidness, liquid takes precense
681 Gets nth node tile (0 <= n <= 5).
683 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
685 INodeDefManager *ndef = data->m_client->ndef();
686 const ContentFeatures &f = ndef->get(mn);
687 tile = f.tiles[tileindex];
688 TileLayer *top_layer = NULL;
689 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
690 TileLayer *layer = &tile.layers[layernum];
691 if (layer->texture_id == 0)
694 if (!layer->has_color)
695 mn.getColor(f, &(layer->color));
697 // Apply temporary crack
698 if (p == data->m_crack_pos_relative)
699 top_layer->material_flags |= MATERIAL_FLAG_CRACK;
703 Gets node tile given a face direction.
705 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
707 INodeDefManager *ndef = data->m_client->ndef();
709 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
710 // (0,0,1), (0,0,-1) or (0,0,0)
711 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
713 // Convert direction to single integer for table lookup
718 // 4 = invalid, treat as (0,0,0)
722 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
724 // Get rotation for things like chests
725 u8 facedir = mn.getFaceDir(ndef);
727 static const u16 dir_to_tile[24 * 16] =
729 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
730 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
731 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
732 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
733 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
735 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
736 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
737 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
738 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
740 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
741 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
742 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
743 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
745 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
746 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
747 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
748 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
750 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
751 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
752 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
753 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
755 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
756 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
757 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
758 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
761 u16 tile_index=facedir*16 + dir_i;
762 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
763 tile.rotation = dir_to_tile[tile_index + 1];
766 static void getTileInfo(
770 const v3s16 &face_dir,
774 v3s16 &face_dir_corrected,
779 VoxelManipulator &vmanip = data->m_vmanip;
780 INodeDefManager *ndef = data->m_client->ndef();
781 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
783 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
785 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
786 if (n0.getContent() == CONTENT_IGNORE) {
791 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
793 if (n1.getContent() == CONTENT_IGNORE) {
799 bool equivalent = false;
800 u8 mf = face_contents(n0.getContent(), n1.getContent(),
814 face_dir_corrected = face_dir;
817 p_corrected = p + face_dir;
818 face_dir_corrected = -face_dir;
821 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
822 const ContentFeatures &f = ndef->get(n);
823 tile.emissive_light = f.light_source;
825 // eg. water and glass
827 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++)
828 tile.layers[layernum].material_flags |=
829 MATERIAL_FLAG_BACKFACE_CULLING;
832 if (!data->m_smooth_lighting) {
833 lights[0] = lights[1] = lights[2] = lights[3] =
834 getFaceLight(n0, n1, face_dir, ndef);
837 v3s16 vertex_dirs[4];
838 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
840 v3s16 light_p = blockpos_nodes + p_corrected;
841 for (u16 i = 0; i < 4; i++) {
842 lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
849 translate_dir: unit vector with only one of x, y or z
850 face_dir: unit vector with only one of x, y or z
852 static void updateFastFaceRow(
854 const v3s16 &&startpos,
856 const v3f &&translate_dir_f,
857 const v3s16 &&face_dir,
858 std::vector<FastFace> &dest)
862 u16 continuous_tiles_count = 1;
864 bool makes_face = false;
866 v3s16 face_dir_corrected;
867 u16 lights[4] = {0,0,0,0};
869 getTileInfo(data, p, face_dir,
870 makes_face, p_corrected, face_dir_corrected,
873 // Unroll this variable which has a significant build cost
875 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
876 // If tiling can be done, this is set to false in the next step
877 bool next_is_different = true;
881 bool next_makes_face = false;
882 v3s16 next_p_corrected;
883 v3s16 next_face_dir_corrected;
884 u16 next_lights[4] = {0,0,0,0};
887 // If at last position, there is nothing to compare to and
888 // the face must be drawn anyway
889 if (j != MAP_BLOCKSIZE - 1) {
890 p_next = p + translate_dir;
892 getTileInfo(data, p_next, face_dir,
893 next_makes_face, next_p_corrected,
894 next_face_dir_corrected, next_lights,
897 if (next_makes_face == makes_face
898 && next_p_corrected == p_corrected + translate_dir
899 && next_face_dir_corrected == face_dir_corrected
900 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
901 && next_tile.isTileable(tile)) {
902 next_is_different = false;
903 continuous_tiles_count++;
907 if (next_is_different) {
909 Create a face if there should be one
912 // Floating point conversion of the position vector
913 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
914 // Center point of face (kind of)
916 ((f32)continuous_tiles_count / 2.0f - 0.5f) * translate_dir_f;
919 if(translate_dir.X != 0) {
920 scale.X = continuous_tiles_count;
922 if(translate_dir.Y != 0) {
923 scale.Y = continuous_tiles_count;
925 if(translate_dir.Z != 0) {
926 scale.Z = continuous_tiles_count;
929 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
930 sp, face_dir_corrected, scale, dest);
932 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
933 for(int i = 1; i < continuous_tiles_count; i++){
934 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
938 continuous_tiles_count = 1;
941 makes_face = next_makes_face;
942 p_corrected = next_p_corrected;
943 face_dir_corrected = next_face_dir_corrected;
944 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
945 if (next_is_different)
951 static void updateAllFastFaceRows(MeshMakeData *data,
952 std::vector<FastFace> &dest)
955 Go through every y,z and get top(y+) faces in rows of x+
957 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
958 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
959 updateFastFaceRow(data,
963 v3s16(0,1,0), //face dir
969 Go through every x,y and get right(x+) faces in rows of z+
971 for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
972 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
973 updateFastFaceRow(data,
977 v3s16(1,0,0), //face dir
983 Go through every y,z and get back(z+) faces in rows of x+
985 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
986 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
987 updateFastFaceRow(data,
991 v3s16(0,0,1), //face dir
1001 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1002 m_minimap_mapblock(NULL),
1003 m_tsrc(data->m_client->getTextureSource()),
1004 m_shdrsrc(data->m_client->getShaderSource()),
1005 m_animation_force_timer(0), // force initial animation
1007 m_last_daynight_ratio((u32) -1)
1009 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1010 m_mesh[m] = new scene::SMesh();
1011 m_enable_shaders = data->m_use_shaders;
1012 m_use_tangent_vertices = data->m_use_tangent_vertices;
1013 m_enable_vbo = g_settings->getBool("enable_vbo");
1015 if (g_settings->getBool("enable_minimap")) {
1016 m_minimap_mapblock = new MinimapMapblock;
1017 m_minimap_mapblock->getMinimapNodes(
1018 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1021 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1022 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1023 //TimeTaker timer1("MapBlockMesh()");
1025 std::vector<FastFace> fastfaces_new;
1026 fastfaces_new.reserve(512);
1029 We are including the faces of the trailing edges of the block.
1030 This means that when something changes, the caller must
1031 also update the meshes of the blocks at the leading edges.
1033 NOTE: This is the slowest part of this method.
1036 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1037 //TimeTaker timer2("updateAllFastFaceRows()");
1038 updateAllFastFaceRows(data, fastfaces_new);
1043 Convert FastFaces to MeshCollector
1046 MeshCollector collector(m_use_tangent_vertices);
1049 // avg 0ms (100ms spikes when loading textures the first time)
1050 // (NOTE: probably outdated)
1051 //TimeTaker timer2("MeshCollector building");
1053 for (u32 i = 0; i < fastfaces_new.size(); i++) {
1054 FastFace &f = fastfaces_new[i];
1056 const u16 indices[] = {0,1,2,2,3,0};
1057 const u16 indices_alternate[] = {0,1,3,2,3,1};
1059 if (!f.layer.texture)
1062 const u16 *indices_p =
1063 f.vertex_0_2_connected ? indices : indices_alternate;
1065 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1071 Add special graphics:
1079 MapblockMeshGenerator generator(data, &collector);
1080 generator.generate();
1083 collector.applyTileColors();
1086 Convert MeshCollector to SMesh
1089 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1090 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1092 PreMeshBuffer &p = collector.prebuffers[layer][i];
1094 // Generate animation data
1096 if(p.layer.material_flags & MATERIAL_FLAG_CRACK)
1098 // Find the texture name plus ^[crack:N:
1099 std::ostringstream os(std::ios::binary);
1100 os<<m_tsrc->getTextureName(p.layer.texture_id)<<"^[crack";
1101 if(p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1102 os<<"o"; // use ^[cracko
1103 os<<":"<<(u32)p.layer.animation_frame_count<<":";
1104 m_crack_materials.insert(std::make_pair(std::pair<u8, u32>(layer, i), os.str()));
1105 // Replace tile texture with the cracked one
1106 p.layer.texture = m_tsrc->getTextureForMesh(
1108 &p.layer.texture_id);
1110 // - Texture animation
1111 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1112 // Add to MapBlockMesh in order to animate these tiles
1113 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1114 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1115 if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1116 // Get starting position from noise
1117 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 100000 * (2.0 + noise3d(
1118 data->m_blockpos.X, data->m_blockpos.Y,
1119 data->m_blockpos.Z, 0));
1121 // Play all synchronized
1122 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1124 // Replace tile texture with the first animation frame
1125 p.layer.texture = (*p.layer.frames)[0].texture;
1128 if (!m_enable_shaders) {
1129 // Extract colors for day-night animation
1130 // Dummy sunlight to handle non-sunlit areas
1131 video::SColorf sunlight;
1132 get_sunlight_color(&sunlight, 0);
1134 m_use_tangent_vertices ?
1135 p.tangent_vertices.size() : p.vertices.size();
1136 for (u32 j = 0; j < vertex_count; j++) {
1138 if (m_use_tangent_vertices) {
1139 vc = &p.tangent_vertices[j].Color;
1141 vc = &p.vertices[j].Color;
1143 video::SColor copy(*vc);
1144 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1145 final_color_blend(vc, copy, sunlight); // Finalize color
1146 else // Record color to animate
1147 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1149 // The sunlight ratio has been stored,
1150 // delete alpha (for the final rendering).
1156 video::SMaterial material;
1157 material.setFlag(video::EMF_LIGHTING, false);
1158 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1159 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1160 material.setFlag(video::EMF_FOG_ENABLE, true);
1161 material.setTexture(0, p.layer.texture);
1163 if (m_enable_shaders) {
1164 material.MaterialType = m_shdrsrc->getShaderInfo(p.layer.shader_id).material;
1165 p.layer.applyMaterialOptionsWithShaders(material);
1166 if (p.layer.normal_texture) {
1167 material.setTexture(1, p.layer.normal_texture);
1169 material.setTexture(2, p.layer.flags_texture);
1171 p.layer.applyMaterialOptions(material);
1174 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1176 // Create meshbuffer, add to mesh
1177 if (m_use_tangent_vertices) {
1178 scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1180 buf->Material = material;
1182 mesh->addMeshBuffer(buf);
1185 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1186 &p.indices[0], p.indices.size());
1188 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1190 buf->Material = material;
1192 mesh->addMeshBuffer(buf);
1195 buf->append(&p.vertices[0], p.vertices.size(),
1196 &p.indices[0], p.indices.size());
1202 Do some stuff to the mesh
1204 m_camera_offset = camera_offset;
1205 translateMesh(m_mesh[layer],
1206 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1208 if (m_use_tangent_vertices) {
1209 scene::IMeshManipulator* meshmanip =
1210 RenderingEngine::get_scene_manager()->getMeshManipulator();
1211 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1217 // Usually 1-700 faces and 1-7 materials
1218 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1219 <<"and uses "<<m_mesh[layer]->getMeshBufferCount()
1220 <<" materials (meshbuffers)"<<std::endl;
1223 // Use VBO for mesh (this just would set this for ever buffer)
1225 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1230 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1232 // Check if animation is required for this mesh
1234 !m_crack_materials.empty() ||
1235 !m_daynight_diffs.empty() ||
1236 !m_animation_tiles.empty();
1239 MapBlockMesh::~MapBlockMesh()
1241 for (int m = 0; m < MAX_TILE_LAYERS; m++) {
1242 if (m_enable_vbo && m_mesh[m])
1243 for (u32 i = 0; i < m_mesh[m]->getMeshBufferCount(); i++) {
1244 scene::IMeshBuffer *buf = m_mesh[m]->getMeshBuffer(i);
1245 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1250 delete m_minimap_mapblock;
1253 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1255 if(!m_has_animation)
1257 m_animation_force_timer = 100000;
1261 m_animation_force_timer = myrand_range(5, 100);
1264 if(crack != m_last_crack)
1266 for (std::map<std::pair<u8, u32>, std::string>::iterator i =
1267 m_crack_materials.begin(); i != m_crack_materials.end(); ++i) {
1268 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1269 getMeshBuffer(i->first.second);
1270 std::string basename = i->second;
1272 // Create new texture name from original
1273 std::ostringstream os;
1274 os<<basename<<crack;
1275 u32 new_texture_id = 0;
1276 video::ITexture *new_texture =
1277 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1278 buf->getMaterial().setTexture(0, new_texture);
1280 // If the current material is also animated,
1281 // update animation info
1282 std::map<std::pair<u8, u32>, TileLayer>::iterator anim_iter =
1283 m_animation_tiles.find(i->first);
1284 if (anim_iter != m_animation_tiles.end()){
1285 TileLayer &tile = anim_iter->second;
1286 tile.texture = new_texture;
1287 tile.texture_id = new_texture_id;
1288 // force animation update
1289 m_animation_frames[i->first] = -1;
1293 m_last_crack = crack;
1296 // Texture animation
1297 for (std::map<std::pair<u8, u32>, TileLayer>::iterator i =
1298 m_animation_tiles.begin(); i != m_animation_tiles.end(); ++i) {
1299 const TileLayer &tile = i->second;
1300 // Figure out current frame
1301 int frameoffset = m_animation_frame_offsets[i->first];
1302 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1303 + frameoffset) % tile.animation_frame_count;
1304 // If frame doesn't change, skip
1305 if(frame == m_animation_frames[i->first])
1308 m_animation_frames[i->first] = frame;
1310 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1311 getMeshBuffer(i->first.second);
1313 const FrameSpec &animation_frame = (*tile.frames)[frame];
1314 buf->getMaterial().setTexture(0, animation_frame.texture);
1315 if (m_enable_shaders) {
1316 if (animation_frame.normal_texture) {
1317 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1319 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1323 // Day-night transition
1324 if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1326 // Force reload mesh to VBO
1328 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1329 m_mesh[m]->setDirty();
1330 video::SColorf day_color;
1331 get_sunlight_color(&day_color, daynight_ratio);
1332 for(std::map<std::pair<u8, u32>, std::map<u32, video::SColor > >::iterator
1333 i = m_daynight_diffs.begin();
1334 i != m_daynight_diffs.end(); ++i)
1336 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1337 getMeshBuffer(i->first.second);
1338 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1339 for(std::map<u32, video::SColor >::iterator
1340 j = i->second.begin();
1341 j != i->second.end(); ++j)
1343 final_color_blend(&(vertices[j->first].Color),
1344 j->second, day_color);
1347 m_last_daynight_ratio = daynight_ratio;
1353 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1355 if (camera_offset != m_camera_offset) {
1356 for (u8 layer = 0; layer < 2; layer++) {
1357 translateMesh(m_mesh[layer],
1358 intToFloat(m_camera_offset - camera_offset, BS));
1360 m_mesh[layer]->setDirty();
1363 m_camera_offset = camera_offset;
1371 void MeshCollector::append(const TileSpec &tile,
1372 const video::S3DVertex *vertices, u32 numVertices,
1373 const u16 *indices, u32 numIndices)
1375 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1376 const TileLayer *layer = &tile.layers[layernum];
1377 if (layer->texture_id == 0)
1379 append(*layer, vertices, numVertices, indices, numIndices,
1384 void MeshCollector::append(const TileLayer &layer,
1385 const video::S3DVertex *vertices, u32 numVertices,
1386 const u16 *indices, u32 numIndices, u8 layernum)
1388 if (numIndices > 65535) {
1389 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1392 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1394 PreMeshBuffer *p = NULL;
1395 for (u32 i = 0; i < buffers->size(); i++) {
1396 PreMeshBuffer &pp = (*buffers)[i];
1397 if (pp.layer != layer)
1399 if (pp.indices.size() + numIndices > 65535)
1409 buffers->push_back(pp);
1410 p = &(*buffers)[buffers->size() - 1];
1414 if (m_use_tangent_vertices) {
1415 vertex_count = p->tangent_vertices.size();
1416 for (u32 i = 0; i < numVertices; i++) {
1417 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1418 vertices[i].Color, vertices[i].TCoords);
1419 p->tangent_vertices.push_back(vert);
1422 vertex_count = p->vertices.size();
1423 for (u32 i = 0; i < numVertices; i++) {
1424 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1425 vertices[i].Color, vertices[i].TCoords);
1426 p->vertices.push_back(vert);
1430 for (u32 i = 0; i < numIndices; i++) {
1431 u32 j = indices[i] + vertex_count;
1432 p->indices.push_back(j);
1437 MeshCollector - for meshnodes and converted drawtypes.
1440 void MeshCollector::append(const TileSpec &tile,
1441 const video::S3DVertex *vertices, u32 numVertices,
1442 const u16 *indices, u32 numIndices,
1443 v3f pos, video::SColor c, u8 light_source)
1445 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1446 const TileLayer *layer = &tile.layers[layernum];
1447 if (layer->texture_id == 0)
1449 append(*layer, vertices, numVertices, indices, numIndices, pos,
1450 c, light_source, layernum);
1454 void MeshCollector::append(const TileLayer &layer,
1455 const video::S3DVertex *vertices, u32 numVertices,
1456 const u16 *indices, u32 numIndices,
1457 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1459 if (numIndices > 65535) {
1460 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1463 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1465 PreMeshBuffer *p = NULL;
1466 for (u32 i = 0; i < buffers->size(); i++) {
1467 PreMeshBuffer &pp = (*buffers)[i];
1468 if(pp.layer != layer)
1470 if(pp.indices.size() + numIndices > 65535)
1480 buffers->push_back(pp);
1481 p = &(*buffers)[buffers->size() - 1];
1484 video::SColor original_c = c;
1486 if (m_use_tangent_vertices) {
1487 vertex_count = p->tangent_vertices.size();
1488 for (u32 i = 0; i < numVertices; i++) {
1489 if (!light_source) {
1491 applyFacesShading(c, vertices[i].Normal);
1493 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1494 vertices[i].Normal, c, vertices[i].TCoords);
1495 p->tangent_vertices.push_back(vert);
1498 vertex_count = p->vertices.size();
1499 for (u32 i = 0; i < numVertices; i++) {
1500 if (!light_source) {
1502 applyFacesShading(c, vertices[i].Normal);
1504 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1505 vertices[i].TCoords);
1506 p->vertices.push_back(vert);
1510 for (u32 i = 0; i < numIndices; i++) {
1511 u32 j = indices[i] + vertex_count;
1512 p->indices.push_back(j);
1516 void MeshCollector::applyTileColors()
1518 if (m_use_tangent_vertices)
1519 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1520 for (auto &pmb : prebuffers[layer]) {
1521 video::SColor tc = pmb.layer.color;
1522 if (tc == video::SColor(0xFFFFFFFF))
1524 for (auto &tangent_vertice : pmb.tangent_vertices) {
1525 video::SColor *c = &tangent_vertice.Color;
1526 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1527 c->getGreen() * tc.getGreen() / 255,
1528 c->getBlue() * tc.getBlue() / 255);
1533 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1534 for (auto &pmb : prebuffers[layer]) {
1535 video::SColor tc = pmb.layer.color;
1536 if (tc == video::SColor(0xFFFFFFFF))
1538 for (auto &vertice : pmb.vertices) {
1539 video::SColor *c = &vertice.Color;
1540 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1541 c->getGreen() * tc.getGreen() / 255,
1542 c->getBlue() * tc.getBlue() / 255);
1548 video::SColor encode_light(u16 light, u8 emissive_light)
1551 u32 day = (light & 0xff);
1552 u32 night = (light >> 8);
1553 // Add emissive light
1554 night += emissive_light * 2.5f;
1557 // Since we don't know if the day light is sunlight or
1558 // artificial light, assume it is artificial when the night
1559 // light bank is also lit.
1564 u32 sum = day + night;
1565 // Ratio of sunlight:
1568 r = day * 255 / sum;
1572 float b = (day + night) / 2;
1573 return video::SColor(r, b, b, b);