Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
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.
9 :
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.
14 :
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.
18 : */
19 :
20 : #include "mapblock_mesh.h"
21 : #include "light.h"
22 : #include "mapblock.h"
23 : #include "map.h"
24 : #include "profiler.h"
25 : #include "nodedef.h"
26 : #include "gamedef.h"
27 : #include "mesh.h"
28 : #include "minimap.h"
29 : #include "content_mapblock.h"
30 : #include "noise.h"
31 : #include "shader.h"
32 : #include "settings.h"
33 : #include "util/directiontables.h"
34 : #include <IMeshManipulator.h>
35 :
36 4987909 : static void applyFacesShading(video::SColor& color, float factor)
37 : {
38 4987909 : color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
39 4987909 : color.setGreen(core::clamp(core::round32(color.getGreen()*factor), 0, 255));
40 4987909 : }
41 :
42 : /*
43 : MeshMakeData
44 : */
45 :
46 3549 : MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders):
47 : m_vmanip(),
48 : m_blockpos(-1337,-1337,-1337),
49 : m_crack_pos_relative(-1337, -1337, -1337),
50 : m_highlighted_pos_relative(-1337, -1337, -1337),
51 : m_smooth_lighting(false),
52 : m_show_hud(false),
53 : m_highlight_mesh_color(255, 255, 255, 255),
54 : m_gamedef(gamedef),
55 3549 : m_use_shaders(use_shaders)
56 3549 : {}
57 :
58 3548 : void MeshMakeData::fill(MapBlock *block)
59 : {
60 3548 : m_blockpos = block->getPos();
61 :
62 3548 : v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
63 :
64 : /*
65 : Copy data
66 : */
67 :
68 : // Allocate this block + neighbors
69 3548 : m_vmanip.clear();
70 7096 : VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
71 10644 : blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
72 3548 : m_vmanip.addArea(voxel_area);
73 :
74 : {
75 : //TimeTaker timer("copy central block data");
76 : // 0ms
77 :
78 : // Copy our data
79 3548 : block->copyTo(m_vmanip);
80 : }
81 : {
82 : //TimeTaker timer("copy neighbor block data");
83 : // 0ms
84 :
85 : /*
86 : Copy neighbors. This is lightning fast.
87 : Copying only the borders would be *very* slow.
88 : */
89 :
90 : // Get map
91 3548 : Map *map = block->getParent();
92 :
93 95796 : for(u16 i=0; i<26; i++)
94 : {
95 92248 : const v3s16 &dir = g_26dirs[i];
96 92248 : v3s16 bp = m_blockpos + dir;
97 92248 : MapBlock *b = map->getBlockNoCreateNoEx(bp);
98 92248 : if(b)
99 52772 : b->copyTo(m_vmanip);
100 : }
101 : }
102 3548 : }
103 :
104 1 : void MeshMakeData::fillSingleNode(MapNode *node)
105 : {
106 1 : m_blockpos = v3s16(0,0,0);
107 :
108 1 : v3s16 blockpos_nodes = v3s16(0,0,0);
109 2 : VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
110 3 : blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
111 1 : s32 volume = area.getVolume();
112 1 : s32 our_node_index = area.index(1,1,1);
113 :
114 : // Allocate this block + neighbors
115 1 : m_vmanip.clear();
116 1 : m_vmanip.addArea(area);
117 :
118 : // Fill in data
119 1 : MapNode *data = new MapNode[volume];
120 110593 : for(s32 i = 0; i < volume; i++)
121 : {
122 110592 : if(i == our_node_index)
123 : {
124 1 : data[i] = *node;
125 : }
126 : else
127 : {
128 110591 : data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
129 : }
130 : }
131 1 : m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
132 1 : delete[] data;
133 1 : }
134 :
135 3548 : void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
136 : {
137 3548 : if(crack_level >= 0)
138 0 : m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
139 3548 : }
140 :
141 3548 : void MeshMakeData::setHighlighted(v3s16 highlighted_pos, bool show_hud)
142 : {
143 3548 : m_show_hud = show_hud;
144 3548 : m_highlighted_pos_relative = highlighted_pos - m_blockpos*MAP_BLOCKSIZE;
145 3548 : }
146 :
147 3548 : void MeshMakeData::setSmoothLighting(bool smooth_lighting)
148 : {
149 3548 : m_smooth_lighting = smooth_lighting;
150 3548 : }
151 :
152 : /*
153 : Light and vertex color functions
154 : */
155 :
156 : /*
157 : Calculate non-smooth lighting at interior of node.
158 : Single light bank.
159 : */
160 329420 : static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
161 : INodeDefManager *ndef)
162 : {
163 329420 : u8 light = n.getLight(bank, ndef);
164 :
165 852176 : while(increment > 0)
166 : {
167 261378 : light = undiminish_light(light);
168 261378 : --increment;
169 : }
170 334460 : while(increment < 0)
171 : {
172 2520 : light = diminish_light(light);
173 2520 : ++increment;
174 : }
175 :
176 329420 : return decode_light(light);
177 : }
178 :
179 : /*
180 : Calculate non-smooth lighting at interior of node.
181 : Both light banks.
182 : */
183 164710 : u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
184 : {
185 164710 : u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
186 164710 : u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
187 164710 : return day | (night << 8);
188 : }
189 :
190 : /*
191 : Calculate non-smooth lighting at face of node.
192 : Single light bank.
193 : */
194 12 : static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
195 : v3s16 face_dir, INodeDefManager *ndef)
196 : {
197 : u8 light;
198 12 : u8 l1 = n.getLight(bank, ndef);
199 12 : u8 l2 = n2.getLight(bank, ndef);
200 12 : if(l1 > l2)
201 3 : light = l1;
202 : else
203 9 : light = l2;
204 :
205 : // Boost light level for light sources
206 12 : u8 light_source = MYMAX(ndef->get(n).light_source,
207 : ndef->get(n2).light_source);
208 12 : if(light_source > light)
209 0 : light = light_source;
210 :
211 12 : return decode_light(light);
212 : }
213 :
214 : /*
215 : Calculate non-smooth lighting at face of node.
216 : Both light banks.
217 : */
218 6 : u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
219 : {
220 6 : u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
221 6 : u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
222 6 : return day | (night << 8);
223 : }
224 :
225 : /*
226 : Calculate smooth lighting at the XYZ- corner of p.
227 : Both light banks
228 : */
229 3433720 : static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
230 : {
231 : static const v3s16 dirs8[8] = {
232 : v3s16(0,0,0),
233 : v3s16(0,0,1),
234 : v3s16(0,1,0),
235 : v3s16(0,1,1),
236 : v3s16(1,0,0),
237 : v3s16(1,1,0),
238 : v3s16(1,0,1),
239 : v3s16(1,1,1),
240 3433720 : };
241 :
242 3433720 : INodeDefManager *ndef = data->m_gamedef->ndef();
243 :
244 3433720 : u16 ambient_occlusion = 0;
245 3433720 : u16 light_count = 0;
246 3433720 : u8 light_source_max = 0;
247 3433720 : u16 light_day = 0;
248 3433720 : u16 light_night = 0;
249 :
250 30903480 : for (u32 i = 0; i < 8; i++)
251 : {
252 27469760 : const MapNode &n = data->m_vmanip.getNodeRefUnsafeCheckFlags(p - dirs8[i]);
253 :
254 : // if it's CONTENT_IGNORE we can't do any light calculations
255 27469760 : if (n.getContent() == CONTENT_IGNORE) {
256 386199 : continue;
257 : }
258 :
259 27083561 : const ContentFeatures &f = ndef->get(n);
260 27083561 : if (f.light_source > light_source_max)
261 175886 : light_source_max = f.light_source;
262 : // Check f.solidness because fast-style leaves look better this way
263 27083561 : if (f.param_type == CPT_LIGHT && f.solidness != 2) {
264 13889392 : light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
265 13889392 : light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
266 13889392 : light_count++;
267 : } else {
268 13194169 : ambient_occlusion++;
269 : }
270 : }
271 :
272 3433720 : if(light_count == 0)
273 0 : return 0xffff;
274 :
275 3433720 : light_day /= light_count;
276 3433720 : light_night /= light_count;
277 :
278 : // Boost brightness around light sources
279 3433720 : bool skip_ambient_occlusion_day = false;
280 3433720 : if(decode_light(light_source_max) >= light_day) {
281 777356 : light_day = decode_light(light_source_max);
282 777356 : skip_ambient_occlusion_day = true;
283 : }
284 :
285 3433720 : bool skip_ambient_occlusion_night = false;
286 3433720 : if(decode_light(light_source_max) >= light_night) {
287 2155926 : light_night = decode_light(light_source_max);
288 2155926 : skip_ambient_occlusion_night = true;
289 : }
290 :
291 3433720 : if (ambient_occlusion > 4)
292 : {
293 1255862 : static const float ao_gamma = rangelim(
294 : g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
295 :
296 : // Table of gamma space multiply factors.
297 : static const float light_amount[3] = {
298 1 : powf(0.75, 1.0 / ao_gamma),
299 1 : powf(0.5, 1.0 / ao_gamma),
300 1 : powf(0.25, 1.0 / ao_gamma)
301 1255865 : };
302 :
303 : //calculate table index for gamma space multiplier
304 1255862 : ambient_occlusion -= 5;
305 :
306 1255862 : if (!skip_ambient_occlusion_day)
307 850354 : light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
308 1255862 : if (!skip_ambient_occlusion_night)
309 449699 : light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
310 : }
311 :
312 3433720 : return light_day | (light_night << 8);
313 : }
314 :
315 : /*
316 : Calculate smooth lighting at the given corner of p.
317 : Both light banks.
318 : */
319 3433720 : u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
320 : {
321 3433720 : if(corner.X == 1) p.X += 1;
322 : // else corner.X == -1
323 3433720 : if(corner.Y == 1) p.Y += 1;
324 : // else corner.Y == -1
325 3433720 : if(corner.Z == 1) p.Z += 1;
326 : // else corner.Z == -1
327 :
328 3433720 : return getSmoothLightCombined(p, data);
329 : }
330 :
331 : /*
332 : Converts from day + night color values (0..255)
333 : and a given daynight_ratio to the final SColor shown on screen.
334 : */
335 74322 : void finalColorBlend(video::SColor& result,
336 : u8 day, u8 night, u32 daynight_ratio)
337 : {
338 74322 : s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
339 74322 : s32 b = rg;
340 :
341 : // Moonlight is blue
342 74322 : b += (day - night) / 13;
343 74322 : rg -= (day - night) / 23;
344 :
345 : // Emphase blue a bit in darker places
346 : // Each entry of this array represents a range of 8 blue levels
347 : static const u8 emphase_blue_when_dark[32] = {
348 : 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
349 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 : };
351 74322 : b += emphase_blue_when_dark[irr::core::clamp(b, 0, 255) / 8];
352 74322 : b = irr::core::clamp(b, 0, 255);
353 :
354 : // Artificial light is yellow-ish
355 : static const u8 emphase_yellow_when_artificial[16] = {
356 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
357 : };
358 74322 : rg += emphase_yellow_when_artificial[night/16];
359 74322 : rg = irr::core::clamp(rg, 0, 255);
360 :
361 74322 : result.setRed(rg);
362 74322 : result.setGreen(rg);
363 74322 : result.setBlue(b);
364 74322 : }
365 :
366 : /*
367 : Mesh generation helpers
368 : */
369 :
370 : /*
371 : vertex_dirs: v3s16[4]
372 : */
373 1632651 : static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
374 : {
375 : /*
376 : If looked from outside the node towards the face, the corners are:
377 : 0: bottom-right
378 : 1: bottom-left
379 : 2: top-left
380 : 3: top-right
381 : */
382 1632651 : if(dir == v3s16(0,0,1))
383 : {
384 : // If looking towards z+, this is the face that is behind
385 : // the center point, facing towards z+.
386 214664 : vertex_dirs[0] = v3s16(-1,-1, 1);
387 214664 : vertex_dirs[1] = v3s16( 1,-1, 1);
388 214664 : vertex_dirs[2] = v3s16( 1, 1, 1);
389 214664 : vertex_dirs[3] = v3s16(-1, 1, 1);
390 : }
391 1417987 : else if(dir == v3s16(0,0,-1))
392 : {
393 : // faces towards Z-
394 214601 : vertex_dirs[0] = v3s16( 1,-1,-1);
395 214601 : vertex_dirs[1] = v3s16(-1,-1,-1);
396 214601 : vertex_dirs[2] = v3s16(-1, 1,-1);
397 214601 : vertex_dirs[3] = v3s16( 1, 1,-1);
398 : }
399 1203386 : else if(dir == v3s16(1,0,0))
400 : {
401 : // faces towards X+
402 228702 : vertex_dirs[0] = v3s16( 1,-1, 1);
403 228702 : vertex_dirs[1] = v3s16( 1,-1,-1);
404 228702 : vertex_dirs[2] = v3s16( 1, 1,-1);
405 228702 : vertex_dirs[3] = v3s16( 1, 1, 1);
406 : }
407 974684 : else if(dir == v3s16(-1,0,0))
408 : {
409 : // faces towards X-
410 227500 : vertex_dirs[0] = v3s16(-1,-1,-1);
411 227500 : vertex_dirs[1] = v3s16(-1,-1, 1);
412 227500 : vertex_dirs[2] = v3s16(-1, 1, 1);
413 227500 : vertex_dirs[3] = v3s16(-1, 1,-1);
414 : }
415 747184 : else if(dir == v3s16(0,1,0))
416 : {
417 : // faces towards Y+ (assume Z- as "down" in texture)
418 580883 : vertex_dirs[0] = v3s16( 1, 1,-1);
419 580883 : vertex_dirs[1] = v3s16(-1, 1,-1);
420 580883 : vertex_dirs[2] = v3s16(-1, 1, 1);
421 580883 : vertex_dirs[3] = v3s16( 1, 1, 1);
422 : }
423 166301 : else if(dir == v3s16(0,-1,0))
424 : {
425 : // faces towards Y- (assume Z+ as "down" in texture)
426 166301 : vertex_dirs[0] = v3s16( 1,-1, 1);
427 166301 : vertex_dirs[1] = v3s16(-1,-1, 1);
428 166301 : vertex_dirs[2] = v3s16(-1,-1,-1);
429 166301 : vertex_dirs[3] = v3s16( 1,-1,-1);
430 : }
431 1632651 : }
432 :
433 3940660 : struct FastFace
434 : {
435 : TileSpec tile;
436 : video::S3DVertex vertices[4]; // Precalculated vertices
437 : };
438 :
439 774221 : static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
440 : v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
441 : {
442 : // Position is at the center of the cube.
443 774221 : v3f pos = p * BS;
444 :
445 774221 : float x0 = 0.0;
446 774221 : float y0 = 0.0;
447 774221 : float w = 1.0;
448 774221 : float h = 1.0;
449 :
450 774221 : v3f vertex_pos[4];
451 774221 : v3s16 vertex_dirs[4];
452 774221 : getNodeVertexDirs(dir, vertex_dirs);
453 :
454 774221 : v3s16 t;
455 : u16 t1;
456 774221 : switch (tile.rotation)
457 : {
458 : case 0:
459 770216 : break;
460 : case 1: //R90
461 1849 : t = vertex_dirs[0];
462 1849 : vertex_dirs[0] = vertex_dirs[3];
463 1849 : vertex_dirs[3] = vertex_dirs[2];
464 1849 : vertex_dirs[2] = vertex_dirs[1];
465 1849 : vertex_dirs[1] = t;
466 1849 : t1=li0;
467 1849 : li0=li3;
468 1849 : li3=li2;
469 1849 : li2=li1;
470 1849 : li1=t1;
471 1849 : break;
472 : case 2: //R180
473 901 : t = vertex_dirs[0];
474 901 : vertex_dirs[0] = vertex_dirs[2];
475 901 : vertex_dirs[2] = t;
476 901 : t = vertex_dirs[1];
477 901 : vertex_dirs[1] = vertex_dirs[3];
478 901 : vertex_dirs[3] = t;
479 901 : t1 = li0;
480 901 : li0 = li2;
481 901 : li2 = t1;
482 901 : t1 = li1;
483 901 : li1 = li3;
484 901 : li3 = t1;
485 901 : break;
486 : case 3: //R270
487 1255 : t = vertex_dirs[0];
488 1255 : vertex_dirs[0] = vertex_dirs[1];
489 1255 : vertex_dirs[1] = vertex_dirs[2];
490 1255 : vertex_dirs[2] = vertex_dirs[3];
491 1255 : vertex_dirs[3] = t;
492 1255 : t1 = li0;
493 1255 : li0 = li1;
494 1255 : li1 = li2;
495 1255 : li2 = li3;
496 1255 : li3 = t1;
497 1255 : break;
498 : case 4: //FXR90
499 0 : t = vertex_dirs[0];
500 0 : vertex_dirs[0] = vertex_dirs[3];
501 0 : vertex_dirs[3] = vertex_dirs[2];
502 0 : vertex_dirs[2] = vertex_dirs[1];
503 0 : vertex_dirs[1] = t;
504 0 : t1 = li0;
505 0 : li0 = li3;
506 0 : li3 = li2;
507 0 : li2 = li1;
508 0 : li1 = t1;
509 0 : y0 += h;
510 0 : h *= -1;
511 0 : break;
512 : case 5: //FXR270
513 0 : t = vertex_dirs[0];
514 0 : vertex_dirs[0] = vertex_dirs[1];
515 0 : vertex_dirs[1] = vertex_dirs[2];
516 0 : vertex_dirs[2] = vertex_dirs[3];
517 0 : vertex_dirs[3] = t;
518 0 : t1 = li0;
519 0 : li0 = li1;
520 0 : li1 = li2;
521 0 : li2 = li3;
522 0 : li3 = t1;
523 0 : y0 += h;
524 0 : h *= -1;
525 0 : break;
526 : case 6: //FYR90
527 0 : t = vertex_dirs[0];
528 0 : vertex_dirs[0] = vertex_dirs[3];
529 0 : vertex_dirs[3] = vertex_dirs[2];
530 0 : vertex_dirs[2] = vertex_dirs[1];
531 0 : vertex_dirs[1] = t;
532 0 : t1 = li0;
533 0 : li0 = li3;
534 0 : li3 = li2;
535 0 : li2 = li1;
536 0 : li1 = t1;
537 0 : x0 += w;
538 0 : w *= -1;
539 0 : break;
540 : case 7: //FYR270
541 0 : t = vertex_dirs[0];
542 0 : vertex_dirs[0] = vertex_dirs[1];
543 0 : vertex_dirs[1] = vertex_dirs[2];
544 0 : vertex_dirs[2] = vertex_dirs[3];
545 0 : vertex_dirs[3] = t;
546 0 : t1 = li0;
547 0 : li0 = li1;
548 0 : li1 = li2;
549 0 : li2 = li3;
550 0 : li3 = t1;
551 0 : x0 += w;
552 0 : w *= -1;
553 0 : break;
554 : case 8: //FX
555 0 : y0 += h;
556 0 : h *= -1;
557 0 : break;
558 : case 9: //FY
559 0 : x0 += w;
560 0 : w *= -1;
561 0 : break;
562 : default:
563 0 : break;
564 : }
565 :
566 3871105 : for(u16 i=0; i<4; i++)
567 : {
568 12387536 : vertex_pos[i] = v3f(
569 3096884 : BS/2*vertex_dirs[i].X,
570 3096884 : BS/2*vertex_dirs[i].Y,
571 3096884 : BS/2*vertex_dirs[i].Z
572 3096884 : );
573 : }
574 :
575 3871105 : for(u16 i=0; i<4; i++)
576 : {
577 3096884 : vertex_pos[i].X *= scale.X;
578 3096884 : vertex_pos[i].Y *= scale.Y;
579 3096884 : vertex_pos[i].Z *= scale.Z;
580 3096884 : vertex_pos[i] += pos;
581 : }
582 :
583 774221 : f32 abs_scale = 1.0;
584 774221 : if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
585 706252 : else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
586 706252 : else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
587 :
588 774221 : v3f normal(dir.X, dir.Y, dir.Z);
589 :
590 774221 : u8 alpha = tile.alpha;
591 :
592 774221 : dest.push_back(FastFace());
593 :
594 774221 : FastFace& face = *dest.rbegin();
595 :
596 2322663 : face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
597 : MapBlock_LightColor(alpha, li0, light_source),
598 1548442 : core::vector2d<f32>(x0+w*abs_scale, y0+h));
599 1548442 : face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
600 : MapBlock_LightColor(alpha, li1, light_source),
601 774221 : core::vector2d<f32>(x0, y0+h));
602 1548442 : face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
603 : MapBlock_LightColor(alpha, li2, light_source),
604 774221 : core::vector2d<f32>(x0, y0));
605 1548442 : face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
606 : MapBlock_LightColor(alpha, li3, light_source),
607 1548442 : core::vector2d<f32>(x0+w*abs_scale, y0));
608 :
609 774221 : face.tile = tile;
610 774221 : }
611 :
612 : /*
613 : Nodes make a face if contents differ and solidness differs.
614 : Return value:
615 : 0: No face
616 : 1: Face uses m1's content
617 : 2: Face uses m2's content
618 : equivalent: Whether the blocks share the same face (eg. water and glass)
619 :
620 : TODO: Add 3: Both faces drawn with backface culling, remove equivalent
621 : */
622 25843456 : static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
623 : INodeDefManager *ndef)
624 : {
625 25843456 : *equivalent = false;
626 :
627 25843456 : if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
628 0 : return 0;
629 :
630 25843456 : bool contents_differ = (m1 != m2);
631 :
632 25843456 : const ContentFeatures &f1 = ndef->get(m1);
633 25843456 : const ContentFeatures &f2 = ndef->get(m2);
634 :
635 : // Contents don't differ for different forms of same liquid
636 25843456 : if(f1.sameLiquid(f2))
637 1363820 : contents_differ = false;
638 :
639 25843456 : u8 c1 = f1.solidness;
640 25843456 : u8 c2 = f2.solidness;
641 :
642 25843456 : bool solidness_differs = (c1 != c2);
643 25843456 : bool makes_face = contents_differ && solidness_differs;
644 :
645 25843456 : if(makes_face == false)
646 24985020 : return 0;
647 :
648 858436 : if(c1 == 0)
649 273361 : c1 = f1.visual_solidness;
650 858436 : if(c2 == 0)
651 443341 : c2 = f2.visual_solidness;
652 :
653 858436 : if(c1 == c2){
654 333 : *equivalent = true;
655 : // If same solidness, liquid takes precense
656 333 : if(f1.isLiquid())
657 83 : return 1;
658 250 : if(f2.isLiquid())
659 250 : return 2;
660 : }
661 :
662 858103 : if(c1 > c2)
663 541426 : return 1;
664 : else
665 316677 : return 2;
666 : }
667 :
668 : /*
669 : Gets nth node tile (0 <= n <= 5).
670 : */
671 1110732 : TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
672 : {
673 1110732 : INodeDefManager *ndef = data->m_gamedef->ndef();
674 1110732 : TileSpec spec = ndef->get(mn).tiles[tileindex];
675 : // Apply temporary crack
676 1110732 : if (p == data->m_crack_pos_relative)
677 0 : spec.material_flags |= MATERIAL_FLAG_CRACK;
678 1110732 : return spec;
679 : }
680 :
681 : /*
682 : Gets node tile given a face direction.
683 : */
684 947744 : TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
685 : {
686 947744 : INodeDefManager *ndef = data->m_gamedef->ndef();
687 :
688 : // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
689 : // (0,0,1), (0,0,-1) or (0,0,0)
690 : assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
691 :
692 : // Convert direction to single integer for table lookup
693 : // 0 = (0,0,0)
694 : // 1 = (1,0,0)
695 : // 2 = (0,1,0)
696 : // 3 = (0,0,1)
697 : // 4 = invalid, treat as (0,0,0)
698 : // 5 = (0,0,-1)
699 : // 6 = (0,-1,0)
700 : // 7 = (-1,0,0)
701 947744 : u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
702 :
703 : // Get rotation for things like chests
704 947744 : u8 facedir = mn.getFaceDir(ndef);
705 :
706 : static const u16 dir_to_tile[24 * 16] =
707 : {
708 : // 0 +X +Y +Z -Z -Y -X -> value=tile,rotation
709 : 0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
710 : 0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
711 : 0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
712 : 0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
713 :
714 : 0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
715 : 0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
716 : 0,0, 3,3 , 4,0 , 0,0 , 0,0, 1,2 , 5,2 , 2,1 ,
717 : 0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
718 :
719 : 0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
720 : 0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
721 : 0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
722 : 0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
723 :
724 : 0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
725 : 0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
726 : 0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
727 : 0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
728 :
729 : 0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
730 : 0,0, 1,2 , 4,1 , 3,3 , 0,0, 2,1 , 5,1 , 0,0 ,
731 : 0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
732 : 0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
733 :
734 : 0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
735 : 0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
736 : 0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
737 : 0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
738 :
739 : };
740 947744 : u16 tile_index=facedir*16 + dir_i;
741 947744 : TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
742 947744 : spec.rotation=dir_to_tile[tile_index + 1];
743 947744 : spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
744 947744 : return spec;
745 : }
746 :
747 26296320 : static void getTileInfo(
748 : // Input:
749 : MeshMakeData *data,
750 : const v3s16 &p,
751 : const v3s16 &face_dir,
752 : // Output:
753 : bool &makes_face,
754 : v3s16 &p_corrected,
755 : v3s16 &face_dir_corrected,
756 : u16 *lights,
757 : TileSpec &tile,
758 : u8 &light_source
759 : )
760 : {
761 26296320 : VoxelManipulator &vmanip = data->m_vmanip;
762 26296320 : INodeDefManager *ndef = data->m_gamedef->ndef();
763 26296320 : v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
764 :
765 26296320 : MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
766 :
767 : // Don't even try to get n1 if n0 is already CONTENT_IGNORE
768 26296320 : if (n0.getContent() == CONTENT_IGNORE) {
769 0 : makes_face = false;
770 0 : return;
771 : }
772 :
773 26296320 : const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
774 :
775 26296320 : if (n1.getContent() == CONTENT_IGNORE) {
776 452864 : makes_face = false;
777 452864 : return;
778 : }
779 :
780 : // This is hackish
781 25843456 : bool equivalent = false;
782 25843456 : u8 mf = face_contents(n0.getContent(), n1.getContent(),
783 25843456 : &equivalent, ndef);
784 :
785 25843456 : if(mf == 0)
786 : {
787 24985020 : makes_face = false;
788 24985020 : return;
789 : }
790 :
791 858436 : makes_face = true;
792 :
793 858436 : if(mf == 1)
794 : {
795 541509 : tile = getNodeTile(n0, p, face_dir, data);
796 541509 : p_corrected = p;
797 541509 : face_dir_corrected = face_dir;
798 541509 : light_source = ndef->get(n0).light_source;
799 : }
800 : else
801 : {
802 316927 : tile = getNodeTile(n1, p + face_dir, -face_dir, data);
803 316927 : p_corrected = p + face_dir;
804 316927 : face_dir_corrected = -face_dir;
805 316927 : light_source = ndef->get(n1).light_source;
806 : }
807 :
808 : // eg. water and glass
809 858436 : if(equivalent)
810 333 : tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
811 :
812 858436 : if(data->m_smooth_lighting == false)
813 : {
814 24 : lights[0] = lights[1] = lights[2] = lights[3] =
815 24 : getFaceLight(n0, n1, face_dir, ndef);
816 : }
817 : else
818 : {
819 858430 : v3s16 vertex_dirs[4];
820 858430 : getNodeVertexDirs(face_dir_corrected, vertex_dirs);
821 4292150 : for(u16 i=0; i<4; i++)
822 : {
823 13734880 : lights[i] = getSmoothLight(
824 6867440 : blockpos_nodes + p_corrected,
825 6867440 : vertex_dirs[i], data);
826 : }
827 : }
828 :
829 858436 : return;
830 : }
831 :
832 : /*
833 : startpos:
834 : translate_dir: unit vector with only one of x, y or z
835 : face_dir: unit vector with only one of x, y or z
836 : */
837 1643520 : static void updateFastFaceRow(
838 : MeshMakeData *data,
839 : v3s16 startpos,
840 : v3s16 translate_dir,
841 : v3f translate_dir_f,
842 : v3s16 face_dir,
843 : v3f face_dir_f,
844 : std::vector<FastFace> &dest)
845 : {
846 1643520 : v3s16 p = startpos;
847 :
848 1643520 : u16 continuous_tiles_count = 0;
849 :
850 1643520 : bool makes_face = false;
851 1643520 : v3s16 p_corrected;
852 1643520 : v3s16 face_dir_corrected;
853 1643520 : u16 lights[4] = {0,0,0,0};
854 3287040 : TileSpec tile;
855 1643520 : u8 light_source = 0;
856 : getTileInfo(data, p, face_dir,
857 : makes_face, p_corrected, face_dir_corrected,
858 1643520 : lights, tile, light_source);
859 :
860 27939840 : for(u16 j=0; j<MAP_BLOCKSIZE; j++)
861 : {
862 : // If tiling can be done, this is set to false in the next step
863 26296320 : bool next_is_different = true;
864 :
865 26296320 : v3s16 p_next;
866 :
867 26296320 : bool next_makes_face = false;
868 26296320 : v3s16 next_p_corrected;
869 26296320 : v3s16 next_face_dir_corrected;
870 26296320 : u16 next_lights[4] = {0,0,0,0};
871 52592640 : TileSpec next_tile;
872 26296320 : u8 next_light_source = 0;
873 :
874 : // If at last position, there is nothing to compare to and
875 : // the face must be drawn anyway
876 26296320 : if(j != MAP_BLOCKSIZE - 1)
877 : {
878 24652800 : p_next = p + translate_dir;
879 :
880 : getTileInfo(data, p_next, face_dir,
881 : next_makes_face, next_p_corrected,
882 : next_face_dir_corrected, next_lights,
883 24652800 : next_tile, next_light_source);
884 :
885 74702262 : if(next_makes_face == makes_face
886 72470676 : && next_p_corrected == p_corrected + translate_dir
887 367107 : && next_face_dir_corrected == face_dir_corrected
888 367107 : && next_lights[0] == lights[0]
889 134854 : && next_lights[1] == lights[1]
890 100124 : && next_lights[2] == lights[2]
891 93503 : && next_lights[3] == lights[3]
892 90621 : && next_tile == tile
893 84246 : && tile.rotation == 0
894 49389815 : && next_light_source == light_source)
895 : {
896 84215 : next_is_different = false;
897 : }
898 : else{
899 : /*if(makes_face){
900 : g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
901 : next_makes_face != makes_face ? 1 : 0);
902 : g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
903 : (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
904 : g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
905 : next_face_dir_corrected != face_dir_corrected ? 1 : 0);
906 : g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
907 : (next_lights[0] != lights[0] ||
908 : next_lights[0] != lights[0] ||
909 : next_lights[0] != lights[0] ||
910 : next_lights[0] != lights[0]) ? 1 : 0);
911 : g_profiler->add("Meshgen: diff: !(next_tile == tile)",
912 : !(next_tile == tile) ? 1 : 0);
913 : }*/
914 : }
915 : /*g_profiler->add("Meshgen: Total faces checked", 1);
916 : if(makes_face)
917 : g_profiler->add("Meshgen: Total makes_face checked", 1);*/
918 : } else {
919 : /*if(makes_face)
920 : g_profiler->add("Meshgen: diff: last position", 1);*/
921 : }
922 :
923 26296320 : continuous_tiles_count++;
924 :
925 26296320 : if(next_is_different)
926 : {
927 : /*
928 : Create a face if there should be one
929 : */
930 26212105 : if(makes_face)
931 : {
932 : // Floating point conversion of the position vector
933 774221 : v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
934 : // Center point of face (kind of)
935 774221 : v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
936 774221 : if(continuous_tiles_count != 1)
937 84215 : sp += translate_dir_f;
938 774221 : v3f scale(1,1,1);
939 :
940 774221 : if(translate_dir.X != 0) {
941 554242 : scale.X = continuous_tiles_count;
942 : }
943 774221 : if(translate_dir.Y != 0) {
944 0 : scale.Y = continuous_tiles_count;
945 : }
946 774221 : if(translate_dir.Z != 0) {
947 219979 : scale.Z = continuous_tiles_count;
948 : }
949 :
950 1548442 : makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
951 : sp, face_dir_corrected, scale, light_source,
952 774221 : dest);
953 :
954 774221 : g_profiler->avg("Meshgen: faces drawn by tiling", 0);
955 858436 : for(int i = 1; i < continuous_tiles_count; i++){
956 84215 : g_profiler->avg("Meshgen: faces drawn by tiling", 1);
957 : }
958 : }
959 :
960 26212105 : continuous_tiles_count = 0;
961 :
962 26212105 : makes_face = next_makes_face;
963 26212105 : p_corrected = next_p_corrected;
964 26212105 : face_dir_corrected = next_face_dir_corrected;
965 26212105 : lights[0] = next_lights[0];
966 26212105 : lights[1] = next_lights[1];
967 26212105 : lights[2] = next_lights[2];
968 26212105 : lights[3] = next_lights[3];
969 26212105 : tile = next_tile;
970 26212105 : light_source = next_light_source;
971 : }
972 :
973 26296320 : p = p_next;
974 : }
975 1643520 : }
976 :
977 2140 : static void updateAllFastFaceRows(MeshMakeData *data,
978 : std::vector<FastFace> &dest)
979 : {
980 : /*
981 : Go through every y,z and get top(y+) faces in rows of x+
982 : */
983 36380 : for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
984 582080 : for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
985 1095680 : updateFastFaceRow(data,
986 : v3s16(0,y,z),
987 : v3s16(1,0,0), //dir
988 : v3f (1,0,0),
989 : v3s16(0,1,0), //face dir
990 : v3f (0,1,0),
991 547840 : dest);
992 : }
993 : }
994 :
995 : /*
996 : Go through every x,y and get right(x+) faces in rows of z+
997 : */
998 36380 : for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
999 582080 : for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1000 1095680 : updateFastFaceRow(data,
1001 : v3s16(x,y,0),
1002 : v3s16(0,0,1), //dir
1003 : v3f (0,0,1),
1004 : v3s16(1,0,0), //face dir
1005 : v3f (1,0,0),
1006 547840 : dest);
1007 : }
1008 : }
1009 :
1010 : /*
1011 : Go through every y,z and get back(z+) faces in rows of x+
1012 : */
1013 36380 : for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1014 582080 : for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1015 1095680 : updateFastFaceRow(data,
1016 : v3s16(0,y,z),
1017 : v3s16(1,0,0), //dir
1018 : v3f (1,0,0),
1019 : v3s16(0,0,1), //face dir
1020 : v3f (0,0,1),
1021 547840 : dest);
1022 : }
1023 : }
1024 2140 : }
1025 :
1026 : /*
1027 : MapBlockMesh
1028 : */
1029 :
1030 2140 : MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1031 0 : m_mesh(new scene::SMesh()),
1032 2140 : m_minimap_mapblock(new MinimapMapblock),
1033 2140 : m_gamedef(data->m_gamedef),
1034 2140 : m_tsrc(m_gamedef->getTextureSource()),
1035 2140 : m_shdrsrc(m_gamedef->getShaderSource()),
1036 : m_animation_force_timer(0), // force initial animation
1037 : m_last_crack(-1),
1038 : m_crack_materials(),
1039 : m_highlighted_materials(),
1040 : m_last_daynight_ratio((u32) -1),
1041 10700 : m_daynight_diffs()
1042 : {
1043 2140 : m_enable_shaders = data->m_use_shaders;
1044 2140 : m_enable_highlighting = g_settings->getBool("enable_node_highlighting");
1045 :
1046 2140 : if (g_settings->getBool("enable_minimap")) {
1047 2140 : v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
1048 36380 : for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
1049 582080 : for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1050 547840 : s16 air_count = 0;
1051 547840 : bool surface_found = false;
1052 547840 : MinimapPixel* minimap_pixel = &m_minimap_mapblock->data[x + z * MAP_BLOCKSIZE];
1053 9313280 : for(s16 y = MAP_BLOCKSIZE -1; y > -1; y--) {
1054 8765440 : v3s16 p(x, y, z);
1055 8765440 : MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
1056 8765440 : if (!surface_found && n.getContent() != CONTENT_AIR) {
1057 392197 : minimap_pixel->height = y;
1058 392197 : minimap_pixel->id = n.getContent();
1059 392197 : surface_found = true;
1060 8373243 : } else if (n.getContent() == CONTENT_AIR) {
1061 3677159 : air_count++;
1062 : }
1063 : }
1064 547840 : if (!surface_found) {
1065 155643 : minimap_pixel->id = CONTENT_AIR;
1066 : }
1067 547840 : minimap_pixel->air_count = air_count;
1068 : }
1069 : }
1070 : }
1071 :
1072 : // 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1073 : // 24-155ms for MAP_BLOCKSIZE=32 (NOTE: probably outdated)
1074 : //TimeTaker timer1("MapBlockMesh()");
1075 :
1076 4280 : std::vector<FastFace> fastfaces_new;
1077 2140 : fastfaces_new.reserve(512);
1078 :
1079 : /*
1080 : We are including the faces of the trailing edges of the block.
1081 : This means that when something changes, the caller must
1082 : also update the meshes of the blocks at the leading edges.
1083 :
1084 : NOTE: This is the slowest part of this method.
1085 : */
1086 : {
1087 : // 4-23ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
1088 : //TimeTaker timer2("updateAllFastFaceRows()");
1089 2140 : updateAllFastFaceRows(data, fastfaces_new);
1090 : }
1091 : // End of slow part
1092 :
1093 : /*
1094 : Convert FastFaces to MeshCollector
1095 : */
1096 :
1097 4280 : MeshCollector collector;
1098 :
1099 : {
1100 : // avg 0ms (100ms spikes when loading textures the first time)
1101 : // (NOTE: probably outdated)
1102 : //TimeTaker timer2("MeshCollector building");
1103 :
1104 776361 : for(u32 i=0; i<fastfaces_new.size(); i++)
1105 : {
1106 774221 : FastFace &f = fastfaces_new[i];
1107 :
1108 774221 : const u16 indices[] = {0,1,2,2,3,0};
1109 774221 : const u16 indices_alternate[] = {0,1,3,2,3,1};
1110 :
1111 774221 : if(f.tile.texture == NULL)
1112 0 : continue;
1113 :
1114 774221 : const u16 *indices_p = indices;
1115 :
1116 : /*
1117 : Revert triangles for nicer looking gradient if vertices
1118 : 1 and 3 have same color or 0 and 2 have different color.
1119 : getRed() is the day color.
1120 : */
1121 1548442 : if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1122 774221 : || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1123 738136 : indices_p = indices_alternate;
1124 :
1125 774221 : collector.append(f.tile, f.vertices, 4, indices_p, 6);
1126 : }
1127 : }
1128 :
1129 : /*
1130 : Add special graphics:
1131 : - torches
1132 : - flowing water
1133 : - fences
1134 : - whatever
1135 : */
1136 :
1137 2140 : mapblock_mesh_generate_special(data, collector);
1138 :
1139 2140 : m_highlight_mesh_color = data->m_highlight_mesh_color;
1140 :
1141 : /*
1142 : Convert MeshCollector to SMesh
1143 : */
1144 :
1145 33252 : for(u32 i = 0; i < collector.prebuffers.size(); i++)
1146 : {
1147 31112 : PreMeshBuffer &p = collector.prebuffers[i];
1148 :
1149 : // Generate animation data
1150 : // - Cracks
1151 31112 : if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1152 : {
1153 : // Find the texture name plus ^[crack:N:
1154 0 : std::ostringstream os(std::ios::binary);
1155 0 : os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1156 0 : if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1157 0 : os<<"o"; // use ^[cracko
1158 0 : os<<":"<<(u32)p.tile.animation_frame_count<<":";
1159 0 : m_crack_materials.insert(std::make_pair(i, os.str()));
1160 : // Replace tile texture with the cracked one
1161 0 : p.tile.texture = m_tsrc->getTextureForMesh(
1162 0 : os.str()+"0",
1163 0 : &p.tile.texture_id);
1164 : }
1165 : // - Texture animation
1166 31112 : if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1167 : {
1168 : // Add to MapBlockMesh in order to animate these tiles
1169 1463 : m_animation_tiles[i] = p.tile;
1170 1463 : m_animation_frames[i] = 0;
1171 1463 : if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1172 : // Get starting position from noise
1173 5852 : m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1174 2926 : data->m_blockpos.X, data->m_blockpos.Y,
1175 2926 : data->m_blockpos.Z, 0));
1176 : } else {
1177 : // Play all synchronized
1178 0 : m_animation_frame_offsets[i] = 0;
1179 : }
1180 : // Replace tile texture with the first animation frame
1181 1463 : FrameSpec animation_frame = p.tile.frames[0];
1182 1463 : p.tile.texture = animation_frame.texture;
1183 : }
1184 :
1185 31112 : if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED)
1186 45 : m_highlighted_materials.push_back(i);
1187 :
1188 7226795 : for(u32 j = 0; j < p.vertices.size(); j++)
1189 : {
1190 7195683 : video::S3DVertexTangents *vertex = &p.vertices[j];
1191 : // Note applyFacesShading second parameter is precalculated sqrt
1192 : // value for speed improvement
1193 : // Skip it for lightsources and top faces.
1194 7195683 : video::SColor &vc = vertex->Color;
1195 7195683 : if (!vc.getBlue()) {
1196 7111615 : if (vertex->Normal.Y < -0.5) {
1197 965534 : applyFacesShading (vc, 0.447213);
1198 6146081 : } else if (vertex->Normal.X > 0.5) {
1199 1044339 : applyFacesShading (vc, 0.670820);
1200 5101742 : } else if (vertex->Normal.X < -0.5) {
1201 1038918 : applyFacesShading (vc, 0.670820);
1202 4062824 : } else if (vertex->Normal.Z > 0.5) {
1203 970406 : applyFacesShading (vc, 0.836660);
1204 3092418 : } else if (vertex->Normal.Z < -0.5) {
1205 968712 : applyFacesShading (vc, 0.836660);
1206 : }
1207 : }
1208 7195683 : if(!m_enable_shaders)
1209 : {
1210 : // - Classic lighting (shaders handle this by themselves)
1211 : // Set initial real color and store for later updates
1212 24 : u8 day = vc.getRed();
1213 24 : u8 night = vc.getGreen();
1214 24 : finalColorBlend(vc, day, night, 1000);
1215 24 : if(day != night)
1216 24 : m_daynight_diffs[i][j] = std::make_pair(day, night);
1217 : }
1218 : }
1219 :
1220 : // Create material
1221 62224 : video::SMaterial material;
1222 31112 : material.setFlag(video::EMF_LIGHTING, false);
1223 31112 : material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1224 31112 : material.setFlag(video::EMF_BILINEAR_FILTER, false);
1225 31112 : material.setFlag(video::EMF_FOG_ENABLE, true);
1226 31112 : material.setTexture(0, p.tile.texture);
1227 :
1228 31112 : if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) {
1229 45 : material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
1230 : } else {
1231 31067 : if (m_enable_shaders) {
1232 31066 : material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
1233 31066 : p.tile.applyMaterialOptionsWithShaders(material);
1234 31066 : if (p.tile.normal_texture) {
1235 0 : material.setTexture(1, p.tile.normal_texture);
1236 0 : material.setTexture(2, m_tsrc->getTextureForMesh("enable_img.png"));
1237 : } else {
1238 31066 : material.setTexture(2, m_tsrc->getTextureForMesh("disable_img.png"));
1239 : }
1240 : } else {
1241 1 : p.tile.applyMaterialOptions(material);
1242 : }
1243 : }
1244 :
1245 : // Create meshbuffer
1246 31112 : scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1247 : // Set material
1248 31112 : buf->Material = material;
1249 : // Add to mesh
1250 31112 : m_mesh->addMeshBuffer(buf);
1251 : // Mesh grabbed it
1252 31112 : buf->drop();
1253 62224 : buf->append(&p.vertices[0], p.vertices.size(),
1254 93336 : &p.indices[0], p.indices.size());
1255 : }
1256 2140 : m_camera_offset = camera_offset;
1257 :
1258 : /*
1259 : Do some stuff to the mesh
1260 : */
1261 :
1262 2140 : translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1263 :
1264 2140 : if (m_enable_shaders) {
1265 2139 : scene::IMeshManipulator* meshmanip = m_gamedef->getSceneManager()->getMeshManipulator();
1266 2139 : meshmanip->recalculateTangents(m_mesh, true, false, false);
1267 : }
1268 :
1269 2140 : if(m_mesh)
1270 : {
1271 : #if 0
1272 : // Usually 1-700 faces and 1-7 materials
1273 : std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1274 : <<"and uses "<<m_mesh->getMeshBufferCount()
1275 : <<" materials (meshbuffers)"<<std::endl;
1276 : #endif
1277 :
1278 : // Use VBO for mesh (this just would set this for ever buffer)
1279 : // This will lead to infinite memory usage because or irrlicht.
1280 : //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1281 :
1282 : /*
1283 : NOTE: If that is enabled, some kind of a queue to the main
1284 : thread should be made which would call irrlicht to delete
1285 : the hardware buffer and then delete the mesh
1286 : */
1287 : }
1288 :
1289 : //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1290 :
1291 : // Check if animation is required for this mesh
1292 : m_has_animation =
1293 4280 : !m_crack_materials.empty() ||
1294 4279 : !m_daynight_diffs.empty() ||
1295 5416 : !m_animation_tiles.empty() ||
1296 3277 : !m_highlighted_materials.empty();
1297 2140 : }
1298 :
1299 4280 : MapBlockMesh::~MapBlockMesh()
1300 : {
1301 2140 : m_mesh->drop();
1302 2140 : m_mesh = NULL;
1303 2140 : }
1304 :
1305 148401 : bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1306 : {
1307 148401 : if(!m_has_animation)
1308 : {
1309 75289 : m_animation_force_timer = 100000;
1310 75289 : return false;
1311 : }
1312 :
1313 73112 : m_animation_force_timer = myrand_range(5, 100);
1314 :
1315 : // Cracks
1316 73112 : if(crack != m_last_crack)
1317 : {
1318 0 : for(std::map<u32, std::string>::iterator
1319 0 : i = m_crack_materials.begin();
1320 0 : i != m_crack_materials.end(); i++)
1321 : {
1322 0 : scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1323 0 : std::string basename = i->second;
1324 :
1325 : // Create new texture name from original
1326 0 : std::ostringstream os;
1327 0 : os<<basename<<crack;
1328 0 : u32 new_texture_id = 0;
1329 : video::ITexture *new_texture =
1330 0 : m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1331 0 : buf->getMaterial().setTexture(0, new_texture);
1332 :
1333 : // If the current material is also animated,
1334 : // update animation info
1335 : std::map<u32, TileSpec>::iterator anim_iter =
1336 0 : m_animation_tiles.find(i->first);
1337 0 : if(anim_iter != m_animation_tiles.end()){
1338 0 : TileSpec &tile = anim_iter->second;
1339 0 : tile.texture = new_texture;
1340 0 : tile.texture_id = new_texture_id;
1341 : // force animation update
1342 0 : m_animation_frames[i->first] = -1;
1343 : }
1344 : }
1345 :
1346 0 : m_last_crack = crack;
1347 : }
1348 :
1349 : // Texture animation
1350 451018 : for(std::map<u32, TileSpec>::iterator
1351 73112 : i = m_animation_tiles.begin();
1352 349420 : i != m_animation_tiles.end(); i++)
1353 : {
1354 101598 : const TileSpec &tile = i->second;
1355 : // Figure out current frame
1356 101598 : int frameoffset = m_animation_frame_offsets[i->first];
1357 101598 : int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1358 101598 : + frameoffset) % tile.animation_frame_count;
1359 : // If frame doesn't change, skip
1360 101598 : if(frame == m_animation_frames[i->first])
1361 88561 : continue;
1362 :
1363 13037 : m_animation_frames[i->first] = frame;
1364 :
1365 13037 : scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1366 :
1367 13037 : FrameSpec animation_frame = tile.frames[frame];
1368 13037 : buf->getMaterial().setTexture(0, animation_frame.texture);
1369 13037 : if (m_enable_shaders) {
1370 13037 : if (animation_frame.normal_texture) {
1371 0 : buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1372 0 : buf->getMaterial().setTexture(2, m_tsrc->getTextureForMesh("enable_img.png"));
1373 : } else {
1374 13037 : buf->getMaterial().setTexture(2, m_tsrc->getTextureForMesh("disable_img.png"));
1375 : }
1376 : }
1377 : }
1378 :
1379 : // Day-night transition
1380 73112 : if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1381 : {
1382 0 : for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1383 0 : i = m_daynight_diffs.begin();
1384 0 : i != m_daynight_diffs.end(); i++)
1385 : {
1386 0 : scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1387 0 : video::S3DVertexTangents *vertices = (video::S3DVertexTangents *)buf->getVertices();
1388 0 : for(std::map<u32, std::pair<u8, u8 > >::iterator
1389 0 : j = i->second.begin();
1390 0 : j != i->second.end(); j++)
1391 : {
1392 0 : u8 day = j->second.first;
1393 0 : u8 night = j->second.second;
1394 0 : finalColorBlend(vertices[j->first].Color, day, night, daynight_ratio);
1395 : }
1396 : }
1397 0 : m_last_daynight_ratio = daynight_ratio;
1398 : }
1399 :
1400 : // Node highlighting
1401 73112 : if (m_enable_highlighting) {
1402 73112 : u8 day = m_highlight_mesh_color.getRed();
1403 73112 : u8 night = m_highlight_mesh_color.getGreen();
1404 73112 : video::SColor hc;
1405 73112 : finalColorBlend(hc, day, night, daynight_ratio);
1406 73112 : float sin_r = 0.07 * sin(1.5 * time);
1407 73112 : float sin_g = 0.07 * sin(1.5 * time + irr::core::PI * 0.5);
1408 73112 : float sin_b = 0.07 * sin(1.5 * time + irr::core::PI);
1409 73112 : hc.setRed(core::clamp(core::round32(hc.getRed() * (0.8 + sin_r)), 0, 255));
1410 73112 : hc.setGreen(core::clamp(core::round32(hc.getGreen() * (0.8 + sin_g)), 0, 255));
1411 73112 : hc.setBlue(core::clamp(core::round32(hc.getBlue() * (0.8 + sin_b)), 0, 255));
1412 :
1413 147904 : for(std::list<u32>::iterator
1414 73112 : i = m_highlighted_materials.begin();
1415 147344 : i != m_highlighted_materials.end(); i++)
1416 : {
1417 560 : scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(*i);
1418 560 : video::S3DVertexTangents *vertices = (video::S3DVertexTangents*)buf->getVertices();
1419 14000 : for (u32 j = 0; j < buf->getVertexCount() ;j++)
1420 13440 : vertices[j].Color = hc;
1421 : }
1422 : }
1423 :
1424 73112 : return true;
1425 : }
1426 :
1427 55109 : void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1428 : {
1429 55109 : if (camera_offset != m_camera_offset) {
1430 0 : translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1431 0 : m_camera_offset = camera_offset;
1432 : }
1433 55109 : }
1434 :
1435 : /*
1436 : MeshCollector
1437 : */
1438 :
1439 1440700 : void MeshCollector::append(const TileSpec &tile,
1440 : const video::S3DVertex *vertices, u32 numVertices,
1441 : const u16 *indices, u32 numIndices)
1442 : {
1443 1440700 : if (numIndices > 65535) {
1444 0 : dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1445 0 : return;
1446 : }
1447 :
1448 1440700 : PreMeshBuffer *p = NULL;
1449 13122566 : for (u32 i = 0; i < prebuffers.size(); i++) {
1450 13099263 : PreMeshBuffer &pp = prebuffers[i];
1451 13099263 : if (pp.tile != tile)
1452 11681866 : continue;
1453 1417397 : if (pp.indices.size() + numIndices > 65535)
1454 0 : continue;
1455 :
1456 1417397 : p = &pp;
1457 1417397 : break;
1458 : }
1459 :
1460 1440700 : if (p == NULL) {
1461 46606 : PreMeshBuffer pp;
1462 23303 : pp.tile = tile;
1463 23303 : prebuffers.push_back(pp);
1464 23303 : p = &prebuffers[prebuffers.size() - 1];
1465 : }
1466 :
1467 1440700 : u32 vertex_count = p->vertices.size();
1468 10084900 : for (u32 i = 0; i < numIndices; i++) {
1469 8644200 : u32 j = indices[i] + vertex_count;
1470 8644200 : p->indices.push_back(j);
1471 : }
1472 :
1473 7203500 : for (u32 i = 0; i < numVertices; i++) {
1474 11525600 : video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1475 17288400 : vertices[i].Color, vertices[i].TCoords);
1476 5762800 : p->vertices.push_back(vert);
1477 : }
1478 : }
1479 :
1480 : /*
1481 : MeshCollector - for meshnodes and converted drawtypes.
1482 : */
1483 :
1484 113667 : void MeshCollector::append(const TileSpec &tile,
1485 : const video::S3DVertex *vertices, u32 numVertices,
1486 : const u16 *indices, u32 numIndices,
1487 : v3f pos, video::SColor c)
1488 : {
1489 113667 : if (numIndices > 65535) {
1490 0 : dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1491 0 : return;
1492 : }
1493 :
1494 113667 : PreMeshBuffer *p = NULL;
1495 1546681 : for (u32 i = 0; i < prebuffers.size(); i++) {
1496 1538872 : PreMeshBuffer &pp = prebuffers[i];
1497 1538872 : if(pp.tile != tile)
1498 1433014 : continue;
1499 105858 : if(pp.indices.size() + numIndices > 65535)
1500 0 : continue;
1501 :
1502 105858 : p = &pp;
1503 105858 : break;
1504 : }
1505 :
1506 113667 : if (p == NULL) {
1507 15618 : PreMeshBuffer pp;
1508 7809 : pp.tile = tile;
1509 7809 : prebuffers.push_back(pp);
1510 7809 : p = &prebuffers[prebuffers.size() - 1];
1511 : }
1512 :
1513 113667 : u32 vertex_count = p->vertices.size();
1514 3391725 : for (u32 i = 0; i < numIndices; i++) {
1515 3278058 : u32 j = indices[i] + vertex_count;
1516 3278058 : p->indices.push_back(j);
1517 : }
1518 :
1519 1546550 : for (u32 i = 0; i < numVertices; i++) {
1520 4298649 : video::S3DVertexTangents vert(vertices[i].Pos + pos, vertices[i].Normal,
1521 5731532 : c, vertices[i].TCoords);
1522 1432883 : p->vertices.push_back(vert);
1523 : }
1524 3 : }
|