]> git.lizzy.rs Git - minetest.git/commitdiff
Implement WieldMeshSceneNode which improves wield mesh rendering
authorKahrl <kahrl@gmx.net>
Sun, 2 Nov 2014 02:47:43 +0000 (03:47 +0100)
committerKahrl <kahrl@gmx.net>
Sat, 8 Nov 2014 22:11:57 +0000 (23:11 +0100)
- Don't create and cache an extruded mesh for every (non-node) item.
  Instead use a single one per image resolution.

- For cubic nodes reuse a single wield mesh too

- Improve lighting of the wielded item

- Increase far value of wield mesh scene camera, fixes #1770

- Also includes some minor refactorings of Camera and GenericCAO.

22 files changed:
build/android/jni/Android.mk
src/CMakeLists.txt
src/camera.cpp
src/camera.h
src/clientobject.h
src/content_cao.cpp
src/content_cao.h
src/environment.cpp
src/game.cpp
src/itemdef.cpp
src/localplayer.cpp
src/localplayer.h
src/mapblock_mesh.cpp
src/mapblock_mesh.h
src/mesh.cpp
src/mesh.h
src/player.cpp
src/player.h
src/test.cpp
src/util/numeric.h
src/wieldmesh.cpp [new file with mode: 0644]
src/wieldmesh.h [new file with mode: 0644]

index 335802d857371326f2b0381a06473853d44ceb46..d23630c6ba2382d75c4f202d43450afc0179c0a7 100644 (file)
@@ -209,8 +209,9 @@ LOCAL_SRC_FILES :=                                \
                jni/src/util/string.cpp                   \
                jni/src/util/timetaker.cpp                \
                jni/src/touchscreengui.cpp                \
-               jni/src/database-leveldb.cpp              \
-               jni/src/settings.cpp
+               jni/src/database-leveldb.cpp              \
+               jni/src/settings.cpp                      \
+               jni/src/wieldmesh.cpp
 
 # lua api
 LOCAL_SRC_FILES +=                                \
index eeceb6358feba219e19abf44a53dc079cfbbcb48..b1fd26247b844948fa53205ef5ab02a00edc499c 100644 (file)
@@ -466,6 +466,7 @@ set(minetest_SRCS
        shader.cpp
        sky.cpp
        tile.cpp
+       wieldmesh.cpp
        ${minetest_SCRIPT_SRCS}
 )
 list(SORT minetest_SRCS)
index d961d45b9c1450b9fbfe4a943b512f9791032367..0b4e4fd53536ac5a6517e2bc7ef3c6fc297163de 100644 (file)
@@ -23,12 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "main.h" // for g_settings
 #include "map.h"
 #include "clientmap.h" // MapDrawControl
-#include "mesh.h"
 #include "player.h"
-#include "tile.h"
 #include <cmath>
 #include "settings.h"
-#include "itemdef.h" // For wield visualization
+#include "wieldmesh.h"
 #include "noise.h" // easeCurve
 #include "gamedef.h"
 #include "sound.h"
@@ -50,7 +48,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
 
        m_wieldmgr(NULL),
        m_wieldnode(NULL),
-       m_wieldlight(0),
 
        m_draw_control(draw_control),
        m_gamedef(gamedef),
@@ -77,12 +74,9 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
 
        m_digging_anim(0),
        m_digging_button(-1),
-       m_dummymesh(createCubeMesh(v3f(1,1,1))),
 
        m_wield_change_timer(0.125),
-       m_wield_mesh_next(NULL),
-       m_previous_playeritem(-1),
-       m_previous_itemname(""),
+       m_wield_item_next(),
 
        m_camera_mode(CAMERA_MODE_FIRST)
 {
@@ -99,14 +93,15 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
        // all other 3D scene nodes and before the GUI.
        m_wieldmgr = smgr->createNewSceneManager();
        m_wieldmgr->addCameraSceneNode();
-       m_wieldnode = m_wieldmgr->addMeshSceneNode(m_dummymesh, NULL);  // need a dummy mesh
+       m_wieldnode = new WieldMeshSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr, -1, true);
+       m_wieldnode->setItem(ItemStack(), m_gamedef);
+       m_wieldnode->drop(); // m_wieldmgr grabbed it
+       m_wieldlightnode = m_wieldmgr->addLightSceneNode(NULL, v3f(0.0, 50.0, 0.0));
 }
 
 Camera::~Camera()
 {
        m_wieldmgr->drop();
-
-       delete m_dummymesh;
 }
 
 bool Camera::successfullyCreated(std::wstring& error_message)
@@ -156,22 +151,10 @@ void Camera::step(f32 dtime)
        }
 
        bool was_under_zero = m_wield_change_timer < 0;
-       if(m_wield_change_timer < 0.125)
-               m_wield_change_timer += dtime;
-       if(m_wield_change_timer > 0.125)
-               m_wield_change_timer = 0.125;
+       m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
 
-       if(m_wield_change_timer >= 0 && was_under_zero)
-       {
-               if(m_wield_mesh_next)
-               {
-                       m_wieldnode->setMesh(m_wield_mesh_next);
-                       m_wieldnode->setVisible(true);
-               } else {
-                       m_wieldnode->setVisible(false);
-               }
-               m_wield_mesh_next = NULL;
-       }
+       if (m_wield_change_timer >= 0 && was_under_zero)
+               m_wieldnode->setItem(m_wield_item_next, m_gamedef);
 
        if (m_view_bobbing_state != 0)
        {
@@ -445,10 +428,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
        v3f wield_position = v3f(55, -35, 65);
        //v3f wield_rotation = v3f(-100, 120, -100);
        v3f wield_rotation = v3f(-100, 120, -100);
-       if(m_wield_change_timer < 0)
-               wield_position.Y -= 40 + m_wield_change_timer*320;
-       else
-               wield_position.Y -= 40 - m_wield_change_timer*320;
+       wield_position.Y += fabs(m_wield_change_timer)*320 - 40;
        if(m_digging_anim < 0.05 || m_digging_anim > 0.5)
        {
                f32 frac = 1.0;
@@ -486,7 +466,12 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
        }
        m_wieldnode->setPosition(wield_position);
        m_wieldnode->setRotation(wield_rotation);
-       m_wieldlight = player->light;
+
+       // Shine light upon the wield mesh
+       video::SColor black(255,0,0,0);
+       m_wieldmgr->setAmbientLight(player->light_color.getInterpolated(black, 0.7));
+       m_wieldlightnode->getLightData().DiffuseColor = player->light_color.getInterpolated(black, 0.3);
+       m_wieldlightnode->setPosition(v3f(30+5*sin(2*player->getYaw()*M_PI/180), -50, 0));
 
        // Render distance feedback loop
        updateViewingRange(frametime, busytime);
@@ -658,48 +643,20 @@ void Camera::setDigging(s32 button)
                m_digging_button = button;
 }
 
