diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/camera.cpp | 293 | ||||
-rw-r--r-- | src/camera.h | 9 | ||||
-rw-r--r-- | src/content_cao.cpp | 13 | ||||
-rw-r--r-- | src/mesh.cpp | 362 | ||||
-rw-r--r-- | src/mesh.h | 66 | ||||
-rw-r--r-- | src/tile.cpp | 38 | ||||
-rw-r--r-- | src/utility.cpp | 21 | ||||
-rw-r--r-- | src/utility.h | 5 |
9 files changed, 474 insertions, 334 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a0e063465..61a0b1be8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -161,6 +161,7 @@ set(minetest_SRCS MyBillboardSceneNode.cpp content_mapblock.cpp content_cao.cpp + mesh.cpp mapblock_mesh.cpp farmesh.cpp keycode.cpp diff --git a/src/camera.cpp b/src/camera.cpp index 8f421e691..c0e171468 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -22,21 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "main.h" // for g_settings #include "map.h" +#include "mesh.h" #include "player.h" #include "tile.h" #include <cmath> -#include <SAnimatedMesh.h> #include "settings.h" #include "nodedef.h" // For wield visualization -// In Irrlicht 1.8 the signature of ITexture::lock was changed from -// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32). -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7 -#define MY_ETLM_READ_ONLY true -#else -#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY -#endif - Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): m_smgr(smgr), m_playernode(NULL), @@ -480,7 +472,6 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef) case NDT_ALLFACES: case NDT_ALLFACES_OPTIONAL: m_wieldnode->setCube(ndef->get(content).tiles); - m_wieldnode->setScale(v3f(30)); isCube = true; break; default: @@ -492,7 +483,6 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef) if (!isCube) { m_wieldnode->setSprite(item->getImageRaw()); - m_wieldnode->setScale(v3f(40)); } m_wieldnode->setVisible(true); @@ -501,7 +491,6 @@ void Camera::wield(const InventoryItem* item, IGameDef *gamedef) { // Bare hands m_wieldnode->setSprite(gamedef->tsrc()->getTextureRaw("wieldhand.png")); - m_wieldnode->setScale(v3f(40)); m_wieldnode->setVisible(true); } } @@ -536,7 +525,6 @@ ExtrudedSpriteSceneNode::ExtrudedSpriteSceneNode( ISceneNode(parent, mgr, id, position, rotation, scale) { m_meshnode = mgr->addMeshSceneNode(NULL, this, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true); - m_thickness = 0.1; m_cubemesh = NULL; m_is_cube = false; m_light = LIGHT_MAX; @@ -551,6 +539,8 @@ ExtrudedSpriteSceneNode::~ExtrudedSpriteSceneNode() void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture) { + const v3f sprite_scale(40.0, 40.0, 4.0); // width, height, thickness + if (texture == NULL) { m_meshnode->setVisible(false); @@ -568,7 +558,9 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture) else { // Texture was not yet extruded, do it now and save in cache - mesh = extrude(texture); + mesh = createExtrudedMesh(texture, + SceneManager->getVideoDriver(), + sprite_scale); if (mesh == NULL) { dstream << "Warning: failed to extrude sprite" << std::endl; @@ -580,7 +572,6 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture) mesh->drop(); } - m_meshnode->setScale(v3f(1, 1, m_thickness)); m_meshnode->getMaterial(0).setTexture(0, texture); m_meshnode->getMaterial(0).setFlag(video::EMF_LIGHTING, false); m_meshnode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, false); @@ -592,11 +583,14 @@ void ExtrudedSpriteSceneNode::setSprite(video::ITexture* texture) void ExtrudedSpriteSceneNode::setCube(const TileSpec tiles[6]) { + const v3f cube_scale(30.0, 30.0, 30.0); + if (m_cubemesh == NULL) - m_cubemesh = createCubeMesh(); + { + m_cubemesh = createCubeMesh(cube_scale); + } m_meshnode->setMesh(m_cubemesh); - m_meshnode->setScale(v3f(1)); for (int i = 0; i < 6; ++i) { // Get the tile texture and atlas transformation @@ -626,7 +620,7 @@ void ExtrudedSpriteSceneNode::updateLight(u8 light) // Set brightness one lower than incoming light diminish_light(li); video::SColor color(255,li,li,li); - setMeshVerticesColor(m_meshnode->getMesh(), color); + setMeshColor(m_meshnode->getMesh(), color); } void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture) @@ -637,13 +631,6 @@ void ExtrudedSpriteSceneNode::removeSpriteFromCache(video::ITexture* texture) cache->removeMesh(mesh); } -void ExtrudedSpriteSceneNode::setSpriteThickness(f32 thickness) -{ - m_thickness = thickness; - if (!m_is_cube) - m_meshnode->setScale(v3f(1, 1, thickness)); -} - const core::aabbox3d<f32>& ExtrudedSpriteSceneNode::getBoundingBox() const { return m_meshnode->getBoundingBox(); @@ -667,259 +654,3 @@ io::path ExtrudedSpriteSceneNode::getExtrudedName(video::ITexture* texture) path.append("/[extruded]"); return path; } - -scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrudeARGB(u32 width, u32 height, u8* data) -{ - const s32 argb_wstep = 4 * width; - const s32 alpha_threshold = 1; - - scene::IMeshBuffer* buf = new scene::SMeshBuffer(); - video::SColor c(255,255,255,255); - - // Front and back - { - video::S3DVertex vertices[8] = - { - video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), - video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), - video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), - video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), - video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1), - video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0), - video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0), - video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1), - }; - u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4}; - buf->append(vertices, 8, indices, 12); - } - - // "Interior" - // (add faces where a solid pixel is next to a transparent one) - u8* solidity = new u8[(width+2) * (height+2)]; - u32 wstep = width + 2; - for (u32 y = 0; y < height + 2; ++y) - { - u8* scanline = solidity + y * wstep; - if (y == 0 || y == height + 1) - { - for (u32 x = 0; x < width + 2; ++x) - scanline[x] = 0; - } - else - { - scanline[0] = 0; - u8* argb_scanline = data + (y - 1) * argb_wstep; - for (u32 x = 0; x < width; ++x) - scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold); - scanline[width + 1] = 0; - } - } - - // without this, there would be occasional "holes" in the mesh - f32 eps = 0.01; - - for (u32 y = 0; y <= height; ++y) - { - u8* scanline = solidity + y * wstep + 1; - for (u32 x = 0; x <= width; ++x) - { - if (scanline[x] && !scanline[x + wstep]) - { - u32 xx = x + 1; - while (scanline[xx] && !scanline[xx + wstep]) - ++xx; - f32 vx1 = (x - eps) / (f32) width - 0.5; - f32 vx2 = (xx + eps) / (f32) width - 0.5; - f32 vy = 0.5 - (y - eps) / (f32) height; - f32 tx1 = x / (f32) width; - f32 tx2 = xx / (f32) width; - f32 ty = (y - 0.5) / (f32) height; - video::S3DVertex vertices[8] = - { - video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty), - video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty), - video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty), - video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty), - }; - u16 indices[6] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - x = xx - 1; - } - if (!scanline[x] && scanline[x + wstep]) - { - u32 xx = x + 1; - while (!scanline[xx] && scanline[xx + wstep]) - ++xx; - f32 vx1 = (x - eps) / (f32) width - 0.5; - f32 vx2 = (xx + eps) / (f32) width - 0.5; - f32 vy = 0.5 - (y + eps) / (f32) height; - f32 tx1 = x / (f32) width; - f32 tx2 = xx / (f32) width; - f32 ty = (y + 0.5) / (f32) height; - video::S3DVertex vertices[8] = - { - video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty), - video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty), - video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty), - video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty), - }; - u16 indices[6] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - x = xx - 1; - } - } - } - - for (u32 x = 0; x <= width; ++x) - { - u8* scancol = solidity + x + wstep; - for (u32 y = 0; y <= height; ++y) - { - if (scancol[y * wstep] && !scancol[y * wstep + 1]) - { - u32 yy = y + 1; - while (scancol[yy * wstep] && !scancol[yy * wstep + 1]) - ++yy; - f32 vx = (x - eps) / (f32) width - 0.5; - f32 vy1 = 0.5 - (y - eps) / (f32) height; - f32 vy2 = 0.5 - (yy + eps) / (f32) height; - f32 tx = (x - 0.5) / (f32) width; - f32 ty1 = y / (f32) height; - f32 ty2 = yy / (f32) height; - video::S3DVertex vertices[8] = - { - video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1), - video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1), - video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2), - video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2), - }; - u16 indices[6] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - y = yy - 1; - } - if (!scancol[y * wstep] && scancol[y * wstep + 1]) - { - u32 yy = y + 1; - while (!scancol[yy * wstep] && scancol[yy * wstep + 1]) - ++yy; - f32 vx = (x + eps) / (f32) width - 0.5; - f32 vy1 = 0.5 - (y - eps) / (f32) height; - f32 vy2 = 0.5 - (yy + eps) / (f32) height; - f32 tx = (x + 0.5) / (f32) width; - f32 ty1 = y / (f32) height; - f32 ty2 = yy / (f32) height; - video::S3DVertex vertices[8] = - { - video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1), - video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2), - video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2), - video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1), - }; - u16 indices[6] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - y = yy - 1; - } - } - } - - // Add to mesh - scene::SMesh* mesh = new scene::SMesh(); - buf->recalculateBoundingBox(); - mesh->addMeshBuffer(buf); - buf->drop(); - mesh->recalculateBoundingBox(); - scene::SAnimatedMesh* anim_mesh = new scene::SAnimatedMesh(mesh); - mesh->drop(); - return anim_mesh; -} - -scene::IAnimatedMesh* ExtrudedSpriteSceneNode::extrude(video::ITexture* texture) -{ - scene::IAnimatedMesh* mesh = NULL; - core::dimension2d<u32> size = texture->getSize(); - video::ECOLOR_FORMAT format = texture->getColorFormat(); - if (format == video::ECF_A8R8G8B8) - { - // Texture is in the correct color format, we can pass it - // to extrudeARGB right away. - void* data = texture->lock(MY_ETLM_READ_ONLY); - if (data == NULL) - return NULL; - mesh = extrudeARGB(size.Width, size.Height, (u8*) data); - texture->unlock(); - } - else - { - video::IVideoDriver* driver = SceneManager->getVideoDriver(); - - video::IImage* img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY)); - if (img1 == NULL) - return NULL; - - // img1 is in the texture's color format, convert to 8-bit ARGB - video::IImage* img2 = driver->createImage(video::ECF_A8R8G8B8, size); - if (img2 != NULL) - { - img1->copyTo(img2); - img1->drop(); - - mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock()); - img2->unlock(); - img2->drop(); - } - img1->drop(); - } - return mesh; -} - -scene::IMesh* ExtrudedSpriteSceneNode::createCubeMesh() -{ - video::SColor c(255,255,255,255); - video::S3DVertex vertices[24] = - { - // Up - video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1), - video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0), - video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0), - video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1), - // Down - video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0), - video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0), - video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1), - video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1), - // Right - video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1), - video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0), - video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0), - video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1), - // Left - video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1), - video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1), - video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0), - video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0), - // Back - video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1), - video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1), - video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0), - video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0), - // Front - video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), - video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), - video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), - video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), - }; - - u16 indices[6] = {0,1,2,2,3,0}; - - scene::SMesh* mesh = new scene::SMesh(); - for (u32 i=0; i<6; ++i) - { - scene::IMeshBuffer* buf = new scene::SMeshBuffer(); - buf->append(vertices + 4 * i, 4, indices, 6); - buf->recalculateBoundingBox(); - mesh->addMeshBuffer(buf); - buf->drop(); - } - mesh->recalculateBoundingBox(); - return mesh; -} diff --git a/src/camera.h b/src/camera.h index 973ae3f31..d5789d807 100644 --- a/src/camera.h +++ b/src/camera.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" #include "inventory.h" +#include "mesh.h" #include "tile.h" #include "utility.h" #include <ICameraSceneNode.h> @@ -206,9 +207,6 @@ public: void setSprite(video::ITexture* texture); void setCube(const TileSpec tiles[6]); - f32 getSpriteThickness() const { return m_thickness; } - void setSpriteThickness(f32 thickness); - void updateLight(u8 light); void removeSpriteFromCache(video::ITexture* texture); @@ -219,16 +217,11 @@ public: private: scene::IMeshSceneNode* m_meshnode; - f32 m_thickness; scene::IMesh* m_cubemesh; bool m_is_cube; u8 m_light; - // internal extrusion helper methods io::path getExtrudedName(video::ITexture* texture); - scene::IAnimatedMesh* extrudeARGB(u32 width, u32 height, u8* data); - scene::IAnimatedMesh* extrude(video::ITexture* texture); - scene::IMesh* createCubeMesh(); }; #endif diff --git a/src/content_cao.cpp b/src/content_cao.cpp index b9dc91e63..da68004ce 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gamedef.h" #include "clientobject.h" #include "content_object.h" +#include "mesh.h" #include "utility.h" // For IntervalLimiter class Settings; #include "MyBillboardSceneNode.h" @@ -630,7 +631,7 @@ void ItemCAO::updateLight(u8 light_at_pos) u8 li = decode_light(light_at_pos); video::SColor color(255,li,li,li); - setMeshVerticesColor(m_node->getMesh(), color); + setMeshColor(m_node->getMesh(), color); } v3s16 ItemCAO::getLightPosition() @@ -778,7 +779,7 @@ void RatCAO::updateLight(u8 light_at_pos) u8 li = decode_light(light_at_pos); video::SColor color(255,li,li,li); - setMeshVerticesColor(m_node->getMesh(), color); + setMeshColor(m_node->getMesh(), color); } v3s16 RatCAO::getLightPosition() @@ -934,7 +935,7 @@ void Oerkki1CAO::updateLight(u8 light_at_pos) u8 li = decode_light(light_at_pos); video::SColor color(255,li,li,li); - setMeshVerticesColor(m_node->getMesh(), color); + setMeshColor(m_node->getMesh(), color); } v3s16 Oerkki1CAO::getLightPosition() @@ -1165,7 +1166,7 @@ void FireflyCAO::updateLight(u8 light_at_pos) u8 li = 255; video::SColor color(255,li,li,li); - setMeshVerticesColor(m_node->getMesh(), color); + setMeshColor(m_node->getMesh(), color); } v3s16 FireflyCAO::getLightPosition() @@ -1866,7 +1867,7 @@ public: u8 li = decode_light(light_at_pos); video::SColor color(255,li,li,li); if(m_meshnode){ - setMeshVerticesColor(m_meshnode->getMesh(), color); + setMeshColor(m_meshnode->getMesh(), color); m_meshnode->setVisible(true); } if(m_spritenode){ @@ -2250,7 +2251,7 @@ public: u8 li = decode_light(light_at_pos); video::SColor color(255,li,li,li); - setMeshVerticesColor(m_node->getMesh(), color); + setMeshColor(m_node->getMesh(), color); } v3s16 getLightPosition() diff --git a/src/mesh.cpp b/src/mesh.cpp new file mode 100644 index 000000000..1d347a09f --- /dev/null +++ b/src/mesh.cpp @@ -0,0 +1,362 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "mesh.h" +#include <IAnimatedMesh.h> +#include <SAnimatedMesh.h> + +// In Irrlicht 1.8 the signature of ITexture::lock was changed from +// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32). +#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7 +#define MY_ETLM_READ_ONLY true +#else +#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY +#endif + +scene::IAnimatedMesh* createCubeMesh(v3f scale) +{ + video::SColor c(255,255,255,255); + video::S3DVertex vertices[24] = + { + // Up + video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1), + video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0), + video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0), + video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1), + // Down + video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0), + video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0), + video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1), + video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1), + // Right + video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1), + video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0), + video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0), + video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1), + // Left + video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1), + video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1), + video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0), + video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0), + // Back + video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1), + video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1), + video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0), + video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0), + // Front + video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), + video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), + video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), + video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), + }; + + u16 indices[6] = {0,1,2,2,3,0}; + + scene::SMesh *mesh = new scene::SMesh(); + for (u32 i=0; i<6; ++i) + { + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + buf->append(vertices + 4 * i, 4, indices, 6); + mesh->addMeshBuffer(buf); + buf->drop(); + } + scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh); + mesh->drop(); + scaleMesh(anim_mesh, scale); // also recalculates bounding box + return anim_mesh; +} + +static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data) +{ + const s32 argb_wstep = 4 * twidth; + const s32 alpha_threshold = 1; + + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + video::SColor c(255,255,255,255); + + // Front and back + { + video::S3DVertex vertices[8] = + { + video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), + video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), + video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), + video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), + video::S3DVertex(+0.5,-0.5,+0.5, 0,0,+1, c, 1,1), + video::S3DVertex(+0.5,+0.5,+0.5, 0,0,+1, c, 1,0), + video::S3DVertex(-0.5,+0.5,+0.5, 0,0,+1, c, 0,0), + video::S3DVertex(-0.5,-0.5,+0.5, 0,0,+1, c, 0,1), + }; + u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4}; + buf->append(vertices, 8, indices, 12); + } + + // "Interior" + // (add faces where a solid pixel is next to a transparent one) + u8 *solidity = new u8[(twidth+2) * (theight+2)]; + u32 wstep = twidth + 2; + for (u32 y = 0; y < theight + 2; ++y) + { + u8 *scanline = solidity + y * wstep; + if (y == 0 || y == theight + 1) + { + for (u32 x = 0; x < twidth + 2; ++x) + scanline[x] = 0; + } + else + { + scanline[0] = 0; + u8 *argb_scanline = data + (y - 1) * argb_wstep; + for (u32 x = 0; x < twidth; ++x) + scanline[x+1] = (argb_scanline[x*4+3] >= alpha_threshold); + scanline[twidth + 1] = 0; + } + } + + // without this, there would be occasional "holes" in the mesh + f32 eps = 0.01; + + for (u32 y = 0; y <= theight; ++y) + { + u8 *scanline = solidity + y * wstep + 1; + for (u32 x = 0; x <= twidth; ++x) + { + if (scanline[x] && !scanline[x + wstep]) + { + u32 xx = x + 1; + while (scanline[xx] && !scanline[xx + wstep]) + ++xx; + f32 vx1 = (x - eps) / (f32) twidth - 0.5; + f32 vx2 = (xx + eps) / (f32) twidth - 0.5; + f32 vy = 0.5 - (y - eps) / (f32) theight; + f32 tx1 = x / (f32) twidth; + f32 tx2 = xx / (f32) twidth; + f32 ty = (y - 0.5) / (f32) theight; + video::S3DVertex vertices[8] = + { + video::S3DVertex(vx1,vy,-0.5, 0,-1,0, c, tx1,ty), + video::S3DVertex(vx2,vy,-0.5, 0,-1,0, c, tx2,ty), + video::S3DVertex(vx2,vy,+0.5, 0,-1,0, c, tx2,ty), + video::S3DVertex(vx1,vy,+0.5, 0,-1,0, c, tx1,ty), + }; + u16 indices[6] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + x = xx - 1; + } + if (!scanline[x] && scanline[x + wstep]) + { + u32 xx = x + 1; + while (!scanline[xx] && scanline[xx + wstep]) + ++xx; + f32 vx1 = (x - eps) / (f32) twidth - 0.5; + f32 vx2 = (xx + eps) / (f32) twidth - 0.5; + f32 vy = 0.5 - (y + eps) / (f32) theight; + f32 tx1 = x / (f32) twidth; + f32 tx2 = xx / (f32) twidth; + f32 ty = (y + 0.5) / (f32) theight; + video::S3DVertex vertices[8] = + { + video::S3DVertex(vx1,vy,-0.5, 0,1,0, c, tx1,ty), + video::S3DVertex(vx1,vy,+0.5, 0,1,0, c, tx1,ty), + video::S3DVertex(vx2,vy,+0.5, 0,1,0, c, tx2,ty), + video::S3DVertex(vx2,vy,-0.5, 0,1,0, c, tx2,ty), + }; + u16 indices[6] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + x = xx - 1; + } + } + } + + for (u32 x = 0; x <= twidth; ++x) + { + u8 *scancol = solidity + x + wstep; + for (u32 y = 0; y <= theight; ++y) + { + if (scancol[y * wstep] && !scancol[y * wstep + 1]) + { + u32 yy = y + 1; + while (scancol[yy * wstep] && !scancol[yy * wstep + 1]) + ++yy; + f32 vx = (x - eps) / (f32) twidth - 0.5; + f32 vy1 = 0.5 - (y - eps) / (f32) theight; + f32 vy2 = 0.5 - (yy + eps) / (f32) theight; + f32 tx = (x - 0.5) / (f32) twidth; + f32 ty1 = y / (f32) theight; + f32 ty2 = yy / (f32) theight; + video::S3DVertex vertices[8] = + { + video::S3DVertex(vx,vy1,-0.5, 1,0,0, c, tx,ty1), + video::S3DVertex(vx,vy1,+0.5, 1,0,0, c, tx,ty1), + video::S3DVertex(vx,vy2,+0.5, 1,0,0, c, tx,ty2), + video::S3DVertex(vx,vy2,-0.5, 1,0,0, c, tx,ty2), + }; + u16 indices[6] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + y = yy - 1; + } + if (!scancol[y * wstep] && scancol[y * wstep + 1]) + { + u32 yy = y + 1; + while (!scancol[yy * wstep] && scancol[yy * wstep + 1]) + ++yy; + f32 vx = (x + eps) / (f32) twidth - 0.5; + f32 vy1 = 0.5 - (y - eps) / (f32) theight; + f32 vy2 = 0.5 - (yy + eps) / (f32) theight; + f32 tx = (x + 0.5) / (f32) twidth; + f32 ty1 = y / (f32) theight; + f32 ty2 = yy / (f32) theight; + video::S3DVertex vertices[8] = + { + video::S3DVertex(vx,vy1,-0.5, -1,0,0, c, tx,ty1), + video::S3DVertex(vx,vy2,-0.5, -1,0,0, c, tx,ty2), + video::S3DVertex(vx,vy2,+0.5, -1,0,0, c, tx,ty2), + video::S3DVertex(vx,vy1,+0.5, -1,0,0, c, tx,ty1), + }; + u16 indices[6] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + y = yy - 1; + } + } + } + + // Add to mesh + scene::SMesh *mesh = new scene::SMesh(); + mesh->addMeshBuffer(buf); + buf->drop(); + scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh); + mesh->drop(); + return anim_mesh; +} + +scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture, + video::IVideoDriver *driver, v3f scale) +{ + scene::IAnimatedMesh *mesh = NULL; + core::dimension2d<u32> size = texture->getSize(); + video::ECOLOR_FORMAT format = texture->getColorFormat(); + if (format == video::ECF_A8R8G8B8) + { + // Texture is in the correct color format, we can pass it + // to extrudeARGB right away. + void *data = texture->lock(MY_ETLM_READ_ONLY); + if (data == NULL) + return NULL; + mesh = extrudeARGB(size.Width, size.Height, (u8*) data); + texture->unlock(); + } + else + { + video::IImage *img1 = driver->createImageFromData(format, size, texture->lock(MY_ETLM_READ_ONLY)); + if (img1 == NULL) + return NULL; + + // img1 is in the texture's color format, convert to 8-bit ARGB + video::IImage *img2 = driver->createImage(video::ECF_A8R8G8B8, size); + if (img2 != NULL) + { + img1->copyTo(img2); + img1->drop(); + + mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock()); + img2->unlock(); + img2->drop(); + } + img1->drop(); + } + scaleMesh(mesh, scale); // also recalculates bounding box + return mesh; +} + +void scaleMesh(scene::IMesh *mesh, v3f scale) +{ + if(mesh == NULL) + return; + + core::aabbox3d<f32> bbox; + bbox.reset(0,0,0); + + u16 mc = mesh->getMeshBufferCount(); + for(u16 j=0; j<mc; j++) + { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; i<vc; i++) + { + vertices[i].Pos *= scale; + } + buf->recalculateBoundingBox(); + + // calculate total bounding box + if(j == 0) + bbox = buf->getBoundingBox(); + else + bbox.addInternalBox(buf->getBoundingBox()); + } + mesh->setBoundingBox(bbox); +} + +void setMeshColor(scene::IMesh *mesh, const video::SColor &color) +{ + if(mesh == NULL) + return; + + u16 mc = mesh->getMeshBufferCount(); + for(u16 j=0; j<mc; j++) + { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; i<vc; i++) + { + vertices[i].Color = color; + } + } +} + +void setMeshColorByNormalXYZ(scene::IMesh *mesh, + const video::SColor &colorX, + const video::SColor &colorY, + const video::SColor &colorZ) +{ + if(mesh == NULL) + return; + + u16 mc = mesh->getMeshBufferCount(); + for(u16 j=0; j<mc; j++) + { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; i<vc; i++) + { + f32 x = fabs(vertices[i].Normal.X); + f32 y = fabs(vertices[i].Normal.Y); + f32 z = fabs(vertices[i].Normal.Z); + if(x >= y && x >= z) + vertices[i].Color = colorX; + else if(y >= z) + vertices[i].Color = colorY; + else + vertices[i].Color = colorZ; + + } + } +} diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 000000000..33e072927 --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,66 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef MESH_HEADER +#define MESH_HEADER + +#include "common_irrlicht.h" + +/* + Create a new cube mesh. + Vertices are at (+-scale.X/2, +-scale.Y/2, +-scale.Z/2). + + The resulting mesh has 6 materials (up, down, right, left, back, front) + which must be defined by the caller. +*/ +scene::IAnimatedMesh* createCubeMesh(v3f scale); + +/* + Create a new extruded mesh from a texture. + Maximum bounding box is (+-scale.X/2, +-scale.Y/2, +-scale.Z). + Thickness is in Z direction. + + The resulting mesh has 1 material which must be defined by the caller. +*/ +scene::IAnimatedMesh* createExtrudedMesh(video::ITexture *texture, + video::IVideoDriver *driver, v3f scale); + +/* + Multiplies each vertex coordinate by the specified scaling factors + (componentwise vector multiplication). +*/ +void scaleMesh(scene::IMesh *mesh, v3f scale); + +/* + Set a constant color for all vertices in the mesh +*/ +void setMeshColor(scene::IMesh *mesh, const video::SColor &color); + +/* + Set the color of all vertices in the mesh. + For each vertex, determine the largest absolute entry in + the normal vector, and choose one of colorX, colorY or + colorZ accordingly. +*/ +void setMeshColorByNormalXYZ(scene::IMesh *mesh, + const video::SColor &colorX, + const video::SColor &colorY, + const video::SColor &colorZ); + +#endif diff --git a/src/tile.cpp b/src/tile.cpp index 27454c321..89f345197 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "utility.h" #include "settings.h" +#include "mesh.h" #include <ICameraSceneNode.h> #include "log.h" #include "mapnode.h" // For texture atlas making @@ -1468,11 +1469,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, assert(img_top && img_left && img_right); // Create textures from images - // TODO: Use them all video::ITexture *texture_top = driver->addTexture( (imagename_top + "__temp__").c_str(), img_top); - assert(texture_top); - + video::ITexture *texture_left = driver->addTexture( + (imagename_left + "__temp__").c_str(), img_left); + video::ITexture *texture_right = driver->addTexture( + (imagename_right + "__temp__").c_str(), img_right); + assert(texture_top && texture_left && texture_right); + // Drop images img_top->drop(); img_left->drop(); @@ -1499,17 +1503,24 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, Create scene: - An unit cube is centered at 0,0,0 - Camera looks at cube from Y+, Z- towards Y-, Z+ - NOTE: Cube has to be changed to something else because - the textures cannot be set individually (or can they?) */ - scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1, - v3f(0,0,0), v3f(0, 45, 0)); + scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1)); + setMeshColor(cube, video::SColor(255, 255, 255, 255)); + + scene::IMeshSceneNode* cubenode = smgr->addMeshSceneNode(cube, NULL, -1, v3f(0,0,0), v3f(0,45,0), v3f(1,1,1), true); + cube->drop(); + // Set texture of cube - cube->setMaterialTexture(0, texture_top); - //cube->setMaterialFlag(video::EMF_LIGHTING, false); - cube->setMaterialFlag(video::EMF_ANTI_ALIASING, false); - cube->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + cubenode->getMaterial(0).setTexture(0, texture_top); + cubenode->getMaterial(1).setTexture(0, texture_top); + cubenode->getMaterial(2).setTexture(0, texture_right); + cubenode->getMaterial(3).setTexture(0, texture_right); + cubenode->getMaterial(4).setTexture(0, texture_left); + cubenode->getMaterial(5).setTexture(0, texture_left); + cubenode->setMaterialFlag(video::EMF_LIGHTING, true); + cubenode->setMaterialFlag(video::EMF_ANTI_ALIASING, true); + cubenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true); scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, v3f(0, 1.0, -1.5), v3f(0, 0, 0)); @@ -1519,7 +1530,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, camera->setProjectionMatrix(pm, true); /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0, - v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000); + v3f(-50, 100, -75), video::SColorf(0.5,0.5,0.5), 1000); smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2)); @@ -1540,8 +1551,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, driver->setRenderTarget(0, true, true, 0); // Free textures of images - // TODO: When all are used, free them all driver->removeTexture(texture_top); + driver->removeTexture(texture_left); + driver->removeTexture(texture_right); // Create image of render target video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim); diff --git a/src/utility.cpp b/src/utility.cpp index 87c81cb2a..4e9f307d8 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -172,27 +172,6 @@ int myrand_range(int min, int max) return (myrand()%(max-min+1))+min; } -#ifndef SERVER -// Sets the color of all vertices in the mesh -void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color) -{ - if(mesh == NULL) - return; - - u16 mc = mesh->getMeshBufferCount(); - for(u16 j=0; j<mc; j++) - { - scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); - video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); - u16 vc = buf->getVertexCount(); - for(u16 i=0; i<vc; i++) - { - vertices[i].Color = color; - } - } -} -#endif - /* blockpos: position of block in block coordinates camera_pos: position of camera in nodes diff --git a/src/utility.h b/src/utility.h index 47696cbf8..14b49772b 100644 --- a/src/utility.h +++ b/src/utility.h @@ -694,11 +694,6 @@ private: u32 *m_result; }; -#ifndef SERVER -// Sets the color of all vertices in the mesh -void setMeshVerticesColor(scene::IMesh* mesh, video::SColor& color); -#endif - // Calculates the borders of a "d-radius" cube inline void getFacePositions(core::list<v3s16> &list, u16 d) { |