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"
32 #include "util/directiontables.h"
33 #include "client/renderingengine.h"
39 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
40 bool use_tangent_vertices):
42 m_use_shaders(use_shaders),
43 m_use_tangent_vertices(use_tangent_vertices)
46 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
48 m_blockpos = blockpos;
50 v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
53 VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
54 blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
55 m_vmanip.addArea(voxel_area);
58 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
60 v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
61 VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
63 v3s16 bp = m_blockpos + block_offset;
64 v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
65 m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
68 void MeshMakeData::fill(MapBlock *block)
70 fillBlockDataBegin(block->getPos());
72 fillBlockData(v3s16(0,0,0), block->getData());
74 // Get map for reading neigbhor blocks
75 Map *map = block->getParent();
77 for (u16 i=0; i<26; i++) {
78 const v3s16 &dir = g_26dirs[i];
79 v3s16 bp = m_blockpos + dir;
80 MapBlock *b = map->getBlockNoCreateNoEx(bp);
82 fillBlockData(dir, b->getData());
86 void MeshMakeData::fillSingleNode(MapNode *node)
88 m_blockpos = v3s16(0,0,0);
90 v3s16 blockpos_nodes = v3s16(0,0,0);
91 VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
92 blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
93 s32 volume = area.getVolume();
94 s32 our_node_index = area.index(1,1,1);
96 // Allocate this block + neighbors
98 m_vmanip.addArea(area);
101 MapNode *data = new MapNode[volume];
102 for(s32 i = 0; i < volume; i++)
104 if(i == our_node_index)
110 data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
113 m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
117 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
120 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
123 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
125 m_smooth_lighting = smooth_lighting;
129 Light and vertex color functions
133 Calculate non-smooth lighting at interior of node.
136 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
137 INodeDefManager *ndef)
139 u8 light = n.getLight(bank, ndef);
143 light = undiminish_light(light);
148 light = diminish_light(light);
152 return decode_light(light);
156 Calculate non-smooth lighting at interior of node.
159 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
161 u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
162 u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
163 return day | (night << 8);
167 Calculate non-smooth lighting at face of node.
170 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
171 v3s16 face_dir, INodeDefManager *ndef)
174 u8 l1 = n.getLight(bank, ndef);
175 u8 l2 = n2.getLight(bank, ndef);
181 // Boost light level for light sources
182 u8 light_source = MYMAX(ndef->get(n).light_source,
183 ndef->get(n2).light_source);
184 if(light_source > light)
185 light = light_source;
187 return decode_light(light);
191 Calculate non-smooth lighting at face of node.
194 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
196 u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
197 u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
198 return day | (night << 8);
202 Calculate smooth lighting at the XYZ- corner of p.
205 static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
207 static const v3s16 dirs8[8] = {
218 INodeDefManager *ndef = data->m_client->ndef();
220 u16 ambient_occlusion = 0;
222 u8 light_source_max = 0;
226 for (u32 i = 0; i < 8; i++)
228 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dirs8[i]);
230 // if it's CONTENT_IGNORE we can't do any light calculations
231 if (n.getContent() == CONTENT_IGNORE) {
235 const ContentFeatures &f = ndef->get(n);
236 if (f.light_source > light_source_max)
237 light_source_max = f.light_source;
238 // Check f.solidness because fast-style leaves look better this way
239 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
240 light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
241 light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
251 light_day /= light_count;
252 light_night /= light_count;
254 // Boost brightness around light sources
255 bool skip_ambient_occlusion_day = false;
256 if(decode_light(light_source_max) >= light_day) {
257 light_day = decode_light(light_source_max);
258 skip_ambient_occlusion_day = true;
261 bool skip_ambient_occlusion_night = false;
262 if(decode_light(light_source_max) >= light_night) {
263 light_night = decode_light(light_source_max);
264 skip_ambient_occlusion_night = true;
267 if (ambient_occlusion > 4)
269 static thread_local const float ao_gamma = rangelim(
270 g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
272 // Table of gamma space multiply factors.
273 static const float light_amount[3] = {
274 powf(0.75, 1.0 / ao_gamma),
275 powf(0.5, 1.0 / ao_gamma),
276 powf(0.25, 1.0 / ao_gamma)
279 //calculate table index for gamma space multiplier
280 ambient_occlusion -= 5;
282 if (!skip_ambient_occlusion_day)
283 light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
284 if (!skip_ambient_occlusion_night)
285 light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
288 return light_day | (light_night << 8);
292 Calculate smooth lighting at the given corner of p.
295 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
297 if(corner.X == 1) p.X += 1;
298 // else corner.X == -1
299 if(corner.Y == 1) p.Y += 1;
300 // else corner.Y == -1
301 if(corner.Z == 1) p.Z += 1;
302 // else corner.Z == -1
304 return getSmoothLightCombined(p, data);
307 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
308 f32 rg = daynight_ratio / 1000.0f - 0.04f;
309 f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
315 void final_color_blend(video::SColor *result,
316 u16 light, u32 daynight_ratio)
318 video::SColorf dayLight;
319 get_sunlight_color(&dayLight, daynight_ratio);
320 final_color_blend(result,
321 encode_light(light, 0), dayLight);
324 void final_color_blend(video::SColor *result,
325 const video::SColor &data, const video::SColorf &dayLight)
327 static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
329 video::SColorf c(data);
332 f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
333 f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
334 f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
336 // Emphase blue a bit in darker places
337 // Each entry of this array represents a range of 8 blue levels
338 static const u8 emphase_blue_when_dark[32] = {
339 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
340 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
343 b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
344 0, 255) / 8] / 255.0f;
346 result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
347 result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
348 result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
352 Mesh generation helpers
356 vertex_dirs: v3s16[4]
358 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
361 If looked from outside the node towards the face, the corners are:
367 if(dir == v3s16(0,0,1))
369 // If looking towards z+, this is the face that is behind
370 // the center point, facing towards z+.
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);
376 else if(dir == v3s16(0,0,-1))
379 vertex_dirs[0] = v3s16( 1,-1,-1);
380 vertex_dirs[1] = v3s16(-1,-1,-1);
381 vertex_dirs[2] = v3s16(-1, 1,-1);
382 vertex_dirs[3] = v3s16( 1, 1,-1);
384 else if(dir == v3s16(1,0,0))
387 vertex_dirs[0] = v3s16( 1,-1, 1);
388 vertex_dirs[1] = v3s16( 1,-1,-1);
389 vertex_dirs[2] = v3s16( 1, 1,-1);
390 vertex_dirs[3] = v3s16( 1, 1, 1);
392 else if(dir == v3s16(-1,0,0))
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);
400 else if(dir == v3s16(0,1,0))
402 // faces towards Y+ (assume Z- as "down" in texture)
403 vertex_dirs[0] = v3s16( 1, 1,-1);
404 vertex_dirs[1] = v3s16(-1, 1,-1);
405 vertex_dirs[2] = v3s16(-1, 1, 1);
406 vertex_dirs[3] = v3s16( 1, 1, 1);
408 else if(dir == v3s16(0,-1,0))
410 // faces towards Y- (assume Z+ as "down" in texture)
411 vertex_dirs[0] = v3s16( 1,-1, 1);
412 vertex_dirs[1] = v3s16(-1,-1, 1);
413 vertex_dirs[2] = v3s16(-1,-1,-1);
414 vertex_dirs[3] = v3s16( 1,-1,-1);
421 video::S3DVertex vertices[4]; // Precalculated vertices
423 * The face is divided into two triangles. If this is true,
424 * vertices 0 and 2 are connected, othervise vertices 1 and 3
427 bool vertex_0_2_connected;
431 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
432 v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
434 // Position is at the center of the cube.
443 v3s16 vertex_dirs[4];
444 getNodeVertexDirs(dir, vertex_dirs);
448 switch (tile.rotation)
454 vertex_dirs[0] = vertex_dirs[3];
455 vertex_dirs[3] = vertex_dirs[2];
456 vertex_dirs[2] = vertex_dirs[1];
466 vertex_dirs[0] = vertex_dirs[2];
469 vertex_dirs[1] = vertex_dirs[3];
480 vertex_dirs[0] = vertex_dirs[1];
481 vertex_dirs[1] = vertex_dirs[2];
482 vertex_dirs[2] = vertex_dirs[3];
492 vertex_dirs[0] = vertex_dirs[3];
493 vertex_dirs[3] = vertex_dirs[2];
494 vertex_dirs[2] = vertex_dirs[1];
506 vertex_dirs[0] = vertex_dirs[1];
507 vertex_dirs[1] = vertex_dirs[2];
508 vertex_dirs[2] = vertex_dirs[3];
520 vertex_dirs[0] = vertex_dirs[3];
521 vertex_dirs[3] = vertex_dirs[2];
522 vertex_dirs[2] = vertex_dirs[1];
534 vertex_dirs[0] = vertex_dirs[1];
535 vertex_dirs[1] = vertex_dirs[2];
536 vertex_dirs[2] = vertex_dirs[3];
558 for(u16 i=0; i<4; i++)
561 BS/2*vertex_dirs[i].X,
562 BS/2*vertex_dirs[i].Y,
563 BS/2*vertex_dirs[i].Z
567 for(u16 i=0; i<4; i++)
569 vertex_pos[i].X *= scale.X;
570 vertex_pos[i].Y *= scale.Y;
571 vertex_pos[i].Z *= scale.Z;
572 vertex_pos[i] += pos;
576 if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
577 else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
578 else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
580 v3f normal(dir.X, dir.Y, dir.Z);
582 u16 li[4] = { li0, li1, li2, li3 };
586 for (u8 i = 0; i < 4; i++) {
588 night[i] = li[i] & 0xFF;
591 bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
592 < abs(day[1] - day[3]) + abs(night[1] - night[3]);
595 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
596 core::vector2d<f32>(x0, y0 + h),
597 core::vector2d<f32>(x0, y0),
598 core::vector2d<f32>(x0 + w * abs_scale, y0) };
600 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
601 const TileLayer *layer = &tile.layers[layernum];
602 if (layer->texture_id == 0)
605 dest.push_back(FastFace());
606 FastFace& face = *dest.rbegin();
608 for (u8 i = 0; i < 4; i++) {
609 video::SColor c = encode_light(li[i], tile.emissive_light);
610 if (!tile.emissive_light)
611 applyFacesShading(c, normal);
613 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
617 Revert triangles for nicer looking gradient if the
618 brightness of vertices 1 and 3 differ less than
619 the brightness of vertices 0 and 2.
621 face.vertex_0_2_connected = vertex_0_2_connected;
624 face.layernum = layernum;
629 Nodes make a face if contents differ and solidness differs.
632 1: Face uses m1's content
633 2: Face uses m2's content
634 equivalent: Whether the blocks share the same face (eg. water and glass)
636 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
638 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
639 INodeDefManager *ndef)
643 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
646 bool contents_differ = (m1 != m2);
648 const ContentFeatures &f1 = ndef->get(m1);
649 const ContentFeatures &f2 = ndef->get(m2);
651 // Contents don't differ for different forms of same liquid
652 if(f1.sameLiquid(f2))
653 contents_differ = false;
655 u8 c1 = f1.solidness;
656 u8 c2 = f2.solidness;
658 bool solidness_differs = (c1 != c2);
659 bool makes_face = contents_differ && solidness_differs;
661 if(makes_face == false)
665 c1 = f1.visual_solidness;
667 c2 = f2.visual_solidness;
671 // If same solidness, liquid takes precense
685 Gets nth node tile (0 <= n <= 5).
687 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
689 INodeDefManager *ndef = data->m_client->ndef();
690 const ContentFeatures &f = ndef->get(mn);
691 tile = f.tiles[tileindex];
692 TileLayer *top_layer = NULL;
693 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
694 TileLayer *layer = &tile.layers[layernum];
695 if (layer->texture_id == 0)
698 if (!layer->has_color)
699 mn.getColor(f, &(layer->color));
701 // Apply temporary crack
702 if (p == data->m_crack_pos_relative)
703 top_layer->material_flags |= MATERIAL_FLAG_CRACK;
707 Gets node tile given a face direction.
709 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
711 INodeDefManager *ndef = data->m_client->ndef();
713 // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
714 // (0,0,1), (0,0,-1) or (0,0,0)
715 assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
717 // Convert direction to single integer for table lookup
722 // 4 = invalid, treat as (0,0,0)
726 u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
728 // Get rotation for things like chests
729 u8 facedir = mn.getFaceDir(ndef);
731 static const u16 dir_to_tile[24 * 16] =
733 // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
734 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
735 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
736 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
737 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
739 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
740 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
741 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
742 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
744 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
745 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
746 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
747 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
749 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
750 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
751 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
752 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
754 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
755 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
756 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
757 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
759 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
760 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
761 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
762 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
765 u16 tile_index=facedir*16 + dir_i;
766 getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
767 tile.rotation = dir_to_tile[tile_index + 1];
770 static void getTileInfo(
774 const v3s16 &face_dir,
778 v3s16 &face_dir_corrected,
783 VoxelManipulator &vmanip = data->m_vmanip;
784 INodeDefManager *ndef = data->m_client->ndef();
785 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
787 const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
789 // Don't even try to get n1 if n0 is already CONTENT_IGNORE
790 if (n0.getContent() == CONTENT_IGNORE) {
795 const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
797 if (n1.getContent() == CONTENT_IGNORE) {
803 bool equivalent = false;
804 u8 mf = face_contents(n0.getContent(), n1.getContent(),
818 face_dir_corrected = face_dir;
821 p_corrected = p + face_dir;
822 face_dir_corrected = -face_dir;
825 getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
826 const ContentFeatures &f = ndef->get(n);
827 tile.emissive_light = f.light_source;
829 // eg. water and glass
831 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++)
832 tile.layers[layernum].material_flags |=
833 MATERIAL_FLAG_BACKFACE_CULLING;
836 if (!data->m_smooth_lighting) {
837 lights[0] = lights[1] = lights[2] = lights[3] =
838 getFaceLight(n0, n1, face_dir, ndef);
841 v3s16 vertex_dirs[4];
842 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
844 v3s16 light_p = blockpos_nodes + p_corrected;
845 for (u16 i = 0; i < 4; i++) {
846 lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
853 translate_dir: unit vector with only one of x, y or z
854 face_dir: unit vector with only one of x, y or z
856 static void updateFastFaceRow(
863 std::vector<FastFace> &dest)
867 u16 continuous_tiles_count = 1;
869 bool makes_face = false;
871 v3s16 face_dir_corrected;
872 u16 lights[4] = {0,0,0,0};
874 getTileInfo(data, p, face_dir,
875 makes_face, p_corrected, face_dir_corrected,
878 // Unroll this variable which has a significant build cost
880 for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
881 // If tiling can be done, this is set to false in the next step
882 bool next_is_different = true;
886 bool next_makes_face = false;
887 v3s16 next_p_corrected;
888 v3s16 next_face_dir_corrected;
889 u16 next_lights[4] = {0,0,0,0};
892 // If at last position, there is nothing to compare to and
893 // the face must be drawn anyway
894 if (j != MAP_BLOCKSIZE - 1) {
895 p_next = p + translate_dir;
897 getTileInfo(data, p_next, face_dir,
898 next_makes_face, next_p_corrected,
899 next_face_dir_corrected, next_lights,
902 if (next_makes_face == makes_face
903 && next_p_corrected == p_corrected + translate_dir
904 && next_face_dir_corrected == face_dir_corrected
905 && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
906 && next_tile.isTileable(tile)) {
907 next_is_different = false;
908 continuous_tiles_count++;
912 if (next_is_different) {
914 Create a face if there should be one
917 // Floating point conversion of the position vector
918 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
919 // Center point of face (kind of)
921 ((f32)continuous_tiles_count / 2.0f - 0.5f) * translate_dir_f;
924 if(translate_dir.X != 0) {
925 scale.X = continuous_tiles_count;
927 if(translate_dir.Y != 0) {
928 scale.Y = continuous_tiles_count;
930 if(translate_dir.Z != 0) {
931 scale.Z = continuous_tiles_count;
934 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
935 sp, face_dir_corrected, scale, dest);
937 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
938 for(int i = 1; i < continuous_tiles_count; i++){
939 g_profiler->avg("Meshgen: faces drawn by tiling", 1);
943 continuous_tiles_count = 1;
946 makes_face = next_makes_face;
947 p_corrected = next_p_corrected;
948 face_dir_corrected = next_face_dir_corrected;
949 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
950 if (next_is_different)
956 static void updateAllFastFaceRows(MeshMakeData *data,
957 std::vector<FastFace> &dest)
960 Go through every y,z and get top(y+) faces in rows of x+
962 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
963 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
964 updateFastFaceRow(data,
968 v3s16(0,1,0), //face dir
975 Go through every x,y and get right(x+) faces in rows of z+
977 for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
978 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
979 updateFastFaceRow(data,
983 v3s16(1,0,0), //face dir
990 Go through every y,z and get back(z+) faces in rows of x+
992 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
993 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
994 updateFastFaceRow(data,
998 v3s16(0,0,1), //face dir
1009 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1010 m_minimap_mapblock(NULL),
1011 m_tsrc(data->m_client->getTextureSource()),
1012 m_shdrsrc(data->m_client->getShaderSource()),
1013 m_animation_force_timer(0), // force initial animation
1015 m_last_daynight_ratio((u32) -1)
1017 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1018 m_mesh[m] = new scene::SMesh();
1019 m_enable_shaders = data->m_use_shaders;
1020 m_use_tangent_vertices = data->m_use_tangent_vertices;
1021 m_enable_vbo = g_settings->getBool("enable_vbo");
1023 if (g_settings->getBool("enable_minimap")) {
1024 m_minimap_mapblock = new MinimapMapblock;
1025 m_minimap_mapblock->getMinimapNodes(
1026 &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1029 // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1030 // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1031 //TimeTaker timer1("MapBlockMesh()");
1033 std::vector<FastFace> fastfaces_new;
1034 fastfaces_new.reserve(512);
1037 We are including the faces of the trailing edges of the block.
1038 This means that when something changes, the caller must
1039 also update the meshes of the blocks at the leading edges.
1041 NOTE: This is the slowest part of this method.
1044 // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1045 //TimeTaker timer2("updateAllFastFaceRows()");
1046 updateAllFastFaceRows(data, fastfaces_new);
1051 Convert FastFaces to MeshCollector
1054 MeshCollector collector(m_use_tangent_vertices);
1057 // avg 0ms (100ms spikes when loading textures the first time)
1058 // (NOTE: probably outdated)
1059 //TimeTaker timer2("MeshCollector building");
1061 for (u32 i = 0; i < fastfaces_new.size(); i++) {
1062 FastFace &f = fastfaces_new[i];
1064 const u16 indices[] = {0,1,2,2,3,0};
1065 const u16 indices_alternate[] = {0,1,3,2,3,1};
1067 if (!f.layer.texture)
1070 const u16 *indices_p =
1071 f.vertex_0_2_connected ? indices : indices_alternate;
1073 collector.append(f.layer, f.vertices, 4, indices_p, 6,
1079 Add special graphics:
1087 MapblockMeshGenerator generator(data, &collector);
1088 generator.generate();
1091 collector.applyTileColors();
1094 Convert MeshCollector to SMesh
1097 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1098 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1100 PreMeshBuffer &p = collector.prebuffers[layer][i];
1102 // Generate animation data
1104 if(p.layer.material_flags & MATERIAL_FLAG_CRACK)
1106 // Find the texture name plus ^[crack:N:
1107 std::ostringstream os(std::ios::binary);
1108 os<<m_tsrc->getTextureName(p.layer.texture_id)<<"^[crack";
1109 if(p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1110 os<<"o"; // use ^[cracko
1111 os<<":"<<(u32)p.layer.animation_frame_count<<":";
1112 m_crack_materials.insert(std::make_pair(std::pair<u8, u32>(layer, i), os.str()));
1113 // Replace tile texture with the cracked one
1114 p.layer.texture = m_tsrc->getTextureForMesh(
1116 &p.layer.texture_id);
1118 // - Texture animation
1119 if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1120 // Add to MapBlockMesh in order to animate these tiles
1121 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1122 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1123 if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1124 // Get starting position from noise
1125 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 100000 * (2.0 + noise3d(
1126 data->m_blockpos.X, data->m_blockpos.Y,
1127 data->m_blockpos.Z, 0));
1129 // Play all synchronized
1130 m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1132 // Replace tile texture with the first animation frame
1133 p.layer.texture = p.layer.frames[0].texture;
1136 if (!m_enable_shaders) {
1137 // Extract colors for day-night animation
1138 // Dummy sunlight to handle non-sunlit areas
1139 video::SColorf sunlight;
1140 get_sunlight_color(&sunlight, 0);
1142 m_use_tangent_vertices ?
1143 p.tangent_vertices.size() : p.vertices.size();
1144 for (u32 j = 0; j < vertex_count; j++) {
1146 if (m_use_tangent_vertices) {
1147 vc = &p.tangent_vertices[j].Color;
1149 vc = &p.vertices[j].Color;
1151 video::SColor copy(*vc);
1152 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1153 final_color_blend(vc, copy, sunlight); // Finalize color
1154 else // Record color to animate
1155 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1157 // The sunlight ratio has been stored,
1158 // delete alpha (for the final rendering).
1164 video::SMaterial material;
1165 material.setFlag(video::EMF_LIGHTING, false);
1166 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1167 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1168 material.setFlag(video::EMF_FOG_ENABLE, true);
1169 material.setTexture(0, p.layer.texture);
1171 if (m_enable_shaders) {
1172 material.MaterialType = m_shdrsrc->getShaderInfo(p.layer.shader_id).material;
1173 p.layer.applyMaterialOptionsWithShaders(material);
1174 if (p.layer.normal_texture) {
1175 material.setTexture(1, p.layer.normal_texture);
1177 material.setTexture(2, p.layer.flags_texture);
1179 p.layer.applyMaterialOptions(material);
1182 scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1184 // Create meshbuffer, add to mesh
1185 if (m_use_tangent_vertices) {
1186 scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1188 buf->Material = material;
1190 mesh->addMeshBuffer(buf);
1193 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1194 &p.indices[0], p.indices.size());
1196 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1198 buf->Material = material;
1200 mesh->addMeshBuffer(buf);
1203 buf->append(&p.vertices[0], p.vertices.size(),
1204 &p.indices[0], p.indices.size());
1210 Do some stuff to the mesh
1212 m_camera_offset = camera_offset;
1213 translateMesh(m_mesh[layer],
1214 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1216 if (m_use_tangent_vertices) {
1217 scene::IMeshManipulator* meshmanip =
1218 RenderingEngine::get_scene_manager()->getMeshManipulator();
1219 meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1225 // Usually 1-700 faces and 1-7 materials
1226 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1227 <<"and uses "<<m_mesh[layer]->getMeshBufferCount()
1228 <<" materials (meshbuffers)"<<std::endl;
1231 // Use VBO for mesh (this just would set this for ever buffer)
1233 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1238 //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1240 // Check if animation is required for this mesh
1242 !m_crack_materials.empty() ||
1243 !m_daynight_diffs.empty() ||
1244 !m_animation_tiles.empty();
1247 MapBlockMesh::~MapBlockMesh()
1249 for (int m = 0; m < MAX_TILE_LAYERS; m++) {
1250 if (m_enable_vbo && m_mesh[m])
1251 for (u32 i = 0; i < m_mesh[m]->getMeshBufferCount(); i++) {
1252 scene::IMeshBuffer *buf = m_mesh[m]->getMeshBuffer(i);
1253 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1258 delete m_minimap_mapblock;
1261 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1263 if(!m_has_animation)
1265 m_animation_force_timer = 100000;
1269 m_animation_force_timer = myrand_range(5, 100);
1272 if(crack != m_last_crack)
1274 for (std::map<std::pair<u8, u32>, std::string>::iterator i =
1275 m_crack_materials.begin(); i != m_crack_materials.end(); ++i) {
1276 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1277 getMeshBuffer(i->first.second);
1278 std::string basename = i->second;
1280 // Create new texture name from original
1281 std::ostringstream os;
1282 os<<basename<<crack;
1283 u32 new_texture_id = 0;
1284 video::ITexture *new_texture =
1285 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1286 buf->getMaterial().setTexture(0, new_texture);
1288 // If the current material is also animated,
1289 // update animation info
1290 std::map<std::pair<u8, u32>, TileLayer>::iterator anim_iter =
1291 m_animation_tiles.find(i->first);
1292 if (anim_iter != m_animation_tiles.end()){
1293 TileLayer &tile = anim_iter->second;
1294 tile.texture = new_texture;
1295 tile.texture_id = new_texture_id;
1296 // force animation update
1297 m_animation_frames[i->first] = -1;
1301 m_last_crack = crack;
1304 // Texture animation
1305 for (std::map<std::pair<u8, u32>, TileLayer>::iterator i =
1306 m_animation_tiles.begin(); i != m_animation_tiles.end(); ++i) {
1307 const TileLayer &tile = i->second;
1308 // Figure out current frame
1309 int frameoffset = m_animation_frame_offsets[i->first];
1310 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1311 + frameoffset) % tile.animation_frame_count;
1312 // If frame doesn't change, skip
1313 if(frame == m_animation_frames[i->first])
1316 m_animation_frames[i->first] = frame;
1318 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1319 getMeshBuffer(i->first.second);
1321 const FrameSpec &animation_frame = tile.frames[frame];
1322 buf->getMaterial().setTexture(0, animation_frame.texture);
1323 if (m_enable_shaders) {
1324 if (animation_frame.normal_texture) {
1325 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1327 buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1331 // Day-night transition
1332 if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1334 // Force reload mesh to VBO
1336 for (int m = 0; m < MAX_TILE_LAYERS; m++)
1337 m_mesh[m]->setDirty();
1338 video::SColorf day_color;
1339 get_sunlight_color(&day_color, daynight_ratio);
1340 for(std::map<std::pair<u8, u32>, std::map<u32, video::SColor > >::iterator
1341 i = m_daynight_diffs.begin();
1342 i != m_daynight_diffs.end(); ++i)
1344 scene::IMeshBuffer *buf = m_mesh[i->first.first]->
1345 getMeshBuffer(i->first.second);
1346 video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1347 for(std::map<u32, video::SColor >::iterator
1348 j = i->second.begin();
1349 j != i->second.end(); ++j)
1351 final_color_blend(&(vertices[j->first].Color),
1352 j->second, day_color);
1355 m_last_daynight_ratio = daynight_ratio;
1361 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1363 if (camera_offset != m_camera_offset) {
1364 for (u8 layer = 0; layer < 2; layer++) {
1365 translateMesh(m_mesh[layer],
1366 intToFloat(m_camera_offset - camera_offset, BS));
1368 m_mesh[layer]->setDirty();
1371 m_camera_offset = camera_offset;
1379 void MeshCollector::append(const TileSpec &tile,
1380 const video::S3DVertex *vertices, u32 numVertices,
1381 const u16 *indices, u32 numIndices)
1383 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1384 const TileLayer *layer = &tile.layers[layernum];
1385 if (layer->texture_id == 0)
1387 append(*layer, vertices, numVertices, indices, numIndices,
1392 void MeshCollector::append(const TileLayer &layer,
1393 const video::S3DVertex *vertices, u32 numVertices,
1394 const u16 *indices, u32 numIndices, u8 layernum)
1396 if (numIndices > 65535) {
1397 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1400 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1402 PreMeshBuffer *p = NULL;
1403 for (u32 i = 0; i < buffers->size(); i++) {
1404 PreMeshBuffer &pp = (*buffers)[i];
1405 if (pp.layer != layer)
1407 if (pp.indices.size() + numIndices > 65535)
1417 buffers->push_back(pp);
1418 p = &(*buffers)[buffers->size() - 1];
1422 if (m_use_tangent_vertices) {
1423 vertex_count = p->tangent_vertices.size();
1424 for (u32 i = 0; i < numVertices; i++) {
1425 video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1426 vertices[i].Color, vertices[i].TCoords);
1427 p->tangent_vertices.push_back(vert);
1430 vertex_count = p->vertices.size();
1431 for (u32 i = 0; i < numVertices; i++) {
1432 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1433 vertices[i].Color, vertices[i].TCoords);
1434 p->vertices.push_back(vert);
1438 for (u32 i = 0; i < numIndices; i++) {
1439 u32 j = indices[i] + vertex_count;
1440 p->indices.push_back(j);
1445 MeshCollector - for meshnodes and converted drawtypes.
1448 void MeshCollector::append(const TileSpec &tile,
1449 const video::S3DVertex *vertices, u32 numVertices,
1450 const u16 *indices, u32 numIndices,
1451 v3f pos, video::SColor c, u8 light_source)
1453 for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1454 const TileLayer *layer = &tile.layers[layernum];
1455 if (layer->texture_id == 0)
1457 append(*layer, vertices, numVertices, indices, numIndices, pos,
1458 c, light_source, layernum);
1462 void MeshCollector::append(const TileLayer &layer,
1463 const video::S3DVertex *vertices, u32 numVertices,
1464 const u16 *indices, u32 numIndices,
1465 v3f pos, video::SColor c, u8 light_source, u8 layernum)
1467 if (numIndices > 65535) {
1468 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1471 std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1473 PreMeshBuffer *p = NULL;
1474 for (u32 i = 0; i < buffers->size(); i++) {
1475 PreMeshBuffer &pp = (*buffers)[i];
1476 if(pp.layer != layer)
1478 if(pp.indices.size() + numIndices > 65535)
1488 buffers->push_back(pp);
1489 p = &(*buffers)[buffers->size() - 1];
1492 video::SColor original_c = c;
1494 if (m_use_tangent_vertices) {
1495 vertex_count = p->tangent_vertices.size();
1496 for (u32 i = 0; i < numVertices; i++) {
1497 if (!light_source) {
1499 applyFacesShading(c, vertices[i].Normal);
1501 video::S3DVertexTangents vert(vertices[i].Pos + pos,
1502 vertices[i].Normal, c, vertices[i].TCoords);
1503 p->tangent_vertices.push_back(vert);
1506 vertex_count = p->vertices.size();
1507 for (u32 i = 0; i < numVertices; i++) {
1508 if (!light_source) {
1510 applyFacesShading(c, vertices[i].Normal);
1512 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1513 vertices[i].TCoords);
1514 p->vertices.push_back(vert);
1518 for (u32 i = 0; i < numIndices; i++) {
1519 u32 j = indices[i] + vertex_count;
1520 p->indices.push_back(j);
1524 void MeshCollector::applyTileColors()
1526 if (m_use_tangent_vertices)
1527 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1528 std::vector<PreMeshBuffer> *p = &prebuffers[layer];
1529 for (std::vector<PreMeshBuffer>::iterator it = p->begin();
1530 it != p->end(); ++it) {
1531 video::SColor tc = it->layer.color;
1532 if (tc == video::SColor(0xFFFFFFFF))
1534 for (u32 index = 0; index < it->tangent_vertices.size(); index++) {
1535 video::SColor *c = &it->tangent_vertices[index].Color;
1536 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1537 c->getGreen() * tc.getGreen() / 255,
1538 c->getBlue() * tc.getBlue() / 255);
1543 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1544 std::vector<PreMeshBuffer> *p = &prebuffers[layer];
1545 for (std::vector<PreMeshBuffer>::iterator it = p->begin();
1546 it != p->end(); ++it) {
1547 video::SColor tc = it->layer.color;
1548 if (tc == video::SColor(0xFFFFFFFF))
1550 for (u32 index = 0; index < it->vertices.size(); index++) {
1551 video::SColor *c = &it->vertices[index].Color;
1552 c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1553 c->getGreen() * tc.getGreen() / 255,
1554 c->getBlue() * tc.getBlue() / 255);
1560 video::SColor encode_light(u16 light, u8 emissive_light)
1563 u32 day = (light & 0xff);
1564 u32 night = (light >> 8);
1565 // Add emissive light
1566 night += emissive_light * 2.5f;
1569 // Since we don't know if the day light is sunlight or
1570 // artificial light, assume it is artificial when the night
1571 // light bank is also lit.
1576 u32 sum = day + night;
1577 // Ratio of sunlight:
1580 r = day * 255 / sum;
1584 float b = (day + night) / 2;
1585 return video::SColor(r, b, b, b);