1604.00
[voxelands.git] / src / mesh.cpp
blob8804cfa920e7787d24c84ced305c4dd4d43e791c
1 /************************************************************************
2 * Minetest-c55
3 * Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 * mesh.cpp
6 * voxelands - 3d voxel world sandbox game
7 * Copyright (C) Lisa 'darkrose' Milne 2014 <lisa@ltmnet.com>
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
22 * License updated from GPLv2 or later to GPLv3 or later by Lisa Milne
23 * for Voxelands.
24 ************************************************************************/
26 #include "mesh.h"
27 #include "log.h"
28 #include "utility.h"
29 #include <cassert>
30 #include <iostream>
31 #include <vector>
32 #include <IAnimatedMesh.h>
33 #include <SAnimatedMesh.h>
34 #include <ICameraSceneNode.h>
35 #include "constants.h"
36 #include "path.h"
37 #include <IMeshLoader.h>
38 #include <IMeshCache.h>
39 #include "main.h"
40 #include "settings.h"
42 // In Irrlicht 1.8 the signature of ITexture::lock was changed from
43 // (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
44 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
45 #define MY_ETLM_READ_ONLY true
46 #else
47 #define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
48 #endif
50 scene::IAnimatedMesh* createNodeBoxMesh(std::vector<NodeBox> nodeboxes, v3f scale)
52 video::SColor c(255,255,255,255);
54 scene::SMesh *mesh = new scene::SMesh();
55 for (std::vector<NodeBox>::const_iterator n = nodeboxes.begin(); n != nodeboxes.end(); n++) {
56 NodeBox box = *n;
57 v3f min = box.m_box.MinEdge;
58 v3f max = box.m_box.MaxEdge;
59 // Compute texture coords
60 f32 tx1 = (box.m_box.MinEdge.X/BS)+0.5;
61 f32 ty1 = (box.m_box.MinEdge.Y/BS)+0.5;
62 f32 tz1 = (box.m_box.MinEdge.Z/BS)+0.5;
63 f32 tx2 = (box.m_box.MaxEdge.X/BS)+0.5;
64 f32 ty2 = (box.m_box.MaxEdge.Y/BS)+0.5;
65 f32 tz2 = (box.m_box.MaxEdge.Z/BS)+0.5;
66 f32 txc[24] = {
67 // up
68 tx1, 1-tz2, tx2, 1-tz1,
69 // down
70 tx1, tz1, tx2, tz2,
71 // right
72 tz1, 1-ty2, tz2, 1-ty1,
73 // left
74 1-tz2, 1-ty2, 1-tz1, 1-ty1,
75 // back
76 1-tx2, 1-ty2, 1-tx1, 1-ty1,
77 // front
78 tx1, 1-ty2, tx2, 1-ty1,
80 video::S3DVertex vertices[24] = {
81 // up
82 video::S3DVertex(min.X/BS,max.Y/BS,max.Z/BS, 0,1,0, c, txc[0],txc[1]),
83 video::S3DVertex(max.X/BS,max.Y/BS,max.Z/BS, 0,1,0, c, txc[2],txc[1]),
84 video::S3DVertex(max.X/BS,max.Y/BS,min.Z/BS, 0,1,0, c, txc[2],txc[3]),
85 video::S3DVertex(min.X/BS,max.Y/BS,min.Z/BS, 0,1,0, c, txc[0],txc[3]),
86 // down
87 video::S3DVertex(min.X/BS,min.Y/BS,min.Z/BS, 0,-1,0, c, txc[4],txc[5]),
88 video::S3DVertex(max.X/BS,min.Y/BS,min.Z/BS, 0,-1,0, c, txc[6],txc[5]),
89 video::S3DVertex(max.X/BS,min.Y/BS,max.Z/BS, 0,-1,0, c, txc[6],txc[7]),
90 video::S3DVertex(min.X/BS,min.Y/BS,max.Z/BS, 0,-1,0, c, txc[4],txc[7]),
91 // right
92 video::S3DVertex(max.X/BS,max.Y/BS,min.Z/BS, 1,0,0, c, txc[ 8],txc[9]),
93 video::S3DVertex(max.X/BS,max.Y/BS,max.Z/BS, 1,0,0, c, txc[10],txc[9]),
94 video::S3DVertex(max.X/BS,min.Y/BS,max.Z/BS, 1,0,0, c, txc[10],txc[11]),
95 video::S3DVertex(max.X/BS,min.Y/BS,min.Z/BS, 1,0,0, c, txc[ 8],txc[11]),
96 // left
97 video::S3DVertex(min.X/BS,max.Y/BS,max.Z/BS, -1,0,0, c, txc[12],txc[13]),
98 video::S3DVertex(min.X/BS,max.Y/BS,min.Z/BS, -1,0,0, c, txc[14],txc[13]),
99 video::S3DVertex(min.X/BS,min.Y/BS,min.Z/BS, -1,0,0, c, txc[14],txc[15]),
100 video::S3DVertex(min.X/BS,min.Y/BS,max.Z/BS, -1,0,0, c, txc[12],txc[15]),
101 // back
102 video::S3DVertex(max.X/BS,max.Y/BS,max.Z/BS, 0,0,1, c, txc[16],txc[17]),
103 video::S3DVertex(min.X/BS,max.Y/BS,max.Z/BS, 0,0,1, c, txc[18],txc[17]),
104 video::S3DVertex(min.X/BS,min.Y/BS,max.Z/BS, 0,0,1, c, txc[18],txc[19]),
105 video::S3DVertex(max.X/BS,min.Y/BS,max.Z/BS, 0,0,1, c, txc[16],txc[19]),
106 // front
107 video::S3DVertex(min.X/BS,max.Y/BS,min.Z/BS, 0,0,-1, c, txc[20],txc[21]),
108 video::S3DVertex(max.X/BS,max.Y/BS,min.Z/BS, 0,0,-1, c, txc[22],txc[21]),
109 video::S3DVertex(max.X/BS,min.Y/BS,min.Z/BS, 0,0,-1, c, txc[22],txc[23]),
110 video::S3DVertex(min.X/BS,min.Y/BS,min.Z/BS, 0,0,-1, c, txc[20],txc[23]),
113 if (box.m_angle != v3s16(0,0,0)) {
114 for (s32 j=0; j<24; j++) {
115 if (box.m_angle.Y)
116 vertices[j].Pos.rotateXZBy(box.m_angle.Y);
117 if (box.m_angle.X)
118 vertices[j].Pos.rotateYZBy(box.m_angle.X);
119 if (box.m_angle.Z)
120 vertices[j].Pos.rotateXYBy(box.m_angle.Z);
124 u16 indices[6] = {0,1,2,2,3,0};
125 for (u32 i=0; i<6; ++i) {
126 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
127 buf->append(vertices + 4 * i, 4, indices, 6);
128 // Set default material
129 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
130 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
131 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
132 // Add mesh buffer to mesh
133 mesh->addMeshBuffer(buf);
134 buf->drop();
138 scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
139 mesh->drop();
140 scaleMesh(anim_mesh, scale); // also recalculates bounding box
141 return anim_mesh;
144 scene::IAnimatedMesh* createCubeMesh(v3f scale)
146 std::vector<NodeBox> nodeboxes;
147 nodeboxes.clear();
148 nodeboxes.push_back(NodeBox(
149 -0.5*BS,
150 -0.5*BS,
151 -0.5*BS,
152 0.5*BS,
153 0.5*BS,
154 0.5*BS
157 return createNodeBoxMesh(nodeboxes,scale);
160 #ifndef SERVER
161 scene::IAnimatedMesh* createModelMesh(scene::ISceneManager* smgr, std::string model, bool unique)
163 std::string model_path = getModelPath(model);
164 scene::IAnimatedMesh* mesh = smgr->getMesh(model_path.c_str());
165 if (mesh && !unique)
166 return mesh;
167 #if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
168 // irrlicht 1.8+ we just manually load the mesh
169 scene::IMeshLoader *loader;
170 u32 lc = smgr->getMeshLoaderCount();
171 io::IReadFile* file = smgr->getFileSystem()->createAndOpenFile(model_path.c_str());
172 if (!file)
173 return 0;
174 for (u32 i=0; i<lc; i++) {
175 loader = smgr->getMeshLoader(i);
176 file->seek(0);
177 if (loader->isALoadableFileExtension(model.c_str())) {
178 mesh = loader->createMesh(file);
179 break;
182 file->drop();
183 #else
184 // irrlicht 1.7 doesn't have a meshloader interface, so rename
185 // the previous mesh from this file to force scenemanager to
186 // load a fresh mesh
187 scene::IMeshCache *mc = smgr->getMeshCache();
188 std::string mp;
189 int i=0;
191 mp = model_path + "-" + itos(i++);
192 } while (mc->getMeshByName(mp.c_str()));
194 mc->renameMesh(mesh,mp.c_str());
196 mesh = smgr->getMesh(model_path.c_str());
197 #endif
198 return mesh;
200 #endif
202 static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
204 const s32 argb_wstep = 4 * twidth;
205 const s32 alpha_threshold = 64;
207 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
208 video::SColor c(255,255,255,255);
210 // Front and back
212 video::S3DVertex vertices[8] = {
213 video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1),
214 video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0),
215 video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0),
216 video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1),
217 video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1),
218 video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0),
219 video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0),
220 video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1),
222 u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
223 buf->append(vertices, 8, indices, 12);
226 // "Interior"
227 // (add faces where a solid pixel is next to a transparent one)
228 u8 *solidity = new u8[(twidth+2) * (theight+2)];
229 u32 wstep = twidth + 2;
230 for (u32 y = 0; y < theight + 2; ++y) {
231 u8 *scanline = solidity + y * wstep;
232 if (y == 0 || y == theight + 1) {
233 for (u32 x = 0; x < twidth + 2; ++x) {
234 scanline[x] = 0;
236 }else{
237 scanline[0] = 0;
238 u8 *argb_scanline = data + (y - 1) * argb_wstep;
239 for (u32 x = 0; x < twidth; ++x) {
240 scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold);
242 scanline[twidth + 1] = 0;
246 // without this, there would be occasional "holes" in the mesh
247 f32 eps = 0.01;
249 for (u32 y = 0; y <= theight; ++y) {
250 u8 *scanline = solidity + y * wstep + 1;
251 for (u32 x = 0; x <= twidth; ++x) {
252 if (scanline[x] && !scanline[x + wstep]) {
253 u32 xx = x + 1;
254 while (scanline[xx] && !scanline[xx + wstep]) {
255 ++xx;
257 f32 vx1 = (x - eps) / (f32) twidth - 0.5;
258 f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
259 f32 vy = 0.5 - (y - eps) / (f32) theight;
260 f32 tx1 = x / (f32) twidth;
261 f32 tx2 = xx / (f32) twidth;
262 f32 ty = (y - 0.5) / (f32) theight;
263 video::S3DVertex vertices[8] = {
264 video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty),
265 video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty),
266 video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty),
267 video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty),
269 u16 indices[6] = {0,1,2,2,3,0};
270 buf->append(vertices, 4, indices, 6);
271 x = xx - 1;
273 if (!scanline[x] && scanline[x + wstep]) {
274 u32 xx = x + 1;
275 while (!scanline[xx] && scanline[xx + wstep]) {
276 ++xx;
278 f32 vx1 = (x - eps) / (f32) twidth - 0.5;
279 f32 vx2 = (xx + eps) / (f32) twidth - 0.5;
280 f32 vy = 0.5 - (y + eps) / (f32) theight;
281 f32 tx1 = x / (f32) twidth;
282 f32 tx2 = xx / (f32) twidth;
283 f32 ty = (y + 0.5) / (f32) theight;
284 video::S3DVertex vertices[8] = {
285 video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty),
286 video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty),
287 video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty),
288 video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty),
290 u16 indices[6] = {0,1,2,2,3,0};
291 buf->append(vertices, 4, indices, 6);
292 x = xx - 1;
297 for (u32 x = 0; x <= twidth; ++x) {
298 u8 *scancol = solidity + x + wstep;
299 for (u32 y = 0; y <= theight; ++y) {
300 if (scancol[y * wstep] && !scancol[y * wstep + 1]) {
301 u32 yy = y + 1;
302 while (scancol[yy * wstep] && !scancol[yy * wstep + 1]) {
303 ++yy;
305 f32 vx = (x - eps) / (f32) twidth - 0.5;
306 f32 vy1 = 0.5 - (y - eps) / (f32) theight;
307 f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
308 f32 tx = (x - 0.5) / (f32) twidth;
309 f32 ty1 = y / (f32) theight;
310 f32 ty2 = yy / (f32) theight;
311 video::S3DVertex vertices[8] = {
312 video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1),
313 video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1),
314 video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2),
315 video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2),
317 u16 indices[6] = {0,1,2,2,3,0};
318 buf->append(vertices, 4, indices, 6);
319 y = yy - 1;
321 if (!scancol[y * wstep] && scancol[y * wstep + 1]) {
322 u32 yy = y + 1;
323 while (!scancol[yy * wstep] && scancol[yy * wstep + 1]) {
324 ++yy;
326 f32 vx = (x + eps) / (f32) twidth - 0.5;
327 f32 vy1 = 0.5 - (y - eps) / (f32) theight;
328 f32 vy2 = 0.5 - (yy + eps) / (f32) theight;
329 f32 tx = (x + 0.5) / (f32) twidth;
330 f32 ty1 = y / (f32) theight;
331 f32 ty2 = yy / (f32) theight;
332 video::S3DVertex vertices[8] = {
333 video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1),
334 video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2),
335 video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2),
336 video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1),
338 u16 indices[6] = {0,1,2,2,3,0};
339 buf->append(vertices, 4, indices, 6);
340 y = yy - 1;
345 delete[] solidity;
347 // Add to mesh
348 scene::SMesh *mesh = new scene::SMesh();
349 mesh->addMeshBuffer(buf);
350 buf->drop();
351 scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh);
352 mesh->drop();
353 return anim_mesh;
356 scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture,
357 video::IVideoDriver *driver, v3f scale)
359 scene::IAnimatedMesh *mesh = NULL;
360 core::dimension2d<u32> size = texture->getSize();
361 video::ECOLOR_FORMAT format = texture->getColorFormat();
362 if (format == video::ECF_A8R8G8B8) {
363 // Texture is in the correct color format, we can pass it
364 // to extrudeARGB right away.
365 void *data = texture->lock(MY_ETLM_READ_ONLY);
366 if (data == NULL)
367 return NULL;
368 mesh = extrudeARGB(size.Width, size.Height, (u8*) data);
369 texture->unlock();
370 }else{
371 video::IImage *img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY));
372 if (img1 == NULL)
373 return NULL;
375 // img1 is in the texture's color format, convert to 8-bit ARGB
376 video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, size);
377 if (img2 != NULL) {
378 img1->copyTo(img2);
380 mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
381 img2->unlock();
382 img2->drop();
384 img1->drop();
387 // Set default material
388 if (mesh && mesh->getMeshBufferCount() > 0) {
389 scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
390 if (buf) {
391 buf->getMaterial().setTexture(0, texture);
392 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
393 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
394 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
398 scaleMesh(mesh, scale); // also recalculates bounding box
399 return mesh;
402 void scaleMesh(scene::IMesh *mesh, v3f scale)
404 if (mesh == NULL)
405 return;
407 core::aabbox3d<f32> bbox;
408 bbox.reset(0,0,0);
410 u16 mc = mesh->getMeshBufferCount();
411 for (u16 j=0; j<mc; j++) {
412 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
413 if (!buf)
414 continue;
415 u16 vc = buf->getVertexCount();
416 if (!vc)
417 continue;
418 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
419 if (!vertices)
420 continue;
421 for (u16 i=0; i<vc; i++) {
422 vertices[i].Pos *= scale;
424 buf->recalculateBoundingBox();
426 // calculate total bounding box
427 if (j == 0) {
428 bbox = buf->getBoundingBox();
429 }else{
430 bbox.addInternalBox(buf->getBoundingBox());
433 mesh->setBoundingBox(bbox);
436 void translateMesh(scene::IMesh *mesh, v3f vec)
438 if (mesh == NULL)
439 return;
441 core::aabbox3d<f32> bbox;
442 bbox.reset(0,0,0);
444 u16 mc = mesh->getMeshBufferCount();
445 for (u16 j=0; j<mc; j++) {
446 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
447 if (!buf)
448 continue;
449 u16 vc = buf->getVertexCount();
450 if (!vc)
451 continue;
452 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
453 if (!vertices)
454 continue;
455 for (u16 i=0; i<vc; i++) {
456 vertices[i].Pos += vec;
458 buf->recalculateBoundingBox();
460 // calculate total bounding box
461 if (j == 0) {
462 bbox = buf->getBoundingBox();
463 }else{
464 bbox.addInternalBox(buf->getBoundingBox());
467 mesh->setBoundingBox(bbox);
470 void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
472 if (mesh == NULL)
473 return;
475 u16 mc = mesh->getMeshBufferCount();
476 for (u16 j=0; j<mc; j++) {
477 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
478 if (!buf)
479 continue;
480 u16 vc = buf->getVertexCount();
481 if (!vc)
482 continue;
483 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
484 if (!vertices)
485 continue;
486 for (u16 i=0; i<vc; i++) {
487 vertices[i].Color = color;
492 void setMeshColorByNormalXYZ(scene::IMesh *mesh,
493 const video::SColor &colorX,
494 const video::SColor &colorY,
495 const video::SColor &colorZ)
497 if (mesh == NULL)
498 return;
500 u16 mc = mesh->getMeshBufferCount();
501 for (u16 j=0; j<mc; j++) {
502 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
503 if (!buf)
504 continue;
505 u16 vc = buf->getVertexCount();
506 if (!vc)
507 continue;
508 video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
509 if (!vertices)
510 continue;
511 for (u16 i=0; i<vc; i++) {
512 f32 x = fabs(vertices[i].Normal.X);
513 f32 y = fabs(vertices[i].Normal.Y);
514 f32 z = fabs(vertices[i].Normal.Z);
515 if (x >= y && x >= z) {
516 vertices[i].Color = colorX;
517 }else if (y >= z) {
518 vertices[i].Color = colorY;
519 }else{
520 vertices[i].Color = colorZ;
526 video::ITexture *generateTextureFromMesh(scene::IMesh *mesh,
527 IrrlichtDevice *device,
528 core::dimension2d<u32> dim,
529 std::string texture_name,
530 v3f camera_position,
531 v3f camera_lookat,
532 core::CMatrix4<f32> camera_projection_matrix,
533 video::SColorf ambient_light,
534 v3f light_position,
535 video::SColorf light_color,
536 f32 light_radius)
538 video::IVideoDriver *driver = device->getVideoDriver();
539 if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
541 static bool warned = false;
542 if(!warned)
544 errorstream<<"generateTextureFromMesh(): EVDF_RENDER_TO_TARGET"
545 " not supported."<<std::endl;
546 warned = true;
548 return NULL;
551 // Create render target texture
552 video::ITexture *rtt = driver->addRenderTargetTexture(
553 dim, texture_name.c_str(), video::ECF_A8R8G8B8);
554 if(rtt == NULL)
556 errorstream<<"generateTextureFromMesh(): addRenderTargetTexture"
557 " returned NULL."<<std::endl;
558 return NULL;
561 // Set render target
562 driver->setRenderTarget(rtt, false, true, video::SColor(0,0,0,0));
564 // Get a scene manager
565 scene::ISceneManager *smgr_main = device->getSceneManager();
566 assert(smgr_main);
567 scene::ISceneManager *smgr = smgr_main->createNewSceneManager();
568 assert(smgr);
570 scene::IMeshSceneNode* meshnode = smgr->addMeshSceneNode(mesh, NULL, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
571 meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
572 meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true);
573 meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
575 scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0,
576 camera_position, camera_lookat);
577 // second parameter of setProjectionMatrix (isOrthogonal) is ignored
578 camera->setProjectionMatrix(camera_projection_matrix, false);
580 smgr->setAmbientLight(ambient_light);
581 smgr->addLightSceneNode(0, light_position, light_color, light_radius);
583 // Render scene
584 driver->beginScene(true, true, video::SColor(0,0,0,0));
585 smgr->drawAll();
586 driver->endScene();
588 // NOTE: The scene nodes should not be dropped, otherwise
589 // smgr->drop() segfaults
590 /*cube->drop();
591 camera->drop();
592 light->drop();*/
593 // Drop scene manager
594 smgr->drop();
596 // Unset render target
597 driver->setRenderTarget(0, false, true, 0);
599 return rtt;
602 ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode(
603 scene::ISceneNode* parent,
604 scene::ISceneManager* mgr,
605 s32 id,
606 const v3f& position,
607 const v3f& rotation,
608 const v3f& scale
610 ISceneNode(parent, mgr, id, position, rotation, scale)
612 m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true);
613 m_thickness = 0.1;
614 m_cubemesh = NULL;
615 m_is_cube = false;
616 m_light = LIGHT_MAX;
619 ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode()
621 removeChild(m_meshnode);
622 if (m_cubemesh)
623 m_cubemesh->drop();
626 void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture)
628 const v3f sprite_scale(1.0,1.0, 1.0); // width, height, thickness
630 if (texture == NULL) {
631 m_meshnode->setVisible(false);
632 return;
635 io::path name = getExtrudedName(texture);
636 scene::IMeshCache* cache = SceneManager->getMeshCache();
637 scene::IAnimatedMesh* mesh = cache->getMeshByName(name);
638 if (mesh != NULL)
640 // Extruded texture has been found in cache.
641 m_meshnode->setMesh(mesh);
643 else
645 // Texture was not yet extruded, do it now and save in cache
646 mesh = createExtrudedMesh(texture, SceneManager->getVideoDriver(), sprite_scale);
647 if (mesh == NULL)
649 dstream << "Warning: failed to extrude sprite" << std::endl;
650 m_meshnode->setVisible(false);
651 return;
653 cache->addMesh(name, mesh);
654 m_meshnode->setMesh(mesh);
655 mesh->drop();
658 m_meshnode->setScale(v3f(1, 1, m_thickness));
659 m_meshnode->getMaterial(0).setTexture(0, texture);
660 m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false);
661 m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false);
662 m_meshnode->getMaterial(0).MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
663 m_meshnode->setVisible(true);
664 m_is_cube = false;
665 updateLight(m_light);
668 void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6])
670 const v3f cube_scale(1.0, 1.0, 1.0);
671 if (m_cubemesh)
672 m_cubemesh->drop();
674 m_cubemesh = createCubeMesh(cube_scale);
676 m_meshnode->setMesh(m_cubemesh);
677 m_meshnode->setScale(v3f(1));
678 for (int i = 0; i < 6; ++i)
680 // Get the tile texture and atlas transformation
681 video::ITexture* atlas = tiles[i].texture.atlas;
682 v2f pos = tiles[i].texture.pos;
683 v2f size = tiles[i].texture.size;
685 // Set material flags and texture
686 video::SMaterial& material = m_meshnode->getMaterial(i);
687 material.setFlag(video::EMF_LIGHTING, false);
688 material.setFlag(video::EMF_BILINEAR_FILTER, false);
689 tiles[i].applyMaterialOptions(material);
690 material.setTexture(0, atlas);
691 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
692 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
694 m_meshnode->setVisible(true);
695 m_is_cube = true;
696 updateLight(m_light);
699 void ExtrudedSpriteSceneNode::setNodeBox(content_t c)
701 const v3f cube_scale(1.0, 1.0, 1.0);
702 if (m_cubemesh)
703 m_cubemesh->drop();
705 std::vector<NodeBox> boxes = content_features(c).getWieldNodeBoxes();
706 m_cubemesh = createNodeBoxMesh(boxes,cube_scale);
708 for (u16 i=0; i < boxes.size(); i++) {
709 for (int t=0; t<6; t++) {
710 video::ITexture* atlas = content_features(c).tiles[t].texture.atlas;
711 v2f pos = content_features(c).tiles[t].texture.pos;
712 v2f size = content_features(c).tiles[t].texture.size;
713 video::SMaterial& material = m_cubemesh->getMeshBuffer((i*6)+t)->getMaterial();
714 material.setFlag(video::EMF_LIGHTING, false);
715 material.setFlag(video::EMF_BILINEAR_FILTER, false);
716 content_features(c).tiles[i].applyMaterialOptions(material);
717 material.setTexture(0, atlas);
718 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
719 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
723 m_meshnode->setMesh(m_cubemesh);
724 m_meshnode->setScale(v3f(1));
726 m_meshnode->setVisible(true);
727 m_is_cube = true;
728 updateLight(m_light);
731 void ExtrudedSpriteSceneNode::setArm(video::ITexture *texture)
733 const v3f cube_scale(0.3, 1.0, 0.3);
734 if (m_cubemesh)
735 m_cubemesh->drop();
737 m_cubemesh = createCubeMesh(cube_scale);
739 m_meshnode->setMesh(m_cubemesh);
740 m_meshnode->setScale(v3f(1));
742 // Get the tile texture and atlas transformation
743 if (texture == NULL)
744 texture = g_texturesource->getTextureRaw("character.png");
745 v2f pos(0.75,0.5);
746 v2f size(0.0625,0.125);
748 // Set material flags and texture
749 video::SMaterial& material = m_meshnode->getMaterial(0);
750 material.setFlag(video::EMF_LIGHTING, false);
751 material.setFlag(video::EMF_BILINEAR_FILTER, false);
752 material.MaterialType = video::EMT_SOLID;
753 material.BackfaceCulling = true;
754 material.setTexture(0, texture);
755 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
756 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
758 for (int i = 1; i < 6; ++i) {
759 // Get the tile texture and atlas transformation
760 v2f pos(0.75,1.);
761 v2f size(0.0625,-0.375);
763 // Set material flags and texture
764 video::SMaterial& material = m_meshnode->getMaterial(i);
765 material.setFlag(video::EMF_LIGHTING, false);
766 material.setFlag(video::EMF_BILINEAR_FILTER, false);
767 material.MaterialType = video::EMT_SOLID;
768 material.BackfaceCulling = true;
769 material.setTexture(0, texture);
770 material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y);
771 material.getTextureMatrix(0).setTextureScale(size.X, size.Y);
773 m_meshnode->setVisible(true);
774 m_is_cube = true;
775 updateLight(m_light);
778 void ExtrudedSpriteSceneNode::updateLight(u8 light)
780 m_light = light;
781 video::SColor color(255,light,light,light);
782 setMeshVerticesColor(m_meshnode->getMesh(), color);
785 void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture)
787 scene::IMeshCache* cache = SceneManager->getMeshCache();
788 scene::IAnimatedMesh* mesh = cache->getMeshByName(getExtrudedName(texture));
789 if (mesh != NULL)
790 cache->removeMesh(mesh);
793 void ExtrudedSpriteSceneNode::setSpriteThickness(f32 thickness)
795 m_thickness = thickness;
796 if (!m_is_cube)
797 m_meshnode->setScale(v3f(1, 1, thickness));
800 const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const
802 return m_meshnode->getBoundingBox();
805 void ExtrudedSpriteSceneNode::OnRegisterSceneNode()
807 if (IsVisible)
808 SceneManager->registerNodeForRendering(this);
809 ISceneNode::OnRegisterSceneNode();
812 void ExtrudedSpriteSceneNode::render()
814 // do nothing
817 io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture)
819 io::path path = texture->getName();
820 path.append("/[extruded]");
821 return path;