-void Camera::wield(const ItemStack &item, u16 playeritem)
+void Camera::wield(const ItemStack &item)
 {
-       IItemDefManager *idef = m_gamedef->idef();
-       std::string itemname = item.getDefinition(idef).name;
-       m_wield_mesh_next = idef->getWieldMesh(itemname, m_gamedef);
-       if(playeritem != m_previous_playeritem &&
-                       !(m_previous_itemname == "" && itemname == ""))
-       {
-               m_previous_playeritem = playeritem;
-               m_previous_itemname = itemname;
-               if(m_wield_change_timer >= 0.125)
-                       m_wield_change_timer = -0.125;
-               else if(m_wield_change_timer > 0)
-               {
+       if (item.name != m_wield_item_next.name) {
+               m_wield_item_next = item;
+               if (m_wield_change_timer > 0)
                        m_wield_change_timer = -m_wield_change_timer;
-               }
-       } else {
-               if(m_wield_mesh_next) {
-                       m_wieldnode->setMesh(m_wield_mesh_next);
-                       m_wieldnode->setVisible(true);
-               } else {
-                       m_wieldnode->setVisible(false);
-               }
-               m_wield_mesh_next = NULL;
-               if(m_previous_itemname != itemname)
-               {
-                       m_previous_itemname = itemname;
-                       m_wield_change_timer = 0;
-               }
-               else
-                       m_wield_change_timer = 0.125;
+               else if (m_wield_change_timer == 0)
+                       m_wield_change_timer = -0.001;
        }
 }
 
 void Camera::drawWieldedTool(irr::core::matrix4* translation)
 {
-       // Set vertex colors of wield mesh according to light level
-       u8 li = m_wieldlight;
-       video::SColor color(255,li,li,li);
-       setMeshColor(m_wieldnode->getMesh(), color);
-
-       // Clear Z buffer
+       // Clear Z buffer so that the wielded tool stay in front of world geometry
        m_wieldmgr->getVideoDriver()->clearZBuffer();
 
        // Draw the wielded node (in a separate scene manager)
@@ -707,7 +664,7 @@ void Camera::drawWieldedTool(irr::core::matrix4* translation)
        cam->setAspectRatio(m_cameranode->getAspectRatio());
        cam->setFOV(72.0*M_PI/180.0);
        cam->setNearValue(0.1);
-       cam->setFarValue(100);
+       cam->setFarValue(1000);
        if (translation != NULL)
        {
                irr::core::matrix4 startMatrix = cam->getAbsoluteTransformation();
index 8831257cc8c2df3b8d7bf51989785779203d31e8..996be79b27e8a054911fa3470b28f880cb6b5ce5 100644 (file)
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 class LocalPlayer;
 struct MapDrawControl;
 class IGameDef;
+class WieldMeshSceneNode;
 
 enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
 
@@ -127,7 +128,7 @@ class Camera
        void setDigging(s32 button);
 
        // Replace the wielded item mesh
-       void wield(const ItemStack &item, u16 playeritem);
+       void wield(const ItemStack &item);
 
        // Draw the wielded tool.
        // This has to happen *after* the main scene is drawn.
@@ -157,8 +158,8 @@ class Camera
        scene::ICameraSceneNode* m_cameranode;
 
        scene::ISceneManager* m_wieldmgr;
-       scene::IMeshSceneNode* m_wieldnode;
-       u8 m_wieldlight;
+       WieldMeshSceneNode* m_wieldnode;
+       scene::ILightSceneNode* m_wieldlightnode;
 
        // draw control
        MapDrawControl& m_draw_control;
@@ -203,14 +204,9 @@ class Camera
        // If 1, right-click digging animation
        s32 m_digging_button;
 
-       //dummymesh for camera
-       irr::scene::IAnimatedMesh* m_dummymesh;
-
        // Animation when changing wielded item
        f32 m_wield_change_timer;
-       scene::IMesh *m_wield_mesh_next;
-       u16 m_previous_playeritem;
-       std::string m_previous_itemname;
+       ItemStack m_wield_item_next;
 
        CameraMode m_camera_mode;
 };
index cae551abc5740451fe77edb69ec00b2f7cbabe08..24150628eaa20ca6274469e0b3e24d972b5b9c36 100644 (file)
@@ -41,6 +41,7 @@ class ITextureSource;
 class IGameDef;
 class LocalPlayer;
 struct ItemStack;
+class WieldMeshSceneNode;
 
 class ClientActiveObject : public ActiveObject
 {
@@ -58,8 +59,10 @@ class ClientActiveObject : public ActiveObject
        virtual bool getCollisionBox(aabb3f *toset){return false;}
        virtual bool collideWithObjects(){return false;}
        virtual v3f getPosition(){return v3f(0,0,0);}
+       virtual scene::ISceneNode *getSceneNode(){return NULL;}
        virtual scene::IMeshSceneNode *getMeshSceneNode(){return NULL;}
        virtual scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode(){return NULL;}
+       virtual WieldMeshSceneNode *getWieldMeshSceneNode(){return NULL;}
        virtual scene::IBillboardSceneNode *getSpriteSceneNode(){return NULL;}
        virtual bool isPlayer() const {return false;}
        virtual bool isLocalPlayer() const {return false;}
index d1de23d2a492e2c527dc8c8c58d34a9d40c82245..8471b7e81408eec598b5542b56cb2370786576f1 100644 (file)
@@ -45,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "main.h" // g_settings
 #include "camera.h" // CameraModes
+#include "wieldmesh.h"
 #include "log.h"
 
 class Settings;
@@ -551,6 +552,7 @@ GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
                m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
                m_meshnode(NULL),
                m_animated_meshnode(NULL),
+               m_wield_meshnode(NULL),
                m_spritenode(NULL),
                m_textnode(NULL),
                m_position(v3f(0,10*BS,0)),
@@ -683,38 +685,47 @@ core::aabbox3d<f32>* GenericCAO::getSelectionBox()
 
 v3f GenericCAO::getPosition()
 {
-       if(getParent() != NULL)
-       {
-               if(m_meshnode)
-                       return m_meshnode->getAbsolutePosition();
-               if(m_animated_meshnode)
-                       return m_animated_meshnode->getAbsolutePosition();
-               if(m_spritenode)
-                       return m_spritenode->getAbsolutePosition();
-               return m_position;
+       if (getParent() != NULL) {
+               scene::ISceneNode *node = getSceneNode();
+               if (node)
+                       return node->getAbsolutePosition();
+               else
+                       return m_position;
        }
        return pos_translator.vect_show;
 }
 
-scene::IMeshSceneNode* GenericCAO::getMeshSceneNode()
+scene::ISceneNode* GenericCAO::getSceneNode()
 {
-       if(m_meshnode)
+       if (m_meshnode)
                return m_meshnode;
+       if (m_animated_meshnode)
+               return m_animated_meshnode;
+       if (m_wield_meshnode)
+               return m_wield_meshnode;
+       if (m_spritenode)
+               return m_spritenode;
        return NULL;
 }
 
+scene::IMeshSceneNode* GenericCAO::getMeshSceneNode()
+{
+       return m_meshnode;
+}
+
 scene::IAnimatedMeshSceneNode* GenericCAO::getAnimatedMeshSceneNode()
 {
-       if(m_animated_meshnode)
-               return m_animated_meshnode;
-       return NULL;
+       return m_animated_meshnode;
+}
+
+WieldMeshSceneNode* GenericCAO::getWieldMeshSceneNode()
+{
+       return m_wield_meshnode;
 }
 
 scene::IBillboardSceneNode* GenericCAO::getSpriteSceneNode()
 {
-       if(m_spritenode)
-               return m_spritenode;
-       return NULL;
+       return m_spritenode;
 }
 
 void GenericCAO::setAttachments()
@@ -769,6 +780,12 @@ void GenericCAO::removeFromScene(bool permanent)
                m_animated_meshnode->drop();
                m_animated_meshnode = NULL;
        }
+       if(m_wield_meshnode)
+       {
+               m_wield_meshnode->remove();
+               m_wield_meshnode->drop();
+               m_wield_meshnode = NULL;
+       }
        if(m_spritenode)
        {
                m_spritenode->remove();
@@ -789,7 +806,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
        m_smgr = smgr;
        m_irr = irr;
 
-       if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL)
+       if (getSceneNode() != NULL)
                return;
 
        m_visuals_expired = false;
@@ -918,28 +935,23 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
                        errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
        }
        else if(m_prop.visual == "wielditem") {
-               infostream<<"GenericCAO::addToScene(): node"<<std::endl;
+               infostream<<"GenericCAO::addToScene(): wielditem"<<std::endl;
                infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
                if(m_prop.textures.size() >= 1){
                        infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
                        IItemDefManager *idef = m_gamedef->idef();
                        ItemStack item(m_prop.textures[0], 1, 0, "", idef);
-                       scene::IMesh *item_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef);
-
-                       // Copy mesh to be able to set unique vertex colors
-                       scene::IMeshManipulator *manip =
-                                       irr->getVideoDriver()->getMeshManipulator();
-                       scene::IMesh *mesh = manip->createMeshUniquePrimitives(item_mesh);
 
-                       m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
-                       m_meshnode->grab();
-                       mesh->drop();
+                       m_wield_meshnode = new WieldMeshSceneNode(
+                                       smgr->getRootSceneNode(), smgr, -1);
+                       m_wield_meshnode->setItem(item, m_gamedef);
+                       m_wield_meshnode->grab();
                        
-                       m_meshnode->setScale(v3f(m_prop.visual_size.X/2,
+                       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;
-                       setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
+                       m_wield_meshnode->setColor(video::SColor(255,li,li,li));
                }
        } else {
                infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
@@ -947,14 +959,8 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
        }
        updateTextures("");
 
-       scene::ISceneNode *node = NULL;
-       if(m_spritenode)
-               node = m_spritenode;
-       else if(m_animated_meshnode)
-               node = m_animated_meshnode;
-       else if(m_meshnode)
-               node = m_meshnode;
-       if(node && m_is_player && !m_is_local_player){
+       scene::ISceneNode *node = getSceneNode();
+       if (node && m_is_player && !m_is_local_player) {
                // Add a text node for showing the name
                gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
                std::wstring wname = narrow_to_wide(m_name);
@@ -981,6 +987,8 @@ void GenericCAO::updateLight(u8 light_at_pos)
                        setMeshColor(m_meshnode->getMesh(), color);
                if(m_animated_meshnode)
                        setMeshColor(m_animated_meshnode->getMesh(), color);
+               if(m_wield_meshnode)
+                       m_wield_meshnode->setColor(color);
                if(m_spritenode)
                        m_spritenode->setColor(color);
        }
@@ -993,27 +1001,19 @@ v3s16 GenericCAO::getLightPosition()
 
 void GenericCAO::updateNodePos()
 {
-       if(getParent() != NULL)
+       if (getParent() != NULL)
                return;
 
-       v3s16 camera_offset = m_env->getCameraOffset();
-       if(m_meshnode)
-       {
-               m_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
-               v3f rot = m_meshnode->getRotation();
-               rot.Y = -m_yaw;
-               m_meshnode->setRotation(rot);
-       }
-       if(m_animated_meshnode)
-       {
-               m_animated_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
-               v3f rot = m_animated_meshnode->getRotation();
-               rot.Y = -m_yaw;
-               m_animated_meshnode->setRotation(rot);
-       }
-       if(m_spritenode)
-       {
-               m_spritenode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
+       scene::ISceneNode *node = getSceneNode();
+
+       if (node) {
+               v3s16 camera_offset = m_env->getCameraOffset();
+               node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS));
+               if (node != m_spritenode) { // rotate if not a sprite
+                       v3f rot = node->getRotation();
+                       rot.Y = -m_yaw;
+                       node->setRotation(rot);
+               }
        }
 }
        
@@ -1107,20 +1107,10 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                                continue;
                        }
                        ClientActiveObject *obj = m_env->getActiveObject(*ci);
-                       if(obj)
-                       {
-                               scene::IMeshSceneNode *m_child_meshnode
-                                               = obj->getMeshSceneNode();
-                               scene::IAnimatedMeshSceneNode *m_child_animated_meshnode
-                                               = obj->getAnimatedMeshSceneNode();
-                               scene::IBillboardSceneNode *m_child_spritenode
-                                               = obj->getSpriteSceneNode();
-                               if(m_child_meshnode)
-                                       m_child_meshnode->setParent(m_smgr->getRootSceneNode());
-                               if(m_child_animated_meshnode)
-                                       m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode());
-                               if(m_child_spritenode)
-                                       m_child_spritenode->setParent(m_smgr->getRootSceneNode());
+                       if (obj) {
+                               scene::ISceneNode *child_node = obj->getSceneNode();
+                               if (child_node)
+                                       child_node->setParent(m_smgr->getRootSceneNode());
                        }
                        ++ci;
                }
@@ -1132,22 +1122,17 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                for(std::vector<u16>::iterator ci = m_children.begin();
                                                ci != m_children.end(); ci++)
                {
-                               // Get the object of the child
-                               ClientActiveObject *obj = m_env->getActiveObject(*ci);
-                               if(obj)
-                                       obj->setAttachments();
+                       // Get the object of the child
+                       ClientActiveObject *obj = m_env->getActiveObject(*ci);
+                       if (obj)
+                               obj->setAttachments();
                }
        }
 
        // Make sure m_is_visible is always applied
