]> git.lizzy.rs Git - minetest.git/blob - src/mesh.cpp
38b3d97bc44d0bde6d6b9322c2c631e681bb699c
[minetest.git] / src / mesh.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 "mesh.h"
21 #include "debug.h"
22 #include "log.h"
23 #include <iostream>
24 #include <IAnimatedMesh.h>
25 #include <SAnimatedMesh.h>
26
27 // In Irrlicht 1.8 the signature of ITexture::lock was changed from
28 // (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
29 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
30 #define MY_ETLM_READ_ONLY true
31 #else
32 #define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
33 #endif
34
35 scene::IAnimatedMesh* createCubeMesh(v3f scale)
36 {
37         video::SColor c(255,255,255,255);
38         video::S3DVertex vertices[24] =
39         {
40                 // Up
41                 video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
42                 video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
43                 video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
44                 video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
45                 // Down
46                 video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
47                 video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
48                 video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
49                 video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
50                 // Right
51                 video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
52                 video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
53                 video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
54                 video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
55                 // Left
56                 video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
57                 video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
58                 video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
59                 video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
60                 // Back
61                 video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
62                 video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
63                 video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
64                 video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
65                 // Front
66                 video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
67                 video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
68                 video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
69                 video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
70         };
71
72         u16 indices[6] = {0,1,2,2,3,0};
73
74         scene::SMesh *mesh = new scene::SMesh();
75         for (u32 i=0; i<6; ++i)
76         {
77                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
78                 buf->append(vertices + 4 * i, 4, indices, 6);
79                 // Set default material
80                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
81                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
82                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
83                 // Add mesh buffer to mesh
84                 mesh->addMeshBuffer(buf);
85                 buf->drop();
86         }
87
88         scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
89         mesh->drop();
90         scaleMesh(anim_mesh, scale);  // also recalculates bounding box
91         return anim_mesh;
92 }
93
94 void scaleMesh(scene::IMesh *mesh, v3f scale)
95 {
96         if(mesh == NULL)
97                 return;
98
99         core::aabbox3d<f32> bbox;
100         bbox.reset(0,0,0);
101
102         u16 mc = mesh->getMeshBufferCount();
103         for(u16 j=0; j<mc; j++)
104         {
105                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
106                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
107                 u16 vc = buf->getVertexCount();
108                 for(u16 i=0; i<vc; i++)
109                 {
110                         vertices[i].Pos *= scale;
111                 }
112                 buf->recalculateBoundingBox();
113
114                 // calculate total bounding box
115                 if(j == 0)
116                         bbox = buf->getBoundingBox();
117                 else
118                         bbox.addInternalBox(buf->getBoundingBox());
119         }
120         mesh->setBoundingBox(bbox);
121 }
122
123 void translateMesh(scene::IMesh *mesh, v3f vec)
124 {
125         if(mesh == NULL)
126                 return;
127
128         core::aabbox3d<f32> bbox;
129         bbox.reset(0,0,0);
130
131         u16 mc = mesh->getMeshBufferCount();
132         for(u16 j=0; j<mc; j++)
133         {
134                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
135                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
136                 u16 vc = buf->getVertexCount();
137                 for(u16 i=0; i<vc; i++)
138                 {
139                         vertices[i].Pos += vec;
140                 }
141                 buf->recalculateBoundingBox();
142
143                 // calculate total bounding box
144                 if(j == 0)
145                         bbox = buf->getBoundingBox();
146                 else
147                         bbox.addInternalBox(buf->getBoundingBox());
148         }
149         mesh->setBoundingBox(bbox);
150 }
151
152 void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
153 {
154         if(mesh == NULL)
155                 return;
156         
157         u16 mc = mesh->getMeshBufferCount();
158         for(u16 j=0; j<mc; j++)
159         {
160                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
161                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
162                 u16 vc = buf->getVertexCount();
163                 for(u16 i=0; i<vc; i++)
164                 {
165                         vertices[i].Color = color;
166                 }
167         }
168 }
169
170 void setMeshColorByNormalXYZ(scene::IMesh *mesh,
171                 const video::SColor &colorX,
172                 const video::SColor &colorY,
173                 const video::SColor &colorZ)
174 {
175         if(mesh == NULL)
176                 return;
177         
178         u16 mc = mesh->getMeshBufferCount();
179         for(u16 j=0; j<mc; j++)
180         {
181                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
182                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
183                 u16 vc = buf->getVertexCount();
184                 for(u16 i=0; i<vc; i++)
185                 {
186                         f32 x = fabs(vertices[i].Normal.X);
187                         f32 y = fabs(vertices[i].Normal.Y);
188                         f32 z = fabs(vertices[i].Normal.Z);
189                         if(x >= y && x >= z)
190                                 vertices[i].Color = colorX;
191                         else if(y >= z)
192                                 vertices[i].Color = colorY;
193                         else
194                                 vertices[i].Color = colorZ;
195
196                 }
197         }
198 }
199
200 void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir)
201 {               
202         int axisdir = facedir>>2;
203         facedir &= 0x03;
204
205         u16 mc = mesh->getMeshBufferCount();
206         for(u16 j = 0; j < mc; j++)
207         {
208                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
209                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
210                 u16 vc = buf->getVertexCount();
211                 for(u16 i=0; i<vc; i++)
212                 {
213                         switch (axisdir)
214                         {
215                         case 0:
216                                 if(facedir == 1)
217                                         vertices[i].Pos.rotateXZBy(-90);
218                                 else if(facedir == 2)
219                                         vertices[i].Pos.rotateXZBy(180);
220                                 else if(facedir == 3)
221                                         vertices[i].Pos.rotateXZBy(90);
222                                 break;
223                         case 1: // z+
224                                 vertices[i].Pos.rotateYZBy(90);
225                                 if(facedir == 1)
226                                         vertices[i].Pos.rotateXYBy(90);
227                                 else if(facedir == 2)
228                                         vertices[i].Pos.rotateXYBy(180);
229                                 else if(facedir == 3)
230                                         vertices[i].Pos.rotateXYBy(-90);
231                                 break;
232                         case 2: //z-
233                                 vertices[i].Pos.rotateYZBy(-90);
234                                 if(facedir == 1)
235                                         vertices[i].Pos.rotateXYBy(-90);
236                                 else if(facedir == 2)
237                                         vertices[i].Pos.rotateXYBy(180);
238                                 else if(facedir == 3)
239                                         vertices[i].Pos.rotateXYBy(90);
240                                 break;
241                         case 3:  //x+
242                                 vertices[i].Pos.rotateXYBy(-90);
243                                 if(facedir == 1)
244                                         vertices[i].Pos.rotateYZBy(90);
245                                 else if(facedir == 2)
246                                         vertices[i].Pos.rotateYZBy(180);
247                                 else if(facedir == 3)
248                                         vertices[i].Pos.rotateYZBy(-90);
249                                 break;
250                         case 4:  //x-
251                                 vertices[i].Pos.rotateXYBy(90);
252                                 if(facedir == 1)
253                                         vertices[i].Pos.rotateYZBy(-90);
254                                 else if(facedir == 2)
255                                         vertices[i].Pos.rotateYZBy(180);
256                                 else if(facedir == 3)
257                                         vertices[i].Pos.rotateYZBy(90);
258                                 break;
259                         case 5:
260                                 vertices[i].Pos.rotateXYBy(-180);
261                                 if(facedir == 1)
262                                         vertices[i].Pos.rotateXZBy(90);
263                                 else if(facedir == 2)
264                                         vertices[i].Pos.rotateXZBy(180);
265                                 else if(facedir == 3)
266                                         vertices[i].Pos.rotateXZBy(-90);
267                                 break;
268                         default:
269                                 break;
270                         }
271                 }
272         }
273 }
274
275 void recalculateBoundingBox(scene::IMesh *src_mesh)
276 {
277         core::aabbox3d<f32> bbox;
278         bbox.reset(0,0,0);
279         for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++)
280         {
281                 scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
282                 buf->recalculateBoundingBox();
283                 if(j == 0)
284                         bbox = buf->getBoundingBox();
285                 else
286                         bbox.addInternalBox(buf->getBoundingBox());
287         }
288         src_mesh->setBoundingBox(bbox);
289 }
290
291 scene::IMesh* cloneMesh(scene::IMesh *src_mesh)
292 {
293         scene::SMesh* dst_mesh = new scene::SMesh();
294         for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++)
295         {
296                 scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j);
297                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
298                 u16 *indices = (u16*)buf->getIndices();
299                 scene::SMeshBuffer *temp_buf = new scene::SMeshBuffer();
300                 temp_buf->append(vertices, buf->getVertexCount(),
301                         indices, buf->getIndexCount());
302                 dst_mesh->addMeshBuffer(temp_buf);
303                 temp_buf->drop();
304         }
305         return dst_mesh;                                        
306 }
307
308 scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f)
309 {
310         scene::SMesh* dst_mesh = new scene::SMesh();
311         for (u16 j = 0; j < 6; j++)
312         {
313                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
314                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
315                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
316                 dst_mesh->addMeshBuffer(buf);
317                 buf->drop();
318         }
319         
320         video::SColor c(255,255,255,255);       
321
322         std::vector<aabb3f> boxes = f->node_box.fixed;
323                 
324         for(std::vector<aabb3f>::iterator
325                         i = boxes.begin();
326                         i != boxes.end(); i++)
327         {
328                 aabb3f box = *i;
329
330                 f32 temp;
331                 if (box.MinEdge.X > box.MaxEdge.X)
332                         {
333                                 temp=box.MinEdge.X;
334                                 box.MinEdge.X=box.MaxEdge.X;
335                                 box.MaxEdge.X=temp;
336                         }
337                 if (box.MinEdge.Y > box.MaxEdge.Y)
338                         {
339                                 temp=box.MinEdge.Y;
340                                 box.MinEdge.Y=box.MaxEdge.Y;
341                                 box.MaxEdge.Y=temp;
342                         }
343                 if (box.MinEdge.Z > box.MaxEdge.Z)
344                         {
345                                 temp=box.MinEdge.Z;
346                                 box.MinEdge.Z=box.MaxEdge.Z;
347                                 box.MaxEdge.Z=temp;
348                         }
349                 // Compute texture coords
350                 f32 tx1 = (box.MinEdge.X/BS)+0.5;
351                 f32 ty1 = (box.MinEdge.Y/BS)+0.5;
352                 f32 tz1 = (box.MinEdge.Z/BS)+0.5;
353                 f32 tx2 = (box.MaxEdge.X/BS)+0.5;
354                 f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
355                 f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
356                 f32 txc[24] = {
357                         // up
358                         tx1, 1-tz2, tx2, 1-tz1,
359                         // down
360                         tx1, tz1, tx2, tz2,
361                         // right
362                         tz1, 1-ty2, tz2, 1-ty1,
363                         // left
364                         1-tz2, 1-ty2, 1-tz1, 1-ty1,
365                         // back
366                         1-tx2, 1-ty2, 1-tx1, 1-ty1,
367                         // front
368                         tx1, 1-ty2, tx2, 1-ty1,
369                 };
370                 v3f min = box.MinEdge;
371                 v3f max = box.MaxEdge;
372
373                 video::S3DVertex vertices[24] =
374                 {
375                         // up
376                         video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
377                         video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
378                         video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
379                         video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
380                         // down
381                         video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
382                         video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
383                         video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
384                         video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
385                         // right
386                         video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
387                         video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
388                         video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
389                         video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
390                         // left
391                         video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
392                         video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
393                         video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
394                         video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
395                         // back
396                         video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
397                         video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
398                         video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
399                         video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
400                         // front
401                         video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
402                         video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
403                         video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
404                         video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
405                 };
406
407                 u16 indices[] = {0,1,2,2,3,0};
408
409                 for(u16 j = 0; j < 24; j += 4)
410                 {
411                         scene::IMeshBuffer *buf = dst_mesh->getMeshBuffer(j / 4);
412                         buf->append(vertices + j, 4, indices, 6);
413                 }
414         }
415         return dst_mesh;                                        
416 }