summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKahrl <kahrl@gmx.net>2014-11-02 03:47:43 +0100
committerKahrl <kahrl@gmx.net>2014-11-08 23:11:57 +0100
commit9b551d5cbcaf71a8c39bbf7e886290649aed4799 (patch)
tree8eb68e4c9a7a006ec6c406da4760403c6748848e
parentcc8d7b86404f2830bcf09d04468e8041db276b98 (diff)
downloadminetest-9b551d5cbcaf71a8c39bbf7e886290649aed4799.tar.gz
minetest-9b551d5cbcaf71a8c39bbf7e886290649aed4799.tar.bz2
minetest-9b551d5cbcaf71a8c39bbf7e886290649aed4799.zip
Implement WieldMeshSceneNode which improves wield mesh rendering
- 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.
-rw-r--r--build/android/jni/Android.mk5
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/camera.cpp91
-rw-r--r--src/camera.h14
-rw-r--r--src/clientobject.h3
-rw-r--r--src/content_cao.cpp313
-rw-r--r--src/content_cao.h5
-rw-r--r--src/environment.cpp40
-rw-r--r--src/game.cpp2
-rw-r--r--src/itemdef.cpp150
-rw-r--r--src/localplayer.cpp1
-rw-r--r--src/localplayer.h2
-rw-r--r--src/mapblock_mesh.cpp2
-rw-r--r--src/mapblock_mesh.h5
-rw-r--r--src/mesh.cpp214
-rw-r--r--src/mesh.h11
-rw-r--r--src/player.cpp1
-rw-r--r--src/player.h2
-rw-r--r--src/test.cpp10
-rw-r--r--src/util/numeric.h5
-rw-r--r--src/wieldmesh.cpp380
-rw-r--r--src/wieldmesh.h71
22 files changed, 696 insertions, 632 deletions
diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk
index 335802d85..d23630c6b 100644
--- a/build/android/jni/Android.mk
+++ b/build/android/jni/Android.mk
@@ -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 += \
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eeceb6358..b1fd26247 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -466,6 +466,7 @@ set(minetest_SRCS
shader.cpp
sky.cpp
tile.cpp
+ wieldmesh.cpp
${minetest_SCRIPT_SRCS}
)
list(SORT minetest_SRCS)
diff --git a/src/camera.cpp b/src/camera.cpp
index d961d45b9..0b4e4fd53 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -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();
diff --git a/src/camera.h b/src/camera.h
index 8831257cc..996be79b2 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -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 @@ public:
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 @@ private:
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 @@ private:
// 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;
};
diff --git a/src/clientobject.h b/src/clientobject.h
index cae551abc..24150628e 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -41,6 +41,7 @@ class ITextureSource;
class IGameDef;
class LocalPlayer;
struct ItemStack;
+class WieldMeshSceneNode;
class ClientActiveObject : public ActiveObject
{
@@ -58,8 +59,10 @@ public:
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;}
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index d1de23d2a..8471b7e81 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -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;
}
diff --git a/src/content_cao.h b/src/content_cao.h
index bf1ac5b3f..69e2e54a2 100644
--- a/src/content_cao.h
+++ b/src/content_cao.h
@@ -70,6 +70,7 @@ private:
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 @@ public:
v3f getPosition();
+ scene::ISceneNode *getSceneNode();
+
scene::IMeshSceneNode *getMeshSceneNode();
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode();
+ WieldMeshSceneNode *getWieldMeshSceneNode();
+
scene::IBillboardSceneNode *getSpriteSceneNode();
inline bool isPlayer() const
diff --git a/src/environment.cpp b/src/environment.cpp
index 01a7e38dc..6e5305b1e 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -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);
}
diff --git a/src/game.cpp b/src/game.cpp
index 272abe783..fee45e31d 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -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;
}
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index f976c3eb7..ac67c5b27 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -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 @@ public:
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 @@ public:
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 @@ public:
/*
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);
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 84b7c1146..bdcf45beb 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -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),
diff --git a/src/localplayer.h b/src/localplayer.h
index 16830f3ec..16b66716d 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -71,6 +71,8 @@ public:
std::string hotbar_image;
std::string hotbar_selected_image;
+ video::SColor light_color;
+
GenericCAO* getCAO() const {
return m_cao;
}
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 2459cf0d7..99a5ce0dd 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -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;
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index e1cccc64e..be56d4c58 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -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);
diff --git a/src/mesh.cpp b/src/mesh.cpp
index 19d75f9f5..38b3d97bc 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -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();
}
diff --git a/src/mesh.h b/src/mesh.h
index 7539298cb..29f5ec76c 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -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.
@@ -34,16 +33,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).
*/
diff --git a/src/player.cpp b/src/player.cpp
index 13866e5f5..64c138d02 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -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),
diff --git a/src/player.h b/src/player.h
index a5cc7123f..435875233 100644
--- a/src/player.h
+++ b/src/player.h
@@ -249,8 +249,6 @@ public:
bool swimming_vertical;
bool camera_barely_in_ceiling;
- u8 light;
-
Inventory inventory;
f32 movement_acceleration_default;
diff --git a/src/test.cpp b/src/test.cpp
index cd353c0ea..6cd7983fc 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -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);
}
};
diff --git a/src/util/numeric.h b/src/util/numeric.h
index ee8fea8cf..e7fdc2599 100644
--- a/src/util/numeric.h
+++ b/src/util/numeric.h
@@ -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
index 000000000..4552d3572
--- /dev/null
+++ b/src/wieldmesh.cpp
@@ -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
index 000000000..7761fd51b
--- /dev/null
+++ b/src/wieldmesh.h
@@ -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