]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock_mesh.cpp
EnvRef:find_nodes_in_area(minp, maxp, nodenames)
[dragonfireclient.git] / src / mapblock_mesh.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "main.h" // for g_profiler
25 #include "profiler.h"
26 #include "nodedef.h"
27 #include "gamedef.h"
28 #include "mesh.h"
29 #include "content_mapblock.h"
30
31 /*
32         MeshMakeData
33 */
34
35 MeshMakeData::MeshMakeData(IGameDef *gamedef):
36         m_vmanip(),
37         m_blockpos(-1337,-1337,-1337),
38         m_crack_pos_relative(-1337, -1337, -1337),
39         m_smooth_lighting(false),
40         m_gamedef(gamedef)
41 {}
42
43 void MeshMakeData::fill(MapBlock *block)
44 {
45         m_blockpos = block->getPos();
46
47         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
48         
49         /*
50                 Copy data
51         */
52
53         // Allocate this block + neighbors
54         m_vmanip.clear();
55         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
56                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
57
58         {
59                 //TimeTaker timer("copy central block data");
60                 // 0ms
61
62                 // Copy our data
63                 block->copyTo(m_vmanip);
64         }
65         {
66                 //TimeTaker timer("copy neighbor block data");
67                 // 0ms
68
69                 /*
70                         Copy neighbors. This is lightning fast.
71                         Copying only the borders would be *very* slow.
72                 */
73                 
74                 // Get map
75                 Map *map = block->getParent();
76
77                 for(u16 i=0; i<6; i++)
78                 {
79                         const v3s16 &dir = g_6dirs[i];
80                         v3s16 bp = m_blockpos + dir;
81                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
82                         if(b)
83                                 b->copyTo(m_vmanip);
84                 }
85         }
86 }
87
88 void MeshMakeData::fillSingleNode(MapNode *node)
89 {
90         m_blockpos = v3s16(0,0,0);
91         
92         v3s16 blockpos_nodes = v3s16(0,0,0);
93         VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
94                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
95         s32 volume = area.getVolume();
96         s32 our_node_index = area.index(1,1,1);
97
98         // Allocate this block + neighbors
99         m_vmanip.clear();
100         m_vmanip.addArea(area);
101
102         // Fill in data
103         MapNode *data = new MapNode[volume];
104         for(s32 i = 0; i < volume; i++)
105         {
106                 if(i == our_node_index)
107                 {
108                         data[i] = *node;
109                 }
110                 else
111                 {
112                         data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
113                 }
114         }
115         m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
116         delete[] data;
117 }
118
119 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
120 {
121         if(crack_level >= 0)
122                 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
123 }
124
125 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
126 {
127         m_smooth_lighting = smooth_lighting;
128 }
129
130 /*
131         Light and vertex color functions
132 */
133
134 /*
135         Calculate non-smooth lighting at interior of node.
136         Single light bank.
137 */
138 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
139                 MeshMakeData *data)
140 {
141         INodeDefManager *ndef = data->m_gamedef->ndef();
142         u8 light = n.getLight(bank, ndef);
143
144         while(increment > 0)
145         {
146                 light = undiminish_light(light);
147                 --increment;
148         }
149         while(increment < 0)
150         {
151                 light = diminish_light(light);
152                 ++increment;
153         }
154
155         return decode_light(light);
156 }
157
158 /*
159         Calculate non-smooth lighting at interior of node.
160         Both light banks.
161 */
162 u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data)
163 {
164         u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, data);
165         u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, data);
166         return day | (night << 8);
167 }
168
169 /*
170         Calculate non-smooth lighting at face of node.
171         Single light bank.
172 */
173 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
174                 v3s16 face_dir, MeshMakeData *data)
175 {
176         INodeDefManager *ndef = data->m_gamedef->ndef();
177
178         u8 light;
179         u8 l1 = n.getLight(bank, ndef);
180         u8 l2 = n2.getLight(bank, ndef);
181         if(l1 > l2)
182                 light = l1;
183         else
184                 light = l2;
185
186         // Boost light level for light sources
187         u8 light_source = MYMAX(ndef->get(n).light_source,
188                         ndef->get(n2).light_source);
189         //if(light_source >= light)
190                 //return decode_light(undiminish_light(light_source));
191         if(light_source > light)
192                 //return decode_light(light_source);
193                 light = light_source;
194
195         // Make some nice difference to different sides
196
197         // This makes light come from a corner
198         /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
199                 light = diminish_light(diminish_light(light));
200         else if(face_dir.X == -1 || face_dir.Z == -1)
201                 light = diminish_light(light);*/
202
203         // All neighboring faces have different shade (like in minecraft)
204         if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
205                 light = diminish_light(diminish_light(light));
206         else if(face_dir.Z == 1 || face_dir.Z == -1)
207                 light = diminish_light(light);
208
209         return decode_light(light);
210 }
211
212 /*
213         Calculate non-smooth lighting at face of node.
214         Both light banks.
215 */
216 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data)
217 {
218         u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data);
219         u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data);
220         return day | (night << 8);
221 }
222
223 /*
224         Calculate smooth lighting at the XYZ- corner of p.
225         Single light bank.
226 */
227 static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
228 {
229         static v3s16 dirs8[8] = {
230                 v3s16(0,0,0),
231                 v3s16(0,0,1),
232                 v3s16(0,1,0),
233                 v3s16(0,1,1),
234                 v3s16(1,0,0),
235                 v3s16(1,1,0),
236                 v3s16(1,0,1),
237                 v3s16(1,1,1),
238         };
239
240         INodeDefManager *ndef = data->m_gamedef->ndef();
241
242         u16 ambient_occlusion = 0;
243         u16 light = 0;
244         u16 light_count = 0;
245         u8 light_source_max = 0;
246         for(u32 i=0; i<8; i++)
247         {
248                 MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
249                 const ContentFeatures &f = ndef->get(n);
250                 if(f.light_source > light_source_max)
251                         light_source_max = f.light_source;
252                 // Check f.solidness because fast-style leaves look
253                 // better this way
254                 if(f.param_type == CPT_LIGHT && f.solidness != 2)
255                 {
256                         light += decode_light(n.getLight(bank, ndef));
257                         light_count++;
258                 }
259                 else if(n.getContent() != CONTENT_IGNORE)
260                 {
261                         ambient_occlusion++;
262                 }
263         }
264
265         if(light_count == 0)
266                 return 255;
267         
268         light /= light_count;
269
270         // Boost brightness around light sources
271         if(decode_light(light_source_max) >= light)
272                 //return decode_light(undiminish_light(light_source_max));
273                 return decode_light(light_source_max);
274
275         if(ambient_occlusion > 4)
276         {
277                 ambient_occlusion -= 4;
278                 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
279         }
280
281         return light;
282 }
283
284 /*
285         Calculate smooth lighting at the XYZ- corner of p.
286         Both light banks.
287 */
288 static u16 getSmoothLight(v3s16 p, MeshMakeData *data)
289 {
290         u16 day = getSmoothLight(LIGHTBANK_DAY, p, data);
291         u16 night = getSmoothLight(LIGHTBANK_NIGHT, p, data);
292         return day | (night << 8);
293 }
294
295 /*
296         Calculate smooth lighting at the given corner of p.
297         Both light banks.
298 */
299 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
300 {
301         if(corner.X == 1) p.X += 1;
302         else              assert(corner.X == -1);
303         if(corner.Y == 1) p.Y += 1;
304         else              assert(corner.Y == -1);
305         if(corner.Z == 1) p.Z += 1;
306         else              assert(corner.Z == -1);
307         
308         return getSmoothLight(p, data);
309 }
310
311 /*
312         Converts from day + night color values (0..255)
313         and a given daynight_ratio to the final SColor shown on screen.
314 */
315 static void finalColorBlend(video::SColor& result,
316                 u8 day, u8 night, u32 daynight_ratio)
317 {
318         s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
319         s32 b = rg;
320
321         // Moonlight is blue
322         b += (day - night) / 13;
323         rg -= (day - night) / 23;
324
325         // Emphase blue a bit in darker places
326         // Each entry of this array represents a range of 8 blue levels
327         static u8 emphase_blue_when_dark[32] = {
328                 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
329                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330         };
331         if(b < 0)
332                 b = 0;
333         if(b > 255)
334                 b = 255;
335         b += emphase_blue_when_dark[b / 8];
336
337         // Artificial light is yellow-ish
338         static u8 emphase_yellow_when_artificial[16] = {
339                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
340         };
341         rg += emphase_yellow_when_artificial[night/16];
342         if(rg < 0)
343                 rg = 0;
344         if(rg > 255)
345                 rg = 255;
346
347         result.setRed(rg);
348         result.setGreen(rg);
349         result.setBlue(b);
350 }
351
352 /*
353         Mesh generation helpers
354 */
355
356 /*
357         vertex_dirs: v3s16[4]
358 */
359 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
360 {
361         /*
362                 If looked from outside the node towards the face, the corners are:
363                 0: bottom-right
364                 1: bottom-left
365                 2: top-left
366                 3: top-right
367         */
368         if(dir == v3s16(0,0,1))
369         {
370                 // If looking towards z+, this is the face that is behind
371                 // the center point, facing towards z+.
372                 vertex_dirs[0] = v3s16(-1,-1, 1);
373                 vertex_dirs[1] = v3s16( 1,-1, 1);
374                 vertex_dirs[2] = v3s16( 1, 1, 1);
375                 vertex_dirs[3] = v3s16(-1, 1, 1);
376         }
377         else if(dir == v3s16(0,0,-1))
378         {
379                 // faces towards Z-
380                 vertex_dirs[0] = v3s16( 1,-1,-1);
381                 vertex_dirs[1] = v3s16(-1,-1,-1);
382                 vertex_dirs[2] = v3s16(-1, 1,-1);
383                 vertex_dirs[3] = v3s16( 1, 1,-1);
384         }
385         else if(dir == v3s16(1,0,0))
386         {
387                 // faces towards X+
388                 vertex_dirs[0] = v3s16( 1,-1, 1);
389                 vertex_dirs[1] = v3s16( 1,-1,-1);
390                 vertex_dirs[2] = v3s16( 1, 1,-1);
391                 vertex_dirs[3] = v3s16( 1, 1, 1);
392         }
393         else if(dir == v3s16(-1,0,0))
394         {
395                 // faces towards X-
396                 vertex_dirs[0] = v3s16(-1,-1,-1);
397                 vertex_dirs[1] = v3s16(-1,-1, 1);
398                 vertex_dirs[2] = v3s16(-1, 1, 1);
399                 vertex_dirs[3] = v3s16(-1, 1,-1);
400         }
401         else if(dir == v3s16(0,1,0))
402         {
403                 // faces towards Y+ (assume Z- as "down" in texture)
404                 vertex_dirs[0] = v3s16( 1, 1,-1);
405                 vertex_dirs[1] = v3s16(-1, 1,-1);
406                 vertex_dirs[2] = v3s16(-1, 1, 1);
407                 vertex_dirs[3] = v3s16( 1, 1, 1);
408         }
409         else if(dir == v3s16(0,-1,0))
410         {
411                 // faces towards Y- (assume Z+ as "down" in texture)
412                 vertex_dirs[0] = v3s16( 1,-1, 1);
413                 vertex_dirs[1] = v3s16(-1,-1, 1);
414                 vertex_dirs[2] = v3s16(-1,-1,-1);
415                 vertex_dirs[3] = v3s16( 1,-1,-1);
416         }
417 }
418
419 struct FastFace
420 {
421         TileSpec tile;
422         video::S3DVertex vertices[4]; // Precalculated vertices
423 };
424
425 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
426                 v3f p, v3s16 dir, v3f scale, core::array<FastFace> &dest)
427 {
428         FastFace face;
429         
430         // Position is at the center of the cube.
431         v3f pos = p * BS;
432
433         v3f vertex_pos[4];
434         v3s16 vertex_dirs[4];
435         getNodeVertexDirs(dir, vertex_dirs);
436         for(u16 i=0; i<4; i++)
437         {
438                 vertex_pos[i] = v3f(
439                                 BS/2*vertex_dirs[i].X,
440                                 BS/2*vertex_dirs[i].Y,
441                                 BS/2*vertex_dirs[i].Z
442                 );
443         }
444
445         for(u16 i=0; i<4; i++)
446         {
447                 vertex_pos[i].X *= scale.X;
448                 vertex_pos[i].Y *= scale.Y;
449                 vertex_pos[i].Z *= scale.Z;
450                 vertex_pos[i] += pos;
451         }
452
453         f32 abs_scale = 1.;
454         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
455         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
456         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
457
458         v3f normal(dir.X, dir.Y, dir.Z);
459
460         u8 alpha = tile.alpha;
461
462         float x0 = tile.texture.pos.X;
463         float y0 = tile.texture.pos.Y;
464         float w = tile.texture.size.X;
465         float h = tile.texture.size.Y;
466
467         face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
468                         MapBlock_LightColor(alpha, li0),
469                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
470         face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
471                         MapBlock_LightColor(alpha, li1),
472                         core::vector2d<f32>(x0, y0+h));
473         face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
474                         MapBlock_LightColor(alpha, li2),
475                         core::vector2d<f32>(x0, y0));
476         face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
477                         MapBlock_LightColor(alpha, li3),
478                         core::vector2d<f32>(x0+w*abs_scale, y0));
479
480         face.tile = tile;
481         
482         dest.push_back(face);
483 }
484
485 /*
486         Nodes make a face if contents differ and solidness differs.
487         Return value:
488                 0: No face
489                 1: Face uses m1's content
490                 2: Face uses m2's content
491         equivalent: Whether the blocks share the same face (eg. water and glass)
492
493         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
494 */
495 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
496                 INodeDefManager *ndef)
497 {
498         *equivalent = false;
499
500         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
501                 return 0;
502         
503         bool contents_differ = (m1 != m2);
504         
505         const ContentFeatures &f1 = ndef->get(m1);
506         const ContentFeatures &f2 = ndef->get(m2);
507
508         // Contents don't differ for different forms of same liquid
509         if(f1.sameLiquid(f2))
510                 contents_differ = false;
511         
512         u8 c1 = f1.solidness;
513         u8 c2 = f2.solidness;
514
515         bool solidness_differs = (c1 != c2);
516         bool makes_face = contents_differ && solidness_differs;
517
518         if(makes_face == false)
519                 return 0;
520         
521         if(c1 == 0)
522                 c1 = f1.visual_solidness;
523         if(c2 == 0)
524                 c2 = f2.visual_solidness;
525         
526         if(c1 == c2){
527                 *equivalent = true;
528                 // If same solidness, liquid takes precense
529                 if(f1.isLiquid())
530                         return 1;
531                 if(f2.isLiquid())
532                         return 2;
533         }
534         
535         if(c1 > c2)
536                 return 1;
537         else
538                 return 2;
539 }
540
541 /*
542         Gets nth node tile (0 <= n <= 5).
543 */
544 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
545 {
546         INodeDefManager *ndef = data->m_gamedef->ndef();
547         TileSpec spec = ndef->get(mn).tiles[tileindex];
548         // Apply temporary crack
549         if(p == data->m_crack_pos_relative)
550         {
551                 spec.material_flags |= MATERIAL_FLAG_CRACK;
552                 spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
553         }
554         return spec;
555 }
556
557 /*
558         Gets node tile given a face direction.
559 */
560 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
561 {
562         INodeDefManager *ndef = data->m_gamedef->ndef();
563
564         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
565         // (0,0,1), (0,0,-1) or (0,0,0)
566         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
567
568         // Convert direction to single integer for table lookup
569         //  0 = (0,0,0)
570         //  1 = (1,0,0)
571         //  2 = (0,1,0)
572         //  3 = (0,0,1)
573         //  4 = invalid, treat as (0,0,0)
574         //  5 = (0,0,-1)
575         //  6 = (0,-1,0)
576         //  7 = (-1,0,0)
577         u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
578
579         // Get rotation for things like chests
580         u8 facedir = mn.getFaceDir(ndef);
581         assert(facedir <= 3);
582         
583         static const u8 dir_to_tile[4 * 8] =
584         {
585                 // 0  +X  +Y  +Z   0  -Z  -Y  -X
586                    0,  2,  0,  4,  0,  5,  1,  3,  // facedir = 0
587                    0,  4,  0,  3,  0,  2,  1,  5,  // facedir = 1
588                    0,  3,  0,  5,  0,  4,  1,  2,  // facedir = 2
589                    0,  5,  0,  2,  0,  3,  1,  4,  // facedir = 3
590         };
591         u8 tileindex = dir_to_tile[facedir*8 + dir_i];
592         return getNodeTileN(mn, p, tileindex, data);
593 }
594
595 static void getTileInfo(
596                 // Input:
597                 MeshMakeData *data,
598                 v3s16 p,
599                 v3s16 face_dir,
600                 // Output:
601                 bool &makes_face,
602                 v3s16 &p_corrected,
603                 v3s16 &face_dir_corrected,
604                 u16 *lights,
605                 TileSpec &tile
606         )
607 {
608         VoxelManipulator &vmanip = data->m_vmanip;
609         INodeDefManager *ndef = data->m_gamedef->ndef();
610         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
611
612         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
613         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
614         TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
615         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
616         
617         // This is hackish
618         bool equivalent = false;
619         u8 mf = face_contents(n0.getContent(), n1.getContent(),
620                         &equivalent, ndef);
621
622         if(mf == 0)
623         {
624                 makes_face = false;
625                 return;
626         }
627
628         makes_face = true;
629         
630         if(mf == 1)
631         {
632                 tile = tile0;
633                 p_corrected = p;
634                 face_dir_corrected = face_dir;
635         }
636         else
637         {
638                 tile = tile1;
639                 p_corrected = p + face_dir;
640                 face_dir_corrected = -face_dir;
641         }
642         
643         // eg. water and glass
644         if(equivalent)
645                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
646         
647         if(data->m_smooth_lighting == false)
648         {
649                 lights[0] = lights[1] = lights[2] = lights[3] =
650                                 getFaceLight(n0, n1, face_dir, data);
651         }
652         else
653         {
654                 v3s16 vertex_dirs[4];
655                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
656                 for(u16 i=0; i<4; i++)
657                 {
658                         lights[i] = getSmoothLight(
659                                         blockpos_nodes + p_corrected,
660                                         vertex_dirs[i], data);
661                 }
662         }
663         
664         return;
665 }
666
667 /*
668         startpos:
669         translate_dir: unit vector with only one of x, y or z
670         face_dir: unit vector with only one of x, y or z
671 */
672 static void updateFastFaceRow(
673                 MeshMakeData *data,
674                 v3s16 startpos,
675                 v3s16 translate_dir,
676                 v3f translate_dir_f,
677                 v3s16 face_dir,
678                 v3f face_dir_f,
679                 core::array<FastFace> &dest)
680 {
681         v3s16 p = startpos;
682         
683         u16 continuous_tiles_count = 0;
684         
685         bool makes_face = false;
686         v3s16 p_corrected;
687         v3s16 face_dir_corrected;
688         u16 lights[4] = {0,0,0,0};
689         TileSpec tile;
690         getTileInfo(data, p, face_dir, 
691                         makes_face, p_corrected, face_dir_corrected,
692                         lights, tile);
693
694         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
695         {
696                 // If tiling can be done, this is set to false in the next step
697                 bool next_is_different = true;
698                 
699                 v3s16 p_next;
700                 
701                 bool next_makes_face = false;
702                 v3s16 next_p_corrected;
703                 v3s16 next_face_dir_corrected;
704                 u16 next_lights[4] = {0,0,0,0};
705                 TileSpec next_tile;
706                 
707                 // If at last position, there is nothing to compare to and
708                 // the face must be drawn anyway
709                 if(j != MAP_BLOCKSIZE - 1)
710                 {
711                         p_next = p + translate_dir;
712                         
713                         getTileInfo(data, p_next, face_dir,
714                                         next_makes_face, next_p_corrected,
715                                         next_face_dir_corrected, next_lights,
716                                         next_tile);
717                         
718                         if(next_makes_face == makes_face
719                                         && next_p_corrected == p_corrected + translate_dir
720                                         && next_face_dir_corrected == face_dir_corrected
721                                         && next_lights[0] == lights[0]
722                                         && next_lights[1] == lights[1]
723                                         && next_lights[2] == lights[2]
724                                         && next_lights[3] == lights[3]
725                                         && next_tile == tile)
726                         {
727                                 next_is_different = false;
728                         }
729                         else{
730                                 /*if(makes_face){
731                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
732                                                         next_makes_face != makes_face ? 1 : 0);
733                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
734                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
735                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
736                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
737                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
738                                                         (next_lights[0] != lights[0] ||
739                                                         next_lights[0] != lights[0] ||
740                                                         next_lights[0] != lights[0] ||
741                                                         next_lights[0] != lights[0]) ? 1 : 0);
742                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
743                                                         !(next_tile == tile) ? 1 : 0);
744                                 }*/
745                         }
746                         /*g_profiler->add("Meshgen: Total faces checked", 1);
747                         if(makes_face)
748                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
749                 } else {
750                         /*if(makes_face)
751                                 g_profiler->add("Meshgen: diff: last position", 1);*/
752                 }
753
754                 continuous_tiles_count++;
755                 
756                 // This is set to true if the texture doesn't allow more tiling
757                 bool end_of_texture = false;
758                 /*
759                         If there is no texture, it can be tiled infinitely.
760                         If tiled==0, it means the texture can be tiled infinitely.
761                         Otherwise check tiled agains continuous_tiles_count.
762                 */
763                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
764                 {
765                         if(tile.texture.tiled <= continuous_tiles_count)
766                                 end_of_texture = true;
767                 }
768                 
769                 // Do this to disable tiling textures
770                 //end_of_texture = true; //DEBUG
771                 
772                 if(next_is_different || end_of_texture)
773                 {
774                         /*
775                                 Create a face if there should be one
776                         */
777                         if(makes_face)
778                         {
779                                 // Floating point conversion of the position vector
780                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
781                                 // Center point of face (kind of)
782                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
783                                 if(continuous_tiles_count != 1)
784                                         sp += translate_dir_f;
785                                 v3f scale(1,1,1);
786
787                                 if(translate_dir.X != 0)
788                                 {
789                                         scale.X = continuous_tiles_count;
790                                 }
791                                 if(translate_dir.Y != 0)
792                                 {
793                                         scale.Y = continuous_tiles_count;
794                                 }
795                                 if(translate_dir.Z != 0)
796                                 {
797                                         scale.Z = continuous_tiles_count;
798                                 }
799                                 
800                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
801                                                 sp, face_dir_corrected, scale,
802                                                 dest);
803                                 
804                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
805                                 for(int i=1; i<continuous_tiles_count; i++){
806                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
807                                 }
808                         }
809
810                         continuous_tiles_count = 0;
811                         
812                         makes_face = next_makes_face;
813                         p_corrected = next_p_corrected;
814                         face_dir_corrected = next_face_dir_corrected;
815                         lights[0] = next_lights[0];
816                         lights[1] = next_lights[1];
817                         lights[2] = next_lights[2];
818                         lights[3] = next_lights[3];
819                         tile = next_tile;
820                 }
821                 
822                 p = p_next;
823         }
824 }
825
826 static void updateAllFastFaceRows(MeshMakeData *data,
827                 core::array<FastFace> &dest)
828 {
829         /*
830                 Go through every y,z and get top(y+) faces in rows of x+
831         */
832         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
833                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
834                         updateFastFaceRow(data,
835                                         v3s16(0,y,z),
836                                         v3s16(1,0,0), //dir
837                                         v3f  (1,0,0),
838                                         v3s16(0,1,0), //face dir
839                                         v3f  (0,1,0),
840                                         dest);
841                 }
842         }
843
844         /*
845                 Go through every x,y and get right(x+) faces in rows of z+
846         */
847         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
848                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
849                         updateFastFaceRow(data,
850                                         v3s16(x,y,0),
851                                         v3s16(0,0,1), //dir
852                                         v3f  (0,0,1),
853                                         v3s16(1,0,0), //face dir
854                                         v3f  (1,0,0),
855                                         dest);
856                 }
857         }
858
859         /*
860                 Go through every y,z and get back(z+) faces in rows of x+
861         */
862         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
863                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
864                         updateFastFaceRow(data,
865                                         v3s16(0,y,z),
866                                         v3s16(1,0,0), //dir
867                                         v3f  (1,0,0),
868                                         v3s16(0,0,1), //face dir
869                                         v3f  (0,0,1),
870                                         dest);
871                 }
872         }
873 }
874
875 /*
876         MapBlockMesh
877 */
878
879 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
880         m_mesh(new scene::SMesh()),
881         m_gamedef(data->m_gamedef),
882         m_animation_force_timer(0), // force initial animation
883         m_last_crack(-1),
884         m_crack_materials(),
885         m_last_daynight_ratio((u32) -1),
886         m_daynight_diffs()
887 {
888         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
889         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
890         //TimeTaker timer1("MapBlockMesh()");
891
892         core::array<FastFace> fastfaces_new;
893
894         /*
895                 We are including the faces of the trailing edges of the block.
896                 This means that when something changes, the caller must
897                 also update the meshes of the blocks at the leading edges.
898
899                 NOTE: This is the slowest part of this method.
900         */
901         {
902                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
903                 //TimeTaker timer2("updateAllFastFaceRows()");
904                 updateAllFastFaceRows(data, fastfaces_new);
905         }
906         // End of slow part
907
908         /*
909                 Convert FastFaces to MeshCollector
910         */
911
912         MeshCollector collector;
913
914         {
915                 // avg 0ms (100ms spikes when loading textures the first time)
916                 // (NOTE: probably outdated)
917                 //TimeTaker timer2("MeshCollector building");
918
919                 for(u32 i=0; i<fastfaces_new.size(); i++)
920                 {
921                         FastFace &f = fastfaces_new[i];
922
923                         const u16 indices[] = {0,1,2,2,3,0};
924                         const u16 indices_alternate[] = {0,1,3,2,3,1};
925                         
926                         if(f.tile.texture.atlas == NULL)
927                                 continue;
928
929                         const u16 *indices_p = indices;
930                         
931                         /*
932                                 Revert triangles for nicer looking gradient if vertices
933                                 1 and 3 have same color or 0 and 2 have different color.
934                                 getRed() is the day color.
935                         */
936                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
937                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
938                                 indices_p = indices_alternate;
939                         
940                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
941                 }
942         }
943
944         /*
945                 Add special graphics:
946                 - torches
947                 - flowing water
948                 - fences
949                 - whatever
950         */
951
952         mapblock_mesh_generate_special(data, collector);
953         
954
955         /*
956                 Convert MeshCollector to SMesh
957                 Also store animation info
958         */
959         for(u32 i = 0; i < collector.prebuffers.size(); i++)
960         {
961                 PreMeshBuffer &p = collector.prebuffers[i];
962                 /*dstream<<"p.vertices.size()="<<p.vertices.size()
963                                 <<", p.indices.size()="<<p.indices.size()
964                                 <<std::endl;*/
965
966                 // Generate animation data
967                 // - Cracks
968                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
969                 {
970                         ITextureSource *tsrc = data->m_gamedef->tsrc();
971                         std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
972                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
973                                 crack_basename += "^[cracko";
974                         else
975                                 crack_basename += "^[crack";
976                         m_crack_materials.insert(std::make_pair(i, crack_basename));
977                 }
978                 // - Lighting
979                 for(u32 j = 0; j < p.vertices.size(); j++)
980                 {
981                         video::SColor &vc = p.vertices[j].Color;
982                         u8 day = vc.getRed();
983                         u8 night = vc.getGreen();
984                         finalColorBlend(vc, day, night, 1000);
985                         if(day != night)
986                                 m_daynight_diffs[i][j] = std::make_pair(day, night);
987                 }
988
989
990                 // Create material
991                 video::SMaterial material;
992                 material.setFlag(video::EMF_LIGHTING, false);
993                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
994                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
995                 material.setFlag(video::EMF_FOG_ENABLE, true);
996                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
997                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
998                 material.MaterialType
999                                 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1000                 material.setTexture(0, p.tile.texture.atlas);
1001                 p.tile.applyMaterialOptions(material);
1002
1003                 // Create meshbuffer
1004
1005                 // This is a "Standard MeshBuffer",
1006                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1007                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1008                 // Set material
1009                 buf->Material = material;
1010                 // Add to mesh
1011                 m_mesh->addMeshBuffer(buf);
1012                 // Mesh grabbed it
1013                 buf->drop();
1014                 buf->append(p.vertices.pointer(), p.vertices.size(),
1015                                 p.indices.pointer(), p.indices.size());
1016         }
1017
1018         /*
1019                 Do some stuff to the mesh
1020         */
1021
1022         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1023         m_mesh->recalculateBoundingBox(); // translateMesh already does this
1024
1025         if(m_mesh)
1026         {
1027 #if 0
1028                 // Usually 1-700 faces and 1-7 materials
1029                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1030                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1031                                 <<" materials (meshbuffers)"<<std::endl;
1032 #endif
1033
1034                 // Use VBO for mesh (this just would set this for ever buffer)
1035                 // This will lead to infinite memory usage because or irrlicht.
1036                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1037
1038                 /*
1039                         NOTE: If that is enabled, some kind of a queue to the main
1040                         thread should be made which would call irrlicht to delete
1041                         the hardware buffer and then delete the mesh
1042                 */
1043         }
1044         
1045         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1046
1047         // Check if animation is required for this mesh
1048         m_has_animation =
1049                 !m_crack_materials.empty() ||
1050                 !m_daynight_diffs.empty();
1051 }
1052
1053 MapBlockMesh::~MapBlockMesh()
1054 {
1055         m_mesh->drop();
1056         m_mesh = NULL;
1057 }
1058
1059 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1060 {
1061         if(!m_has_animation)
1062         {
1063                 m_animation_force_timer = 100000;
1064                 return false;
1065         }
1066
1067         m_animation_force_timer = myrand_range(5, 100);
1068
1069         // Cracks
1070         if(crack != m_last_crack)
1071         {
1072                 for(std::map<u32, std::string>::iterator
1073                                 i = m_crack_materials.begin();
1074                                 i != m_crack_materials.end(); i++)
1075                 {
1076                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1077                         std::string basename = i->second;
1078
1079                         // Create new texture name from original
1080                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1081                         std::ostringstream os;
1082                         os<<basename<<crack;
1083                         AtlasPointer ap = tsrc->getTexture(os.str());
1084                         buf->getMaterial().setTexture(0, ap.atlas);
1085                 }
1086
1087                 m_last_crack = crack;
1088         }
1089
1090         // Day-night transition
1091         if(daynight_ratio != m_last_daynight_ratio)
1092         {
1093                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1094                                 i = m_daynight_diffs.begin();
1095                                 i != m_daynight_diffs.end(); i++)
1096                 {
1097                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1098                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1099                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1100                                         j = i->second.begin();
1101                                         j != i->second.end(); j++)
1102                         {
1103                                 u32 vertexIndex = j->first;
1104                                 u8 day = j->second.first;
1105                                 u8 night = j->second.second;
1106                                 finalColorBlend(vertices[vertexIndex].Color,
1107                                                 day, night, daynight_ratio);
1108                         }
1109                 }
1110                 m_last_daynight_ratio = daynight_ratio;
1111         }
1112
1113         return true;
1114 }
1115
1116 /*
1117         MeshCollector
1118 */
1119
1120 void MeshCollector::append(const TileSpec &tile,
1121                 const video::S3DVertex *vertices, u32 numVertices,
1122                 const u16 *indices, u32 numIndices)
1123 {
1124         PreMeshBuffer *p = NULL;
1125         for(u32 i=0; i<prebuffers.size(); i++)
1126         {
1127                 PreMeshBuffer &pp = prebuffers[i];
1128                 if(pp.tile != tile)
1129                         continue;
1130
1131                 p = &pp;
1132                 break;
1133         }
1134
1135         if(p == NULL)
1136         {
1137                 PreMeshBuffer pp;
1138                 pp.tile = tile;
1139                 prebuffers.push_back(pp);
1140                 p = &prebuffers[prebuffers.size()-1];
1141         }
1142
1143         u32 vertex_count = p->vertices.size();
1144         for(u32 i=0; i<numIndices; i++)
1145         {
1146                 u32 j = indices[i] + vertex_count;
1147                 if(j > 65535)
1148                 {
1149                         dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
1150                         // NOTE: Fix is to just add an another MeshBuffer
1151                 }
1152                 p->indices.push_back(j);
1153         }
1154         for(u32 i=0; i<numVertices; i++)
1155         {
1156                 p->vertices.push_back(vertices[i]);
1157         }
1158 }