]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_mapblock.cpp
fd2a30bafe14f6fc57fa668e1b4ea7e5368b04fe
[dragonfireclient.git] / src / content_mapblock.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 "content_mapblock.h"
21
22 #include "main.h" // For g_settings
23 #include "mineral.h"
24 #include "mapblock_mesh.h" // For MapBlock_LightColor()
25 #include "settings.h"
26 #include "nodedef.h"
27 #include "gamedef.h"
28
29 #ifndef SERVER
30 // Create a cuboid.
31 //  material  - the material to use (for all 6 faces)
32 //  collector - the MeshCollector for the resulting polygons
33 //  pa        - texture atlas pointer for the material
34 //  c         - vertex colour - used for all
35 //  pos       - the position of the centre of the cuboid
36 //  rz,ry,rz  - the radius of the cuboid in each dimension
37 //  txc       - texture coordinates - this is a list of texture coordinates
38 //              for the opposite corners of each face - therefore, there
39 //              should be (2+2)*6=24 values in the list. Alternatively, pass
40 //              NULL to use the entire texture for each face. The order of
41 //              the faces in the list is top-backi-right-front-left-bottom
42 //              If you specified 0,0,1,1 for each face, that would be the
43 //              same as passing NULL.
44 void makeCuboid(video::SMaterial &material, MeshCollector *collector,
45         AtlasPointer* pa, video::SColor &c,
46         v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
47 {
48         f32 tu0=pa->x0();
49         f32 tu1=pa->x1();
50         f32 tv0=pa->y0();
51         f32 tv1=pa->y1();
52         f32 txus=tu1-tu0;
53         f32 txvs=tv1-tv0;
54
55         video::S3DVertex v[4] =
56         {
57                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
58                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
59                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
60                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
61         };
62
63         for(int i=0;i<6;i++)
64         {
65                 switch(i)
66                 {
67                         case 0: // top
68                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
69                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
70                                 v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
71                                 v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
72                                 break;
73                         case 1: // back
74                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
75                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
76                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
77                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
78                                 break;
79                         case 2: //right
80                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
81                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
82                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
83                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
84                                 break;
85                         case 3: // front
86                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
87                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
88                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
89                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
90                                 break;
91                         case 4: // left
92                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
93                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
94                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
95                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
96                                 break;
97                         case 5: // bottom
98                                 v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
99                                 v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
100                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
101                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
102                                 break;
103                 }
104
105                 if(txc!=NULL)
106                 {
107                         v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
108                         v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
109                         v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
110                         v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
111                         txc+=4;
112                 }
113
114                 for(u16 i=0; i<4; i++)
115                         v[i].Pos += pos;
116                 u16 indices[] = {0,1,2,2,3,0};
117                 collector->append(material, v, 4, indices, 6);
118
119         }
120
121 }
122 #endif
123
124 #ifndef SERVER
125 void mapblock_mesh_generate_special(MeshMakeData *data,
126                 MeshCollector &collector, IGameDef *gamedef)
127 {
128         INodeDefManager *nodedef = gamedef->ndef();
129
130         // 0ms
131         //TimeTaker timer("mapblock_mesh_generate_special()");
132
133         /*
134                 Some settings
135         */
136         bool new_style_water = g_settings->getBool("new_style_water");
137         
138         float node_liquid_level = 1.0;
139         if(new_style_water)
140                 node_liquid_level = 0.85;
141         
142         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
143
144         /*// General ground material for special output
145         // Texture is modified just before usage
146         video::SMaterial material_general;
147         material_general.setFlag(video::EMF_LIGHTING, false);
148         material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
149         material_general.setFlag(video::EMF_FOG_ENABLE, true);
150         material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;*/
151
152         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
153         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
154         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
155         {
156                 v3s16 p(x,y,z);
157
158                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
159                 const ContentFeatures &f = nodedef->get(n);
160
161                 // Only solidness=0 stuff is drawn here
162                 if(f.solidness != 0)
163                         continue;
164                 
165                 switch(f.drawtype){
166                 default:
167                         infostream<<"Got "<<f.drawtype<<std::endl;
168                         assert(0);
169                         break;
170                 case NDT_AIRLIKE:
171                         break;
172                 case NDT_LIQUID:
173                 {
174                         /*
175                                 Add water sources to mesh if using new style
176                         */
177                         assert(nodedef->get(n).special_materials[0]);
178                         //assert(nodedef->get(n).special_materials[1]);
179                         assert(nodedef->get(n).special_aps[0]);
180
181                         video::SMaterial &liquid_material =
182                                         *nodedef->get(n).special_materials[0];
183                         /*video::SMaterial &liquid_material_bfculled =
184                                         *nodedef->get(n).special_materials[1];*/
185                         AtlasPointer &pa_liquid1 =
186                                         *nodedef->get(n).special_aps[0];
187
188                         bool top_is_air = false;
189                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
190                         if(n.getContent() == CONTENT_AIR)
191                                 top_is_air = true;
192                         
193                         if(top_is_air == false)
194                                 continue;
195
196                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
197                         video::SColor c = MapBlock_LightColor(
198                                         nodedef->get(n).alpha, l);
199                         
200                         video::S3DVertex vertices[4] =
201                         {
202                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
203                                                 pa_liquid1.x0(), pa_liquid1.y1()),
204                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
205                                                 pa_liquid1.x1(), pa_liquid1.y1()),
206                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
207                                                 pa_liquid1.x1(), pa_liquid1.y0()),
208                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
209                                                 pa_liquid1.x0(), pa_liquid1.y0()),
210                         };
211
212                         for(s32 i=0; i<4; i++)
213                         {
214                                 vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS;
215                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
216                         }
217
218                         u16 indices[] = {0,1,2,2,3,0};
219                         // Add to mesh collector
220                         collector.append(liquid_material, vertices, 4, indices, 6);
221                 break;}
222                 case NDT_FLOWINGLIQUID:
223                 {
224                         /*
225                                 Add flowing liquid to mesh
226                         */
227                         assert(nodedef->get(n).special_materials[0]);
228                         assert(nodedef->get(n).special_materials[1]);
229                         assert(nodedef->get(n).special_aps[0]);
230
231                         video::SMaterial &liquid_material =
232                                         *nodedef->get(n).special_materials[0];
233                         video::SMaterial &liquid_material_bfculled =
234                                         *nodedef->get(n).special_materials[1];
235                         AtlasPointer &pa_liquid1 =
236                                         *nodedef->get(n).special_aps[0];
237
238                         bool top_is_same_liquid = false;
239                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
240                         content_t c_flowing = nodedef->get(n).liquid_alternative_flowing;
241                         content_t c_source = nodedef->get(n).liquid_alternative_source;
242                         if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
243                                 top_is_same_liquid = true;
244                         
245                         u8 l = 0;
246                         // Use the light of the node on top if possible
247                         if(nodedef->get(ntop).param_type == CPT_LIGHT)
248                                 l = decode_light(ntop.getLightBlend(data->m_daynight_ratio, nodedef));
249                         // Otherwise use the light of this node (the liquid)
250                         else
251                                 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
252                         video::SColor c = MapBlock_LightColor(
253                                         nodedef->get(n).alpha, l);
254                         
255                         // Neighbor liquid levels (key = relative position)
256                         // Includes current node
257                         core::map<v3s16, f32> neighbor_levels;
258                         core::map<v3s16, content_t> neighbor_contents;
259                         core::map<v3s16, u8> neighbor_flags;
260                         const u8 neighborflag_top_is_same_liquid = 0x01;
261                         v3s16 neighbor_dirs[9] = {
262                                 v3s16(0,0,0),
263                                 v3s16(0,0,1),
264                                 v3s16(0,0,-1),
265                                 v3s16(1,0,0),
266                                 v3s16(-1,0,0),
267                                 v3s16(1,0,1),
268                                 v3s16(-1,0,-1),
269                                 v3s16(1,0,-1),
270                                 v3s16(-1,0,1),
271                         };
272                         for(u32 i=0; i<9; i++)
273                         {
274                                 content_t content = CONTENT_AIR;
275                                 float level = -0.5 * BS;
276                                 u8 flags = 0;
277                                 // Check neighbor
278                                 v3s16 p2 = p + neighbor_dirs[i];
279                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
280                                 if(n2.getContent() != CONTENT_IGNORE)
281                                 {
282                                         content = n2.getContent();
283
284                                         if(n2.getContent() == c_source)
285                                                 level = (-0.5+node_liquid_level) * BS;
286                                         else if(n2.getContent() == c_flowing)
287                                                 level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK)
288                                                                 + 0.5) / 8.0 * node_liquid_level) * BS;
289
290                                         // Check node above neighbor.
291                                         // NOTE: This doesn't get executed if neighbor
292                                         //       doesn't exist
293                                         p2.Y += 1;
294                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
295                                         if(n2.getContent() == c_source ||
296                                                         n2.getContent() == c_flowing)
297                                                 flags |= neighborflag_top_is_same_liquid;
298                                 }
299                                 
300                                 neighbor_levels.insert(neighbor_dirs[i], level);
301                                 neighbor_contents.insert(neighbor_dirs[i], content);
302                                 neighbor_flags.insert(neighbor_dirs[i], flags);
303                         }
304
305                         // Corner heights (average between four liquids)
306                         f32 corner_levels[4];
307                         
308                         v3s16 halfdirs[4] = {
309                                 v3s16(0,0,0),
310                                 v3s16(1,0,0),
311                                 v3s16(1,0,1),
312                                 v3s16(0,0,1),
313                         };
314                         for(u32 i=0; i<4; i++)
315                         {
316                                 v3s16 cornerdir = halfdirs[i];
317                                 float cornerlevel = 0;
318                                 u32 valid_count = 0;
319                                 u32 air_count = 0;
320                                 for(u32 j=0; j<4; j++)
321                                 {
322                                         v3s16 neighbordir = cornerdir - halfdirs[j];
323                                         content_t content = neighbor_contents[neighbordir];
324                                         // If top is liquid, draw starting from top of node
325                                         if(neighbor_flags[neighbordir] &
326                                                         neighborflag_top_is_same_liquid)
327                                         {
328                                                 cornerlevel = 0.5*BS;
329                                                 valid_count = 1;
330                                                 break;
331                                         }
332                                         // Source is always the same height
333                                         else if(content == c_source)
334                                         {
335                                                 cornerlevel = (-0.5+node_liquid_level)*BS;
336                                                 valid_count = 1;
337                                                 break;
338                                         }
339                                         // Flowing liquid has level information
340                                         else if(content == c_flowing)
341                                         {
342                                                 cornerlevel += neighbor_levels[neighbordir];
343                                                 valid_count++;
344                                         }
345                                         else if(content == CONTENT_AIR)
346                                         {
347                                                 air_count++;
348                                         }
349                                 }
350                                 if(air_count >= 2)
351                                         cornerlevel = -0.5*BS;
352                                 else if(valid_count > 0)
353                                         cornerlevel /= valid_count;
354                                 corner_levels[i] = cornerlevel;
355                         }
356
357                         /*
358                                 Generate sides
359                         */
360
361                         v3s16 side_dirs[4] = {
362                                 v3s16(1,0,0),
363                                 v3s16(-1,0,0),
364                                 v3s16(0,0,1),
365                                 v3s16(0,0,-1),
366                         };
367                         s16 side_corners[4][2] = {
368                                 {1, 2},
369                                 {3, 0},
370                                 {2, 3},
371                                 {0, 1},
372                         };
373                         for(u32 i=0; i<4; i++)
374                         {
375                                 v3s16 dir = side_dirs[i];
376
377                                 /*
378                                         If our topside is liquid and neighbor's topside
379                                         is liquid, don't draw side face
380                                 */
381                                 if(top_is_same_liquid &&
382                                                 neighbor_flags[dir] & neighborflag_top_is_same_liquid)
383                                         continue;
384
385                                 content_t neighbor_content = neighbor_contents[dir];
386                                 const ContentFeatures &n_feat = nodedef->get(neighbor_content);
387                                 
388                                 // Don't draw face if neighbor is blocking the view
389                                 if(n_feat.solidness == 2)
390                                         continue;
391                                 
392                                 bool neighbor_is_same_liquid = (neighbor_content == c_source
393                                                 || neighbor_content == c_flowing);
394                                 
395                                 // Don't draw any faces if neighbor same is liquid and top is
396                                 // same liquid
397                                 if(neighbor_is_same_liquid == true
398                                                 && top_is_same_liquid == false)
399                                         continue;
400
401                                 // Use backface culled material if neighbor doesn't have a
402                                 // solidness of 0
403                                 video::SMaterial *current_material = &liquid_material;
404                                 if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
405                                         current_material = &liquid_material_bfculled;
406                                 
407                                 video::S3DVertex vertices[4] =
408                                 {
409                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
410                                                         pa_liquid1.x0(), pa_liquid1.y1()),
411                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
412                                                         pa_liquid1.x1(), pa_liquid1.y1()),
413                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
414                                                         pa_liquid1.x1(), pa_liquid1.y0()),
415                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
416                                                         pa_liquid1.x0(), pa_liquid1.y0()),
417                                 };
418                                 
419                                 /*
420                                         If our topside is liquid, set upper border of face
421                                         at upper border of node
422                                 */
423                                 if(top_is_same_liquid)
424                                 {
425                                         vertices[2].Pos.Y = 0.5*BS;
426                                         vertices[3].Pos.Y = 0.5*BS;
427                                 }
428                                 /*
429                                         Otherwise upper position of face is corner levels
430                                 */
431                                 else
432                                 {
433                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
434                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
435                                 }
436                                 
437                                 /*
438                                         If neighbor is liquid, lower border of face is corner
439                                         liquid levels
440                                 */
441                                 if(neighbor_is_same_liquid)
442                                 {
443                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
444                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
445                                 }
446                                 /*
447                                         If neighbor is not liquid, lower border of face is
448                                         lower border of node
449                                 */
450                                 else
451                                 {
452                                         vertices[0].Pos.Y = -0.5*BS;
453                                         vertices[1].Pos.Y = -0.5*BS;
454                                 }
455                                 
456                                 for(s32 j=0; j<4; j++)
457                                 {
458                                         if(dir == v3s16(0,0,1))
459                                                 vertices[j].Pos.rotateXZBy(0);
460                                         if(dir == v3s16(0,0,-1))
461                                                 vertices[j].Pos.rotateXZBy(180);
462                                         if(dir == v3s16(-1,0,0))
463                                                 vertices[j].Pos.rotateXZBy(90);
464                                         if(dir == v3s16(1,0,-0))
465                                                 vertices[j].Pos.rotateXZBy(-90);
466                                                 
467                                         // Do this to not cause glitches when two liquids are
468                                         // side-by-side
469                                         /*if(neighbor_is_same_liquid == false){
470                                                 vertices[j].Pos.X *= 0.98;
471                                                 vertices[j].Pos.Z *= 0.98;
472                                         }*/
473
474                                         vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
475                                 }
476
477                                 u16 indices[] = {0,1,2,2,3,0};
478                                 // Add to mesh collector
479                                 collector.append(*current_material, vertices, 4, indices, 6);
480                         }
481                         
482                         /*
483                                 Generate top side, if appropriate
484                         */
485                         
486                         if(top_is_same_liquid == false)
487                         {
488                                 video::S3DVertex vertices[4] =
489                                 {
490                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
491                                                         pa_liquid1.x0(), pa_liquid1.y1()),
492                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
493                                                         pa_liquid1.x1(), pa_liquid1.y1()),
494                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
495                                                         pa_liquid1.x1(), pa_liquid1.y0()),
496                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
497                                                         pa_liquid1.x0(), pa_liquid1.y0()),
498                                 };
499                                 
500                                 // This fixes a strange bug
501                                 s32 corner_resolve[4] = {3,2,1,0};
502
503                                 for(s32 i=0; i<4; i++)
504                                 {
505                                         //vertices[i].Pos.Y += liquid_level;
506                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
507                                         s32 j = corner_resolve[i];
508                                         vertices[i].Pos.Y += corner_levels[j];
509                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
510                                 }
511
512                                 u16 indices[] = {0,1,2,2,3,0};
513                                 // Add to mesh collector
514                                 collector.append(liquid_material, vertices, 4, indices, 6);
515                         }
516                 break;}
517                 case NDT_GLASSLIKE:
518                 {
519                         video::SMaterial material_glass;
520                         material_glass.setFlag(video::EMF_LIGHTING, false);
521                         material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
522                         material_glass.setFlag(video::EMF_FOG_ENABLE, true);
523                         material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
524                         AtlasPointer pa_glass = f.tiles[0].texture;
525                         material_glass.setTexture(0, pa_glass.atlas);
526
527                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
528                         video::SColor c = MapBlock_LightColor(255, l);
529
530                         for(u32 j=0; j<6; j++)
531                         {
532                                 video::S3DVertex vertices[4] =
533                                 {
534                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
535                                                 pa_glass.x0(), pa_glass.y1()),
536                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
537                                                 pa_glass.x1(), pa_glass.y1()),
538                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
539                                                 pa_glass.x1(), pa_glass.y0()),
540                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
541                                                 pa_glass.x0(), pa_glass.y0()),
542                                 };
543
544                                 if(j == 0)
545                                 {
546                                         for(u16 i=0; i<4; i++)
547                                                 vertices[i].Pos.rotateXZBy(0);
548                                 }
549                                 else if(j == 1)
550                                 {
551                                         for(u16 i=0; i<4; i++)
552                                                 vertices[i].Pos.rotateXZBy(180);
553                                 }
554                                 else if(j == 2)
555                                 {
556                                         for(u16 i=0; i<4; i++)
557                                                 vertices[i].Pos.rotateXZBy(-90);
558                                 }
559                                 else if(j == 3)
560                                 {
561                                         for(u16 i=0; i<4; i++)
562                                                 vertices[i].Pos.rotateXZBy(90);
563                                 }
564                                 else if(j == 4)
565                                 {
566                                         for(u16 i=0; i<4; i++)
567                                                 vertices[i].Pos.rotateYZBy(-90);
568                                 }
569                                 else if(j == 5)
570                                 {
571                                         for(u16 i=0; i<4; i++)
572                                                 vertices[i].Pos.rotateYZBy(90);
573                                 }
574
575                                 for(u16 i=0; i<4; i++)
576                                 {
577                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
578                                 }
579
580                                 u16 indices[] = {0,1,2,2,3,0};
581                                 // Add to mesh collector
582                                 collector.append(material_glass, vertices, 4, indices, 6);
583                         }
584                 break;}
585                 case NDT_ALLFACES:
586                 {
587                         video::SMaterial material_leaves1;
588                         material_leaves1.setFlag(video::EMF_LIGHTING, false);
589                         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
590                         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
591                         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
592                         AtlasPointer pa_leaves1 = f.tiles[0].texture;
593                         material_leaves1.setTexture(0, pa_leaves1.atlas);
594
595                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
596                         video::SColor c = MapBlock_LightColor(255, l);
597
598                         for(u32 j=0; j<6; j++)
599                         {
600                                 video::S3DVertex vertices[4] =
601                                 {
602                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
603                                                 pa_leaves1.x0(), pa_leaves1.y1()),
604                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
605                                                 pa_leaves1.x1(), pa_leaves1.y1()),
606                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
607                                                 pa_leaves1.x1(), pa_leaves1.y0()),
608                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
609                                                 pa_leaves1.x0(), pa_leaves1.y0()),
610                                 };
611
612                                 if(j == 0)
613                                 {
614                                         for(u16 i=0; i<4; i++)
615                                                 vertices[i].Pos.rotateXZBy(0);
616                                 }
617                                 else if(j == 1)
618                                 {
619                                         for(u16 i=0; i<4; i++)
620                                                 vertices[i].Pos.rotateXZBy(180);
621                                 }
622                                 else if(j == 2)
623                                 {
624                                         for(u16 i=0; i<4; i++)
625                                                 vertices[i].Pos.rotateXZBy(-90);
626                                 }
627                                 else if(j == 3)
628                                 {
629                                         for(u16 i=0; i<4; i++)
630                                                 vertices[i].Pos.rotateXZBy(90);
631                                 }
632                                 else if(j == 4)
633                                 {
634                                         for(u16 i=0; i<4; i++)
635                                                 vertices[i].Pos.rotateYZBy(-90);
636                                 }
637                                 else if(j == 5)
638                                 {
639                                         for(u16 i=0; i<4; i++)
640                                                 vertices[i].Pos.rotateYZBy(90);
641                                 }
642
643                                 for(u16 i=0; i<4; i++)
644                                 {
645                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
646                                 }
647
648                                 u16 indices[] = {0,1,2,2,3,0};
649                                 // Add to mesh collector
650                                 collector.append(material_leaves1, vertices, 4, indices, 6);
651                         }
652                 break;}
653                 case NDT_ALLFACES_OPTIONAL:
654                         // This is always pre-converted to something else
655                         assert(0);
656                         break;
657                 case NDT_TORCHLIKE:
658                 {
659                         v3s16 dir = unpackDir(n.param2);
660                         
661                         AtlasPointer ap(0);
662                         if(dir == v3s16(0,-1,0)){
663                                 ap = f.tiles[0].texture; // floor
664                         } else if(dir == v3s16(0,1,0)){
665                                 ap = f.tiles[1].texture; // ceiling
666                         // For backwards compatibility
667                         } else if(dir == v3s16(0,0,0)){
668                                 ap = f.tiles[0].texture; // floor
669                         } else {
670                                 ap = f.tiles[2].texture; // side
671                         }
672
673                         // Set material
674                         video::SMaterial material;
675                         material.setFlag(video::EMF_LIGHTING, false);
676                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
677                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
678                         material.setFlag(video::EMF_FOG_ENABLE, true);
679                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
680                         material.MaterialType
681                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
682                         material.setTexture(0, ap.atlas);
683
684                         video::SColor c(255,255,255,255);
685
686                         // Wall at X+ of node
687                         video::S3DVertex vertices[4] =
688                         {
689                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
690                                                 ap.x0(), ap.y1()),
691                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
692                                                 ap.x1(), ap.y1()),
693                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
694                                                 ap.x1(), ap.y0()),
695                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
696                                                 ap.x0(), ap.y0()),
697                         };
698
699                         for(s32 i=0; i<4; i++)
700                         {
701                                 if(dir == v3s16(1,0,0))
702                                         vertices[i].Pos.rotateXZBy(0);
703                                 if(dir == v3s16(-1,0,0))
704                                         vertices[i].Pos.rotateXZBy(180);
705                                 if(dir == v3s16(0,0,1))
706                                         vertices[i].Pos.rotateXZBy(90);
707                                 if(dir == v3s16(0,0,-1))
708                                         vertices[i].Pos.rotateXZBy(-90);
709                                 if(dir == v3s16(0,-1,0))
710                                         vertices[i].Pos.rotateXZBy(45);
711                                 if(dir == v3s16(0,1,0))
712                                         vertices[i].Pos.rotateXZBy(-45);
713
714                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
715                         }
716
717                         u16 indices[] = {0,1,2,2,3,0};
718                         // Add to mesh collector
719                         collector.append(material, vertices, 4, indices, 6);
720                 break;}
721                 case NDT_SIGNLIKE:
722                 {
723                         // Set material
724                         video::SMaterial material;
725                         material.setFlag(video::EMF_LIGHTING, false);
726                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
727                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
728                         material.setFlag(video::EMF_FOG_ENABLE, true);
729                         material.MaterialType
730                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
731                         AtlasPointer ap = f.tiles[0].texture;
732                         material.setTexture(0, ap.atlas);
733
734                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
735                         video::SColor c = MapBlock_LightColor(255, l);
736                                 
737                         float d = (float)BS/16;
738                         // Wall at X+ of node
739                         video::S3DVertex vertices[4] =
740                         {
741                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
742                                                 ap.x0(), ap.y1()),
743                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
744                                                 ap.x1(), ap.y1()),
745                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
746                                                 ap.x1(), ap.y0()),
747                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
748                                                 ap.x0(), ap.y0()),
749                         };
750
751                         v3s16 dir = unpackDir(n.param2);
752
753                         for(s32 i=0; i<4; i++)
754                         {
755                                 if(dir == v3s16(1,0,0))
756                                         vertices[i].Pos.rotateXZBy(0);
757                                 if(dir == v3s16(-1,0,0))
758                                         vertices[i].Pos.rotateXZBy(180);
759                                 if(dir == v3s16(0,0,1))
760                                         vertices[i].Pos.rotateXZBy(90);
761                                 if(dir == v3s16(0,0,-1))
762                                         vertices[i].Pos.rotateXZBy(-90);
763                                 if(dir == v3s16(0,-1,0))
764                                         vertices[i].Pos.rotateXYBy(-90);
765                                 if(dir == v3s16(0,1,0))
766                                         vertices[i].Pos.rotateXYBy(90);
767
768                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
769                         }
770
771                         u16 indices[] = {0,1,2,2,3,0};
772                         // Add to mesh collector
773                         collector.append(material, vertices, 4, indices, 6);
774                 break;}
775                 case NDT_PLANTLIKE:
776                 {
777                         video::SMaterial material_papyrus;
778                         material_papyrus.setFlag(video::EMF_LIGHTING, false);
779                         material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
780                         material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
781                         material_papyrus.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
782                         AtlasPointer pa_papyrus = f.tiles[0].texture;
783                         material_papyrus.setTexture(0, pa_papyrus.atlas);
784                         
785                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
786                         video::SColor c = MapBlock_LightColor(255, l);
787
788                         for(u32 j=0; j<4; j++)
789                         {
790                                 video::S3DVertex vertices[4] =
791                                 {
792                                         video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
793                                                 pa_papyrus.x0(), pa_papyrus.y1()),
794                                         video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
795                                                 pa_papyrus.x1(), pa_papyrus.y1()),
796                                         video::S3DVertex( BS/2*f.visual_scale,
797                                                 -BS/2 + f.visual_scale*BS,0, 0,0,0, c,
798                                                 pa_papyrus.x1(), pa_papyrus.y0()),
799                                         video::S3DVertex(-BS/2*f.visual_scale,
800                                                 -BS/2 + f.visual_scale*BS,0, 0,0,0, c,
801                                                 pa_papyrus.x0(), pa_papyrus.y0()),
802                                 };
803
804                                 if(j == 0)
805                                 {
806                                         for(u16 i=0; i<4; i++)
807                                                 vertices[i].Pos.rotateXZBy(45);
808                                 }
809                                 else if(j == 1)
810                                 {
811                                         for(u16 i=0; i<4; i++)
812                                                 vertices[i].Pos.rotateXZBy(-45);
813                                 }
814                                 else if(j == 2)
815                                 {
816                                         for(u16 i=0; i<4; i++)
817                                                 vertices[i].Pos.rotateXZBy(135);
818                                 }
819                                 else if(j == 3)
820                                 {
821                                         for(u16 i=0; i<4; i++)
822                                                 vertices[i].Pos.rotateXZBy(-135);
823                                 }
824
825                                 for(u16 i=0; i<4; i++)
826                                 {
827                                         vertices[i].Pos *= f.visual_scale;
828                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
829                                 }
830
831                                 u16 indices[] = {0,1,2,2,3,0};
832                                 // Add to mesh collector
833                                 collector.append(material_papyrus, vertices, 4, indices, 6);
834                         }
835                 break;}
836                 case NDT_FENCELIKE:
837                 {
838                         video::SMaterial material_wood;
839                         material_wood.setFlag(video::EMF_LIGHTING, false);
840                         material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
841                         material_wood.setFlag(video::EMF_FOG_ENABLE, true);
842                         material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
843                         AtlasPointer pa_wood = f.tiles[0].texture;
844                         material_wood.setTexture(0, pa_wood.atlas);
845
846                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
847                         video::SColor c = MapBlock_LightColor(255, l);
848
849                         const f32 post_rad=(f32)BS/10;
850                         const f32 bar_rad=(f32)BS/20;
851                         const f32 bar_len=(f32)(BS/2)-post_rad;
852
853                         // The post - always present
854                         v3f pos = intToFloat(p+blockpos_nodes, BS);
855                         f32 postuv[24]={
856                                         0.4,0.4,0.6,0.6,
857                                         0.35,0,0.65,1,
858                                         0.35,0,0.65,1,
859                                         0.35,0,0.65,1,
860                                         0.35,0,0.65,1,
861                                         0.4,0.4,0.6,0.6};
862                         makeCuboid(material_wood, &collector,
863                                 &pa_wood, c, pos,
864                                 post_rad,BS/2,post_rad, postuv);
865
866                         // Now a section of fence, +X, if there's a post there
867                         v3s16 p2 = p;
868                         p2.X++;
869                         MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
870                         const ContentFeatures *f2 = &nodedef->get(n2);
871                         if(f2->drawtype == NDT_FENCELIKE)
872                         {
873                                 pos = intToFloat(p+blockpos_nodes, BS);
874                                 pos.X += BS/2;
875                                 pos.Y += BS/4;
876                                 f32 xrailuv[24]={
877                                         0,0.4,1,0.6,
878                                         0,0.4,1,0.6,
879                                         0,0.4,1,0.6,
880                                         0,0.4,1,0.6,
881                                         0,0.4,1,0.6,
882                                         0,0.4,1,0.6};
883                                 makeCuboid(material_wood, &collector,
884                                         &pa_wood, c, pos,
885                                         bar_len,bar_rad,bar_rad, xrailuv);
886
887                                 pos.Y -= BS/2;
888                                 makeCuboid(material_wood, &collector,
889                                         &pa_wood, c, pos,
890                                         bar_len,bar_rad,bar_rad, xrailuv);
891                         }
892
893                         // Now a section of fence, +Z, if there's a post there
894                         p2 = p;
895                         p2.Z++;
896                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
897                         f2 = &nodedef->get(n2);
898                         if(f2->drawtype == NDT_FENCELIKE)
899                         {
900                                 pos = intToFloat(p+blockpos_nodes, BS);
901                                 pos.Z += BS/2;
902                                 pos.Y += BS/4;
903                                 f32 zrailuv[24]={
904                                         0,0.4,1,0.6,
905                                         0,0.4,1,0.6,
906                                         0,0.4,1,0.6,
907                                         0,0.4,1,0.6,
908                                         0,0.4,1,0.6,
909                                         0,0.4,1,0.6};
910                                 makeCuboid(material_wood, &collector,
911                                         &pa_wood, c, pos,
912                                         bar_rad,bar_rad,bar_len, zrailuv);
913                                 pos.Y -= BS/2;
914                                 makeCuboid(material_wood, &collector,
915                                         &pa_wood, c, pos,
916                                         bar_rad,bar_rad,bar_len, zrailuv);
917
918                         }
919                 break;}
920                 case NDT_RAILLIKE:
921                 {
922                         bool is_rail_x [] = { false, false };  /* x-1, x+1 */
923                         bool is_rail_z [] = { false, false };  /* z-1, z+1 */
924
925                         MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
926                         MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
927                         MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
928                         MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
929                         
930                         content_t thiscontent = n.getContent();
931                         if(n_minus_x.getContent() == thiscontent)
932                                 is_rail_x[0] = true;
933                         if(n_plus_x.getContent() == thiscontent)
934                                 is_rail_x[1] = true;
935                         if(n_minus_z.getContent() == thiscontent)
936                                 is_rail_z[0] = true;
937                         if(n_plus_z.getContent() == thiscontent)
938                                 is_rail_z[1] = true;
939
940                         int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
941
942                         // Assign textures
943                         AtlasPointer ap = f.tiles[0].texture; // straight
944                         if(adjacencies < 2)
945                                 ap = f.tiles[0].texture; // straight
946                         else if(adjacencies == 2)
947                         {
948                                 if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
949                                         ap = f.tiles[0].texture; // straight
950                                 else
951                                         ap = f.tiles[1].texture; // curved
952                         }
953                         else if(adjacencies == 3)
954                                 ap = f.tiles[2].texture; // t-junction
955                         else if(adjacencies == 4)
956                                 ap = f.tiles[3].texture; // crossing
957                         
958                         video::SMaterial material_rail;
959                         material_rail.setFlag(video::EMF_LIGHTING, false);
960                         material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
961                         material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
962                         material_rail.setFlag(video::EMF_FOG_ENABLE, true);
963                         material_rail.MaterialType
964                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
965                         material_rail.setTexture(0, ap.atlas);
966
967                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
968                         video::SColor c = MapBlock_LightColor(255, l);
969
970                         float d = (float)BS/16;
971                         video::S3DVertex vertices[4] =
972                         {
973                                 video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
974                                                 ap.x0(), ap.y1()),
975                                 video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
976                                                 ap.x1(), ap.y1()),
977                                 video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
978                                                 ap.x1(), ap.y0()),
979                                 video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
980                                                 ap.x0(), ap.y0()),
981                         };
982
983                         // Rotate textures
984                         int angle = 0;
985
986                         if(adjacencies == 1)
987                         {
988                                 if(is_rail_x[0] || is_rail_x[1])
989                                         angle = 90;
990                         }
991                         else if(adjacencies == 2)
992                         {
993                                 if(is_rail_x[0] && is_rail_x[1])
994                                         angle = 90;
995                                 else if(is_rail_x[0] && is_rail_z[0])
996                                         angle = 270;
997                                 else if(is_rail_x[0] && is_rail_z[1])
998                                         angle = 180;
999                                 else if(is_rail_x[1] && is_rail_z[1])
1000                                         angle = 90;
1001                         }
1002                         else if(adjacencies == 3)
1003                         {
1004                                 if(!is_rail_x[0])
1005                                         angle=0;
1006                                 if(!is_rail_x[1])
1007                                         angle=180;
1008                                 if(!is_rail_z[0])
1009                                         angle=90;
1010                                 if(!is_rail_z[1])
1011                                         angle=270;
1012                         }
1013
1014                         if(angle != 0) {
1015                                 for(u16 i=0; i<4; i++)
1016                                         vertices[i].Pos.rotateXZBy(angle);
1017                         }
1018
1019                         for(s32 i=0; i<4; i++)
1020                         {
1021                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1022                         }
1023
1024                         u16 indices[] = {0,1,2,2,3,0};
1025                         collector.append(material_rail, vertices, 4, indices, 6);
1026                 break;}
1027                 }
1028         }
1029 }
1030 #endif
1031