Add support for using arbitrary meshes as items 3479/head
authorSapier <sapier AT gmx dot net>
Sat, 19 Dec 2015 03:43:59 +0000 (04:43 +0100)
committerSapier <sapier AT gmx dot net>
Tue, 29 Dec 2015 15:27:06 +0000 (16:27 +0100)
src/content_cao.cpp
src/itemdef.cpp
src/itemdef.h
src/script/common/c_content.cpp
src/wieldmesh.cpp

index 1b8e84c8fb4f8ec61a4c25ff25edb20437561dfa..bde0dd320889a3754650c4e4bbd1de42ab6d932a 100644 (file)
@@ -954,15 +954,43 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
                        IItemDefManager *idef = m_gamedef->idef();
                        ItemStack item(m_prop.textures[0], 1, 0, "", idef);
 
-                       m_wield_meshnode = new WieldMeshSceneNode(
-                                       smgr->getRootSceneNode(), smgr, -1);
-                       m_wield_meshnode->setItem(item, m_gamedef);
-
-                       m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
-                                       m_prop.visual_size.Y/2,
-                                       m_prop.visual_size.X/2));
-                       u8 li = m_last_light;
-                       m_wield_meshnode->setColor(video::SColor(255,li,li,li));
+                       if (!item.getDefinition(idef).meshname.empty())
+                       {
+                               scene::IAnimatedMesh *mesh = m_gamedef->getMesh(item.getDefinition(idef).meshname);
+                               if(mesh)
+                               {
+                                       m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
+
+                                       m_animated_meshnode->grab();
+                                       mesh->drop(); // The scene node took hold of it
+                                       m_animated_meshnode->animateJoints(); // Needed for some animations
+                                       m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
+                                                       m_prop.visual_size.Y,
+                                                       m_prop.visual_size.X));
+                                       u8 li = m_last_light;
+                                       setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
+
+                                       bool backface_culling = m_prop.backface_culling;
+                                       if (m_is_player)
+                                               backface_culling = false;
+
+                                       m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
+                                       m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
+                                       m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
+                                       m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+                                       m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, backface_culling);
+                               }
+                       }
+                       else {
+                               m_wield_meshnode = new WieldMeshSceneNode(
+                                               smgr->getRootSceneNode(), smgr, -1);
+                               m_wield_meshnode->setItem(item, m_gamedef);
+                               m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
+                                               m_prop.visual_size.Y/2,
+                                               m_prop.visual_size.X/2));
+                               u8 li = m_last_light;
+                               m_wield_meshnode->setColor(video::SColor(255,li,li,li));
+                       }
                }
        } else {
                infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
@@ -1402,6 +1430,21 @@ void GenericCAO::updateTextures(const std::string &mod)
                                m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
                        }
                }
+               else if (m_prop.visual == "wielditem") {
+                       IItemDefManager *idef = m_gamedef->idef();
+                       ItemStack item(m_prop.textures[0], 1, 0, "", idef);
+
+                       if (!item.getDefinition(idef).meshname.empty()) {
+
+                               unsigned int materialcount = m_animated_meshnode->getMaterialCount();
+
+                               for (unsigned int i = 0; i < materialcount; i++) {
+                                       m_animated_meshnode->getMaterial(i)
+                                                       .setTexture(0, tsrc->getTexture(item
+                                                                       .getDefinition(idef).meshtexture));
+                               }
+                       }
+               }
        }
        if(m_meshnode)
        {
index fa277f4ffe1ddb5310022b565a4165c607ae90b8..e37f10d61ffb836dded8e59f4a2c2648c9cb8595 100644 (file)
@@ -77,6 +77,8 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
        sound_place = def.sound_place;
        sound_place_failed = def.sound_place_failed;
        range = def.range;
+       meshname = def.meshname;
+       meshtexture = def.meshtexture;
        return *this;
 }
 
@@ -157,6 +159,10 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
                os << serializeString(sound_place_failed.name);
                writeF1000(os, sound_place_failed.gain);
        }
+
+       //TODO check for protocol version?
+       os<<serializeString(meshname);
+       os<<serializeString(meshtexture);
 }
 
 void ItemDefinition::deSerialize(std::istream &is)
@@ -214,6 +220,10 @@ void ItemDefinition::deSerialize(std::istream &is)
                sound_place_failed.name = deSerializeString(is);
                sound_place_failed.gain = readF1000(is);
        } catch(SerializationError &e) {};
