From 0066bd77d25793b76fdaa9a62755cca934f0121d Mon Sep 17 00:00:00 2001 From: RealBadAngel Date: Wed, 15 Oct 2014 04:13:53 +0200 Subject: [PATCH] Add meshnode drawtype. --- doc/lua_api.txt | 14 ++- src/client.cpp | 2 +- src/content_mapblock.cpp | 12 ++ src/mapblock_mesh.cpp | 51 ++++++++ src/mapblock_mesh.h | 4 + src/mesh.cpp | 216 ++++++++++++++++++++++++++++++++ src/mesh.h | 21 ++++ src/nodedef.cpp | 48 ++++++- src/nodedef.h | 8 +- src/script/common/c_content.cpp | 3 + src/script/cpp_api/s_node.cpp | 1 + 11 files changed, 374 insertions(+), 6 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 131a63fa5..8f77366f7 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -103,6 +103,7 @@ mods | |-- screenshot.png | |-- description.txt | |-- init.lua +| |-- models | |-- textures | | |-- modname_stuff.png | | `-- modname_something_else.png @@ -137,6 +138,9 @@ init.lua: minetest.setting_get(name) and minetest.setting_getbool(name) can be used to read custom or existing settings at load time, if necessary. +models: + Models for entities or meshnodes. + textures, sounds, media: Media files (textures, sounds, whatever) that will be transferred to the client and will be available for use by the mod. @@ -430,6 +434,7 @@ Look for examples in games/minimal or games/minetest_game. - fencelike - raillike - nodebox -- See below. EXPERIMENTAL +- mesh -- use models for nodes *_optional drawtypes need less rendering time if deactivated (always client side) @@ -469,6 +474,12 @@ A box of a regular node would look like: type = "leveled" is same as "fixed", but y2 will be automatically set to level from param2 +Meshes +----------- +If drawtype "mesh" is used tiles should hold model materials textures. +Only static meshes are implemented. +For supported model formats see Irrlicht engine documentation. + Ore types --------------- These tell in what manner the ore is generated. @@ -2405,7 +2416,7 @@ Node definition (register_node) drawtype = "normal", -- See "Node drawtypes" visual_scale = 1.0, - ^ Supported for drawtypes "plantlike", "signlike", "torchlike". + ^ Supported for drawtypes "plantlike", "signlike", "torchlike", "mesh". ^ For plantlike, the image will start at the bottom of the node; for the ^ other drawtypes, the image will be centered on the node. ^ Note that positioning for "torchlike" may still change. @@ -2439,6 +2450,7 @@ Node definition (register_node) light_source = 0, -- Amount of light emitted by node damage_per_second = 0, -- If player is inside node, this damage is caused node_box = {type="regular"}, -- See "Node boxes" + mesh = "model", selection_box = {type="regular"}, -- See "Node boxes" ^ If drawtype "nodebox" is used and selection_box is nil, then node_box is used legacy_facedir_simple = false, -- Support maps made in and before January 2012 diff --git a/src/client.cpp b/src/client.cpp index 4a00283ee..0bc2e66a5 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -2678,7 +2678,7 @@ void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font) // Update node textures and assign shaders to each tile infostream<<"- Updating node textures"<updateTextures(m_tsrc, m_shsrc); + m_nodedef->updateTextures(this); // Preload item textures and meshes if configured to if(g_settings->getBool("preload_item_visuals")) diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index c84e75ac0..53b9874d4 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -1715,6 +1715,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data, makeCuboid(&collector, box, tiles, 6, c, txc); } break;} + case NDT_MESH: + { + v3f pos = intToFloat(p, BS); + video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source); + u8 facedir = n.getFaceDir(nodedef); + for(u16 j = 0; j < f.mesh_ptr[facedir]->getMeshBufferCount(); j++) { + scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j); + collector.append(getNodeTileN(n, p, j, data), + (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(), + buf->getIndices(), buf->getIndexCount(), pos, c); + } + break;} } } } diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index d75d3e148..a7fafa683 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -1428,3 +1428,54 @@ void MeshCollector::append(const TileSpec &tile, p->vertices.push_back(vertices[i]); } } + +/* + MeshCollector - for meshnodes and converted drawtypes. +*/ + +void MeshCollector::append(const TileSpec &tile, + const video::S3DVertex *vertices, u32 numVertices, + const u16 *indices, u32 numIndices, + v3f pos, video::SColor c) +{ + if(numIndices > 65535) + { + dstream<<"FIXME: MeshCollector::append() called with numIndices="< 65535) + continue; + + p = &pp; + break; + } + + if(p == NULL) + { + PreMeshBuffer pp; + pp.tile = tile; + prebuffers.push_back(pp); + p = &prebuffers[prebuffers.size()-1]; + } + + u32 vertex_count = p->vertices.size(); + for(u32 i=0; iindices.push_back(j); + } + for(u32 i=0; ivertices.push_back(vert); + } +} diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index c52954998..e1cccc64e 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -174,6 +174,10 @@ struct MeshCollector void append(const TileSpec &material, const video::S3DVertex *vertices, u32 numVertices, const u16 *indices, u32 numIndices); + void append(const TileSpec &material, + const video::S3DVertex *vertices, u32 numVertices, + const u16 *indices, u32 numIndices, + v3f pos, video::SColor c); }; // This encodes diff --git a/src/mesh.cpp b/src/mesh.cpp index 3200d5fa6..19d75f9f5 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -408,3 +408,219 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh, } } } + +void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir) +{ + int axisdir = facedir>>2; + facedir &= 0x03; + + 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 bbox; + bbox.reset(0,0,0); + for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) + { + scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j); + buf->recalculateBoundingBox(); + if(j == 0) + bbox = buf->getBoundingBox(); + else + bbox.addInternalBox(buf->getBoundingBox()); + } + src_mesh->setBoundingBox(bbox); +} + +scene::IMesh* cloneMesh(scene::IMesh *src_mesh) +{ + scene::SMesh* dst_mesh = new scene::SMesh(); + for(u16 j = 0; j < src_mesh->getMeshBufferCount(); j++) + { + scene::IMeshBuffer *buf = src_mesh->getMeshBuffer(j); + video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices(); + u16 *indices = (u16*)buf->getIndices(); + scene::SMeshBuffer *temp_buf = new scene::SMeshBuffer(); + temp_buf->append(vertices, buf->getVertexCount(), + indices, buf->getIndexCount()); + dst_mesh->addMeshBuffer(temp_buf); + temp_buf->drop(); + } + return dst_mesh; +} + +scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f) +{ + scene::SMesh* dst_mesh = new scene::SMesh(); + for (u16 j = 0; j < 6; j++) + { + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + dst_mesh->addMeshBuffer(buf); + buf->drop(); + } + + video::SColor c(255,255,255,255); + + std::vector boxes = f->node_box.fixed; + + for(std::vector::iterator + i = boxes.begin(); + i != boxes.end(); i++) + { + aabb3f box = *i; + + f32 temp; + if (box.MinEdge.X > box.MaxEdge.X) + { + temp=box.MinEdge.X; + box.MinEdge.X=box.MaxEdge.X; + box.MaxEdge.X=temp; + } + if (box.MinEdge.Y > box.MaxEdge.Y) + { + temp=box.MinEdge.Y; + box.MinEdge.Y=box.MaxEdge.Y; + box.MaxEdge.Y=temp; + } + if (box.MinEdge.Z > box.MaxEdge.Z) + { + temp=box.MinEdge.Z; + box.MinEdge.Z=box.MaxEdge.Z; + box.MaxEdge.Z=temp; + } + // Compute texture coords + f32 tx1 = (box.MinEdge.X/BS)+0.5; + f32 ty1 = (box.MinEdge.Y/BS)+0.5; + f32 tz1 = (box.MinEdge.Z/BS)+0.5; + f32 tx2 = (box.MaxEdge.X/BS)+0.5; + f32 ty2 = (box.MaxEdge.Y/BS)+0.5; + f32 tz2 = (box.MaxEdge.Z/BS)+0.5; + f32 txc[24] = { + // up + tx1, 1-tz2, tx2, 1-tz1, + // down + tx1, tz1, tx2, tz2, + // right + tz1, 1-ty2, tz2, 1-ty1, + // left + 1-tz2, 1-ty2, 1-tz1, 1-ty1, + // back + 1-tx2, 1-ty2, 1-tx1, 1-ty1, + // front + tx1, 1-ty2, tx2, 1-ty1, + }; + v3f min = box.MinEdge; + v3f max = box.MaxEdge; + + video::S3DVertex vertices[24] = + { + // up + video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]), + video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]), + video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]), + video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]), + // down + video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]), + video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]), + video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]), + video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]), + // right + video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]), + video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]), + video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]), + video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]), + // left + video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]), + video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]), + video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]), + video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]), + // back + video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]), + video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]), + video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]), + video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]), + // front + video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]), + video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]), + video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]), + video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]), + }; + + u16 indices[] = {0,1,2,2,3,0}; + + for(u16 j = 0; j < 24; j += 4) + { + scene::IMeshBuffer *buf = dst_mesh->getMeshBuffer(j / 4); + buf->append(vertices + j, 4, indices, 6); + } + } + return dst_mesh; +} diff --git a/src/mesh.h b/src/mesh.h index a89bea385..7539298cb 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define MESH_HEADER #include "irrlichttypes_extrabloated.h" +#include "nodedef.h" #include /* @@ -68,5 +69,25 @@ void setMeshColorByNormalXYZ(scene::IMesh *mesh, const video::SColor &colorX, const video::SColor &colorY, const video::SColor &colorZ); +/* + Rotate the mesh by 6d facedir value. + Method only for meshnodes, not suitable for entities. +*/ +void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir); + +/* + Clone the mesh. +*/ +scene::IMesh* cloneMesh(scene::IMesh *src_mesh); + +/* + Convert nodebox drawtype node to mesh. +*/ +scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f); + +/* + Update bounding box for a mesh. +*/ +void recalculateBoundingBox(scene::IMesh *src_mesh); #endif diff --git a/src/nodedef.cpp b/src/nodedef.cpp index f1a7ad694..ef61d0722 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemdef.h" #ifndef SERVER #include "tile.h" +#include "mesh.h" #endif #include "log.h" #include "settings.h" @@ -31,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/serialize.h" #include "exceptions.h" #include "debug.h" +#include "gamedef.h" /* NodeBox @@ -195,6 +197,11 @@ void ContentFeatures::reset() // Unknown nodes can be dug groups["dig_immediate"] = 2; drawtype = NDT_NORMAL; + mesh = ""; +#ifndef SERVER + for(u32 i = 0; i < 24; i++) + mesh_ptr[i] = NULL; +#endif visual_scale = 1.0; for(u32 i = 0; i < 6; i++) tiledef[i] = TileDef(); @@ -295,6 +302,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) writeU8(os, waving); // Stuff below should be moved to correct place in a version that otherwise changes // the protocol version + os<tsrc(); + IShaderSource *shdsrc = gamedef->getShaderSource(); bool new_style_water = g_settings->getBool("new_style_water"); bool new_style_leaves = g_settings->getBool("new_style_leaves"); @@ -771,6 +783,10 @@ void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc f->backface_culling = false; f->solidness = 0; break; + case NDT_MESH: + f->solidness = 0; + f->backface_culling = false; + break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: case NDT_FENCELIKE: @@ -810,6 +826,34 @@ void CNodeDefManager::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc tile_shader[j], use_normal_texture, f->tiledef_special[j].backface_culling, f->alpha, material_type); } + + // Meshnode drawtype + // Read the mesh and apply scale + if ((f->drawtype == NDT_MESH) && (f->mesh != "")) { + f->mesh_ptr[0] = gamedef->getMesh(f->mesh); + scaleMesh(f->mesh_ptr[0], v3f(f->visual_scale,f->visual_scale,f->visual_scale)); + recalculateBoundingBox(f->mesh_ptr[0]); + } + + //Convert regular nodebox nodes to meshnodes + //Change the drawtype and apply scale + if ((f->drawtype == NDT_NODEBOX) && + ((f->node_box.type == NODEBOX_REGULAR) || (f->node_box.type == NODEBOX_FIXED)) && + (!f->node_box.fixed.empty())) { + f->drawtype = NDT_MESH; + f->mesh_ptr[0] = convertNodeboxNodeToMesh(f); + scaleMesh(f->mesh_ptr[0], v3f(f->visual_scale,f->visual_scale,f->visual_scale)); + recalculateBoundingBox(f->mesh_ptr[0]); + } + + //Cache 6dfacedir rotated clones of meshes + if (f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) { + for (u16 j = 1; j < 24; j++) { + f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]); + rotateMeshBy6dFacedir(f->mesh_ptr[j], j); + recalculateBoundingBox(f->mesh_ptr[j]); + } + } } #endif } diff --git a/src/nodedef.h b/src/nodedef.h index b737e0237..2400f5f73 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -152,6 +152,7 @@ enum NodeDrawType NDT_FIRELIKE, // Draw faces slightly rotated and only on connecting nodes, NDT_GLASSLIKE_FRAMED_OPTIONAL, // enabled -> connected, disabled -> Glass-like // uses 2 textures, one for frames, second for faces + NDT_MESH, // Uses static meshes }; #define CF_SPECIAL_COUNT 6 @@ -187,6 +188,10 @@ struct ContentFeatures // Visual definition enum NodeDrawType drawtype; + std::string mesh; +#ifndef SERVER + scene::IMesh *mesh_ptr[24]; +#endif float visual_scale; // Misc. scale parameter TileDef tiledef[6]; TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid @@ -328,8 +333,7 @@ public: /* Update tile textures to latest return values of TextueSource. */ - virtual void updateTextures(ITextureSource *tsrc, - IShaderSource *shdsrc)=0; + virtual void updateTextures(IGameDef *gamedef)=0; virtual void serialize(std::ostream &os, u16 protocol_version)=0; virtual void deSerialize(std::istream &is)=0; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 2f749043e..4737f1993 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -281,6 +281,9 @@ ContentFeatures read_content_features(lua_State *L, int index) ScriptApiNode::es_DrawType,NDT_NORMAL); getfloatfield(L, index, "visual_scale", f.visual_scale); + /* Meshnode model filename */ + getstringfield(L, index, "mesh", f.mesh); + // tiles = {} lua_getfield(L, index, "tiles"); // If nil, try the deprecated name "tile_images" instead diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index 05f908004..e3d3fb58b 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -45,6 +45,7 @@ struct EnumString ScriptApiNode::es_DrawType[] = {NDT_FENCELIKE, "fencelike"}, {NDT_RAILLIKE, "raillike"}, {NDT_NODEBOX, "nodebox"}, + {NDT_MESH, "mesh"}, {0, NULL}, };