3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
21 #include <IAnimatedMesh.h>
22 #include <SAnimatedMesh.h>
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
29 #define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
32 scene::IAnimatedMesh* createCubeMesh(v3f scale)
34 video::SColor c(255,255,255,255);
35 video::S3DVertex vertices[24] =
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),
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),
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),
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),
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),
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),
69 u16 indices[6] = {0,1,2,2,3,0};
71 scene::SMesh *mesh = new scene::SMesh();
72 for (u32 i=0; i<6; ++i)
74 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
75 buf->append(vertices + 4 * i, 4, indices, 6);
76 mesh->addMeshBuffer(buf);
79 scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
81 scaleMesh(anim_mesh, scale); // also recalculates bounding box
85 static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
87 const s32 argb_wstep = 4 * twidth;
88 const s32 alpha_threshold = 1;
90 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
91 video::SColor c(255,255,255,255);
95 video::S3DVertex vertices[8] =
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),
106 u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
107 buf->append(vertices, 8, indices, 12);
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)
116 u8 *scanline = solidity + y * wstep;
117 if (y == 0 || y == theight + 1)
119 for (u32 x = 0; x < twidth + 2; ++x)
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;
132 // without this, there would be occasional "holes" in the mesh
135 for (u32 y = 0; y <= theight; ++y)
137 u8 *scanline = solidity + y * wstep + 1;
138 for (u32 x = 0; x <= twidth; ++x)
140 if (scanline[x] && !scanline[x + wstep])
143 while (scanline[xx] && !scanline[xx + wstep])
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] =
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),
158 u16 indices[6] = {0,1,2,2,3,0};
159 buf->append(vertices, 4, indices, 6);
162 if (!scanline[x] && scanline[x + wstep])
165 while (!scanline[xx] && scanline[xx + wstep])
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] =
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),
180 u16 indices[6] = {0,1,2,2,3,0};
181 buf->append(vertices, 4, indices, 6);
187 for (u32 x = 0; x <= twidth; ++x)
189 u8 *scancol = solidity + x + wstep;
190 for (u32 y = 0; y <= theight; ++y)
192 if (scancol[y * wstep] && !scancol[y * wstep + 1])
195 while (scancol[yy * wstep] && !scancol[yy * wstep + 1])
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] =
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),
210 u16 indices[6] = {0,1,2,2,3,0};
211 buf->append(vertices, 4, indices, 6);
214 if (!scancol[y * wstep] && scancol[y * wstep + 1])
217 while (!scancol[yy * wstep] && scancol[yy * wstep + 1])
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] =
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),
232 u16 indices[6] = {0,1,2,2,3,0};
233 buf->append(vertices, 4, indices, 6);
240 scene::SMesh *mesh = new scene::SMesh();
241 mesh->addMeshBuffer(buf);
243 scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
248 scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
249 video::IVideoDriver *driver, v3f scale)
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)
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);
261 mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
266 video::IImage *img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY));
270 // img1 is in the texture's color format, convert to 8-bit ARGB
271 video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, size);
277 mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
283 scaleMesh(mesh, scale); // also recalculates bounding box
287 void scaleMesh(scene::IMesh *mesh, v3f scale)
292 core::aabbox3d<f32> bbox;
295 u16 mc = mesh->getMeshBufferCount();
296 for(u16 j=0; j<mc; j++)
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++)
303 vertices[i].Pos *= scale;
305 buf->recalculateBoundingBox();
307 // calculate total bounding box
309 bbox = buf->getBoundingBox();
311 bbox.addInternalBox(buf->getBoundingBox());
313 mesh->setBoundingBox(bbox);
316 void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
321 u16 mc = mesh->getMeshBufferCount();
322 for(u16 j=0; j<mc; j++)
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++)
329 vertices[i].Color = color;
334 void setMeshColorByNormalXYZ(scene::IMesh *mesh,
335 const video::SColor &colorX,
336 const video::SColor &colorY,
337 const video::SColor &colorZ)
342 u16 mc = mesh->getMeshBufferCount();
343 for(u16 j=0; j<mc; j++)
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++)
350 f32 x = fabs(vertices[i].Normal.X);
351 f32 y = fabs(vertices[i].Normal.Y);
352 f32 z = fabs(vertices[i].Normal.Z);
354 vertices[i].Color = colorX;
356 vertices[i].Color = colorY;
358 vertices[i].Color = colorZ;