+
+       //TODO check for protocol?
+       meshname = deSerializeString(is);
+       meshtexture = deSerializeString(is);
 }
 
 /*
@@ -341,7 +351,7 @@ CItemDefManager::ClientCached* CItemDefManager::createClientCachedDirect(const s
 
        // Create an inventory texture
        cc->inventory_texture = NULL;
-       if (def.inventory_image != "")
+       if (!def.inventory_image.empty())
                cc->inventory_texture = tsrc->getTexture(def.inventory_image);
 
        // Additional processing for nodes:
@@ -352,6 +362,10 @@ CItemDefManager::ClientCached* CItemDefManager::createClientCachedDirect(const s
        if (def.type == ITEM_NODE) {
                createNodeItemTexture(name, def, nodedef, cc, gamedef, tsrc);
        }
+       else if (def.type == ITEM_CRAFT) {
+               if ( !def.meshname.empty())
+                       createMeshItemTexture(name, def, nodedef, cc, gamedef, tsrc);
+       }
 
        // Put in cache
        m_clientcached.set(name, cc);
@@ -650,6 +664,100 @@ void CItemDefManager::createNodeItemTexture(const std::string& name,
        if (node_mesh)
                node_mesh->drop();
 }
+
+/******************************************************************************/
+void CItemDefManager::renderMeshToTexture(const ItemDefinition& def, scene::IMesh* mesh,
+               ClientCached* cc, ITextureSource* tsrc) const
+{
+       video::ITexture *itemimage = cc->inventory_texture;
+
+       /*
+        Draw node mesh into a render target texture
+        */
+       TextureFromMeshParams params;
+       params.mesh = mesh;
+       params.dim.set(64, 64);
+       params.rtt_texture_name = "INVENTORY_" + def.name + "_RTT";
+       params.delete_texture_on_shutdown = true;
+       params.camera_position.set(0, 1.0, -1.5);
+       params.camera_position.rotateXZBy(45);
+       params.camera_lookat.set(0, 0, 0);
+       // Set orthogonal projection
+       params.camera_projection_matrix.buildProjectionMatrixOrthoLH(1.65, 1.65, 0,
+                       100);
+       params.ambient_light.set(1.0, 0.9, 0.9, 0.9);
+       params.light_position.set(10, 100, -50);
+       params.light_color.set(1.0, 0.5, 0.5, 0.5);
+       params.light_radius = 1000;
+       cc->inventory_texture = tsrc->generateTextureFromMesh(params);
+
+       // render-to-target didn't work
+       if (cc->inventory_texture == NULL) {
+
+               cc->inventory_texture = itemimage;
+       }
+}
+
+/******************************************************************************/
+void CItemDefManager::createMeshItemTexture(const std::string& name,
+               const ItemDefinition& def, INodeDefManager* nodedef,
+               ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const
+{
+       // Get node properties
+       content_t id = nodedef->getId(name);
+       const ContentFeatures& f = nodedef->get(id);
+
+       if (def.meshname == "")
+               return;
+
+       video::ITexture *texture = tsrc->getTexture(def.meshtexture);
+
+       infostream<<"CItemDefManager::createMeshItemTexture(): mesh"<<std::endl;
+
+       scene::IAnimatedMesh *mesh = gamedef->getMesh(def.meshname);
+       if(mesh)
+       {
+
+               video::SColor c(255, 255, 255, 255);
+               setMeshColor(mesh, c);
+
+               rotateMeshXZby(mesh, 180);
+
+               // scale and translate the mesh so it's a
+               // unit cube centered on the origin
+               scaleMesh(mesh, v3f(1.0 / BS, 1.0 / BS, 1.0 / BS));
+
+               // Customize materials
+               for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
+
+                       video::SMaterial &material = mesh->getMeshBuffer(i)->getMaterial();
+                       material.setTexture(0, texture);
+                       material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+                       material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                       material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+               }
+
+               /*
+                Draw node mesh into a render target texture
+                */
+               renderMeshToTexture(def, mesh, cc, tsrc);
+
+               /*
+                Use the ingot mesh as the wield mesh
+                */
+
+               cc->wield_mesh = mesh;
+               cc->wield_mesh->grab();
+               // no way reference count can be smaller than 2 in this place!
+               assert(cc->wield_mesh->getReferenceCount() >= 2);
+
+               if (mesh)
+                       mesh->drop();
+
+       }
+       else
+               errorstream<<"CItemDefManager::createMeshItemTexture(): Could not load mesh "<<def.meshname<<std::endl;
+}
 #endif
 
 /******************************************************************************/
index fb157705f2b04006ae7d9e54374e657e65c73924..74c6d0b3e2f3c5548006991cf6aba26aee18266a 100644 (file)
@@ -66,6 +66,8 @@ struct ItemDefinition
        std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
        std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
        v3f wield_scale;
+       std::string meshname;    // name of internal mesh (or meshfile to use TBD)
+       std::string meshtexture; // meshtexture
 
        /*
                Item stack and interaction properties
@@ -211,6 +213,13 @@ private:
                        const ItemDefinition& def, INodeDefManager* nodedef,
                        ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const;
 
+       void createMeshItemTexture(const std::string& name,
+                       const ItemDefinition& def, INodeDefManager* nodedef,
+                       ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const;
+
+       void renderMeshToTexture(const ItemDefinition& def, scene::IMesh* mesh,
+                       ClientCached* cc, ITextureSource* tsrc) const;
+
        ClientCached* createClientCachedDirect(const std::string &name,
                        IGameDef *gamedef) const;
 
index 36a5c2ddd700e96d21304d1317a342e091015eaa..78f3c943f0bf49105a448b819a296636f31e3265 100644 (file)
@@ -58,6 +58,8 @@ ItemDefinition read_item_definition(lua_State* L,int index,
        getstringfield(L, index, "description", def.description);
        getstringfield(L, index, "inventory_image", def.inventory_image);
        getstringfield(L, index, "wield_image", def.wield_image);
+       getstringfield(L, index, "mesh", def.meshname);
+       getstringfield(L, index, "meshtexture", def.meshtexture);
 
        lua_getfield(L, index, "wield_scale");
        if(lua_istable(L, -1)){
index a022754a6864da4fce61ad64285043caa00723f7..77a5cf73a92b2f592add73050d90604414231414 100644 (file)
@@ -386,6 +386,20 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
                }
                return;
        }
+       else if (idef->getWieldMesh(def.name, gamedef) != 0) {
+               irr::scene::IMesh * mesh = idef->getWieldMesh(def.name, gamedef);
+               m_meshnode->setMesh(mesh);
+               u32 material_count = m_meshnode->getMaterialCount();
+               for (u32 i = 0; i < material_count; ++i) {
+                       video::SMaterial &material = m_meshnode->getMaterial(i);
+                       material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+                       material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
+                       material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
+                       material.MaterialType = m_material_type;
+                       material.setTexture(0, tsrc->getTexture(def.meshtexture));
+               }
+               return;
+       }
        else if (def.inventory_image != "") {
                setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
                return;