more reorganizing of map code
[oweals/minetest.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_settings and g_texturesource
25 #include "content_mapblock.h"
26
27 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
28 {
29         m_daynight_ratio = daynight_ratio;
30         m_blockpos = block->getPos();
31
32         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
33         
34         /*
35                 There is no harm not copying the TempMods of the neighbors
36                 because they are already copied to this block
37         */
38         m_temp_mods.clear();
39         block->copyTempMods(m_temp_mods);
40         
41         /*
42                 Copy data
43         */
44
45         // Allocate this block + neighbors
46         m_vmanip.clear();
47         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
48                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
49
50         {
51                 //TimeTaker timer("copy central block data");
52                 // 0ms
53
54                 // Copy our data
55                 block->copyTo(m_vmanip);
56         }
57         {
58                 //TimeTaker timer("copy neighbor block data");
59                 // 0ms
60
61                 /*
62                         Copy neighbors. This is lightning fast.
63                         Copying only the borders would be *very* slow.
64                 */
65                 
66                 // Get map
67                 Map *map = block->getParent();
68
69                 for(u16 i=0; i<6; i++)
70                 {
71                         const v3s16 &dir = g_6dirs[i];
72                         v3s16 bp = m_blockpos + dir;
73                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
74                         if(b)
75                                 b->copyTo(m_vmanip);
76                 }
77         }
78 }
79
80 /*
81         vertex_dirs: v3s16[4]
82 */
83 void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
84 {
85         /*
86                 If looked from outside the node towards the face, the corners are:
87                 0: bottom-right
88                 1: bottom-left
89                 2: top-left
90                 3: top-right
91         */
92         if(dir == v3s16(0,0,1))
93         {
94                 // If looking towards z+, this is the face that is behind
95                 // the center point, facing towards z+.
96                 vertex_dirs[0] = v3s16(-1,-1, 1);
97                 vertex_dirs[1] = v3s16( 1,-1, 1);
98                 vertex_dirs[2] = v3s16( 1, 1, 1);
99                 vertex_dirs[3] = v3s16(-1, 1, 1);
100         }
101         else if(dir == v3s16(0,0,-1))
102         {
103                 // faces towards Z-
104                 vertex_dirs[0] = v3s16( 1,-1,-1);
105                 vertex_dirs[1] = v3s16(-1,-1,-1);
106                 vertex_dirs[2] = v3s16(-1, 1,-1);
107                 vertex_dirs[3] = v3s16( 1, 1,-1);
108         }
109         else if(dir == v3s16(1,0,0))
110         {
111                 // faces towards X+
112                 vertex_dirs[0] = v3s16( 1,-1, 1);
113                 vertex_dirs[1] = v3s16( 1,-1,-1);
114                 vertex_dirs[2] = v3s16( 1, 1,-1);
115                 vertex_dirs[3] = v3s16( 1, 1, 1);
116         }
117         else if(dir == v3s16(-1,0,0))
118         {
119                 // faces towards X-
120                 vertex_dirs[0] = v3s16(-1,-1,-1);
121                 vertex_dirs[1] = v3s16(-1,-1, 1);
122                 vertex_dirs[2] = v3s16(-1, 1, 1);
123                 vertex_dirs[3] = v3s16(-1, 1,-1);
124         }
125         else if(dir == v3s16(0,1,0))
126         {
127                 // faces towards Y+ (assume Z- as "down" in texture)
128                 vertex_dirs[0] = v3s16( 1, 1,-1);
129                 vertex_dirs[1] = v3s16(-1, 1,-1);
130                 vertex_dirs[2] = v3s16(-1, 1, 1);
131                 vertex_dirs[3] = v3s16( 1, 1, 1);
132         }
133         else if(dir == v3s16(0,-1,0))
134         {
135                 // faces towards Y- (assume Z+ as "down" in texture)
136                 vertex_dirs[0] = v3s16( 1,-1, 1);
137                 vertex_dirs[1] = v3s16(-1,-1, 1);
138                 vertex_dirs[2] = v3s16(-1,-1,-1);
139                 vertex_dirs[3] = v3s16( 1,-1,-1);
140         }
141 }
142
143 inline video::SColor lightColor(u8 alpha, u8 light)
144 {
145         return video::SColor(alpha,light,light,light);
146 }
147
148 struct FastFace
149 {
150         TileSpec tile;
151         video::S3DVertex vertices[4]; // Precalculated vertices
152 };
153
154 void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
155                 v3s16 dir, v3f scale, v3f posRelative_f,
156                 core::array<FastFace> &dest)
157 {
158         FastFace face;
159         
160         // Position is at the center of the cube.
161         v3f pos = p * BS;
162         posRelative_f *= BS;
163
164         v3f vertex_pos[4];
165         v3s16 vertex_dirs[4];
166         getNodeVertexDirs(dir, vertex_dirs);
167         for(u16 i=0; i<4; i++)
168         {
169                 vertex_pos[i] = v3f(
170                                 BS/2*vertex_dirs[i].X,
171                                 BS/2*vertex_dirs[i].Y,
172                                 BS/2*vertex_dirs[i].Z
173                 );
174         }
175
176         for(u16 i=0; i<4; i++)
177         {
178                 vertex_pos[i].X *= scale.X;
179                 vertex_pos[i].Y *= scale.Y;
180                 vertex_pos[i].Z *= scale.Z;
181                 vertex_pos[i] += pos + posRelative_f;
182         }
183
184         f32 abs_scale = 1.;
185         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
186         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
187         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
188
189         v3f zerovector = v3f(0,0,0);
190         
191         u8 alpha = tile.alpha;
192         /*u8 alpha = 255;
193         if(tile.id == TILE_WATER)
194                 alpha = WATER_ALPHA;*/
195
196         float x0 = tile.texture.pos.X;
197         float y0 = tile.texture.pos.Y;
198         float w = tile.texture.size.X;
199         float h = tile.texture.size.Y;
200
201         /*video::SColor c = lightColor(alpha, li);
202
203         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
204                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
205         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
206                         core::vector2d<f32>(x0, y0+h));
207         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
208                         core::vector2d<f32>(x0, y0));
209         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
210                         core::vector2d<f32>(x0+w*abs_scale, y0));*/
211
212         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
213                         lightColor(alpha, li0),
214                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
215         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
216                         lightColor(alpha, li1),
217                         core::vector2d<f32>(x0, y0+h));
218         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
219                         lightColor(alpha, li2),
220                         core::vector2d<f32>(x0, y0));
221         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
222                         lightColor(alpha, li3),
223                         core::vector2d<f32>(x0+w*abs_scale, y0));
224
225         face.tile = tile;
226         //DEBUG
227         //f->tile = TILE_STONE;
228         
229         dest.push_back(face);
230 }
231         
232 /*
233         Gets node tile from any place relative to block.
234         Returns TILE_NODE if doesn't exist or should not be drawn.
235 */
236 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
237                 NodeModMap &temp_mods)
238 {
239         TileSpec spec;
240         spec = mn.getTile(face_dir);
241         
242         /*
243                 Check temporary modifications on this node
244         */
245         /*core::map<v3s16, NodeMod>::Node *n;
246         n = m_temp_mods.find(p);
247         // If modified
248         if(n != NULL)
249         {
250                 struct NodeMod mod = n->getValue();*/
251         NodeMod mod;
252         if(temp_mods.get(p, &mod))
253         {
254                 if(mod.type == NODEMOD_CHANGECONTENT)
255                 {
256                         MapNode mn2(mod.param);
257                         spec = mn2.getTile(face_dir);
258                 }
259                 if(mod.type == NODEMOD_CRACK)
260                 {
261                         /*
262                                 Get texture id, translate it to name, append stuff to
263                                 name, get texture id
264                         */
265
266                         // Get original texture name
267                         u32 orig_id = spec.texture.id;
268                         std::string orig_name = g_texturesource->getTextureName(orig_id);
269
270                         // Create new texture name
271                         std::ostringstream os;
272                         os<<orig_name<<"^[crack"<<mod.param;
273
274                         // Get new texture
275                         u32 new_id = g_texturesource->getTextureId(os.str());
276                         
277                         /*dstream<<"MapBlock::getNodeTile(): Switching from "
278                                         <<orig_name<<" to "<<os.str()<<" ("
279                                         <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
280                         
281                         spec.texture = g_texturesource->getTexture(new_id);
282                 }
283         }
284         
285         return spec;
286 }
287
288 u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
289 {
290         /*
291                 Check temporary modifications on this node
292         */
293         /*core::map<v3s16, NodeMod>::Node *n;
294         n = m_temp_mods.find(p);
295         // If modified
296         if(n != NULL)
297         {
298                 struct NodeMod mod = n->getValue();*/
299         NodeMod mod;
300         if(temp_mods.get(p, &mod))
301         {
302                 if(mod.type == NODEMOD_CHANGECONTENT)
303                 {
304                         // Overrides content
305                         return mod.param;
306                 }
307                 if(mod.type == NODEMOD_CRACK)
308                 {
309                         /*
310                                 Content doesn't change.
311                                 
312                                 face_contents works just like it should, because
313                                 there should not be faces between differently cracked
314                                 nodes.
315
316                                 If a semi-transparent node is cracked in front an
317                                 another one, it really doesn't matter whether there
318                                 is a cracked face drawn in between or not.
319                         */
320                 }
321         }
322
323         return mn.d;
324 }
325
326 v3s16 dirs8[8] = {
327         v3s16(0,0,0),
328         v3s16(0,0,1),
329         v3s16(0,1,0),
330         v3s16(0,1,1),
331         v3s16(1,0,0),
332         v3s16(1,1,0),
333         v3s16(1,0,1),
334         v3s16(1,1,1),
335 };
336
337 // Calculate lighting at the XYZ- corner of p
338 u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
339 {
340         u16 ambient_occlusion = 0;
341         u16 light = 0;
342         u16 light_count = 0;
343         for(u32 i=0; i<8; i++)
344         {
345                 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
346                 if(content_features(n.d).param_type == CPT_LIGHT
347                                 // Fast-style leaves look better this way
348                                 && content_features(n.d).solidness != 2)
349                 {
350                         light += decode_light(n.getLightBlend(daynight_ratio));
351                         light_count++;
352                 }
353                 else
354                 {
355                         if(n.d != CONTENT_IGNORE)
356                                 ambient_occlusion++;
357                 }
358         }
359
360         if(light_count == 0)
361                 return 255;
362         
363         light /= light_count;
364
365         if(ambient_occlusion > 4)
366         {
367                 ambient_occlusion -= 4;
368                 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
369         }
370
371         return light;
372 }
373
374 // Calculate lighting at the given corner of p
375 u8 getSmoothLight(v3s16 p, v3s16 corner,
376                 VoxelManipulator &vmanip, u32 daynight_ratio)
377 {
378         if(corner.X == 1) p.X += 1;
379         else              assert(corner.X == -1);
380         if(corner.Y == 1) p.Y += 1;
381         else              assert(corner.Y == -1);
382         if(corner.Z == 1) p.Z += 1;
383         else              assert(corner.Z == -1);
384         
385         return getSmoothLight(p, vmanip, daynight_ratio);
386 }
387
388 void getTileInfo(
389                 // Input:
390                 v3s16 blockpos_nodes,
391                 v3s16 p,
392                 v3s16 face_dir,
393                 u32 daynight_ratio,
394                 VoxelManipulator &vmanip,
395                 NodeModMap &temp_mods,
396                 bool smooth_lighting,
397                 // Output:
398                 bool &makes_face,
399                 v3s16 &p_corrected,
400                 v3s16 &face_dir_corrected,
401                 u8 *lights,
402                 TileSpec &tile
403         )
404 {
405         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
406         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
407         TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
408         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
409         
410         // This is hackish
411         u8 content0 = getNodeContent(p, n0, temp_mods);
412         u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
413         u8 mf = face_contents(content0, content1);
414
415         if(mf == 0)
416         {
417                 makes_face = false;
418                 return;
419         }
420
421         makes_face = true;
422         
423         if(mf == 1)
424         {
425                 tile = tile0;
426                 p_corrected = p;
427                 face_dir_corrected = face_dir;
428         }
429         else
430         {
431                 tile = tile1;
432                 p_corrected = p + face_dir;
433                 face_dir_corrected = -face_dir;
434         }
435         
436         if(smooth_lighting == false)
437         {
438                 lights[0] = lights[1] = lights[2] = lights[3] =
439                                 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
440         }
441         else
442         {
443                 v3s16 vertex_dirs[4];
444                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
445                 for(u16 i=0; i<4; i++)
446                 {
447                         lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
448                                         vertex_dirs[i], vmanip, daynight_ratio);
449                 }
450         }
451         
452         return;
453 }
454
455 /*
456         startpos:
457         translate_dir: unit vector with only one of x, y or z
458         face_dir: unit vector with only one of x, y or z
459 */
460 void updateFastFaceRow(
461                 u32 daynight_ratio,
462                 v3f posRelative_f,
463                 v3s16 startpos,
464                 u16 length,
465                 v3s16 translate_dir,
466                 v3f translate_dir_f,
467                 v3s16 face_dir,
468                 v3f face_dir_f,
469                 core::array<FastFace> &dest,
470                 NodeModMap &temp_mods,
471                 VoxelManipulator &vmanip,
472                 v3s16 blockpos_nodes,
473                 bool smooth_lighting)
474 {
475         v3s16 p = startpos;
476         
477         u16 continuous_tiles_count = 0;
478         
479         bool makes_face;
480         v3s16 p_corrected;
481         v3s16 face_dir_corrected;
482         u8 lights[4];
483         TileSpec tile;
484         getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
485                         vmanip, temp_mods, smooth_lighting,
486                         makes_face, p_corrected, face_dir_corrected, lights, tile);
487
488         for(u16 j=0; j<length; j++)
489         {
490                 // If tiling can be done, this is set to false in the next step
491                 bool next_is_different = true;
492                 
493                 v3s16 p_next;
494                 
495                 bool next_makes_face = false;
496                 v3s16 next_p_corrected;
497                 v3s16 next_face_dir_corrected;
498                 u8 next_lights[4] = {0,0,0,0};
499                 TileSpec next_tile;
500                 
501                 // If at last position, there is nothing to compare to and
502                 // the face must be drawn anyway
503                 if(j != length - 1)
504                 {
505                         p_next = p + translate_dir;
506                         
507                         getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
508                                         vmanip, temp_mods, smooth_lighting,
509                                         next_makes_face, next_p_corrected,
510                                         next_face_dir_corrected, next_lights,
511                                         next_tile);
512                         
513                         if(next_makes_face == makes_face
514                                         && next_p_corrected == p_corrected
515                                         && next_face_dir_corrected == face_dir_corrected
516                                         && next_lights[0] == lights[0]
517                                         && next_lights[1] == lights[1]
518                                         && next_lights[2] == lights[2]
519                                         && next_lights[3] == lights[3]
520                                         && next_tile == tile)
521                         {
522                                 next_is_different = false;
523                         }
524                 }
525
526                 continuous_tiles_count++;
527                 
528                 // This is set to true if the texture doesn't allow more tiling
529                 bool end_of_texture = false;
530                 /*
531                         If there is no texture, it can be tiled infinitely.
532                         If tiled==0, it means the texture can be tiled infinitely.
533                         Otherwise check tiled agains continuous_tiles_count.
534                 */
535                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
536                 {
537                         if(tile.texture.tiled <= continuous_tiles_count)
538                                 end_of_texture = true;
539                 }
540                 
541                 // Do this to disable tiling textures
542                 //end_of_texture = true; //DEBUG
543                 
544                 if(next_is_different || end_of_texture)
545                 {
546                         /*
547                                 Create a face if there should be one
548                         */
549                         if(makes_face)
550                         {
551                                 // Floating point conversion of the position vector
552                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
553                                 // Center point of face (kind of)
554                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
555                                 v3f scale(1,1,1);
556
557                                 if(translate_dir.X != 0)
558                                 {
559                                         scale.X = continuous_tiles_count;
560                                 }
561                                 if(translate_dir.Y != 0)
562                                 {
563                                         scale.Y = continuous_tiles_count;
564                                 }
565                                 if(translate_dir.Z != 0)
566                                 {
567                                         scale.Z = continuous_tiles_count;
568                                 }
569                                 
570                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
571                                                 sp, face_dir_corrected, scale,
572                                                 posRelative_f, dest);
573                         }
574
575                         continuous_tiles_count = 0;
576                         
577                         makes_face = next_makes_face;
578                         p_corrected = next_p_corrected;
579                         face_dir_corrected = next_face_dir_corrected;
580                         lights[0] = next_lights[0];
581                         lights[1] = next_lights[1];
582                         lights[2] = next_lights[2];
583                         lights[3] = next_lights[3];
584                         tile = next_tile;
585                 }
586                 
587                 p = p_next;
588         }
589 }
590
591 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
592 {
593         // 4-21ms for MAP_BLOCKSIZE=16
594         // 24-155ms for MAP_BLOCKSIZE=32
595         //TimeTaker timer1("makeMapBlockMesh()");
596
597         core::array<FastFace> fastfaces_new;
598
599         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
600         
601         // floating point conversion
602         v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
603         
604         /*
605                 Some settings
606         */
607         //bool new_style_water = g_settings.getBool("new_style_water");
608         //bool new_style_leaves = g_settings.getBool("new_style_leaves");
609         bool smooth_lighting = g_settings.getBool("smooth_lighting");
610         
611         /*
612                 We are including the faces of the trailing edges of the block.
613                 This means that when something changes, the caller must
614                 also update the meshes of the blocks at the leading edges.
615
616                 NOTE: This is the slowest part of this method.
617         */
618         
619         {
620                 // 4-23ms for MAP_BLOCKSIZE=16
621                 //TimeTaker timer2("updateMesh() collect");
622
623                 /*
624                         Go through every y,z and get top(y+) faces in rows of x+
625                 */
626                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
627                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
628                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
629                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
630                                                 v3s16(1,0,0), //dir
631                                                 v3f  (1,0,0),
632                                                 v3s16(0,1,0), //face dir
633                                                 v3f  (0,1,0),
634                                                 fastfaces_new,
635                                                 data->m_temp_mods,
636                                                 data->m_vmanip,
637                                                 blockpos_nodes,
638                                                 smooth_lighting);
639                         }
640                 }
641                 /*
642                         Go through every x,y and get right(x+) faces in rows of z+
643                 */
644                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
645                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
646                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
647                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
648                                                 v3s16(0,0,1),
649                                                 v3f  (0,0,1),
650                                                 v3s16(1,0,0),
651                                                 v3f  (1,0,0),
652                                                 fastfaces_new,
653                                                 data->m_temp_mods,
654                                                 data->m_vmanip,
655                                                 blockpos_nodes,
656                                                 smooth_lighting);
657                         }
658                 }
659                 /*
660                         Go through every y,z and get back(z+) faces in rows of x+
661                 */
662                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
663                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
664                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
665                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
666                                                 v3s16(1,0,0),
667                                                 v3f  (1,0,0),
668                                                 v3s16(0,0,1),
669                                                 v3f  (0,0,1),
670                                                 fastfaces_new,
671                                                 data->m_temp_mods,
672                                                 data->m_vmanip,
673                                                 blockpos_nodes,
674                                                 smooth_lighting);
675                         }
676                 }
677         }
678
679         // End of slow part
680
681         /*
682                 Convert FastFaces to SMesh
683         */
684
685         MeshCollector collector;
686
687         if(fastfaces_new.size() > 0)
688         {
689                 // avg 0ms (100ms spikes when loading textures the first time)
690                 //TimeTaker timer2("updateMesh() mesh building");
691
692                 video::SMaterial material;
693                 material.setFlag(video::EMF_LIGHTING, false);
694                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
695                 material.setFlag(video::EMF_FOG_ENABLE, true);
696                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
697                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
698
699                 for(u32 i=0; i<fastfaces_new.size(); i++)
700                 {
701                         FastFace &f = fastfaces_new[i];
702
703                         const u16 indices[] = {0,1,2,2,3,0};
704                         const u16 indices_alternate[] = {0,1,3,2,3,1};
705                         
706                         video::ITexture *texture = f.tile.texture.atlas;
707                         if(texture == NULL)
708                                 continue;
709
710                         material.setTexture(0, texture);
711                         
712                         f.tile.applyMaterialOptions(material);
713
714                         const u16 *indices_p = indices;
715                         
716                         /*
717                                 Revert triangles for nicer looking gradient if vertices
718                                 1 and 3 have same color or 0 and 2 have different color.
719                         */
720                         if(f.vertices[0].Color != f.vertices[2].Color
721                                         || f.vertices[1].Color == f.vertices[3].Color)
722                                 indices_p = indices_alternate;
723                         
724                         collector.append(material, f.vertices, 4, indices_p, 6);
725                 }
726         }
727
728         /*
729                 Add special graphics:
730                 - torches
731                 - flowing water
732                 - fences
733                 - whatever
734         */
735
736         mapblock_mesh_generate_special(data, collector);
737         
738         /*
739                 Add stuff from collector to mesh
740         */
741         
742         scene::SMesh *mesh_new = NULL;
743         mesh_new = new scene::SMesh();
744         
745         collector.fillMesh(mesh_new);
746
747         /*
748                 Do some stuff to the mesh
749         */
750
751         mesh_new->recalculateBoundingBox();
752
753         /*
754                 Delete new mesh if it is empty
755         */
756
757         if(mesh_new->getMeshBufferCount() == 0)
758         {
759                 mesh_new->drop();
760                 mesh_new = NULL;
761         }
762
763         if(mesh_new)
764         {
765 #if 0
766                 // Usually 1-700 faces and 1-7 materials
767                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
768                                 <<"and uses "<<mesh_new->getMeshBufferCount()
769                                 <<" materials (meshbuffers)"<<std::endl;
770 #endif
771
772                 // Use VBO for mesh (this just would set this for ever buffer)
773                 // This will lead to infinite memory usage because or irrlicht.
774                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
775
776                 /*
777                         NOTE: If that is enabled, some kind of a queue to the main
778                         thread should be made which would call irrlicht to delete
779                         the hardware buffer and then delete the mesh
780                 */
781         }
782
783         return mesh_new;
784         
785         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
786 }
787