]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_mapblock.cpp
Merge branch 'view_bobbing_and_vielded_tool'
[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 #include "content_mapnode.h"
22 #include "main.h" // For g_settings and g_texturesource
23 #include "mineral.h"
24 #include "mapblock_mesh.h" // For MapBlock_LightColor()
25
26 #ifndef SERVER
27 // Create a cuboid.
28 //  material  - the material to use (for all 6 faces)
29 //  collector - the MeshCollector for the resulting polygons
30 //  pa        - texture atlas pointer for the material
31 //  c         - vertex colour - used for all
32 //  pos       - the position of the centre of the cuboid
33 //  rz,ry,rz  - the radius of the cuboid in each dimension
34 //  txc       - texture coordinates - this is a list of texture coordinates
35 //              for the opposite corners of each face - therefore, there
36 //              should be (2+2)*6=24 values in the list. Alternatively, pass
37 //              NULL to use the entire texture for each face. The order of
38 //              the faces in the list is top-backi-right-front-left-bottom
39 //              If you specified 0,0,1,1 for each face, that would be the
40 //              same as passing NULL.
41 void makeCuboid(video::SMaterial &material, MeshCollector *collector,
42         AtlasPointer* pa, video::SColor &c,
43         v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
44 {
45         f32 tu0=pa->x0();
46         f32 tu1=pa->x1();
47         f32 tv0=pa->y0();
48         f32 tv1=pa->y1();
49         f32 txus=tu1-tu0;
50         f32 txvs=tv1-tv0;
51
52         video::S3DVertex v[4] =
53         {
54                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
55                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
56                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
57                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
58         };
59
60         for(int i=0;i<6;i++)
61         {
62                 switch(i)
63                 {
64                         case 0: // top
65                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
66                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
67                                 v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
68                                 v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
69                                 break;
70                         case 1: // back
71                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
72                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
73                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
74                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
75                                 break;
76                         case 2: //right
77                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
78                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
79                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
80                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
81                                 break;
82                         case 3: // front
83                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
84                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
85                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
86                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
87                                 break;
88                         case 4: // left
89                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
90                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
91                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
92                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
93                                 break;
94                         case 5: // bottom
95                                 v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
96                                 v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
97                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
98                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
99                                 break;
100                 }
101
102                 if(txc!=NULL)
103                 {
104                         v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
105                         v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
106                         v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
107                         v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
108                         txc+=4;
109                 }
110
111                 for(u16 i=0; i<4; i++)
112                         v[i].Pos += pos;
113                 u16 indices[] = {0,1,2,2,3,0};
114                 collector->append(material, v, 4, indices, 6);
115
116         }
117
118 }
119 #endif
120
121 #ifndef SERVER
122 void mapblock_mesh_generate_special(MeshMakeData *data,
123                 MeshCollector &collector)
124 {
125         // 0ms
126         //TimeTaker timer("mapblock_mesh_generate_special()");
127
128         /*
129                 Some settings
130         */
131         bool new_style_water = g_settings.getBool("new_style_water");
132         bool new_style_leaves = g_settings.getBool("new_style_leaves");
133         //bool smooth_lighting = g_settings.getBool("smooth_lighting");
134         bool invisible_stone = g_settings.getBool("invisible_stone");
135         
136         float node_liquid_level = 1.0;
137         if(new_style_water)
138                 node_liquid_level = 0.85;
139         
140         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
141
142         // New-style leaves material
143         video::SMaterial material_leaves1;
144         material_leaves1.setFlag(video::EMF_LIGHTING, false);
145         //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
146         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
147         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
148         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
149         AtlasPointer pa_leaves1 = g_texturesource->getTexture(
150                         g_texturesource->getTextureId("leaves.png"));
151         material_leaves1.setTexture(0, pa_leaves1.atlas);
152
153         // Glass material
154         video::SMaterial material_glass;
155         material_glass.setFlag(video::EMF_LIGHTING, false);
156         material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
157         material_glass.setFlag(video::EMF_FOG_ENABLE, true);
158         material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
159         AtlasPointer pa_glass = g_texturesource->getTexture(
160                         g_texturesource->getTextureId("glass.png"));
161         material_glass.setTexture(0, pa_glass.atlas);
162
163         // Wood material
164         video::SMaterial material_wood;
165         material_wood.setFlag(video::EMF_LIGHTING, false);
166         material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
167         material_wood.setFlag(video::EMF_FOG_ENABLE, true);
168         material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
169         AtlasPointer pa_wood = g_texturesource->getTexture(
170                         g_texturesource->getTextureId("wood.png"));
171         material_wood.setTexture(0, pa_wood.atlas);
172
173         // General ground material for special output
174         // Texture is modified just before usage
175         video::SMaterial material_general;
176         material_general.setFlag(video::EMF_LIGHTING, false);
177         material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
178         material_general.setFlag(video::EMF_FOG_ENABLE, true);
179         material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
180
181
182         // Papyrus material
183         video::SMaterial material_papyrus;
184         material_papyrus.setFlag(video::EMF_LIGHTING, false);
185         material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
186         material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
187         material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
188         AtlasPointer pa_papyrus = g_texturesource->getTexture(
189                         g_texturesource->getTextureId("papyrus.png"));
190         material_papyrus.setTexture(0, pa_papyrus.atlas);
191         
192         // Apple material
193         video::SMaterial material_apple;
194         material_apple.setFlag(video::EMF_LIGHTING, false);
195         material_apple.setFlag(video::EMF_BILINEAR_FILTER, false);
196         material_apple.setFlag(video::EMF_FOG_ENABLE, true);
197         material_apple.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
198         AtlasPointer pa_apple = g_texturesource->getTexture(
199                         g_texturesource->getTextureId("apple.png"));
200         material_apple.setTexture(0, pa_apple.atlas);
201
202         // junglegrass material
203         video::SMaterial material_junglegrass;
204         material_junglegrass.setFlag(video::EMF_LIGHTING, false);
205         material_junglegrass.setFlag(video::EMF_BILINEAR_FILTER, false);
206         material_junglegrass.setFlag(video::EMF_FOG_ENABLE, true);
207         material_junglegrass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
208         AtlasPointer pa_junglegrass = g_texturesource->getTexture(
209                         g_texturesource->getTextureId("junglegrass.png"));
210         material_junglegrass.setTexture(0, pa_junglegrass.atlas);
211
212         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
213         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
214         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
215         {
216                 v3s16 p(x,y,z);
217
218                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
219                 
220                 /*
221                         Add torches to mesh
222                 */
223                 if(n.getContent() == CONTENT_TORCH)
224                 {
225                         video::SColor c(255,255,255,255);
226
227                         // Wall at X+ of node
228                         video::S3DVertex vertices[4] =
229                         {
230                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
231                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
232                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
233                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
234                         };
235
236                         v3s16 dir = unpackDir(n.param2);
237
238                         for(s32 i=0; i<4; i++)
239                         {
240                                 if(dir == v3s16(1,0,0))
241                                         vertices[i].Pos.rotateXZBy(0);
242                                 if(dir == v3s16(-1,0,0))
243                                         vertices[i].Pos.rotateXZBy(180);
244                                 if(dir == v3s16(0,0,1))
245                                         vertices[i].Pos.rotateXZBy(90);
246                                 if(dir == v3s16(0,0,-1))
247                                         vertices[i].Pos.rotateXZBy(-90);
248                                 if(dir == v3s16(0,-1,0))
249                                         vertices[i].Pos.rotateXZBy(45);
250                                 if(dir == v3s16(0,1,0))
251                                         vertices[i].Pos.rotateXZBy(-45);
252
253                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
254                         }
255
256                         // Set material
257                         video::SMaterial material;
258                         material.setFlag(video::EMF_LIGHTING, false);
259                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
260                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
261                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
262                         material.MaterialType
263                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
264
265                         if(dir == v3s16(0,-1,0))
266                                 material.setTexture(0,
267                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
268                         else if(dir == v3s16(0,1,0))
269                                 material.setTexture(0,
270                                                 g_texturesource->getTextureRaw("torch_on_ceiling.png"));
271                         // For backwards compatibility
272                         else if(dir == v3s16(0,0,0))
273                                 material.setTexture(0,
274                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
275                         else
276                                 material.setTexture(0, 
277                                                 g_texturesource->getTextureRaw("torch.png"));
278
279                         u16 indices[] = {0,1,2,2,3,0};
280                         // Add to mesh collector
281                         collector.append(material, vertices, 4, indices, 6);
282                 }
283                 /*
284                         Signs on walls
285                 */
286                 else if(n.getContent() == CONTENT_SIGN_WALL)
287                 {
288                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
289                         video::SColor c = MapBlock_LightColor(255, l);
290                                 
291                         float d = (float)BS/16;
292                         // Wall at X+ of node
293                         video::S3DVertex vertices[4] =
294                         {
295                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
296                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
297                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
298                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
299                         };
300
301                         v3s16 dir = unpackDir(n.param2);
302
303                         for(s32 i=0; i<4; i++)
304                         {
305                                 if(dir == v3s16(1,0,0))
306                                         vertices[i].Pos.rotateXZBy(0);
307                                 if(dir == v3s16(-1,0,0))
308                                         vertices[i].Pos.rotateXZBy(180);
309                                 if(dir == v3s16(0,0,1))
310                                         vertices[i].Pos.rotateXZBy(90);
311                                 if(dir == v3s16(0,0,-1))
312                                         vertices[i].Pos.rotateXZBy(-90);
313                                 if(dir == v3s16(0,-1,0))
314                                         vertices[i].Pos.rotateXYBy(-90);
315                                 if(dir == v3s16(0,1,0))
316                                         vertices[i].Pos.rotateXYBy(90);
317
318                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
319                         }
320
321                         // Set material
322                         video::SMaterial material;
323                         material.setFlag(video::EMF_LIGHTING, false);
324                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
325                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
326                         material.setFlag(video::EMF_FOG_ENABLE, true);
327                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
328                         material.MaterialType
329                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
330
331                         material.setTexture(0, 
332                                         g_texturesource->getTextureRaw("sign_wall.png"));
333
334                         u16 indices[] = {0,1,2,2,3,0};
335                         // Add to mesh collector
336                         collector.append(material, vertices, 4, indices, 6);
337                 }
338                 /*
339                         Add flowing liquid to mesh
340                 */
341                 else if(content_features(n).liquid_type == LIQUID_FLOWING)
342                 {
343                         assert(content_features(n).special_material);
344                         video::SMaterial &liquid_material =
345                                         *content_features(n).special_material;
346                         assert(content_features(n).special_atlas);
347                         AtlasPointer &pa_liquid1 =
348                                         *content_features(n).special_atlas;
349
350                         bool top_is_same_liquid = false;
351                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
352                         content_t c_flowing = content_features(n).liquid_alternative_flowing;
353                         content_t c_source = content_features(n).liquid_alternative_source;
354                         if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
355                                 top_is_same_liquid = true;
356                         
357                         u8 l = 0;
358                         // Use the light of the node on top if possible
359                         if(content_features(ntop).param_type == CPT_LIGHT)
360                                 l = decode_light(ntop.getLightBlend(data->m_daynight_ratio));
361                         // Otherwise use the light of this node (the liquid)
362                         else
363                                 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
364                         video::SColor c = MapBlock_LightColor(
365                                         content_features(n).vertex_alpha, l);
366                         
367                         // Neighbor liquid levels (key = relative position)
368                         // Includes current node
369                         core::map<v3s16, f32> neighbor_levels;
370                         core::map<v3s16, content_t> neighbor_contents;
371                         core::map<v3s16, u8> neighbor_flags;
372                         const u8 neighborflag_top_is_same_liquid = 0x01;
373                         v3s16 neighbor_dirs[9] = {
374                                 v3s16(0,0,0),
375                                 v3s16(0,0,1),
376                                 v3s16(0,0,-1),
377                                 v3s16(1,0,0),
378                                 v3s16(-1,0,0),
379                                 v3s16(1,0,1),
380                                 v3s16(-1,0,-1),
381                                 v3s16(1,0,-1),
382                                 v3s16(-1,0,1),
383                         };
384                         for(u32 i=0; i<9; i++)
385                         {
386                                 content_t content = CONTENT_AIR;
387                                 float level = -0.5 * BS;
388                                 u8 flags = 0;
389                                 // Check neighbor
390                                 v3s16 p2 = p + neighbor_dirs[i];
391                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
392                                 if(n2.getContent() != CONTENT_IGNORE)
393                                 {
394                                         content = n2.getContent();
395
396                                         if(n2.getContent() == c_source)
397                                                 level = (-0.5+node_liquid_level) * BS;
398                                         else if(n2.getContent() == c_flowing)
399                                                 level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK)
400                                                                 + 0.5) / 8.0 * node_liquid_level) * BS;
401
402                                         // Check node above neighbor.
403                                         // NOTE: This doesn't get executed if neighbor
404                                         //       doesn't exist
405                                         p2.Y += 1;
406                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
407                                         if(n2.getContent() == c_source ||
408                                                         n2.getContent() == c_flowing)
409                                                 flags |= neighborflag_top_is_same_liquid;
410                                 }
411                                 
412                                 neighbor_levels.insert(neighbor_dirs[i], level);
413                                 neighbor_contents.insert(neighbor_dirs[i], content);
414                                 neighbor_flags.insert(neighbor_dirs[i], flags);
415                         }
416
417                         // Corner heights (average between four liquids)
418                         f32 corner_levels[4];
419                         
420                         v3s16 halfdirs[4] = {
421                                 v3s16(0,0,0),
422                                 v3s16(1,0,0),
423                                 v3s16(1,0,1),
424                                 v3s16(0,0,1),
425                         };
426                         for(u32 i=0; i<4; i++)
427                         {
428                                 v3s16 cornerdir = halfdirs[i];
429                                 float cornerlevel = 0;
430                                 u32 valid_count = 0;
431                                 u32 air_count = 0;
432                                 for(u32 j=0; j<4; j++)
433                                 {
434                                         v3s16 neighbordir = cornerdir - halfdirs[j];
435                                         content_t content = neighbor_contents[neighbordir];
436                                         // If top is liquid, draw starting from top of node
437                                         if(neighbor_flags[neighbordir] &
438                                                         neighborflag_top_is_same_liquid)
439                                         {
440                                                 cornerlevel = 0.5*BS;
441                                                 valid_count = 1;
442                                                 break;
443                                         }
444                                         // Source is always the same height
445                                         else if(content == c_source)
446                                         {
447                                                 cornerlevel = (-0.5+node_liquid_level)*BS;
448                                                 valid_count = 1;
449                                                 break;
450                                         }
451                                         // Flowing liquid has level information
452                                         else if(content == c_flowing)
453                                         {
454                                                 cornerlevel += neighbor_levels[neighbordir];
455                                                 valid_count++;
456                                         }
457                                         else if(content == CONTENT_AIR)
458                                         {
459                                                 air_count++;
460                                         }
461                                 }
462                                 if(air_count >= 2)
463                                         cornerlevel = -0.5*BS;
464                                 else if(valid_count > 0)
465                                         cornerlevel /= valid_count;
466                                 corner_levels[i] = cornerlevel;
467                         }
468
469                         /*
470                                 Generate sides
471                         */
472
473                         v3s16 side_dirs[4] = {
474                                 v3s16(1,0,0),
475                                 v3s16(-1,0,0),
476                                 v3s16(0,0,1),
477                                 v3s16(0,0,-1),
478                         };
479                         s16 side_corners[4][2] = {
480                                 {1, 2},
481                                 {3, 0},
482                                 {2, 3},
483                                 {0, 1},
484                         };
485                         for(u32 i=0; i<4; i++)
486                         {
487                                 v3s16 dir = side_dirs[i];
488
489                                 /*
490                                         If our topside is liquid and neighbor's topside
491                                         is liquid, don't draw side face
492                                 */
493                                 if(top_is_same_liquid &&
494                                                 neighbor_flags[dir] & neighborflag_top_is_same_liquid)
495                                         continue;
496
497                                 content_t neighbor_content = neighbor_contents[dir];
498                                 
499                                 // Don't draw face if neighbor is not air or liquid
500                                 if(neighbor_content != CONTENT_AIR
501                                                 && content_liquid(neighbor_content) == false)
502                                         continue;
503                                 
504                                 bool neighbor_is_same_liquid = (neighbor_content == c_source
505                                                 || neighbor_content == c_flowing);
506                                 
507                                 // Don't draw any faces if neighbor same is liquid and top is
508                                 // same liquid
509                                 if(neighbor_is_same_liquid == true
510                                                 && top_is_same_liquid == false)
511                                         continue;
512                                 
513                                 video::S3DVertex vertices[4] =
514                                 {
515                                         /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
516                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
517                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
518                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
519                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
520                                                         pa_liquid1.x0(), pa_liquid1.y1()),
521                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
522                                                         pa_liquid1.x1(), pa_liquid1.y1()),
523                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
524                                                         pa_liquid1.x1(), pa_liquid1.y0()),
525                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
526                                                         pa_liquid1.x0(), pa_liquid1.y0()),
527                                 };
528                                 
529                                 /*
530                                         If our topside is liquid, set upper border of face
531                                         at upper border of node
532                                 */
533                                 if(top_is_same_liquid)
534                                 {
535                                         vertices[2].Pos.Y = 0.5*BS;
536                                         vertices[3].Pos.Y = 0.5*BS;
537                                 }
538                                 /*
539                                         Otherwise upper position of face is corner levels
540                                 */
541                                 else
542                                 {
543                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
544                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
545                                 }
546                                 
547                                 /*
548                                         If neighbor is liquid, lower border of face is corner
549                                         liquid levels
550                                 */
551                                 if(neighbor_is_same_liquid)
552                                 {
553                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
554                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
555                                 }
556                                 /*
557                                         If neighbor is not liquid, lower border of face is
558                                         lower border of node
559                                 */
560                                 else
561                                 {
562                                         vertices[0].Pos.Y = -0.5*BS;
563                                         vertices[1].Pos.Y = -0.5*BS;
564                                 }
565                                 
566                                 for(s32 j=0; j<4; j++)
567                                 {
568                                         if(dir == v3s16(0,0,1))
569                                                 vertices[j].Pos.rotateXZBy(0);
570                                         if(dir == v3s16(0,0,-1))
571                                                 vertices[j].Pos.rotateXZBy(180);
572                                         if(dir == v3s16(-1,0,0))
573                                                 vertices[j].Pos.rotateXZBy(90);
574                                         if(dir == v3s16(1,0,-0))
575                                                 vertices[j].Pos.rotateXZBy(-90);
576                                                 
577                                         // Do this to not cause glitches when two liquids are
578                                         // side-by-side
579                                         if(neighbor_is_same_liquid == false){
580                                                 vertices[j].Pos.X *= 0.98;
581                                                 vertices[j].Pos.Z *= 0.98;
582                                         }
583
584                                         vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
585                                 }
586
587                                 u16 indices[] = {0,1,2,2,3,0};
588                                 // Add to mesh collector
589                                 collector.append(liquid_material, vertices, 4, indices, 6);
590                         }
591                         
592                         /*
593                                 Generate top side, if appropriate
594                         */
595                         
596                         if(top_is_same_liquid == false)
597                         {
598                                 video::S3DVertex vertices[4] =
599                                 {
600                                         /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
601                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
602                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
603                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
604                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
605                                                         pa_liquid1.x0(), pa_liquid1.y1()),
606                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
607                                                         pa_liquid1.x1(), pa_liquid1.y1()),
608                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
609                                                         pa_liquid1.x1(), pa_liquid1.y0()),
610                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
611                                                         pa_liquid1.x0(), pa_liquid1.y0()),
612                                 };
613                                 
614                                 // This fixes a strange bug
615                                 s32 corner_resolve[4] = {3,2,1,0};
616
617                                 for(s32 i=0; i<4; i++)
618                                 {
619                                         //vertices[i].Pos.Y += liquid_level;
620                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
621                                         s32 j = corner_resolve[i];
622                                         vertices[i].Pos.Y += corner_levels[j];
623                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
624                                 }
625
626                                 u16 indices[] = {0,1,2,2,3,0};
627                                 // Add to mesh collector
628                                 collector.append(liquid_material, vertices, 4, indices, 6);
629                         }
630                 }
631                 /*
632                         Add water sources to mesh if using new style
633                 */
634                 else if(content_features(n).liquid_type == LIQUID_SOURCE
635                                 && new_style_water)
636                 {
637                         assert(content_features(n).special_material);
638                         video::SMaterial &liquid_material =
639                                         *content_features(n).special_material;
640                         assert(content_features(n).special_atlas);
641                         AtlasPointer &pa_liquid1 =
642                                         *content_features(n).special_atlas;
643
644                         bool top_is_air = false;
645                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
646                         if(n.getContent() == CONTENT_AIR)
647                                 top_is_air = true;
648                         
649                         if(top_is_air == false)
650                                 continue;
651
652                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
653                         video::SColor c = MapBlock_LightColor(
654                                         content_features(n).vertex_alpha, l);
655                         
656                         video::S3DVertex vertices[4] =
657                         {
658                                 /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
659                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
660                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
661                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
662                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
663                                                 pa_liquid1.x0(), pa_liquid1.y1()),
664                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
665                                                 pa_liquid1.x1(), pa_liquid1.y1()),
666                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
667                                                 pa_liquid1.x1(), pa_liquid1.y0()),
668                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
669                                                 pa_liquid1.x0(), pa_liquid1.y0()),
670                         };
671
672                         for(s32 i=0; i<4; i++)
673                         {
674                                 vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS;
675                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
676                         }
677
678                         u16 indices[] = {0,1,2,2,3,0};
679                         // Add to mesh collector
680                         collector.append(liquid_material, vertices, 4, indices, 6);
681                 }
682                 /*
683                         Add leaves if using new style
684                 */
685                 else if(n.getContent() == CONTENT_LEAVES && new_style_leaves)
686                 {
687                         /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
688                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
689                         video::SColor c = MapBlock_LightColor(255, l);
690
691                         for(u32 j=0; j<6; j++)
692                         {
693                                 video::S3DVertex vertices[4] =
694                                 {
695                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
696                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
697                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
698                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
699                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
700                                                 pa_leaves1.x0(), pa_leaves1.y1()),
701                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
702                                                 pa_leaves1.x1(), pa_leaves1.y1()),
703                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
704                                                 pa_leaves1.x1(), pa_leaves1.y0()),
705                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
706                                                 pa_leaves1.x0(), pa_leaves1.y0()),
707                                 };
708
709                                 if(j == 0)
710                                 {
711                                         for(u16 i=0; i<4; i++)
712                                                 vertices[i].Pos.rotateXZBy(0);
713                                 }
714                                 else if(j == 1)
715                                 {
716                                         for(u16 i=0; i<4; i++)
717                                                 vertices[i].Pos.rotateXZBy(180);
718                                 }
719                                 else if(j == 2)
720                                 {
721                                         for(u16 i=0; i<4; i++)
722                                                 vertices[i].Pos.rotateXZBy(-90);
723                                 }
724                                 else if(j == 3)
725                                 {
726                                         for(u16 i=0; i<4; i++)
727                                                 vertices[i].Pos.rotateXZBy(90);
728                                 }
729                                 else if(j == 4)
730                                 {
731                                         for(u16 i=0; i<4; i++)
732                                                 vertices[i].Pos.rotateYZBy(-90);
733                                 }
734                                 else if(j == 5)
735                                 {
736                                         for(u16 i=0; i<4; i++)
737                                                 vertices[i].Pos.rotateYZBy(90);
738                                 }
739
740                                 for(u16 i=0; i<4; i++)
741                                 {
742                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
743                                 }
744
745                                 u16 indices[] = {0,1,2,2,3,0};
746                                 // Add to mesh collector
747                                 collector.append(material_leaves1, vertices, 4, indices, 6);
748                         }
749                 }
750                 /*
751                         Add glass
752                 */
753                 else if(n.getContent() == CONTENT_GLASS)
754                 {
755                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
756                         video::SColor c = MapBlock_LightColor(255, l);
757
758                         for(u32 j=0; j<6; j++)
759                         {
760                                 video::S3DVertex vertices[4] =
761                                 {
762                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
763                                                 pa_glass.x0(), pa_glass.y1()),
764                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
765                                                 pa_glass.x1(), pa_glass.y1()),
766                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
767                                                 pa_glass.x1(), pa_glass.y0()),
768                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
769                                                 pa_glass.x0(), pa_glass.y0()),
770                                 };
771
772                                 if(j == 0)
773                                 {
774                                         for(u16 i=0; i<4; i++)
775                                                 vertices[i].Pos.rotateXZBy(0);
776                                 }
777                                 else if(j == 1)
778                                 {
779                                         for(u16 i=0; i<4; i++)
780                                                 vertices[i].Pos.rotateXZBy(180);
781                                 }
782                                 else if(j == 2)
783                                 {
784                                         for(u16 i=0; i<4; i++)
785                                                 vertices[i].Pos.rotateXZBy(-90);
786                                 }
787                                 else if(j == 3)
788                                 {
789                                         for(u16 i=0; i<4; i++)
790                                                 vertices[i].Pos.rotateXZBy(90);
791                                 }
792                                 else if(j == 4)
793                                 {
794                                         for(u16 i=0; i<4; i++)
795                                                 vertices[i].Pos.rotateYZBy(-90);
796                                 }
797                                 else if(j == 5)
798                                 {
799                                         for(u16 i=0; i<4; i++)
800                                                 vertices[i].Pos.rotateYZBy(90);
801                                 }
802
803                                 for(u16 i=0; i<4; i++)
804                                 {
805                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
806                                 }
807
808                                 u16 indices[] = {0,1,2,2,3,0};
809                                 // Add to mesh collector
810                                 collector.append(material_glass, vertices, 4, indices, 6);
811                         }
812                 }
813                 /*
814                         Add fence
815                 */
816                 else if(n.getContent() == CONTENT_FENCE)
817                 {
818                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
819                         video::SColor c = MapBlock_LightColor(255, l);
820
821                         const f32 post_rad=(f32)BS/10;
822                         const f32 bar_rad=(f32)BS/20;
823                         const f32 bar_len=(f32)(BS/2)-post_rad;
824
825                         // The post - always present
826                         v3f pos = intToFloat(p+blockpos_nodes, BS);
827                         f32 postuv[24]={
828                                         0.4,0.4,0.6,0.6,
829                                         0.35,0,0.65,1,
830                                         0.35,0,0.65,1,
831                                         0.35,0,0.65,1,
832                                         0.35,0,0.65,1,
833                                         0.4,0.4,0.6,0.6};
834                         makeCuboid(material_wood, &collector,
835                                 &pa_wood, c, pos,
836                                 post_rad,BS/2,post_rad, postuv);
837
838                         // Now a section of fence, +X, if there's a post there
839                         v3s16 p2 = p;
840                         p2.X++;
841                         MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
842                         if(n2.getContent() == CONTENT_FENCE)
843                         {
844                                 pos = intToFloat(p+blockpos_nodes, BS);
845                                 pos.X += BS/2;
846                                 pos.Y += BS/4;
847                                 f32 xrailuv[24]={
848                                         0,0.4,1,0.6,
849                                         0,0.4,1,0.6,
850                                         0,0.4,1,0.6,
851                                         0,0.4,1,0.6,
852                                         0,0.4,1,0.6,
853                                         0,0.4,1,0.6};
854                                 makeCuboid(material_wood, &collector,
855                                         &pa_wood, c, pos,
856                                         bar_len,bar_rad,bar_rad, xrailuv);
857
858                                 pos.Y -= BS/2;
859                                 makeCuboid(material_wood, &collector,
860                                         &pa_wood, c, pos,
861                                         bar_len,bar_rad,bar_rad, xrailuv);
862                         }
863
864                         // Now a section of fence, +Z, if there's a post there
865                         p2 = p;
866                         p2.Z++;
867                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
868                         if(n2.getContent() == CONTENT_FENCE)
869                         {
870                                 pos = intToFloat(p+blockpos_nodes, BS);
871                                 pos.Z += BS/2;
872                                 pos.Y += BS/4;
873                                 f32 zrailuv[24]={
874                                         0,0.4,1,0.6,
875                                         0,0.4,1,0.6,
876                                         0,0.4,1,0.6,
877                                         0,0.4,1,0.6,
878                                         0,0.4,1,0.6,
879                                         0,0.4,1,0.6};
880                                 makeCuboid(material_wood, &collector,
881                                         &pa_wood, c, pos,
882                                         bar_rad,bar_rad,bar_len, zrailuv);
883                                 pos.Y -= BS/2;
884                                 makeCuboid(material_wood, &collector,
885                                         &pa_wood, c, pos,
886                                         bar_rad,bar_rad,bar_len, zrailuv);
887
888                         }
889
890                 }
891 #if 1
892                 /*
893                         Add stones with minerals if stone is invisible
894                 */
895                 else if(n.getContent() == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE)
896                 {
897                         for(u32 j=0; j<6; j++)
898                         {
899                                 // NOTE: Hopefully g_6dirs[j] is the right direction...
900                                 v3s16 dir = g_6dirs[j];
901                                 /*u8 l = 0;
902                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + dir);
903                                 if(content_features(n2).param_type == CPT_LIGHT)
904                                         l = decode_light(n2.getLightBlend(data->m_daynight_ratio));
905                                 else
906                                         l = 255;*/
907                                 u8 l = 255;
908                                 video::SColor c = MapBlock_LightColor(255, l);
909                                 
910                                 // Get the right texture
911                                 TileSpec ts = n.getTile(dir);
912                                 AtlasPointer ap = ts.texture;
913                                 material_general.setTexture(0, ap.atlas);
914
915                                 video::S3DVertex vertices[4] =
916                                 {
917                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
918                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
919                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
920                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
921                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
922                                                 ap.x0(), ap.y1()),
923                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
924                                                 ap.x1(), ap.y1()),
925                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
926                                                 ap.x1(), ap.y0()),
927                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
928                                                 ap.x0(), ap.y0()),
929                                 };
930
931                                 if(j == 0)
932                                 {
933                                         for(u16 i=0; i<4; i++)
934                                                 vertices[i].Pos.rotateXZBy(0);
935                                 }
936                                 else if(j == 1)
937                                 {
938                                         for(u16 i=0; i<4; i++)
939                                                 vertices[i].Pos.rotateXZBy(180);
940                                 }
941                                 else if(j == 2)
942                                 {
943                                         for(u16 i=0; i<4; i++)
944                                                 vertices[i].Pos.rotateXZBy(-90);
945                                 }
946                                 else if(j == 3)
947                                 {
948                                         for(u16 i=0; i<4; i++)
949                                                 vertices[i].Pos.rotateXZBy(90);
950                                 }
951                                 else if(j == 4)
952
953                                 for(u16 i=0; i<4; i++)
954                                 {
955                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
956                                 }
957
958                                 u16 indices[] = {0,1,2,2,3,0};
959                                 // Add to mesh collector
960                                 collector.append(material_general, vertices, 4, indices, 6);
961                         }
962                 }
963 #endif
964                 else if(n.getContent() == CONTENT_PAPYRUS)
965                 {
966                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
967                         video::SColor c = MapBlock_LightColor(255, l);
968
969                         for(u32 j=0; j<4; j++)
970                         {
971                                 video::S3DVertex vertices[4] =
972                                 {
973                                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
974                                                 pa_papyrus.x0(), pa_papyrus.y1()),
975                                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
976                                                 pa_papyrus.x1(), pa_papyrus.y1()),
977                                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
978                                                 pa_papyrus.x1(), pa_papyrus.y0()),
979                                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
980                                                 pa_papyrus.x0(), pa_papyrus.y0()),
981                                 };
982
983                                 if(j == 0)
984                                 {
985                                         for(u16 i=0; i<4; i++)
986                                                 vertices[i].Pos.rotateXZBy(45);
987                                 }
988                                 else if(j == 1)
989                                 {
990                                         for(u16 i=0; i<4; i++)
991                                                 vertices[i].Pos.rotateXZBy(-45);
992                                 }
993                                 else if(j == 2)
994                                 {
995                                         for(u16 i=0; i<4; i++)
996                                                 vertices[i].Pos.rotateXZBy(135);
997                                 }
998                                 else if(j == 3)
999                                 {
1000                                         for(u16 i=0; i<4; i++)
1001                                                 vertices[i].Pos.rotateXZBy(-135);
1002                                 }
1003
1004                                 for(u16 i=0; i<4; i++)
1005                                 {
1006                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1007                                 }
1008
1009                                 u16 indices[] = {0,1,2,2,3,0};
1010                                 // Add to mesh collector
1011                                 collector.append(material_papyrus, vertices, 4, indices, 6);
1012                         }
1013                 }
1014                 else if(n.getContent() == CONTENT_JUNGLEGRASS)
1015                 {
1016                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1017                         video::SColor c = MapBlock_LightColor(255, l);
1018
1019                         for(u32 j=0; j<4; j++)
1020                         {
1021                                 video::S3DVertex vertices[4] =
1022                                 {
1023                                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
1024                                                 pa_papyrus.x0(), pa_papyrus.y1()),
1025                                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
1026                                                 pa_papyrus.x1(), pa_papyrus.y1()),
1027                                         video::S3DVertex(BS/2,BS/1,0, 0,0,0, c,
1028                                                 pa_papyrus.x1(), pa_papyrus.y0()),
1029                                         video::S3DVertex(-BS/2,BS/1,0, 0,0,0, c,
1030                                                 pa_papyrus.x0(), pa_papyrus.y0()),
1031                                 };
1032
1033                                 if(j == 0)
1034                                 {
1035                                         for(u16 i=0; i<4; i++)
1036                                                 vertices[i].Pos.rotateXZBy(45);
1037                                 }
1038                                 else if(j == 1)
1039                                 {
1040                                         for(u16 i=0; i<4; i++)
1041                                                 vertices[i].Pos.rotateXZBy(-45);
1042                                 }
1043                                 else if(j == 2)
1044                                 {
1045                                         for(u16 i=0; i<4; i++)
1046                                                 vertices[i].Pos.rotateXZBy(135);
1047                                 }
1048                                 else if(j == 3)
1049                                 {
1050                                         for(u16 i=0; i<4; i++)
1051                                                 vertices[i].Pos.rotateXZBy(-135);
1052                                 }
1053
1054                                 for(u16 i=0; i<4; i++)
1055                                 {
1056                                         vertices[i].Pos *= 1.3;
1057                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1058                                 }
1059
1060                                 u16 indices[] = {0,1,2,2,3,0};
1061                                 // Add to mesh collector
1062                                 collector.append(material_junglegrass, vertices, 4, indices, 6);
1063                         }
1064                 }
1065                 else if(n.getContent() == CONTENT_RAIL)
1066                 {
1067                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1068                         video::SColor c = MapBlock_LightColor(255, l);
1069
1070                         bool is_rail_x [] = { false, false };  /* x-1, x+1 */
1071                         bool is_rail_z [] = { false, false };  /* z-1, z+1 */
1072
1073                         MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
1074                         MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
1075                         MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
1076                         MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
1077
1078                         if(n_minus_x.getContent() == CONTENT_RAIL)
1079                                 is_rail_x[0] = true;
1080                         if(n_plus_x.getContent() == CONTENT_RAIL)
1081                                 is_rail_x[1] = true;
1082                         if(n_minus_z.getContent() == CONTENT_RAIL)
1083                                 is_rail_z[0] = true;
1084                         if(n_plus_z.getContent() == CONTENT_RAIL)
1085                                 is_rail_z[1] = true;
1086
1087                         float d = (float)BS/16;
1088                         video::S3DVertex vertices[4] =
1089                         {
1090                                 video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
1091                                         0, 1),
1092                                 video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
1093                                         1, 1),
1094                                 video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
1095                                         1, 0),
1096                                 video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
1097                                         0, 0),
1098                         };
1099
1100                         video::SMaterial material_rail;
1101                         material_rail.setFlag(video::EMF_LIGHTING, false);
1102                         material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
1103                         material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
1104                         material_rail.setFlag(video::EMF_FOG_ENABLE, true);
1105                         material_rail.MaterialType
1106                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1107
1108                         int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];
1109
1110                         // Assign textures
1111                         if(adjacencies < 2)
1112                                 material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
1113                         else if(adjacencies == 2)
1114                         {
1115                                 if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
1116                                         material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png"));
1117                                 else
1118                                         material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png"));
1119                         }
1120                         else if(adjacencies == 3)
1121                                 material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png"));
1122                         else if(adjacencies == 4)
1123                                 material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png"));
1124
1125                         // Rotate textures
1126                         int angle = 0;
1127
1128                         if(adjacencies == 1)
1129                         {
1130                                 if(is_rail_x[0] || is_rail_x[1])
1131                                         angle = 90;
1132                         }
1133                         else if(adjacencies == 2)
1134                         {
1135                                 if(is_rail_x[0] && is_rail_x[1])
1136                                         angle = 90;
1137                                 else if(is_rail_x[0] && is_rail_z[0])
1138                                         angle = 270;
1139                                 else if(is_rail_x[0] && is_rail_z[1])
1140                                         angle = 180;
1141                                 else if(is_rail_x[1] && is_rail_z[1])
1142                                         angle = 90;
1143                         }
1144                         else if(adjacencies == 3)
1145                         {
1146                                 if(!is_rail_x[0])
1147                                         angle=0;
1148                                 if(!is_rail_x[1])
1149                                         angle=180;
1150                                 if(!is_rail_z[0])
1151                                         angle=90;
1152                                 if(!is_rail_z[1])
1153                                         angle=270;
1154                         }
1155
1156                         if(angle != 0) {
1157                                 for(u16 i=0; i<4; i++)
1158                                         vertices[i].Pos.rotateXZBy(angle);
1159                         }
1160
1161                         for(s32 i=0; i<4; i++)
1162                         {
1163                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1164                         }
1165
1166                         u16 indices[] = {0,1,2,2,3,0};
1167                         collector.append(material_rail, vertices, 4, indices, 6);
1168                 }
1169                 else if (n.getContent() == CONTENT_LADDER) {
1170                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1171                         video::SColor c(255,l,l,l);
1172
1173                         float d = (float)BS/16;
1174
1175                         // Assume wall is at X+
1176                         video::S3DVertex vertices[4] =
1177                         {
1178                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
1179                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
1180                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
1181                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
1182                         };
1183
1184                         v3s16 dir = unpackDir(n.param2);
1185
1186                         for(s32 i=0; i<4; i++)
1187                         {
1188                                 if(dir == v3s16(1,0,0))
1189                                         vertices[i].Pos.rotateXZBy(0);
1190                                 if(dir == v3s16(-1,0,0))
1191                                         vertices[i].Pos.rotateXZBy(180);
1192                                 if(dir == v3s16(0,0,1))
1193                                         vertices[i].Pos.rotateXZBy(90);
1194                                 if(dir == v3s16(0,0,-1))
1195                                         vertices[i].Pos.rotateXZBy(-90);
1196                                 if(dir == v3s16(0,-1,0))
1197                                         vertices[i].Pos.rotateXYBy(-90);
1198                                 if(dir == v3s16(0,1,0))
1199                                         vertices[i].Pos.rotateXYBy(90);
1200
1201                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1202                         }
1203
1204                         video::SMaterial material_ladder;
1205                         material_ladder.setFlag(video::EMF_LIGHTING, false);
1206                         material_ladder.setFlag(video::EMF_BACK_FACE_CULLING, false);
1207                         material_ladder.setFlag(video::EMF_BILINEAR_FILTER, false);
1208                         material_ladder.setFlag(video::EMF_FOG_ENABLE, true);
1209                         material_ladder.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1210                         material_ladder.setTexture(0, g_texturesource->getTextureRaw("ladder.png"));
1211
1212                         u16 indices[] = {0,1,2,2,3,0};
1213                         // Add to mesh collector
1214                         collector.append(material_ladder, vertices, 4, indices, 6);
1215                 }
1216                 else if(n.getContent() == CONTENT_APPLE)
1217                 {
1218                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1219                         video::SColor c = MapBlock_LightColor(255, l);
1220
1221                         for(u32 j=0; j<4; j++)
1222                         {
1223                                 video::S3DVertex vertices[4] =
1224                                 {
1225                                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
1226                                                 pa_apple.x0(), pa_apple.y1()),
1227                                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
1228                                                 pa_apple.x1(), pa_apple.y1()),
1229                                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
1230                                                 pa_apple.x1(), pa_apple.y0()),
1231                                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
1232                                                 pa_apple.x0(), pa_apple.y0()),
1233                                 };
1234
1235                                 if(j == 0)
1236                                 {
1237                                         for(u16 i=0; i<4; i++)
1238                                                 vertices[i].Pos.rotateXZBy(45);
1239                                 }
1240                                 else if(j == 1)
1241                                 {
1242                                         for(u16 i=0; i<4; i++)
1243                                                 vertices[i].Pos.rotateXZBy(-45);
1244                                 }
1245                                 else if(j == 2)
1246                                 {
1247                                         for(u16 i=0; i<4; i++)
1248                                                 vertices[i].Pos.rotateXZBy(135);
1249                                 }
1250                                 else if(j == 3)
1251                                 {
1252                                         for(u16 i=0; i<4; i++)
1253                                                 vertices[i].Pos.rotateXZBy(-135);
1254                                 }
1255
1256                                 for(u16 i=0; i<4; i++)
1257                                 {
1258                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1259                                 }
1260
1261                                 u16 indices[] = {0,1,2,2,3,0};
1262                                 // Add to mesh collector
1263                                 collector.append(material_apple, vertices, 4, indices, 6);
1264                         }
1265                 }
1266         }
1267 }
1268 #endif
1269