]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mesh.cpp
inventorycube: use all three specified textures; also moved mesh creation / modificat...
[dragonfireclient.git] / src / mesh.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mesh.h"
21 #include <IAnimatedMesh.h>
22 #include <SAnimatedMesh.h>
23
24 // In Irrlicht 1.8 the signature of ITexture::lock was changed from
25 // (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
26 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
27 #define MY_ETLM_READ_ONLY true
28 #else
29 #define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
30 #endif
31
32 scene::IAnimatedMesh* createCubeMesh(v3f scale)
33 {
34         video::SColor c(255,255,255,255);
35         video::S3DVertex vertices[24] =
36         {
37                 // Up
38                 video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1),
39                 video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0),
40                 video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0),
41                 video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1),
42                 // Down
43                 video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0),
44                 video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0),
45                 video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1),
46                 video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1),
47                 // Right
48                 video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1),
49                 video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0),
50                 video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0),
51                 video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1),
52                 // Left
53                 video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1),
54                 video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1),
55                 video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0),
56                 video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0),
57                 // Back
58                 video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1),
59                 video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1),
60                 video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0),
61                 video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0),
62                 // Front
63                 video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
64                 video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
65                 video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
66                 video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
67         };
68
69         u16 indices[6] = {0,1,2,2,3,0};
70
71         scene::SMesh *mesh = new scene::SMesh();
72         for (u32 i=0; i<6; ++i)
73         {
74                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
75                 buf->append(vertices + 4 * i, 4, indices, 6);
76                 mesh->addMeshBuffer(buf);
77                 buf->drop();
78         }
79         scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
80         mesh->drop();
81         scaleMesh(anim_mesh, scale);  // also recalculates bounding box
82         return anim_mesh;
83 }
84
85 static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
86 {
87         const s32 argb_wstep = 4 * twidth;
88         const s32 alpha_threshold = 1;
89
90         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
91         video::SColor c(255,255,255,255);
92
93         // Front and back
94         {
95                 video::S3DVertex vertices[8] =
96                 {
97                         video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
98                         video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
99                         video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
100                         video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
101                         video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
102                         video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
103                         video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
104                         video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
105                 };
106                 u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
107                 buf->append(vertices, 8, indices, 12);
108         }
109
110         // "Interior"
111         // (add faces where a solid pixel is next to a transparent one)
112         u8 *solidity = new u8[(twidth+2) * (theight+2)];
113         u32 wstep = twidth + 2;
114         for (u32 y = 0; y < theight + 2; ++y)
115         {
116                 u8 *scanline = solidity + y * wstep;
117                 if (y == 0 || y == theight + 1)
118                 {
119                         for (u32 x = 0; x < twidth + 2; ++x)
120                                 scanline[x] = 0;
121                 }
122                 else
123                 {
124                         scanline[0] = 0;
125                         u8 *argb_scanline = data + (y - 1) * argb_wstep;
126                         for (u32 x = 0; x < twidth; ++x)
127                                 scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
128                         scanline[twidth + 1] = 0;
129                 }
130         }
131
132         // without this, there would be occasional "holes" in the mesh
133         f32 eps = 0.01;
134
135         for (u32 y = 0; y <= theight; ++y)
136         {
137                 u8 *scanline = solidity + y * wstep + 1;
138                 for (u32 x = 0; x <= twidth; ++x)
139                 {
140                         if (scanline[x] && !scanline[x + wstep])
141                         {
142                                 u32 xx = x + 1;
143                                 while (scanline[xx] && !scanline[xx + wstep])
144                                         ++xx;
145                                 f32 vx1 = (x - eps) / (f32) twidth - 0.5;
146                                 f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
147                                 f32 vy = 0.5 - (y - eps) / (f32) theight;
148                                 f32 tx1 = x / (f32) twidth;
149                                 f32 tx2 = xx / (f32) twidth;
150                                 f32 ty = (y - 0.5) / (f32) theight;
151                                 video::S3DVertex vertices[8] =
152                                 {
153                                         video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
154                                         video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
155                                         video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
156                                         video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
157                                 };
158                                 u16 indices[6] = {0,1,2,2,3,0};
159                                 buf->append(vertices, 4, indices, 6);
160                                 x = xx - 1;
161                         }
162                         if (!scanline[x] && scanline[x + wstep])
163                         {
164                                 u32 xx = x + 1;
165                                 while (!scanline[xx] && scanline[xx + wstep])
166                                         ++xx;
167                                 f32 vx1 = (x - eps) / (f32) twidth - 0.5;
168                                 f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
169                                 f32 vy = 0.5 - (y + eps) / (f32) theight;
170                                 f32 tx1 = x / (f32) twidth;
171                                 f32 tx2 = xx / (f32) twidth;
172                                 f32 ty = (y + 0.5) / (f32) theight;
173                                 video::S3DVertex vertices[8] =
174                                 {
175                                         video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
176                                         video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
177                                         video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
178                                         video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
179                                 };
180                                 u16 indices[6] = {0,1,2,2,3,0};
181                                 buf->append(vertices, 4, indices, 6);
182                                 x = xx - 1;
183                         }
184                 }
185         }
186
187         for (u32 x = 0; x <= twidth; ++x)
188         {
189                 u8 *scancol = solidity + x + wstep;
190                 for (u32 y = 0; y <= theight; ++y)
191                 {
192                         if (scancol[y * wstep] && !scancol[y * wstep + 1])
193                         {
194                                 u32 yy = y + 1;
195                                 while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
196                                         ++yy;
197                                 f32 vx = (x - eps) / (f32) twidth - 0.5;
198                                 f32 vy1 = 0.5 - (y - eps) / (f32) theight;
199                                 f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
200                                 f32 tx = (x - 0.5) / (f32) twidth;
201                                 f32 ty1 = y / (f32) theight;
202                                 f32 ty2 = yy / (f32) theight;
203                                 video::S3DVertex vertices[8] =
204                                 {
205                                         video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
206                                         video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
207                                         video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
208                                         video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
209                                 };
210                                 u16 indices[6] = {0,1,2,2,3,0};
211                                 buf->append(vertices, 4, indices, 6);
212                                 y = yy - 1;
213                         }
214                         if (!scancol[y * wstep] && scancol[y * wstep + 1])
215                         {
216                                 u32 yy = y + 1;
217                                 while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
218                                         ++yy;
219                                 f32 vx = (x + eps) / (f32) twidth - 0.5;
220                                 f32 vy1 = 0.5 - (y - eps) / (f32) theight;
221                                 f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
222                                 f32 tx = (x + 0.5) / (f32) twidth;
223                                 f32 ty1 = y / (f32) theight;
224                                 f32 ty2 = yy / (f32) theight;
225                                 video::S3DVertex vertices[8] =
226                                 {
227                                         video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
228                                         video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
229                                         video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
230                                         video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
231                                 };
232                                 u16 indices[6] = {0,1,2,2,3,0};
233                                 buf->append(vertices, 4, indices, 6);
234                                 y = yy - 1;
235                         }
236                 }
237         }
238
239         // Add to mesh
240         scene::SMesh *mesh = new scene::SMesh();
241         mesh->addMeshBuffer(buf);
242         buf->drop();
243         scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
244         mesh->drop();
245         return anim_mesh;
246 }
247
248 scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
249                 video::IVideoDriver *driver, v3f scale)
250 {
251         scene::IAnimatedMesh *mesh = NULL;
252         core::dimension2d<u32> size = texture->getSize();
253         video::ECOLOR_FORMAT format = texture->getColorFormat();
254         if (format == video::ECF_A8R8G8B8)
255         {
256                 // Texture is in the correct color format, we can pass it
257                 // to extrudeARGB right away.
258                 void *data = texture->lock(MY_ETLM_READ_ONLY);
259                 if (data == NULL)
260                         return NULL;
261                 mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
262                 texture->unlock();
263         }
264         else
265         {
266                 video::IImage *img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY));
267                 if (img1 == NULL)
268                         return NULL;
269
270                 // img1 is in the texture's color format, convert to 8-bit ARGB
271                 video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, size);
272                 if (img2 != NULL)
273                 {
274                         img1->copyTo(img2);
275                         img1->drop();
276
277                         mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
278                         img2->unlock();
279                         img2->drop();
280                 }
281                 img1->drop();
282         }
283         scaleMesh(mesh, scale);  // also recalculates bounding box
284         return mesh;
285 }
286
287 void scaleMesh(scene::IMesh *mesh, v3f scale)
288 {
289         if(mesh == NULL)
290                 return;
291
292         core::aabbox3d<f32> bbox;
293         bbox.reset(0,0,0);
294
295         u16 mc = mesh->getMeshBufferCount();
296         for(u16 j=0; j<mc; j++)
297         {
298                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
299                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
300                 u16 vc = buf->getVertexCount();
301                 for(u16 i=0; i<vc; i++)
302                 {
303                         vertices[i].Pos *= scale;
304                 }
305                 buf->recalculateBoundingBox();
306
307                 // calculate total bounding box
308                 if(j == 0)
309                         bbox = buf->getBoundingBox();
310                 else
311                         bbox.addInternalBox(buf->getBoundingBox());
312         }
313         mesh->setBoundingBox(bbox);
314 }
315
316 void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
317 {
318         if(mesh == NULL)
319                 return;
320         
321         u16 mc = mesh->getMeshBufferCount();
322         for(u16 j=0; j<mc; j++)
323         {
324                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
325                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
326                 u16 vc = buf->getVertexCount();
327                 for(u16 i=0; i<vc; i++)
328                 {
329                         vertices[i].Color = color;
330                 }
331         }
332 }
333
334 void setMeshColorByNormalXYZ(scene::IMesh *mesh,
335                 const video::SColor &colorX,
336                 const video::SColor &colorY,
337                 const video::SColor &colorZ)
338 {
339         if(mesh == NULL)
340                 return;
341         
342         u16 mc = mesh->getMeshBufferCount();
343         for(u16 j=0; j<mc; j++)
344         {
345                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
346                 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
347                 u16 vc = buf->getVertexCount();
348                 for(u16 i=0; i<vc; i++)
349                 {
350                         f32 x = fabs(vertices[i].Normal.X);
351                         f32 y = fabs(vertices[i].Normal.Y);
352                         f32 z = fabs(vertices[i].Normal.Z);
353                         if(x >= y && x >= z)
354                                 vertices[i].Color = colorX;
355                         else if(y >= z)
356                                 vertices[i].Color = colorY;
357                         else
358                                 vertices[i].Color = colorZ;
359
360                 }
361         }
362 }