mirror of
https://github.com/moparisthebest/minetest
synced 2024-12-22 15:48:48 -05:00
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.
This commit is contained in:
parent
cc8d7b8640
commit
9b551d5cbc
@ -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 += \
|
||||
|
@ -466,6 +466,7 @@ set(minetest_SRCS
|
||||
shader.cpp
|
||||
sky.cpp
|
||||
tile.cpp
|
||||
wieldmesh.cpp
|
||||
${minetest_SCRIPT_SRCS}
|
||||
)
|
||||
list(SORT minetest_SRCS)
|
||||
|
@ -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();
|
||||
|
14
src/camera.h
14
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;
|
||||
};
|
||||
|
@ -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;}
|
||||
|
@ -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::ISceneNode* GenericCAO::getSceneNode()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if(m_meshnode)
|
||||
return m_meshnode;
|
||||
return NULL;
|
||||
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::ISceneNode *my_node = getSceneNode();
|
||||
|
||||
scene::IBoneSceneNode *parent_bone = NULL;
|
||||
if(parent_animated_mesh && m_attachment_bone != "")
|
||||
{
|
||||
parent_bone =
|
||||
parent_animated_mesh->getJointNode(m_attachment_bone.c_str());
|
||||
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());
|
||||
}
|
||||
// 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 (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_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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(m_is_local_player)
|
||||
{
|
||||
if (m_is_local_player) {
|
||||
LocalPlayer *player = m_env->getLocalPlayer();
|
||||
player->isAttached = true;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
150
src/itemdef.cpp
150
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_node_mesh)
|
||||
{
|
||||
/*
|
||||
Get node properties
|
||||
*/
|
||||
content_t id = nodedef->getId(def->name);
|
||||
// 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);
|
||||
|
||||
u8 param1 = 0;
|
||||
if(f.param_type == CPT_LIGHT)
|
||||
param1 = 0xee;
|
||||
bool need_rtt_mesh = cc->inventory_texture == NULL;
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
// no way reference count can be smaller than 2 in this place!
|
||||
assert(cc->wield_mesh->getReferenceCount() >= 2);
|
||||
}
|
||||
|
||||
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);
|
||||
if (node_mesh)
|
||||
node_mesh->drop();
|
||||
|
||||
if (reenable_shaders)
|
||||
g_settings->setBool("enable_shaders",true);
|
||||
|
@ -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),
|
||||
|
@ -71,6 +71,8 @@ public:
|
||||
std::string hotbar_image;
|
||||
std::string hotbar_selected_image;
|
||||
|
||||
video::SColor light_color;
|
||||
|
||||
GenericCAO* getCAO() const {
|
||||
return m_cao;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
214
src/mesh.cpp
214
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();
|
||||
}
|
||||
|
11
src/mesh.h
11
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.
|
||||
@ -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).
|
||||
|
@ -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),
|
||||
|
@ -249,8 +249,6 @@ public:
|
||||
bool swimming_vertical;
|
||||
bool camera_barely_in_ceiling;
|
||||
|
||||
u8 light;
|
||||
|
||||
Inventory inventory;
|
||||
|
||||
f32 movement_acceleration_default;
|
||||
|
10
src/test.cpp
10
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
380
src/wieldmesh.cpp
Normal file
380
src/wieldmesh.cpp
Normal file
@ -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);
|
||||
|
||||
}
|
71
src/wieldmesh.h
Normal file
71
src/wieldmesh.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user