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 (u16 i=0; i<26; i++) {
75 const v3s16 &dir = g_26dirs[i];
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)
107 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
110 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
114 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
117 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
120 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
122 m_smooth_lighting = smooth_lighting;
126 Light and vertex color functions
130 Calculate non-smooth lighting at interior of node.
133 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
134 INodeDefManager *ndef)
136 u8 light = n.getLight(bank, ndef);
140 light = undiminish_light(light);
145 light = diminish_light(light);
149 return decode_light(light);
153 Calculate non-smooth lighting at interior of node.
156 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
158 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
159 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
160 return day | (night << 8);
164 Calculate non-smooth lighting at face of node.
167 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
168 v3s16 face_dir, INodeDefManager *ndef)
171 u8 l1 = n.getLight(bank, ndef);
172 u8 l2 = n2.getLight(bank, ndef);
178 // Boost light level for light sources
179 u8 light_source = MYMAX(ndef->get(n).light_source,
180 ndef->get(n2).light_source);
181 if(light_source > light)
182 light = light_source;
184 return decode_light(light);
188 Calculate non-smooth lighting at face of node.
191 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
193 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
194 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
195 return day | (night << 8);
199 Calculate smooth lighting at the XYZ- corner of p.
202 static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
204 static const v3s16 dirs8[8] = {
215 INodeDefManager *ndef = data->m_client->ndef();
217 u16 ambient_occlusion = 0;
219 u8 light_source_max = 0;
223 for (u32 i = 0; i < 8; i++)
225 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dirs8[i]);
227 // if it's CONTENT_IGNORE we can't do any light calculations
228 if (n.getContent() == CONTENT_IGNORE) {
232 const ContentFeatures &f = ndef->get(n);
233 if (f.light_source > light_source_max)
234 light_source_max = f.light_source;
235 // Check f.solidness because fast-style leaves look better this way
236 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
237 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
238 light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
248 light_day /= light_count;
249 light_night /= light_count;
251 // Boost brightness around light sources
252 bool skip_ambient_occlusion_day = false;
253 if(decode_light(light_source_max) >= light_day) {
254 light_day = decode_light(light_source_max);
255 skip_ambient_occlusion_day = true;
258 bool skip_ambient_occlusion_night = false;
259 if(decode_light(light_source_max) >= light_night) {
260 light_night = decode_light(light_source_max);
261 skip_ambient_occlusion_night = true;
264 if (ambient_occlusion > 4)
266 static thread_local const float ao_gamma = rangelim(
267 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
269 // Table of gamma space multiply factors.
270 static const float light_amount[3] = {
271 powf(0.75, 1.0 / ao_gamma),
272 powf(0.5, 1.0 / ao_gamma),
273 powf(0.25, 1.0 / ao_gamma)
276 //calculate table index for gamma space multiplier
277 ambient_occlusion -= 5;
279 if (!skip_ambient_occlusion_day)
280 light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
281 if (!skip_ambient_occlusion_night)
282 light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
285 return light_day | (light_night << 8);
289 Calculate smooth lighting at the given corner of p.
292 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
294 if(corner.X == 1) p.X += 1;
295 // else corner.X == -1
296 if(corner.Y == 1) p.Y += 1;
297 // else corner.Y == -1
298 if(corner.Z == 1) p.Z += 1;
299 // else corner.Z == -1
301 return getSmoothLightCombined(p, data);
304 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
305 f32 rg = daynight_ratio / 1000.0f - 0.04f;
306 f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
312 void final_color_blend(video::SColor *result,
313 u16 light, u32 daynight_ratio)
315 video::SColorf dayLight;
316 get_sunlight_color(&dayLight, daynight_ratio);
317 final_color_blend(result,
318 encode_light(light, 0), dayLight);
321 void final_color_blend(video::SColor *result,
322 const video::SColor &data, const video::SColorf &dayLight)
324 static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
326 video::SColorf c(data);
329 f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
330 f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
331 f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
333 // Emphase blue a bit in darker places
334 // Each entry of this array represents a range of 8 blue levels
335 static const u8 emphase_blue_when_dark[32] = {
336 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
337 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
340 b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
341 0, 255) / 8] / 255.0f;
343 result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
344 result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
345 result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
349 Mesh generation helpers
353 vertex_dirs: v3s16[4]
355 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
358 If looked from outside the node towards the face, the corners are:
364 if(dir == v3s16(0,0,1))
366 // If looking towards z+, this is the face that is behind
367 // the center point, facing towards z+.
368 vertex_dirs[0] = v3s16(-1,-1, 1);
369 vertex_dirs[1] = v3s16( 1,-1, 1);
370 vertex_dirs[2] = v3s16( 1, 1, 1);
371 vertex_dirs[3] = v3s16(-1, 1, 1);
373 else if(dir == v3s16(0,0,-1))
376 vertex_dirs[0] = v3s16( 1,-1,-1);
377 vertex_dirs[1] = v3s16(-1,-1,-1);
378 vertex_dirs[2] = v3s16(-1, 1,-1);
379 vertex_dirs[3] = v3s16( 1, 1,-1);
381 else if(dir == v3s16(1,0,0))
384 vertex_dirs[0] = v3s16( 1,-1, 1);
385 vertex_dirs[1] = v3s16( 1,-1,-1);
386 vertex_dirs[2] = v3s16( 1, 1,-1);
387 vertex_dirs[3] = v3s16( 1, 1, 1);
389 else if(dir == v3s16(-1,0,0))
392 vertex_dirs[0] = v3s16(-1,-1,-1);
393 vertex_dirs[1] = v3s16(-1,-1, 1);
394 vertex_dirs[2] = v3s16(-1, 1, 1);
395 vertex_dirs[3] = v3s16(-1, 1,-1);
397 else if(dir == v3s16(0,1,0))
399 // faces towards Y+ (assume Z- as "down" in texture)
400 vertex_dirs[0] = v3s16( 1, 1,-1);
401 vertex_dirs[1] = v3s16(-1, 1,-1);
402 vertex_dirs[2] = v3s16(-1, 1, 1);
403 vertex_dirs[3] = v3s16( 1, 1, 1);
405 else if(dir == v3s16(0,-1,0))
407 // faces towards Y- (assume Z+ as "down" in texture)
408 vertex_dirs[0] = v3s16( 1,-1, 1);
409 vertex_dirs[1] = v3s16(-1,-1, 1);
410 vertex_dirs[2] = v3s16(-1,-1,-1);
411 vertex_dirs[3] = v3s16( 1,-1,-1);
418 video::S3DVertex vertices[4]; // Precalculated vertices
420 * The face is divided into two triangles. If this is true,
421 * vertices 0 and 2 are connected, othervise vertices 1 and 3
424 bool vertex_0_2_connected;
428 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
429 v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
431 // Position is at the center of the cube.
440 v3s16 vertex_dirs[4];
441 getNodeVertexDirs(dir, vertex_dirs);
445 switch (tile.rotation)
451 vertex_dirs[0] = vertex_dirs[3];
452 vertex_dirs[3] = vertex_dirs[2];
453 vertex_dirs[2] = vertex_dirs[1];
463 vertex_dirs[0] = vertex_dirs[2];
466 vertex_dirs[1] = vertex_dirs[3];
477 vertex_dirs[0] = vertex_dirs[1];
478 vertex_dirs[1] = vertex_dirs[2];
479 vertex_dirs[2] = vertex_dirs[3];
489 vertex_dirs[0] = vertex_dirs[3];
490 vertex_dirs[3] = vertex_dirs[2];
491 vertex_dirs[2] = vertex_dirs[1];
503 vertex_dirs[0] = vertex_dirs[1];
504 vertex_dirs[1] = vertex_dirs[2];
505 vertex_dirs[2] = vertex_dirs[3];
517 vertex_dirs[0] = vertex_dirs[3];
518 vertex_dirs[3] = vertex_dirs[2];
519 vertex_dirs[2] = vertex_dirs[1];
531 vertex_dirs[0] = vertex_dirs[1];
532 vertex_dirs[1] = vertex_dirs[2];
533 vertex_dirs[2] = vertex_dirs[3];
555 for(u16 i=0; i<4; i++)
558 BS/2*vertex_dirs[i].X,
559 BS/2*vertex_dirs[i].Y,
560 BS/2*vertex_dirs[i].Z
564 for(u16 i=0; i<4; i++)
566 vertex_pos[i].X *= scale.X;
567 vertex_pos[i].Y *= scale.Y;
568 vertex_pos[i].Z *= scale.Z;
569 vertex_pos[i] += pos;
573 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
574 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
575 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
577 v3f normal(dir.X, dir.Y, dir.Z);
579 u16 li[4] = { li0, li1, li2, li3 };
583 for (u8 i = 0; i < 4; i++) {
585 night[i] = li[i] & 0xFF;
588 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
589 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
592 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
593 core::vector2d<f32>(x0, y0 + h),
594 core::vector2d<f32>(x0, y0),
595 core::vector2d<f32>(x0 + w * abs_scale, y0) };
597 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
598 const TileLayer *layer = &tile.layers[layernum];
599 if (layer->texture_id == 0)
602 // equivalent to dest.push_back(FastFace()) but faster
604 FastFace& face = *dest.rbegin();
606 for (u8 i = 0; i < 4; i++) {
607 video::SColor c = encode_light(li[i], tile.emissive_light);
608 if (!tile.emissive_light)
609 applyFacesShading(c, normal);
611 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
615 Revert triangles for nicer looking gradient if the
616 brightness of vertices 1 and 3 differ less than
617 the brightness of vertices 0 and 2.
619 face.vertex_0_2_connected = vertex_0_2_connected;
622 face.layernum = layernum;
627 Nodes make a face if contents differ and solidness differs.
630 1: Face uses m1's content
631 2: Face uses m2's content
632 equivalent: Whether the blocks share the same face (eg. water and glass)
634 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
636 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
637 INodeDefManager *ndef)
641 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
644 bool contents_differ = (m1 != m2);
646 const ContentFeatures &f1 = ndef->get(m1);
647 const ContentFeatures &f2 = ndef->get(m2);
649 // Contents don't differ for different forms of same liquid
650 if(f1.sameLiquid(f2))
651 contents_differ = false;
653 u8 c1 = f1.solidness;
654 u8 c2 = f2.solidness;
656 bool solidness_differs = (c1 != c2);
657 bool makes_face = contents_differ && solidness_differs;
659 if(makes_face == false)
663 c1 = f1.visual_solidness;
665 c2 = f2.visual_solidness;
669 // If same solidness, liquid takes precense
683 Gets nth node tile (0 <= n <= 5).
685 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
687 INodeDefManager *ndef = data->m_client->ndef();
688 const ContentFeatures &f = ndef->get(mn);
689 tile = f.tiles[tileindex];
690 TileLayer *top_layer = NULL;
691 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
692 TileLayer *layer = &tile.layers[layernum];
693 if (layer->texture_id == 0)
696 if (!layer->has_color)
697 mn.getColor(f, &(layer->color));
699 // Apply temporary crack
700 if (p == data->m_crack_pos_relative)
701 top_layer->material_flags |= MATERIAL_FLAG_CRACK;
705 Gets node tile given a face direction.
707 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
709 INodeDefManager *ndef = data->m_client->ndef();
711 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
712 // (0,0,1), (0,0,-1) or (0,0,0)
713 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
715 // Convert direction to single integer for table lookup
720 // 4 = invalid, treat as (0,0,0)
724 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
726 // Get rotation for things like chests
727 u8 facedir = mn.getFaceDir(ndef);
729 static const u16 dir_to_tile[24 * 16] =
731 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
732 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
733 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
734 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
735 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
737 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
738 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
739 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
740 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
742 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
743 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
744 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
745 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
747 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
748 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
749 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
750 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
752 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
753 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
754 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
755 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
757 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
758 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
759 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
760 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
763 u16 tile_index=facedir*16 + dir_i;
764 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
765 tile.rotation = dir_to_tile[tile_index + 1];
768 static void getTileInfo(
772 const v3s16 &face_dir,
776 v3s16 &face_dir_corrected,
781 VoxelManipulator &vmanip = data->m_vmanip;
782 INodeDefManager *ndef = data->m_client->ndef();
783 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
785 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
787 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
788 if (n0.getContent() == CONTENT_IGNORE) {
793 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
795 if (n1.getContent() == CONTENT_IGNORE) {
801 bool equivalent = false;
802 u8 mf = face_contents(n0.getContent(), n1.getContent(),
816 face_dir_corrected = face_dir;
819 p_corrected = p + face_dir;
820 face_dir_corrected = -face_dir;
823 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
824 const ContentFeatures &f = ndef->get(n);
825 tile.emissive_light = f.light_source;
827 // eg. water and glass
829 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++)
830 tile.layers[layernum].material_flags |=
831 MATERIAL_FLAG_BACKFACE_CULLING;
834 if (!data->m_smooth_lighting) {
835 lights[0] = lights[1] = lights[2] = lights[3] =
836 getFaceLight(n0, n1, face_dir, ndef);
839 v3s16 vertex_dirs[4];
840 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
842 v3s16 light_p = blockpos_nodes + p_corrected;
843 for (u16 i = 0; i < 4; i++) {
844 lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
851 translate_dir: unit vector with only one of x, y or z
852 face_dir: unit vector with only one of x, y or z
854 static void updateFastFaceRow(
856 const v3s16 &&startpos,
858 const v3f &&translate_dir_f,
859 const v3s16 &&face_dir,
860 std::vector<FastFace> &dest)
864 u16 continuous_tiles_count = 1;
866 bool makes_face = false;
868 v3s16 face_dir_corrected;
869 u16 lights[4] = {0,0,0,0};
871 getTileInfo(data, p, face_dir,
872 makes_face, p_corrected, face_dir_corrected,
875 // Unroll this variable which has a significant build cost
877 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
878 // If tiling can be done, this is set to false in the next step
879 bool next_is_different = true;
883 bool next_makes_face = false;
884 v3s16 next_p_corrected;
885 v3s16 next_face_dir_corrected;
886 u16 next_lights[4] = {0,0,0,0};
889 // If at last position, there is nothing to compare to and
890 // the face must be drawn anyway
891 if (j != MAP_BLOCKSIZE - 1) {
892 p_next = p + translate_dir;
894 getTileInfo(data, p_next, face_dir,
895 next_makes_face, next_p_corrected,
896 next_face_dir_corrected, next_lights,
899 if (next_makes_face == makes_face
900 && next_p_corrected == p_corrected + translate_dir
901 && next_face_dir_corrected == face_dir_corrected
902 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
903 && next_tile.isTileable(tile)) {
904 next_is_different = false;
905 continuous_tiles_count++;
909 if (next_is_different) {
911 Create a face if there should be one
914 // Floating point conversion of the position vector
915 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
916 // Center point of face (kind of)
918 ((f32)continuous_tiles_count / 2.0f - 0.5f) * translate_dir_f;
921 if(translate_dir.X != 0) {
922 scale.X = continuous_tiles_count;
924 if(translate_dir.Y != 0) {
925 scale.Y = continuous_tiles_count;
927 if(translate_dir.Z != 0) {
928 scale.Z = continuous_tiles_count;
931 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
932 sp, face_dir_corrected, scale, dest);
934 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
935 for(int i = 1; i < continuous_tiles_count; i++){
936 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
940 continuous_tiles_count = 1;
943 makes_face = next_makes_face;
944 p_corrected = next_p_corrected;
945 face_dir_corrected = next_face_dir_corrected;
946 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
947 if (next_is_different)
953 static void updateAllFastFaceRows(MeshMakeData *data,
954 std::vector<FastFace> &dest)
957 Go through every y,z and get top(y+) faces in rows of x+
959 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
960 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
961 updateFastFaceRow(data,
965 v3s16(0,1,0), //face dir
971 Go through every x,y and get right(x+) faces in rows of z+
973 for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
974 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
975 updateFastFaceRow(data,
979 v3s16(1,0,0), //face dir
985 Go through every y,z and get back(z+) faces in rows of x+
987 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
988 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
989 updateFastFaceRow(data,
993 v3s16(0,0,1), //face dir
1003 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1004 m_minimap_mapblock(NULL),
1005 m_tsrc(data->m_client->getTextureSource()),
1006 m_shdrsrc(data->m_client->getShaderSource()),
1007 m_animation_force_timer(0), // force initial animation
1009 m_last_daynight_ratio((u32) -1)
1011 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1012 m_mesh[m] = new scene::SMesh();
1013 m_enable_shaders = data->m_use_shaders;
1014 m_use_tangent_vertices = data->m_use_tangent_vertices;
1015 m_enable_vbo = g_settings->getBool("enable_vbo");
1017 if (g_settings->getBool("enable_minimap")) {
1018 m_minimap_mapblock = new MinimapMapblock;
1019 m_minimap_mapblock->getMinimapNodes(
1020 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1023 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1024 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1025 //TimeTaker timer1("MapBlockMesh()");
1027 std::vector<FastFace> fastfaces_new;
1028 fastfaces_new.reserve(512);
1031 We are including the faces of the trailing edges of the block.
1032 This means that when something changes, the caller must
1033 also update the meshes of the blocks at the leading edges.
1035 NOTE: This is the slowest part of this method.
1038 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1039 //TimeTaker timer2("updateAllFastFaceRows()");
1040 updateAllFastFaceRows(data, fastfaces_new);
1045 Convert FastFaces to MeshCollector
1048 MeshCollector collector(m_use_tangent_vertices);
1051 // avg 0ms (100ms spikes when loading textures the first time)
1052 // (NOTE: probably outdated)
1053 //TimeTaker timer2("MeshCollector building");
1055 for (u32 i = 0; i < fastfaces_new.size(); i++) {
1056 FastFace &f = fastfaces_new[i];
1058 const u16 indices[] = {0,1,2,2,3,0};
1059 const u16 indices_alternate[] = {0,1,3,2,3,1};
1061 if (!f.layer.texture)
1064 const u16 *indices_p =
1065 f.vertex_0_2_connected ? indices : indices_alternate;
1067 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1073 Add special graphics:
1081 MapblockMeshGenerator generator(data, &collector);
1082 generator.generate();
1085 collector.applyTileColors();
1088 Convert MeshCollector to SMesh
1091 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1092 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1094 PreMeshBuffer &p = collector.prebuffers[layer][i];
1096 // Generate animation data
1098 if(p.layer.material_flags & MATERIAL_FLAG_CRACK)
1100 // Find the texture name plus ^[crack:N:
1101 std::ostringstream os(std::ios::binary);
1102 os<<m_tsrc->getTextureName(p.layer.texture_id)<<"^[crack";
1103 if(p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1104 os<<"o"; // use ^[cracko
1105 os<<":"<<(u32)p.layer.animation_frame_count<<":";
1106 m_crack_materials.insert(std::make_pair(std::pair<u8, u32>(layer, i), os.str()));
1107 // Replace tile texture with the cracked one
1108 p.layer.texture = m_tsrc->getTextureForMesh(
1110 &p.layer.texture_id);
1112 // - Texture animation
1113 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1114 // Add to MapBlockMesh in order to animate these tiles
1115 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1116 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1117 if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1118 // Get starting position from noise
1119 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 100000 * (2.0 + noise3d(
1120 data->m_blockpos.X, data->m_blockpos.Y,
1121 data->m_blockpos.Z, 0));
1123 // Play all synchronized
1124 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1126 // Replace tile texture with the first animation frame
1127 p.layer.texture = (*p.layer.frames)[0].texture;
1130 if (!m_enable_shaders) {
1131 // Extract colors for day-night animation
1132 // Dummy sunlight to handle non-sunlit areas
1133 video::SColorf sunlight;
1134 get_sunlight_color(&sunlight, 0);
1136 m_use_tangent_vertices ?
1137 p.tangent_vertices.size() : p.vertices.size();
1138 for (u32 j = 0; j < vertex_count; j++) {
1140 if (m_use_tangent_vertices) {
1141 vc = &p.tangent_vertices[j].Color;
1143 vc = &p.vertices[j].Color;
1145 video::SColor copy(*vc);
1146 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1147 final_color_blend(vc, copy, sunlight); // Finalize color
1148 else // Record color to animate
1149 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1151 // The sunlight ratio has been stored,
1152 // delete alpha (for the final rendering).
1158 video::SMaterial material;
1159 material.setFlag(video::EMF_LIGHTING, false);
1160 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1161 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1162 material.setFlag(video::EMF_FOG_ENABLE, true);
1163 material.setTexture(0, p.layer.texture);
1165 if (m_enable_shaders) {
1166 material.MaterialType = m_shdrsrc->getShaderInfo(p.layer.shader_id).material;
1167 p.layer.applyMaterialOptionsWithShaders(material);
1168 if (p.layer.normal_texture) {
1169 material.setTexture(1, p.layer.normal_texture);
1171 material.setTexture(2, p.layer.flags_texture);
1173 p.layer.applyMaterialOptions(material);
1176 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1178 // Create meshbuffer, add to mesh
1179 if (m_use_tangent_vertices) {
1180 scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1182 buf->Material = material;
1184 mesh->addMeshBuffer(buf);
1187 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1188 &p.indices[0], p.indices.size());
1190 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1192 buf->Material = material;
1194 mesh->addMeshBuffer(buf);
1197 buf->append(&p.vertices[0], p.vertices.size(),
1198 &p.indices[0], p.indices.size());
1204 Do some stuff to the mesh
1206 m_camera_offset = camera_offset;
1207 translateMesh(m_mesh[layer],
1208 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1210 if (m_use_tangent_vertices) {
1211 scene::IMeshManipulator* meshmanip =
1212 RenderingEngine::get_scene_manager()->getMeshManipulator();
1213 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1219 // Usually 1-700 faces and 1-7 materials
1220 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1221 <<"and uses "<<m_mesh[layer]->getMeshBufferCount()
1222 <<" materials (meshbuffers)"<<std::endl;
1225 // Use VBO for mesh (this just would set this for ever buffer)
1227 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1232 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1234 // Check if animation is required for this mesh
1236 !m_crack_materials.empty() ||
1237 !m_daynight_diffs.empty() ||
1238 !m_animation_tiles.empty();
1241 MapBlockMesh::~MapBlockMesh()
1243 for (int m = 0; m < MAX_TILE_LAYERS; m++) {
1244 if (m_enable_vbo && m_mesh[m])
1245 for (u32 i = 0; i < m_mesh[m]->getMeshBufferCount(); i++) {
1246 scene::IMeshBuffer *buf = m_mesh[m]->getMeshBuffer(i);
1247 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1252 delete m_minimap_mapblock;
1255 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1257 if(!m_has_animation)
1259 m_animation_force_timer = 100000;
1263 m_animation_force_timer = myrand_range(5, 100);
1266 if(crack != m_last_crack)
1268 for (std::map<std::pair<u8, u32>, std::string>::iterator i =
1269 m_crack_materials.begin(); i != m_crack_materials.end(); ++i) {
1270 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1271 getMeshBuffer(i->first.second);
1272 std::string basename = i->second;
1274 // Create new texture name from original
1275 std::ostringstream os;
1276 os<<basename<<crack;
1277 u32 new_texture_id = 0;
1278 video::ITexture *new_texture =
1279 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1280 buf->getMaterial().setTexture(0, new_texture);
1282 // If the current material is also animated,
1283 // update animation info
1284 std::map<std::pair<u8, u32>, TileLayer>::iterator anim_iter =
1285 m_animation_tiles.find(i->first);
1286 if (anim_iter != m_animation_tiles.end()){
1287 TileLayer &tile = anim_iter->second;
1288 tile.texture = new_texture;
1289 tile.texture_id = new_texture_id;
1290 // force animation update
1291 m_animation_frames[i->first] = -1;
1295 m_last_crack = crack;
1298 // Texture animation
1299 for (std::map<std::pair<u8, u32>, TileLayer>::iterator i =
1300 m_animation_tiles.begin(); i != m_animation_tiles.end(); ++i) {
1301 const TileLayer &tile = i->second;
1302 // Figure out current frame
1303 int frameoffset = m_animation_frame_offsets[i->first];
1304 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1305 + frameoffset) % tile.animation_frame_count;
1306 // If frame doesn't change, skip
1307 if(frame == m_animation_frames[i->first])
1310 m_animation_frames[i->first] = frame;
1312 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1313 getMeshBuffer(i->first.second);
1315 const FrameSpec &animation_frame = (*tile.frames)[frame];
1316 buf->getMaterial().setTexture(0, animation_frame.texture);
1317 if (m_enable_shaders) {
1318 if (animation_frame.normal_texture) {
1319 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1321 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1325 // Day-night transition
1326 if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1328 // Force reload mesh to VBO
1330 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1331 m_mesh[m]->setDirty();
1332 video::SColorf day_color;
1333 get_sunlight_color(&day_color, daynight_ratio);
1334 for(std::map<std::pair<u8, u32>, std::map<u32, video::SColor > >::iterator
1335 i = m_daynight_diffs.begin();
1336 i != m_daynight_diffs.end(); ++i)
1338 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1339 getMeshBuffer(i->first.second);
1340 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1341 for(std::map<u32, video::SColor >::iterator
1342 j = i->second.begin();
1343 j != i->second.end(); ++j)
1345 final_color_blend(&(vertices[j->first].Color),
1346 j->second, day_color);
1349 m_last_daynight_ratio = daynight_ratio;
1355 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1357 if (camera_offset != m_camera_offset) {
1358 for (u8 layer = 0; layer < 2; layer++) {
1359 translateMesh(m_mesh[layer],
1360 intToFloat(m_camera_offset - camera_offset, BS));
1362 m_mesh[layer]->setDirty();
1365 m_camera_offset = camera_offset;
1373 void MeshCollector::append(const TileSpec &tile,
1374 const video::S3DVertex *vertices, u32 numVertices,
1375 const u16 *indices, u32 numIndices)
1377 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1378 const TileLayer *layer = &tile.layers[layernum];
1379 if (layer->texture_id == 0)
1381 append(*layer, vertices, numVertices, indices, numIndices,
1386 void MeshCollector::append(const TileLayer &layer,
1387 const video::S3DVertex *vertices, u32 numVertices,
1388 const u16 *indices, u32 numIndices, u8 layernum)
1390 if (numIndices > 65535) {
1391 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1394 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1396 PreMeshBuffer *p = NULL;
1397 for (u32 i = 0; i < buffers->size(); i++) {
1398 PreMeshBuffer &pp = (*buffers)[i];
1399 if (pp.layer != layer)
1401 if (pp.indices.size() + numIndices > 65535)
1411 buffers->push_back(pp);
1412 p = &(*buffers)[buffers->size() - 1];
1416 if (m_use_tangent_vertices) {
1417 vertex_count = p->tangent_vertices.size();
1418 for (u32 i = 0; i < numVertices; i++) {
1419 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1420 vertices[i].Color, vertices[i].TCoords);
1421 p->tangent_vertices.push_back(vert);
1424 vertex_count = p->vertices.size();
1425 for (u32 i = 0; i < numVertices; i++) {
1426 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1427 vertices[i].Color, vertices[i].TCoords);
1428 p->vertices.push_back(vert);
1432 for (u32 i = 0; i < numIndices; i++) {
1433 u32 j = indices[i] + vertex_count;
1434 p->indices.push_back(j);
1439 MeshCollector - for meshnodes and converted drawtypes.
1442 void MeshCollector::append(const TileSpec &tile,
1443 const video::S3DVertex *vertices, u32 numVertices,
1444 const u16 *indices, u32 numIndices,
1445 v3f pos, video::SColor c, u8 light_source)
1447 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1448 const TileLayer *layer = &tile.layers[layernum];
1449 if (layer->texture_id == 0)
1451 append(*layer, vertices, numVertices, indices, numIndices, pos,
1452 c, light_source, layernum);
1456 void MeshCollector::append(const TileLayer &layer,
1457 const video::S3DVertex *vertices, u32 numVertices,
1458 const u16 *indices, u32 numIndices,
1459 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1461 if (numIndices > 65535) {
1462 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1465 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1467 PreMeshBuffer *p = NULL;
1468 for (u32 i = 0; i < buffers->size(); i++) {
1469 PreMeshBuffer &pp = (*buffers)[i];
1470 if(pp.layer != layer)
1472 if(pp.indices.size() + numIndices > 65535)
1482 buffers->push_back(pp);
1483 p = &(*buffers)[buffers->size() - 1];
1486 video::SColor original_c = c;
1488 if (m_use_tangent_vertices) {
1489 vertex_count = p->tangent_vertices.size();
1490 for (u32 i = 0; i < numVertices; i++) {
1491 if (!light_source) {
1493 applyFacesShading(c, vertices[i].Normal);
1495 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1496 vertices[i].Normal, c, vertices[i].TCoords);
1497 p->tangent_vertices.push_back(vert);
1500 vertex_count = p->vertices.size();
1501 for (u32 i = 0; i < numVertices; i++) {
1502 if (!light_source) {
1504 applyFacesShading(c, vertices[i].Normal);
1506 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1507 vertices[i].TCoords);
1508 p->vertices.push_back(vert);
1512 for (u32 i = 0; i < numIndices; i++) {
1513 u32 j = indices[i] + vertex_count;
1514 p->indices.push_back(j);
1518 void MeshCollector::applyTileColors()
1520 if (m_use_tangent_vertices)
1521 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1522 for (auto &pmb : prebuffers[layer]) {
1523 video::SColor tc = pmb.layer.color;
1524 if (tc == video::SColor(0xFFFFFFFF))
1526 for (auto &tangent_vertice : pmb.tangent_vertices) {
1527 video::SColor *c = &tangent_vertice.Color;
1528 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1529 c->getGreen() * tc.getGreen() / 255,
1530 c->getBlue() * tc.getBlue() / 255);
1535 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1536 for (auto &pmb : prebuffers[layer]) {
1537 video::SColor tc = pmb.layer.color;
1538 if (tc == video::SColor(0xFFFFFFFF))
1540 for (auto &vertice : pmb.vertices) {
1541 video::SColor *c = &vertice.Color;
1542 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1543 c->getGreen() * tc.getGreen() / 255,
1544 c->getBlue() * tc.getBlue() / 255);
1550 video::SColor encode_light(u16 light, u8 emissive_light)
1553 u32 day = (light & 0xff);
1554 u32 night = (light >> 8);
1555 // Add emissive light
1556 night += emissive_light * 2.5f;
1559 // Since we don't know if the day light is sunlight or
1560 // artificial light, assume it is artificial when the night
1561 // light bank is also lit.
1566 u32 sum = day + night;
1567 // Ratio of sunlight:
1570 r = day * 255 / sum;
1574 float b = (day + night) / 2;
1575 return video::SColor(r, b, b, b);