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