-       if(m_meshnode)
-               m_meshnode->setVisible(m_is_visible);
-       if(m_animated_meshnode)
-               m_animated_meshnode->setVisible(m_is_visible);
-       if(m_spritenode)
-               m_spritenode->setVisible(m_is_visible);
-       if(m_textnode)
-               m_textnode->setVisible(m_is_visible);
+       scene::ISceneNode *node = getSceneNode();
+       if (node)
+               node->setVisible(m_is_visible);
 
        if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
        {
@@ -1516,154 +1501,38 @@ void GenericCAO::updateAttachments()
 
        if(getParent() == NULL || m_attached_to_local) // Detach or don't attach
        {
-               if(m_meshnode)
-               {
-                       v3f old_position = m_meshnode->getAbsolutePosition();
-                       v3f old_rotation = m_meshnode->getRotation();
-                       m_meshnode->setParent(m_smgr->getRootSceneNode());
-                       m_meshnode->setPosition(old_position);
-                       m_meshnode->setRotation(old_rotation);
-                       m_meshnode->updateAbsolutePosition();
+               scene::ISceneNode *node = getSceneNode();
+               if (node) {
+                       v3f old_position = node->getAbsolutePosition();
+                       v3f old_rotation = node->getRotation();
+                       node->setParent(m_smgr->getRootSceneNode());
+                       node->setPosition(old_position);
+                       node->setRotation(old_rotation);
+                       node->updateAbsolutePosition();
                }
-               if(m_animated_meshnode)
-               {
-                       v3f old_position = m_animated_meshnode->getAbsolutePosition();
-                       v3f old_rotation = m_animated_meshnode->getRotation();
-                       m_animated_meshnode->setParent(m_smgr->getRootSceneNode());
-                       m_animated_meshnode->setPosition(old_position);
-                       m_animated_meshnode->setRotation(old_rotation);
-                       m_animated_meshnode->updateAbsolutePosition();
-               }
-               if(m_spritenode)
-               {
-                       v3f old_position = m_spritenode->getAbsolutePosition();
-                       v3f old_rotation = m_spritenode->getRotation();
-                       m_spritenode->setParent(m_smgr->getRootSceneNode());
-                       m_spritenode->setPosition(old_position);
-                       m_spritenode->setRotation(old_rotation);
-                       m_spritenode->updateAbsolutePosition();
-               }
-               if(m_is_local_player)
-               {
+               if (m_is_local_player) {
                        LocalPlayer *player = m_env->getLocalPlayer();
                        player->isAttached = false;
                }
        }
        else // Attach
        {
-               scene::IMeshSceneNode *parent_mesh = NULL;
-               if(getParent()->getMeshSceneNode())
-                       parent_mesh = getParent()->getMeshSceneNode();
-               scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL;
-               if(getParent()->getAnimatedMeshSceneNode())
-                       parent_animated_mesh = getParent()->getAnimatedMeshSceneNode();
-               scene::IBillboardSceneNode *parent_sprite = NULL;
-               if(getParent()->getSpriteSceneNode())
-                       parent_sprite = getParent()->getSpriteSceneNode();
-
-               scene::IBoneSceneNode *parent_bone = NULL;
-               if(parent_animated_mesh && m_attachment_bone != "")
-               {
-                       parent_bone =
-                                       parent_animated_mesh->getJointNode(m_attachment_bone.c_str());
-               }
-               // The spaghetti code below makes sure attaching works if either the
-               // parent or child is a spritenode, meshnode, or animatedmeshnode
-               // TODO: Perhaps use polymorphism here to save code duplication
-               if(m_meshnode)
-               {
-                       if(parent_bone)
-                       {
-                               m_meshnode->setParent(parent_bone);
-                               m_meshnode->setPosition(m_attachment_position);
-                               m_meshnode->setRotation(m_attachment_rotation);
-                               m_meshnode->updateAbsolutePosition();
-                       }
-                       else
-                       {
-                               if(parent_mesh)
-                               {
-                                       m_meshnode->setParent(parent_mesh);
-                                       m_meshnode->setPosition(m_attachment_position);
-                                       m_meshnode->setRotation(m_attachment_rotation);
-                                       m_meshnode->updateAbsolutePosition();
-                               }
-                               else if(parent_animated_mesh) {
-                                       m_meshnode->setParent(parent_animated_mesh);
-                                       m_meshnode->setPosition(m_attachment_position);
-                                       m_meshnode->setRotation(m_attachment_rotation);
-                                       m_meshnode->updateAbsolutePosition();
-                               }
-                               else if(parent_sprite) {
-                                       m_meshnode->setParent(parent_sprite);
-                                       m_meshnode->setPosition(m_attachment_position);
-                                       m_meshnode->setRotation(m_attachment_rotation);
-                                       m_meshnode->updateAbsolutePosition();
-                               }
-                       }
-               }
-               if(m_animated_meshnode)
-               {
-                       if(parent_bone)
-                       {
-                               m_animated_meshnode->setParent(parent_bone);
-                               m_animated_meshnode->setPosition(m_attachment_position);
-                               m_animated_meshnode->setRotation(m_attachment_rotation);
-                               m_animated_meshnode->updateAbsolutePosition();
-                       }
-                       else
-                       {
-                               if(parent_mesh)
-                               {
-                                       m_animated_meshnode->setParent(parent_mesh);
-                                       m_animated_meshnode->setPosition(m_attachment_position);
-                                       m_animated_meshnode->setRotation(m_attachment_rotation);
-                                       m_animated_meshnode->updateAbsolutePosition();
-                               } else if(parent_animated_mesh) {
-                                       m_animated_meshnode->setParent(parent_animated_mesh);
-                                       m_animated_meshnode->setPosition(m_attachment_position);
-                                       m_animated_meshnode->setRotation(m_attachment_rotation);
-                                       m_animated_meshnode->updateAbsolutePosition();
-                               } else if(parent_sprite) {
-                                       m_animated_meshnode->setParent(parent_sprite);
-                                       m_animated_meshnode->setPosition(m_attachment_position);
-                                       m_animated_meshnode->setRotation(m_attachment_rotation);
-                                       m_animated_meshnode->updateAbsolutePosition();
-                               }
-                       }
+               scene::ISceneNode *my_node = getSceneNode();
+
+               scene::ISceneNode *parent_node = getParent()->getSceneNode();
+               scene::IAnimatedMeshSceneNode *parent_animated_mesh_node =
+                               getParent()->getAnimatedMeshSceneNode();
+               if (parent_animated_mesh_node && m_attachment_bone != "") {
+                       parent_node = parent_animated_mesh_node->getJointNode(m_attachment_bone.c_str());
                }
-               if(m_spritenode)
-               {
-                       if(parent_bone)
-                       {
-                               m_spritenode->setParent(parent_bone);
-                               m_spritenode->setPosition(m_attachment_position);
-                               m_spritenode->setRotation(m_attachment_rotation);
-                               m_spritenode->updateAbsolutePosition();
-                       } else {
-                               if(parent_mesh)
-                               {
-                                       m_spritenode->setParent(parent_mesh);
-                                       m_spritenode->setPosition(m_attachment_position);
-                                       m_spritenode->setRotation(m_attachment_rotation);
-                                       m_spritenode->updateAbsolutePosition();
-                               }
-                               else if(parent_animated_mesh) {
-                                       m_spritenode->setParent(parent_animated_mesh);
-                                       m_spritenode->setPosition(m_attachment_position);
-                                       m_spritenode->setRotation(m_attachment_rotation);
-                                       m_spritenode->updateAbsolutePosition();
-                               }
-                               else if(parent_sprite) {
-                                       m_spritenode->setParent(parent_sprite);
-                                       m_spritenode->setPosition(m_attachment_position);
-                                       m_spritenode->setRotation(m_attachment_rotation);
-                                       m_spritenode->updateAbsolutePosition();
-                               }
-                       }
+
+               if (my_node && parent_node) {
+                       my_node->setParent(parent_node);
+                       my_node->setPosition(m_attachment_position);
+                       my_node->setRotation(m_attachment_rotation);
+                       my_node->updateAbsolutePosition();
                }
-               if(m_is_local_player)
-               {
+               if (m_is_local_player) {
                        LocalPlayer *player = m_env->getLocalPlayer();
                        player->isAttached = true;
                }
index bf1ac5b3fa02db8d7e03d8a78bb6ae2d1468ad63..69e2e54a264502fef563f2a48de2e3065d750e20 100644 (file)
@@ -70,6 +70,7 @@ class GenericCAO : public ClientActiveObject
        core::aabbox3d<f32> m_selection_box;
        scene::IMeshSceneNode *m_meshnode;
        scene::IAnimatedMeshSceneNode *m_animated_meshnode;
+       WieldMeshSceneNode *m_wield_meshnode;
        scene::IBillboardSceneNode *m_spritenode;
        scene::ITextSceneNode* m_textnode;
        v3f m_position;
@@ -131,10 +132,14 @@ class GenericCAO : public ClientActiveObject
 
        v3f getPosition();
 
+       scene::ISceneNode *getSceneNode();
+
        scene::IMeshSceneNode *getMeshSceneNode();
 
        scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode();
 
+       WieldMeshSceneNode *getWieldMeshSceneNode();
+
        scene::IBillboardSceneNode *getSpriteSceneNode();
 
        inline bool isPlayer() const
index 01a7e38dcee5a33964de14a4e92d6f2eee4ff426..6e5305b1e014778dde7ec52478a3787b3666d2db 100644 (file)
@@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef SERVER
 #include "clientmap.h"
 #include "localplayer.h"
+#include "mapblock_mesh.h"
 #include "event.h"
 #endif
 #include "daynightratio.h"
@@ -2330,21 +2331,28 @@ void ClientEnvironment::step(float dtime)
                        player->move(dtime, this, 100*BS);
 
                }
-               
-               // Update lighting on all players on client
-               float light = 1.0;
-               try{
-                       // Get node at head
-                       v3s16 p = player->getLightPosition();
-                       MapNode n = m_map->getNode(p);
-                       light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
-               }
-               catch(InvalidPositionException &e){
-                       light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
-               }
-               player->light = light;
        }
-       
+
+       // Update lighting on local player (used for wield item)
+       u32 day_night_ratio = getDayNightRatio();
+       {
+               // Get node at head
+
+               // On InvalidPositionException, use this as default
+               // (day: LIGHT_SUN, night: 0)
+               MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
+
+               try {
+                       v3s16 p = lplayer->getLightPosition();
+                       node_at_lplayer = m_map->getNode(p);
+               } catch (InvalidPositionException &e) {}
+
+               u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef());
+               u8 day = light & 0xff;
+               u8 night = (light >> 8) & 0xff;
+               finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
+       }
+
        /*
                Step active objects and update lighting of them
        */
@@ -2367,10 +2375,10 @@ void ClientEnvironment::step(float dtime)
                                // Get node at head
                                v3s16 p = obj->getLightPosition();
                                MapNode n = m_map->getNode(p);
-                               light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
+                               light = n.getLightBlend(day_night_ratio, m_gamedef->ndef());
                        }
                        catch(InvalidPositionException &e){
-                               light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
+                               light = blend_light(day_night_ratio, LIGHT_SUN, 0);
                        }
                        obj->updateLight(light);
                }
index 272abe78359596804d096b356cdea4a829300e9f..fee45e31d25acbac439fb0afc627b3bf502300c4 100644 (file)
@@ -3656,7 +3656,7 @@ void Game::updateFrame(std::vector<aabb3f> &highlight_boxes,
 
                if (mlist && (client->getPlayerItem() < mlist->getSize())) {
                        ItemStack item = mlist->getItem(client->getPlayerItem());
-                       camera->wield(item, client->getPlayerItem());
+                       camera->wield(item);
                }
                runData->update_wielded_item_trigger = false;
        }
index f976c3eb7ad7a2a61a16d9e8cfe44960a9c90b04..ac67c5b271994827502559cf0fc28543e4357674 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef SERVER
 #include "mapblock_mesh.h"
 #include "mesh.h"
+#include "wieldmesh.h"
 #include "tile.h"
 #endif
 #include "log.h"
@@ -330,104 +331,78 @@ class CItemDefManager: public IWritableItemDefManager
 
                ITextureSource *tsrc = gamedef->getTextureSource();
                INodeDefManager *nodedef = gamedef->getNodeDefManager();
-               IrrlichtDevice *device = tsrc->getDevice();
-               video::IVideoDriver *driver = device->getVideoDriver();
-               const ItemDefinition *def = &get(name);
+               const ItemDefinition &def = get(name);
 
                // Create new ClientCached
                cc = new ClientCached();
 
-               bool need_node_mesh = false;
-
                // Create an inventory texture
                cc->inventory_texture = NULL;
-               if(def->inventory_image != "")
-               {
-                       cc->inventory_texture = tsrc->getTexture(def->inventory_image);
-               }
-               else if(def->type == ITEM_NODE)
-               {
-                       need_node_mesh = true;
-               }
+               if(def.inventory_image != "")
+                       cc->inventory_texture = tsrc->getTexture(def.inventory_image);
+
+               // Additional processing for nodes:
+               // - Create a wield mesh if WieldMeshSceneNode can't render
+               //   the node on its own.
+               // - If inventory_texture isn't set yet, create one using
+               //   render-to-texture.
+               if (def.type == ITEM_NODE) {
+                       // Get node properties
+                       content_t id = nodedef->getId(name);
+                       const ContentFeatures &f = nodedef->get(id);
 
-               // Create a wield mesh
-               assert(cc->wield_mesh == NULL);
-               if(def->type == ITEM_NODE && def->wield_image == "")
-               {
-                       need_node_mesh = true;
-               }
-               else if(def->wield_image != "" || def->inventory_image != "")
-               {
-                       // Extrude the wield image into a mesh
-
-                       std::string imagename;
-                       if(def->wield_image != "")
-                               imagename = def->wield_image;
-                       else
-                               imagename = def->inventory_image;
-
-                       cc->wield_mesh = createExtrudedMesh(
-                                       tsrc->getTexture(imagename),
-                                       driver,
-                                       def->wield_scale * v3f(40.0, 40.0, 4.0));
-                       if(cc->wield_mesh == NULL)
-                       {
-                               infostream<<"ItemDefManager: WARNING: "
-                                       <<"updateTexturesAndMeshes(): "
-                                       <<"Unable to create extruded mesh for item "
-                                       <<def->name<<std::endl;
-                       }
-               }
+                       bool need_rtt_mesh = cc->inventory_texture == NULL;
 
-               if(need_node_mesh)
-               {
-                       /*
-                               Get node properties
-                       */
-                       content_t id = nodedef->getId(def->name);
-                       const ContentFeatures &f = nodedef->get(id);
+                       // Keep this in sync with WieldMeshSceneNode::setItem()
+                       bool need_wield_mesh =
+                               !(f.mesh_ptr[0] ||
+                                 f.drawtype == NDT_NORMAL ||
+                                 f.drawtype == NDT_ALLFACES ||
+                                 f.drawtype == NDT_AIRLIKE);
 
-                       u8 param1 = 0;
-                       if(f.param_type == CPT_LIGHT)
-                               param1 = 0xee;
+                       scene::IMesh *node_mesh = NULL;
 
-                       /*
-                               Make a mesh from the node
-                       */
                        bool reenable_shaders = false;
-                       if(g_settings->getBool("enable_shaders")){
-                               reenable_shaders = true;
-                               g_settings->setBool("enable_shaders",false);
-                       }
-                       MeshMakeData mesh_make_data(gamedef);
-                       u8 param2 = 0;
-                       if (f.param_type_2 == CPT2_WALLMOUNTED)
-                               param2 = 1;
-                       MapNode mesh_make_node(id, param1, param2);
-                       mesh_make_data.fillSingleNode(&mesh_make_node);
-                       MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
-                       scene::IMesh *node_mesh = mapblock_mesh.getMesh();
-                       assert(node_mesh);
-                       video::SColor c(255, 255, 255, 255);
-                       setMeshColor(node_mesh, c);
 
-                       /*
-                               Scale and translate the mesh so it's a unit cube
-                               centered on the origin
-                       */
-                       scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
-                       translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
+                       if (need_rtt_mesh || need_wield_mesh) {
+                               u8 param1 = 0;
+                               if (f.param_type == CPT_LIGHT)
+                                       param1 = 0xee;
+
+                               /*
+                                       Make a mesh from the node
+                               */
+                               if (g_settings->getBool("enable_shaders")) {
+                                       reenable_shaders = true;
+                                       g_settings->setBool("enable_shaders", false);
+                               }
+                               MeshMakeData mesh_make_data(gamedef);
+                               u8 param2 = 0;
+                               if (f.param_type_2 == CPT2_WALLMOUNTED)
+                                       param2 = 1;
+                               MapNode mesh_make_node(id, param1, param2);
+                               mesh_make_data.fillSingleNode(&mesh_make_node);
+                               MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
+                               node_mesh = mapblock_mesh.getMesh();
+                               node_mesh->grab();
+                               video::SColor c(255, 255, 255, 255);
+                               setMeshColor(node_mesh, c);
+
+                               // scale and translate the mesh so it's a
+                               // unit cube centered on the origin
+                               scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
+                               translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
+                       }
 
                        /*
                                Draw node mesh into a render target texture
                        */
-                       if(cc->inventory_texture == NULL)
-                       {
+                       if (need_rtt_mesh) {
                                TextureFromMeshParams params;
                                params.mesh = node_mesh;
                                params.dim.set(64, 64);
                                params.rtt_texture_name = "INVENTORY_"
-                                       + def->name + "_RTT";
+                                       + def.name + "_RTT";
                                params.delete_texture_on_shutdown = true;
                                params.camera_position.set(0, 1.0, -1.5);
                                params.camera_position.rotateXZBy(45);
@@ -449,8 +424,7 @@ class CItemDefManager: public IWritableItemDefManager
                                        tsrc->generateTextureFromMesh(params);
 
                                // render-to-target didn't work
-                               if(cc->inventory_texture == NULL)
-                               {
+                               if (cc->inventory_texture == NULL) {
                                        cc->inventory_texture =
                                                tsrc->getTexture(f.tiledef[0].name);
                                }
@@ -459,16 +433,16 @@ class CItemDefManager: public IWritableItemDefManager
                        /*
                                Use the node mesh as the wield mesh
                        */
+                       if (need_wield_mesh) {
+                               cc->wield_mesh = node_mesh;
+                               cc->wield_mesh->grab();
 
-                       // Scale to proper wield mesh proportions
-                       scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
-                                       * def->wield_scale);
-
-                       cc->wield_mesh = node_mesh;
-                       cc->wield_mesh->grab();
+                               // no way reference count can be smaller than 2 in this place!
+                               assert(cc->wield_mesh->getReferenceCount() >= 2);
+                       }
 
-                       //no way reference count can be smaller than 2 in this place!
-                       assert(cc->wield_mesh->getReferenceCount() >= 2);
+                       if (node_mesh)
+                               node_mesh->drop();
 
                        if (reenable_shaders)
                                g_settings->setBool("enable_shaders",true);
index 84b7c11466b2ca2d3287a28907dc767945d1d21f..bdcf45beb2cd566d53118b4d93a7fe8d56c4c56b 100644 (file)
@@ -48,6 +48,7 @@ LocalPlayer::LocalPlayer(IGameDef *gamedef, const char *name):
        last_animation(NO_ANIM),
        hotbar_image(""),
        hotbar_selected_image(""),
+       light_color(255,255,255,255),
        m_sneak_node(32767,32767,32767),
        m_sneak_node_exists(false),
        m_old_node_below(32767,32767,32767),
index 16830f3ec87343aeb17abfe46b7f793354d65f81..16b66716da66e1874fdbee00690663b2ab8b9379 100644 (file)
@@ -71,6 +71,8 @@ class LocalPlayer : public Player
        std::string hotbar_image;
        std::string hotbar_selected_image;
 
+       video::SColor light_color;
+
        GenericCAO* getCAO() const {
                return m_cao;
        }
index 2459cf0d7e5963818ce1dea5b61c970a253e0f70..99a5ce0dd24b20fb4b6bdd5b5c63dfd9d33bf8d5 100644 (file)
@@ -320,7 +320,7 @@ u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
        Converts from day + night color values (0..255)
        and a given daynight_ratio to the final SColor shown on screen.
 */
-static void finalColorBlend(video::SColor& result,
+void finalColorBlend(video::SColor& result,
                u8 day, u8 night, u32 daynight_ratio)
 {
        s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
index e1cccc64e1156061d69905be4951cdcdccdea4b2..be56d4c586a03e37ac20bcc7120f988073665b68 100644 (file)
@@ -195,6 +195,11 @@ u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
 
+// Converts from day + night color values (0..255)
+// and a given daynight_ratio to the final SColor shown on screen.
+void finalColorBlend(video::SColor& result,
+               u8 day, u8 night, u32 daynight_ratio);
+
 // Retrieves the TileSpec of a face of a node
 // Adds MATERIAL_FLAG_CRACK if the node is cracked
 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data);
index 19d75f9f5e7c3480a868b91e426351f4bf853488..38b3d97bc44d0bde6d6b9322c2c631e681bb699c 100644 (file)
@@ -91,218 +91,6 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale)
        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;
-                       }
-               }
-       }
-
-       delete[] solidity;
-
-       // 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->getOriginalSize();
-       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->drop();
-                       return NULL;
-               }
-
-               img1->copyTo(img2);
-               img1->drop();
-               mesh = extrudeARGB(size.Width, size.Height, (u8*) img2->lock());
-               img2->unlock();
-               img2->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)
@@ -523,6 +311,8 @@ scene::IMesh* convertNodeboxNodeToMesh(ContentFeatures *f)
        for (u16 j = 0; j < 6; j++)
        {
                scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+               buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+               buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
                dst_mesh->addMeshBuffer(buf);
                buf->drop();
        }
index 7539298cb8c1fd5758a0eb2ae2653f0b0cb8e940..29f5ec76ca6aae178c61e5978d7972f382364d62 100644 (file)
@@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "irrlichttypes_extrabloated.h"
 #include "nodedef.h"
-#include <string>
 
 /*
        Create a new cube mesh.
@@ -33,16 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 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).
index 13866e5f55370656eaf8c2b7d09c114af6fe3a53..64c138d02682111b1cea145055db40d344c8f4d9 100644 (file)
@@ -39,7 +39,6 @@ Player::Player(IGameDef *gamedef, const char *name):
        is_climbing(false),
        swimming_vertical(false),
        camera_barely_in_ceiling(false),
-       light(0),
        inventory(gamedef->idef()),
        hp(PLAYER_MAX_HP),
        hurt_tilt_timer(0),
index a5cc7123f146f96dca1374e2cdf2d8fe30de4793..435875233b45250368eae095f84292de4c56a0a2 100644 (file)
@@ -249,8 +249,6 @@ class Player
        bool swimming_vertical;
        bool camera_barely_in_ceiling;
        
-       u8 light;
-
        Inventory inventory;
 
        f32 movement_acceleration_default;
index cd353c0ea473abd4b1c10718578eb510280294f0..6cd7983fc36220987085cde1863c507b1301881d 100644 (file)
@@ -199,6 +199,16 @@ struct TestUtilities: public TestBase
                UASSERT(is_number("123") == true);
                UASSERT(is_number("") == false);
                UASSERT(is_number("123a") == false);
+               UASSERT(is_power_of_two(0) == false);
+               UASSERT(is_power_of_two(1) == true);
+               UASSERT(is_power_of_two(2) == true);
+               UASSERT(is_power_of_two(3) == false);
+               for (int exponent = 2; exponent <= 31; ++exponent) {
+                       UASSERT(is_power_of_two((1 << exponent) - 1) == false);
+                       UASSERT(is_power_of_two((1 << exponent)) == true);
+                       UASSERT(is_power_of_two((1 << exponent) + 1) == false);
+               }
+               UASSERT(is_power_of_two((u32)-1) == false);
        }
 };
 
index ee8fea8cfb0e68ad7c231c1ddae360a0c6375e14..e7fdc25999e81e6d96431c37ccdef02d90b911f1 100644 (file)
@@ -361,5 +361,10 @@ inline float cycle_shift(float value, float by = 0, float max = 1)
     return value + by;
 }
 
+inline bool is_power_of_two(u32 n)
+{
+       return n != 0 && (n & (n-1)) == 0;
+}
+
 #endif
 
diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp
new file mode 100644 (file)
index 0000000..4552d35
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+Minetest
+Copyright (C) 2010-2014 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 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 "wieldmesh.h"
+#include "inventory.h"
+#include "gamedef.h"
+#include "itemdef.h"
+#include "nodedef.h"
+#include "mesh.h"
+#include "tile.h"
+#include "log.h"
+#include "util/numeric.h"
+#include <map>
+#include <IMeshManipulator.h>
+
+#define WIELD_SCALE_FACTOR 30.0
+#define WIELD_SCALE_FACTOR_EXTRUDED 40.0
+
+#define MIN_EXTRUSION_MESH_RESOLUTION 32   // not 16: causes too many "holes"
+#define MAX_EXTRUSION_MESH_RESOLUTION 512
+
+static scene::IMesh* createExtrusionMesh(int resolution_x, int resolution_y)
+{
+       const f32 r = 0.5;
+
+       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+       video::SColor c(255,255,255,255);
+       v3f scale(1.0, 1.0, 0.1);
+
+       // Front and back
+       {
+               video::S3DVertex vertices[8] = {
+                       // z-
+                       video::S3DVertex(-r,+r,-r, 0,0,-1, c, 0,0),
+                       video::S3DVertex(+r,+r,-r, 0,0,-1, c, 1,0),
+                       video::S3DVertex(+r,-r,-r, 0,0,-1, c, 1,1),
+                       video::S3DVertex(-r,-r,-r, 0,0,-1, c, 0,1),
+                       // z+
+                       video::S3DVertex(-r,+r,+r, 0,0,+1, c, 0,0),
+                       video::S3DVertex(-r,-r,+r, 0,0,+1, c, 0,1),
+                       video::S3DVertex(+r,-r,+r, 0,0,+1, c, 1,1),
+                       video::S3DVertex(+r,+r,+r, 0,0,+1, c, 1,0),
+               };
+               u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
+               buf->append(vertices, 8, indices, 12);
+       }
+
+       f32 pixelsize_x = 1 / (f32) resolution_x;
+       f32 pixelsize_y = 1 / (f32) resolution_y;
+
+       for (int i = 0; i < resolution_x; ++i) {
+               f32 pixelpos_x = i * pixelsize_x - 0.5;
+               f32 x0 = pixelpos_x;
+               f32 x1 = pixelpos_x + pixelsize_x;
+               f32 tex0 = (i + 0.1) * pixelsize_x;
+               f32 tex1 = (i + 0.9) * pixelsize_x;
+               video::S3DVertex vertices[8] = {
+                       // x-
+                       video::S3DVertex(x0,-r,-r, -1,0,0, c, tex0,1),
+                       video::S3DVertex(x0,-r,+r, -1,0,0, c, tex1,1),
+                       video::S3DVertex(x0,+r,+r, -1,0,0, c, tex1,0),
+                       video::S3DVertex(x0,+r,-r, -1,0,0, c, tex0,0),
+                       // x+
+                       video::S3DVertex(x1,-r,-r, +1,0,0, c, tex0,1),
+                       video::S3DVertex(x1,+r,-r, +1,0,0, c, tex0,0),
+                       video::S3DVertex(x1,+r,+r, +1,0,0, c, tex1,0),
+                       video::S3DVertex(x1,-r,+r, +1,0,0, c, tex1,1),
+               };
+               u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
+               buf->append(vertices, 8, indices, 12);
+       }
+       for (int i = 0; i < resolution_y; ++i) {
+               f32 pixelpos_y = i * pixelsize_y - 0.5;
+               f32 y0 = -pixelpos_y - pixelsize_y;
+               f32 y1 = -pixelpos_y;
+               f32 tex0 = (i + 0.1) * pixelsize_y;
+               f32 tex1 = (i + 0.9) * pixelsize_y;
+               video::S3DVertex vertices[8] = {
+                       // y-
+                       video::S3DVertex(-r,y0,-r, 0,-1,0, c, 0,tex0),
+                       video::S3DVertex(+r,y0,-r, 0,-1,0, c, 1,tex0),
+                       video::S3DVertex(+r,y0,+r, 0,-1,0, c, 1,tex1),
+                       video::S3DVertex(-r,y0,+r, 0,-1,0, c, 0,tex1),
+                       // y+
+                       video::S3DVertex(-r,y1,-r, 0,+1,0, c, 0,tex0),
+                       video::S3DVertex(-r,y1,+r, 0,+1,0, c, 0,tex1),
+                       video::S3DVertex(+r,y1,+r, 0,+1,0, c, 1,tex1),
+                       video::S3DVertex(+r,y1,-r, 0,+1,0, c, 1,tex0),
+               };
+               u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4};
+               buf->append(vertices, 8, indices, 12);
+       }
+
+       // Define default material
+       video::SMaterial *material = &buf->getMaterial();
+       material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       material->BackfaceCulling = true;
+       material->setFlag(video::EMF_LIGHTING, false);
+       material->setFlag(video::EMF_BILINEAR_FILTER, false);
+       material->setFlag(video::EMF_TRILINEAR_FILTER, false);
+       // anisotropic filtering removes "thin black line" artifacts
+       material->setFlag(video::EMF_ANISOTROPIC_FILTER, true);
+       material->setFlag(video::EMF_TEXTURE_WRAP, false);
+
+       // Create mesh object
+       scene::SMesh *mesh = new scene::SMesh();
+       mesh->addMeshBuffer(buf);
+       buf->drop();
+       scaleMesh(mesh, scale);  // also recalculates bounding box
+       return mesh;
+}
+
+/*
+       Caches extrusion meshes so that only one of them per resolution
+       is needed. Also caches one cube (for convenience).
+
+       E.g. there is a single extrusion mesh that is used for all
+       16x16 px images, another for all 256x256 px images, and so on.
+
+       WARNING: Not thread safe. This should not be a problem since
+       rendering related classes (such as WieldMeshSceneNode) will be
+       used from the rendering thread only.
+*/
+class ExtrusionMeshCache: public IReferenceCounted
+{
+public:
+       // Constructor
+       ExtrusionMeshCache()
+       {
+               for (int resolution = MIN_EXTRUSION_MESH_RESOLUTION;
+                               resolution <= MAX_EXTRUSION_MESH_RESOLUTION;
+                               resolution *= 2) {
+                       m_extrusion_meshes[resolution] =
+                               createExtrusionMesh(resolution, resolution);
+               }
+               m_cube = createCubeMesh(v3f(1.0, 1.0, 1.0));
+       }
+       // Destructor
+       virtual ~ExtrusionMeshCache()
+       {
+               for (std::map<int, scene::IMesh*>::iterator
+                               it = m_extrusion_meshes.begin();
+                               it != m_extrusion_meshes.end(); ++it) {
+                       it->second->drop();
+               }
+               m_cube->drop();
+       }
+       // Get closest extrusion mesh for given image dimensions
+       // Caller must drop the returned pointer
+       scene::IMesh* create(core::dimension2d<u32> dim)
+       {
+               // handle non-power of two textures inefficiently without cache
+               if (!is_power_of_two(dim.Width) || !is_power_of_two(dim.Height)) {
+                       return createExtrusionMesh(dim.Width, dim.Height);
+               }
+
+               int maxdim = MYMAX(dim.Width, dim.Height);
+
+               std::map<int, scene::IMesh*>::iterator
+                       it = m_extrusion_meshes.lower_bound(maxdim);
+
+               if (it == m_extrusion_meshes.end()) {
+                       // no viable resolution found; use largest one
+                       it = m_extrusion_meshes.find(MAX_EXTRUSION_MESH_RESOLUTION);
+                       assert(it != m_extrusion_meshes.end());
+               }
+
+               scene::IMesh *mesh = it->second;
+               mesh->grab();
+               return mesh;
+       }
+       // Returns a 1x1x1 cube mesh with one meshbuffer (material) per face
+       // Caller must drop the returned pointer
+       scene::IMesh* createCube()
+       {
+               m_cube->grab();
+               return m_cube;
+       }
+
+private:
+       std::map<int, scene::IMesh*> m_extrusion_meshes;
+       scene::IMesh *m_cube;
+};
+
+ExtrusionMeshCache *g_extrusion_mesh_cache = NULL;
+
+
+WieldMeshSceneNode::WieldMeshSceneNode(
+               scene::ISceneNode *parent,
+               scene::ISceneManager *mgr,
+               s32 id,
+               bool lighting
+):
+       scene::ISceneNode(parent, mgr, id),
+       m_meshnode(NULL),
+       m_lighting(lighting),
+       m_bounding_box(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
+{
+       // If this is the first wield mesh scene node, create a cache
+       // for extrusion meshes (and a cube mesh), otherwise reuse it
+       if (g_extrusion_mesh_cache == NULL)
+               g_extrusion_mesh_cache = new ExtrusionMeshCache();
+       else
+               g_extrusion_mesh_cache->grab();
+
+       // Disable bounding box culling for this scene node
+       // since we won't calculate the bounding box.
+       setAutomaticCulling(scene::EAC_OFF);
+
+       // Create the child scene node
+       scene::IMesh *dummymesh = g_extrusion_mesh_cache->createCube();
+       m_meshnode = SceneManager->addMeshSceneNode(dummymesh, this, -1);
+       m_meshnode->setReadOnlyMaterials(false);
+       m_meshnode->setVisible(false);
+       dummymesh->drop(); // m_meshnode grabbed it
+}
+
+WieldMeshSceneNode::~WieldMeshSceneNode()
+{
+       assert(g_extrusion_mesh_cache);
+       if (g_extrusion_mesh_cache->drop())
+               g_extrusion_mesh_cache = NULL;
+}
+
+void WieldMeshSceneNode::setCube(const TileSpec tiles[6],
+                       v3f wield_scale, ITextureSource *tsrc)
+{
+       scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
+       changeToMesh(cubemesh);
+       cubemesh->drop();
+
+       m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
+
+       // Customize materials
+       for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) {
+               assert(i < 6);
+               video::SMaterial &material = m_meshnode->getMaterial(i);
+               material.setTexture(0, tiles[i].texture);
+               tiles[i].applyMaterialOptions(material);
+       }
+}
+
+void WieldMeshSceneNode::setExtruded(const std::string &imagename,
+               v3f wield_scale, ITextureSource *tsrc)
+{
+       video::ITexture *texture = tsrc->getTexture(imagename);
+       if (!texture) {
+               changeToMesh(NULL);
+               return;
+       }
+
+       scene::IMesh *mesh = g_extrusion_mesh_cache->create(texture->getSize());
+       changeToMesh(mesh);
+       mesh->drop();
+
+       m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR_EXTRUDED);
+
+       // Customize material
+       assert(m_meshnode->getMaterialCount() == 1);
+       video::SMaterial &material = m_meshnode->getMaterial(0);
+       material.setTexture(0, texture);
+}
+
+void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
+{
+       ITextureSource *tsrc = gamedef->getTextureSource();
+       IItemDefManager *idef = gamedef->getItemDefManager();
+
+       const ItemDefinition &def = item.getDefinition(idef);
+
+       // If wield_image is defined, it overrides everything else
+       if (def.wield_image != "") {
+               setExtruded(def.wield_image, def.wield_scale, tsrc);
+               return;
+       }
+
+       // Handle nodes
+       // See also CItemDefManager::createClientCached()
+       if (def.type == ITEM_NODE) {
+               INodeDefManager *ndef = gamedef->getNodeDefManager();
+               const ContentFeatures &f = ndef->get(def.name);
+               if (f.mesh_ptr[0]) {
+                       // e.g. mesh nodes and nodeboxes
+                       changeToMesh(f.mesh_ptr[0]);
+                       // mesh_ptr[0] is pre-scaled by BS * f->visual_scale
+                       m_meshnode->setScale(
+                                       def.wield_scale * WIELD_SCALE_FACTOR
+                                       / (BS * f.visual_scale));
+                       // Customize materials
+                       for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) {
+                               assert(i < 6);
+                               video::SMaterial &material = m_meshnode->getMaterial(i);
+                               material.setTexture(0, f.tiles[i].texture);
+                               f.tiles[i].applyMaterialOptions(material);
+                       }
+                       return;
+               } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
+                       setCube(f.tiles, def.wield_scale, tsrc);
+                       return;
+               } else if (f.drawtype == NDT_AIRLIKE) {
+                       changeToMesh(NULL);
+                       return;
+               }
+
+               // If none of the above standard cases worked, use the wield mesh from ClientCached
+               scene::IMesh *mesh = idef->getWieldMesh(item.name, gamedef);
+               if (mesh) {
+                       changeToMesh(mesh);
+                       m_meshnode->setScale(def.wield_scale * WIELD_SCALE_FACTOR);
+                       return;
+               }
+       }
+
+       // default to inventory_image
+       if (def.inventory_image != "") {
+               setExtruded(def.inventory_image, def.wield_scale, tsrc);
+               return;
+       }
+
+       // no wield mesh found
+       changeToMesh(NULL);
+}
+
+void WieldMeshSceneNode::setColor(video::SColor color)
+{
+       assert(!m_lighting);
+       setMeshColor(m_meshnode->getMesh(), color);
+}
+
+void WieldMeshSceneNode::render()
+{
+       // note: if this method is changed to actually do something,
+       // you probably should implement OnRegisterSceneNode as well
+}
+
+void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
+{
+       if (mesh == NULL) {
+               scene::IMesh *dummymesh = g_extrusion_mesh_cache->createCube();
+               m_meshnode->setVisible(false);
+               m_meshnode->setMesh(dummymesh);
+               dummymesh->drop();  // m_meshnode grabbed it
+       }
+
+       if (m_lighting) {
+               m_meshnode->setMesh(mesh);
+       } else {
+               /*
+                       Lighting is disabled, this means the caller can (and probably will)
+                       call setColor later. We therefore need to clone the mesh so that
+                       setColor will only modify this scene node's mesh, not others'.
+               */
+               scene::IMeshManipulator *meshmanip = SceneManager->getMeshManipulator();
+               scene::IMesh *new_mesh = meshmanip->createMeshCopy(mesh);
+               m_meshnode->setMesh(new_mesh);
+               new_mesh->drop();  // m_meshnode grabbed it
+       }
+
+       m_meshnode->setMaterialFlag(video::EMF_LIGHTING, m_lighting);
+       // need to normalize normals when lighting is enabled (because of setScale())
+       m_meshnode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, m_lighting);
+       m_meshnode->setVisible(true);
+
+}
diff --git a/src/wieldmesh.h b/src/wieldmesh.h
new file mode 100644 (file)
index 0000000..7761fd5
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Minetest
+Copyright (C) 2010-2014 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 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 WIELDMESH_HEADER
+#define WIELDMESH_HEADER
+
+#include "irrlichttypes_extrabloated.h"
+#include <string>
+
+class ItemStack;
+class IGameDef;
+class ITextureSource;
+struct TileSpec;
+
+/*
+       Wield item scene node, renders the wield mesh of some item
+*/
+class WieldMeshSceneNode: public scene::ISceneNode
+{
+public:
+       WieldMeshSceneNode(scene::ISceneNode *parent, scene::ISceneManager *mgr,
+                       s32 id = -1, bool lighting = false);
+       virtual ~WieldMeshSceneNode();
+
+       void setCube(const TileSpec tiles[6],
+                       v3f wield_scale, ITextureSource *tsrc);
+       void setExtruded(const std::string &imagename,
+                       v3f wield_scale, ITextureSource *tsrc);
+       void setItem(const ItemStack &item, IGameDef *gamedef);
+
+       // Sets the vertex color of the wield mesh.
+       // Must only be used if the constructor was called with lighting = false
+       void setColor(video::SColor color);
+
+       virtual void render();
+
+       virtual const core::aabbox3d<f32>& getBoundingBox() const
+       { return m_bounding_box; }
+
+private:
+       void changeToMesh(scene::IMesh *mesh);
+
+       // Child scene node with the current wield mesh
+       scene::IMeshSceneNode *m_meshnode;
+
+       // True if EMF_LIGHTING should be enabled.
+       bool m_lighting;
+
+       // Bounding box culling is disabled for this type of scene node,
+       // so this variable is just required so we can implement
+       // getBoundingBox() and is set to an empty box.
+       core::aabbox3d<f32> m_bounding_box;
+};
+
+#endif