From f846e341de42619b35851beba8c282eb1dbde7ad Mon Sep 17 00:00:00 2001 From: darkrose Date: Tue, 16 Apr 2013 19:30:05 +1000 Subject: [PATCH] fix inventory cube, and more cleanups --- src/CMakeLists.txt | 11 +- src/content_mapnode.cpp | 19 +- src/guiInventoryMenu.cpp | 23 -- src/mesh.cpp | 484 +++++++++++++++++++++++++++++++++++++++ src/mesh.h | 99 ++++++++ src/tile.cpp | 125 ++++------ 6 files changed, 648 insertions(+), 113 deletions(-) create mode 100644 src/mesh.cpp create mode 100644 src/mesh.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afe8a58..35cdad3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -121,6 +121,7 @@ set(common_SRCS mapblock.cpp mapsector.cpp map.cpp + mesh.cpp player.cpp utility.cpp test.cpp @@ -238,7 +239,7 @@ if(MSVC) # Flags for C files (sqlite) # /MT = Link statically with standard library stuff set(CMAKE_C_FLAGS_RELEASE "/O2 /Ob2 /MT") - + if(BUILD_SERVER) set_target_properties(${PROJECT_NAME}server PROPERTIES COMPILE_DEFINITIONS "SERVER") @@ -246,20 +247,20 @@ if(MSVC) else() # Probably GCC - + if(WARN_ALL) set(RELEASE_WARNING_FLAGS "-Wall") else() set(RELEASE_WARNING_FLAGS "") endif() - + if(NOT APPLE AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") CHECK_CXX_COMPILER_FLAG("-Wno-unused-but-set-variable" HAS_UNUSED_BUT_SET_VARIABLE_WARNING) if(HAS_UNUSED_BUT_SET_VARIABLE_WARNING) set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-unused-but-set-variable") endif(HAS_UNUSED_BUT_SET_VARIABLE_WARNING) endif() - + if(APPLE) set(CMAKE_OSX_ARCHITECTURES i386 CACHE STRING "do not build for 64-bit" FORCE) set(ARCH i386) @@ -271,7 +272,7 @@ else() if(USE_GPROF) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg") endif() - + if(BUILD_SERVER) set_target_properties(${PROJECT_NAME}server PROPERTIES COMPILE_DEFINITIONS "SERVER") diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index f170fa3..2b3c44d 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -205,6 +205,7 @@ void content_mapnode_init() f->setAllTextures("tree.png"); f->setTexture(0, "tree_top.png"); f->setTexture(1, "tree_top.png"); + f->setInventoryTextureCube("tree_top.png", "tree.png", "tree.png"); f->param_type = CPT_MINERAL; f->is_ground_content = true; f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; @@ -215,6 +216,7 @@ void content_mapnode_init() f->setAllTextures("jungletree.png"); f->setTexture(0, "jungletree_top.png"); f->setTexture(1, "jungletree_top.png"); + f->setInventoryTextureCube("jungletree_top.png", "jungletree.png", "jungletree.png"); f->param_type = CPT_MINERAL; //f->is_ground_content = true; f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; @@ -283,9 +285,7 @@ void content_mapnode_init() f->setAllTextures("bookshelf.png"); f->setTexture(0, "wood.png"); f->setTexture(1, "wood.png"); - // FIXME: setInventoryTextureCube() only cares for the first texture - f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png"); - //f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png"); + f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png"); f->param_type = CPT_MINERAL; f->is_ground_content = true; setWoodLikeDiggingProperties(f->digging_properties, 0.75); @@ -623,7 +623,7 @@ void content_mapnode_init() f->setTexture(1, "chest_top.png"); f->setTexture(5, "chest_front.png"); // Z- f->setInventoryTexture("chest_top.png"); - //f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png"); + f->setInventoryTextureCube("chest_top.png", "chest_front.png", "chest_side.png"); f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; if(f->initial_metadata == NULL) f->initial_metadata = new ChestNodeMetadata(); @@ -637,7 +637,7 @@ void content_mapnode_init() f->setTexture(1, "chest_top.png"); f->setTexture(5, "chest_lock.png"); // Z- f->setInventoryTexture("chest_lock.png"); - //f->setInventoryTextureCube("chest_top.png", "chest_side.png", "chest_side.png"); + f->setInventoryTextureCube("chest_top.png", "chest_lock.png", "chest_side.png"); f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; if(f->initial_metadata == NULL) f->initial_metadata = new LockingChestNodeMetadata(); @@ -648,7 +648,7 @@ void content_mapnode_init() f->param_type = CPT_FACEDIR_SIMPLE; f->setAllTextures("furnace_side.png"); f->setTexture(5, "furnace_front.png"); // Z- - f->setInventoryTexture("furnace_front.png"); + f->setInventoryTextureCube("furnace_side.png", "furnace_front.png", "furnace_side.png"); //f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem2 ")+itos(CONTENT_COBBLE)+" 6"; if(f->initial_metadata == NULL) @@ -676,8 +676,7 @@ void content_mapnode_init() i = CONTENT_STEEL; f = &content_features(i); f->setAllTextures("steel_block.png"); - f->setInventoryTextureCube("steel_block.png", "steel_block.png", - "steel_block.png"); + f->setInventoryTextureCube("steel_block.png", "steel_block.png", "steel_block.png"); f->param_type = CPT_NONE; f->is_ground_content = true; f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; @@ -689,14 +688,14 @@ void content_mapnode_init() f->setAllTextures("nc_side.png"); f->setTexture(5, "nc_front.png"); // Z- f->setTexture(4, "nc_back.png"); // Z+ - f->setInventoryTexture("nc_front.png"); + f->setInventoryTextureCube("nc_front.png", "nc_side.png", "nc_side.png"); f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; setStoneLikeDiggingProperties(f->digging_properties, 3.0); i = CONTENT_NC_RB; f = &content_features(i); f->setAllTextures("nc_rb.png"); - f->setInventoryTexture("nc_rb.png"); + f->setInventoryTextureCube("nc_rb.png", "nc_rb.png", "nc_rb.png"); f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; setStoneLikeDiggingProperties(f->digging_properties, 3.0); diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp index 6bcfa25..3e1dbca 100644 --- a/src/guiInventoryMenu.cpp +++ b/src/guiInventoryMenu.cpp @@ -134,10 +134,6 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize) // Remove children removeChildren(); - /*padding = v2s32(24,24); - spacing = v2s32(60,56); - imgsize = v2s32(48,48);*/ - padding = v2s32(screensize.Y/40, screensize.Y/40); spacing = v2s32(screensize.Y/12, screensize.Y/13); imgsize = v2s32(screensize.Y/15, screensize.Y/15); @@ -173,16 +169,6 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize) } } - /* - m_draw_spec.clear(); - m_draw_spec.push_back(ListDrawSpec("main", - basepos + v2s32(spacing.X*0, spacing.Y*3), v2s32(8, 4))); - m_draw_spec.push_back(ListDrawSpec("craft", - basepos + v2s32(spacing.X*3, spacing.Y*0), v2s32(3, 3))); - m_draw_spec.push_back(ListDrawSpec("craftresult", - basepos + v2s32(spacing.X*7, spacing.Y*1), v2s32(1, 1))); - */ - // Add children { core::rect rect(0, 0, size.X-padding.X*2, helptext_h); @@ -247,15 +233,6 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s) if(m_selected_item != NULL && m_selected_item->listname == s.listname && m_selected_item->i == i) { - /*s32 border = imgsize.X/12; - driver->draw2DRectangle(video::SColor(255,192,192,192), - core::rect(rect.UpperLeftCorner - v2s32(1,1)*border, - rect.LowerRightCorner + v2s32(1,1)*border), - NULL); - driver->draw2DRectangle(video::SColor(255,0,0,0), - core::rect(rect.UpperLeftCorner - v2s32(1,1)*((border+1)/2), - rect.LowerRightCorner + v2s32(1,1)*((border+1)/2)), - NULL);*/ s32 border = 2; driver->draw2DRectangle(video::SColor(255,255,0,0), core::rect(rect.UpperLeftCorner - v2s32(1,1)*border, diff --git a/src/mesh.cpp b/src/mesh.cpp new file mode 100644 index 0000000..c2e6bca --- /dev/null +++ b/src/mesh.cpp @@ -0,0 +1,484 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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 "log.h" +#include +#include +#include +#include +#include + +// 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); + // Set default material + buf->getMaterial().setFlag(video::EMF_LIGHTING, false); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + // Add mesh buffer to mesh + 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 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(); + } + + // Set default material + mesh->getMeshBuffer(0)->getMaterial().setTexture(0, texture); + mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_LIGHTING, false); + mesh->getMeshBuffer(0)->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + mesh->getMeshBuffer(0)->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + scaleMesh(mesh, scale); // also recalculates bounding box + return mesh; +} + +void scaleMesh(scene::IMesh *mesh, v3f scale) +{ + if(mesh == NULL) + return; + + core::aabbox3d bbox; + bbox.reset(0,0,0); + + u16 mc = mesh->getMeshBufferCount(); + for(u16 j=0; jgetMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; irecalculateBoundingBox(); + + // calculate total bounding box + if(j == 0) + bbox = buf->getBoundingBox(); + else + bbox.addInternalBox(buf->getBoundingBox()); + } + mesh->setBoundingBox(bbox); +} + +void translateMesh(scene::IMesh *mesh, v3f vec) +{ + if(mesh == NULL) + return; + + core::aabbox3d bbox; + bbox.reset(0,0,0); + + u16 mc = mesh->getMeshBufferCount(); + for(u16 j=0; jgetMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; irecalculateBoundingBox(); + + // 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; jgetMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; igetMeshBufferCount(); + for(u16 j=0; jgetMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 vc = buf->getVertexCount(); + for(u16 i=0; i= y && x >= z) + vertices[i].Color = colorX; + else if(y >= z) + vertices[i].Color = colorY; + else + vertices[i].Color = colorZ; + + } + } +} + +video::ITexture *generateTextureFromMesh(scene::IMesh *mesh, + IrrlichtDevice *device, + core::dimension2d dim, + std::string texture_name, + v3f camera_position, + v3f camera_lookat, + core::CMatrix4 camera_projection_matrix, + video::SColorf ambient_light, + v3f light_position, + video::SColorf light_color, + f32 light_radius) +{ + video::IVideoDriver *driver = device->getVideoDriver(); + if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false) + { + static bool warned = false; + if(!warned) + { + errorstream<<"generateTextureFromMesh(): EVDF_RENDER_TO_TARGET" + " not supported."<addRenderTargetTexture( + dim, texture_name.c_str(), video::ECF_A8R8G8B8); + if(rtt == NULL) + { + errorstream<<"generateTextureFromMesh(): addRenderTargetTexture" + " returned NULL."<setRenderTarget(rtt, false, true, video::SColor(0,0,0,0)); + + // Get a scene manager + scene::ISceneManager *smgr_main = device->getSceneManager(); + assert(smgr_main); + scene::ISceneManager *smgr = smgr_main->createNewSceneManager(); + assert(smgr); + + scene::IMeshSceneNode* meshnode = smgr->addMeshSceneNode(mesh, NULL, -1, v3f(0,0,0), v3f(0,0,0), v3f(1,1,1), true); + meshnode->setMaterialFlag(video::EMF_LIGHTING, true); + meshnode->setMaterialFlag(video::EMF_ANTI_ALIASING, true); + meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, true); + + scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, + camera_position, camera_lookat); + // second parameter of setProjectionMatrix (isOrthogonal) is ignored + camera->setProjectionMatrix(camera_projection_matrix, false); + + smgr->setAmbientLight(ambient_light); + smgr->addLightSceneNode(0, light_position, light_color, light_radius); + + // Render scene + driver->beginScene(true, true, video::SColor(0,0,0,0)); + smgr->drawAll(); + driver->endScene(); + + // NOTE: The scene nodes should not be dropped, otherwise + // smgr->drop() segfaults + /*cube->drop(); + camera->drop(); + light->drop();*/ + // Drop scene manager + smgr->drop(); + + // Unset render target + driver->setRenderTarget(0, false, true, 0); + + return rtt; +} diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 0000000..7d6e0fc --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,99 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser 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" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + 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); + +/* + Translate each vertex coordinate by the specified vector. +*/ +void translateMesh(scene::IMesh *mesh, v3f vec); + +/* + 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); + +/* + Render a mesh to a texture. + Returns NULL if render-to-texture failed. +*/ +video::ITexture *generateTextureFromMesh(scene::IMesh *mesh, + IrrlichtDevice *device, + core::dimension2d dim, + std::string texture_name, + v3f camera_position, + v3f camera_lookat, + core::CMatrix4 camera_projection_matrix, + video::SColorf ambient_light, + v3f light_position, + video::SColorf light_color, + f32 light_radius); + +#endif diff --git a/src/tile.cpp b/src/tile.cpp index c32f31d..dd0ee35 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 #include "log.h" #include "mapnode.h" // For texture atlas making @@ -1207,7 +1208,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, { if(baseimg != NULL) { - infostream<<"generate_image(): baseimg!=NULL " + errorstream<<"generate_image(): baseimg!=NULL " <<"for part_of_name=\""<queryFeature(video::EVDF_RENDER_TO_TARGET) == false) - { - infostream<<"generate_image(): EVDF_RENDER_TO_TARGET" - " not supported. Creating fallback image"<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(); img_right->drop(); - // Create render target texture - video::ITexture *rtt = NULL; - std::string rtt_name = part_of_name + "_RTT"; - rtt = driver->addRenderTargetTexture(dim, rtt_name.c_str(), - video::ECF_A8R8G8B8); - assert(rtt); - - // Set render target - driver->setRenderTarget(rtt, true, true, - video::SColor(0,0,0,0)); - - // Get a scene manager - scene::ISceneManager *smgr_main = device->getSceneManager(); - assert(smgr_main); - scene::ISceneManager *smgr = smgr_main->createNewSceneManager(); - assert(smgr); - /* - 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?) + Draw a cube mesh into a render target texture */ + scene::IMesh* cube = createCubeMesh(v3f(1, 1, 1)); + setMeshColor(cube, video::SColor(255, 255, 255, 255)); + cube->getMeshBuffer(0)->getMaterial().setTexture(0, texture_top); + cube->getMeshBuffer(1)->getMaterial().setTexture(0, texture_top); + cube->getMeshBuffer(2)->getMaterial().setTexture(0, texture_right); + cube->getMeshBuffer(3)->getMaterial().setTexture(0, texture_right); + cube->getMeshBuffer(4)->getMaterial().setTexture(0, texture_left); + cube->getMeshBuffer(5)->getMaterial().setTexture(0, texture_left); - scene::ISceneNode* cube = smgr->addCubeSceneNode(1.0, NULL, -1, - v3f(0,0,0), v3f(0, 45, 0)); - // 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); + core::dimension2d dim(64,64); + std::string rtt_texture_name = part_of_name + "_RTT"; - scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, - v3f(0, 1.0, -1.5), v3f(0, 0, 0)); + v3f camera_position(0, 1.0, -1.5); + camera_position.rotateXZBy(45); + v3f camera_lookat(0, 0, 0); + core::CMatrix4 camera_projection_matrix; // Set orthogonal projection - core::CMatrix4 pm; - pm.buildProjectionMatrixOrthoLH(1.65, 1.65, 0, 100); - camera->setProjectionMatrix(pm, true); + camera_projection_matrix.buildProjectionMatrixOrthoLH( + 1.65, 1.65, 0, 100); - /*scene::ILightSceneNode *light =*/ smgr->addLightSceneNode(0, - v3f(-50, 100, 0), video::SColorf(0.5,0.5,0.5), 1000); + video::SColorf ambient_light(0.2,0.2,0.2); + v3f light_position(10, 100, -50); + video::SColorf light_color(0.5,0.5,0.5); + f32 light_radius = 1000; - smgr->setAmbientLight(video::SColorf(0.2,0.2,0.2)); + video::ITexture *rtt = generateTextureFromMesh( + cube, device, dim, rtt_texture_name, + camera_position, + camera_lookat, + camera_projection_matrix, + ambient_light, + light_position, + light_color, + light_radius); - // Render scene - driver->beginScene(true, true, video::SColor(0,0,0,0)); - smgr->drawAll(); - driver->endScene(); + // Drop mesh + cube->drop(); - // NOTE: The scene nodes should not be dropped, otherwise - // smgr->drop() segfaults - /*cube->drop(); - camera->drop(); - light->drop();*/ - // Drop scene manager - smgr->drop(); - - // Unset render target - driver->setRenderTarget(0, true, true, 0); - - //TODO: Free textures of images + // Free textures of images driver->removeTexture(texture_top); + driver->removeTexture(texture_left); + driver->removeTexture(texture_right); + + if(rtt == NULL) + { + baseimg = generate_image_from_scratch( + imagename_top, device); + return true; + } // Create image of render target video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim); - assert(image); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); @@ -1332,7 +1308,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, image->copyTo(baseimg); image->drop(); } -#endif } else {