]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/content_cao.cpp
Disable HW stereo for IrrLicht 1.9 (not supported anymore)
[dragonfireclient.git] / src / content_cao.cpp
index 2e9f8f39daa73b211ea50f487c7b0857a0482a0b..e2d146d43d256d0483493739ee551a0b4a8f59f3 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/numeric.h" // For IntervalLimiter
 #include "util/serialize.h"
 #include "util/basic_macros.h"
+#include "client/sound.h"
 #include "client/tile.h"
 #include "environment.h"
 #include "collision.h"
@@ -44,6 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client.h"
 #include "wieldmesh.h"
 #include <algorithm>
+#include <cmath>
 #include "client/renderingengine.h"
 
 class Settings;
@@ -51,51 +53,65 @@ struct ToolCapabilities;
 
 std::unordered_map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
 
-void SmoothTranslator::init(v3f vect)
+template<typename T>
+void SmoothTranslator<T>::init(T current)
 {
-       vect_old = vect;
-       vect_show = vect;
-       vect_aim = vect;
-       anim_counter = 0;
+       val_old = current;
+       val_current = current;
+       val_target = current;
        anim_time = 0;
        anim_time_counter = 0;
        aim_is_end = true;
 }
 
-void SmoothTranslator::update(v3f vect_new, bool is_end_position, float update_interval)
+template<typename T>
+void SmoothTranslator<T>::update(T new_target, bool is_end_position, float update_interval)
 {
        aim_is_end = is_end_position;
-       vect_old = vect_show;
-       vect_aim = vect_new;
-       if(update_interval > 0)
-       {
+       val_old = val_current;
+       val_target = new_target;
+       if (update_interval > 0) {
                anim_time = update_interval;
        } else {
-               if(anim_time < 0.001 || anim_time > 1.0)
+               if (anim_time < 0.001 || anim_time > 1.0)
                        anim_time = anim_time_counter;
                else
                        anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
        }
        anim_time_counter = 0;
-       anim_counter = 0;
 }
 
-void SmoothTranslator::translate(f32 dtime)
+template<typename T>
+void SmoothTranslator<T>::translate(f32 dtime)
+{
+       anim_time_counter = anim_time_counter + dtime;
+       T val_diff = val_target - val_old;
+       f32 moveratio = 1.0;
+       if (anim_time > 0.001)
+               moveratio = anim_time_counter / anim_time;
+       f32 move_end = aim_is_end ? 1.0 : 1.5;
+
+       // Move a bit less than should, to avoid oscillation
+       moveratio = std::min(moveratio * 0.8f, move_end);
+       val_current = val_old + val_diff * moveratio;
+}
+
+void SmoothTranslatorWrapped::translate(f32 dtime)
 {
        anim_time_counter = anim_time_counter + dtime;
-       anim_counter = anim_counter + dtime;
-       v3f vect_move = vect_aim - vect_old;
+       f32 val_diff = std::abs(val_target - val_old);
+       if (val_diff > 180.f)
+               val_diff = 360.f - val_diff;
+
        f32 moveratio = 1.0;
-       if(anim_time > 0.001)
+       if (anim_time > 0.001)
                moveratio = anim_time_counter / anim_time;
+       f32 move_end = aim_is_end ? 1.0 : 1.5;
+
        // Move a bit less than should, to avoid oscillation
-       moveratio = moveratio * 0.8;
-       float move_end = 1.5;
-       if(aim_is_end)
-               move_end = 1.0;
-       if(moveratio > move_end)
-               moveratio = move_end;
-       vect_show = vect_old + vect_move * moveratio;
+       moveratio = std::min(moveratio * 0.8f, move_end);
+       wrappedApproachShortest(val_current, val_target,
+               val_diff * moveratio, 360.f);
 }
 
 /*
@@ -329,7 +345,9 @@ void GenericCAO::processInitData(const std::string &data)
                processMessage(message);
        }
 
+       m_yaw = wrapDegrees_0_360(m_yaw);
        pos_translator.init(m_position);
+       yaw_translator.init(m_yaw);
        updateNodePos();
 }
 
@@ -341,7 +359,7 @@ GenericCAO::~GenericCAO()
 bool GenericCAO::getSelectionBox(aabb3f *toset) const
 {
        if (!m_prop.is_visible || !m_is_visible || m_is_local_player
-                       || !m_prop.pointable || getParent() != NULL) {
+                       || !m_prop.pointable) {
                return false;
        }
        *toset = m_selection_box;
@@ -357,7 +375,7 @@ v3f GenericCAO::getPosition()
 
                return m_position;
        }
-       return pos_translator.vect_show;
+       return pos_translator.val_current;
 }
 
 const bool GenericCAO::isImmortal()
@@ -428,6 +446,7 @@ void GenericCAO::removeFromScene(bool permanent)
                                m_env->attachement_parent_ids[ci] = 0;
                        }
                }
+               m_children.clear();
 
                m_env->attachement_parent_ids[getId()] = 0;
 
@@ -476,6 +495,9 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                return;
        }
 
+       video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
+               video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+
        if (m_prop.visual == "sprite") {
                infostream<<"GenericCAO::addToScene(): single_sprite"<<std::endl;
                m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
@@ -485,7 +507,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                                tsrc->getTextureForMesh("unknown_node.png"));
                m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
                m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-               m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
+               m_spritenode->setMaterialType(material_type);
                m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
                u8 li = m_last_light;
                m_spritenode->setColor(video::SColor(255,li,li,li));
@@ -511,6 +533,11 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                                video::S3DVertex( dx,  dy, 0, 0,0,0, c, 0,0),
                                video::S3DVertex(-dx,  dy, 0, 0,0,0, c, 1,0),
                        };
+                       if (m_is_player) {
+                               // Move minimal Y position to 0 (feet position)
+                               for (video::S3DVertex &vertex : vertices)
+                                       vertex.Pos.Y += dy;
+                       }
                        u16 indices[] = {0,1,2,2,3,0};
                        buf->append(vertices, 4, indices, 6);
                        // Set material
@@ -530,6 +557,11 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                                video::S3DVertex(-dx, dy, 0, 0,0,0, c, 0,0),
                                video::S3DVertex( dx, dy, 0, 0,0,0, c, 1,0),
                        };
+                       if (m_is_player) {
+                               // Move minimal Y position to 0 (feet position)
+                               for (video::S3DVertex &vertex : vertices)
+                                       vertex.Pos.Y += dy;
+                       }
                        u16 indices[] = {0,1,2,2,3,0};
                        buf->append(vertices, 4, indices, 6);
                        // Set material
@@ -563,7 +595,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
 
                m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
                m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-               m_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
+               m_meshnode->setMaterialType(material_type);
                m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
        }
        else if(m_prop.visual == "mesh") {
@@ -586,15 +618,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
 
                        setAnimatedMeshColor(m_animated_meshnode, video::SColor(255,li,li,li));
 
-                       bool backface_culling = m_prop.backface_culling;
-                       if (m_is_player)
-                               backface_culling = false;
-
                        m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
                        m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-                       m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
+                       m_animated_meshnode->setMaterialType(material_type);
                        m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
-                       m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, backface_culling);
+                       m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
+                               m_prop.backface_culling);
                }
                else
                        errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
@@ -704,10 +733,10 @@ void GenericCAO::updateNodePos()
 
        if (node) {
                v3s16 camera_offset = m_env->getCameraOffset();
-               node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS));
+               node->setPosition(pos_translator.val_current - intToFloat(camera_offset, BS));
                if (node != m_spritenode) { // rotate if not a sprite
                        v3f rot = node->getRotation();
-                       rot.Y = -m_yaw;
+                       rot.Y = m_is_local_player ? -m_yaw : -yaw_translator.val_current;
                        node->setRotation(rot);
                }
        }
@@ -722,10 +751,11 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        int old_anim = player->last_animation;
                        float old_anim_speed = player->last_animation_speed;
                        m_position = player->getPosition();
+                       m_yaw = wrapDegrees_0_360(player->getYaw());
                        m_velocity = v3f(0,0,0);
                        m_acceleration = v3f(0,0,0);
-                       pos_translator.vect_show = m_position;
-                       m_yaw = player->getYaw();
+                       pos_translator.val_current = m_position;
+                       yaw_translator.val_current = m_yaw;
                        const PlayerControl &controls = player->getPlayerControl();
 
                        bool walking = false;
@@ -828,7 +858,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                m_position = getPosition();
                m_velocity = v3f(0,0,0);
                m_acceleration = v3f(0,0,0);
-               pos_translator.vect_show = m_position;
+               pos_translator.val_current = m_position;
 
                if(m_is_local_player) // Update local player attachment position
                {
@@ -837,7 +867,8 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        m_env->getLocalPlayer()->parent = getParent();
                }
        } else {
-               v3f lastpos = pos_translator.vect_show;
+               yaw_translator.translate(dtime);
+               v3f lastpos = pos_translator.val_current;
 
                if(m_prop.physical)
                {
@@ -869,7 +900,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        updateNodePos();
                }
 
-               float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
+               float moved = lastpos.getDistanceFrom(pos_translator.val_current);
                m_step_distance_counter += moved;
                if (m_step_distance_counter > 1.5f * BS) {
                        m_step_distance_counter = 0.0f;
@@ -906,9 +937,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        updateTextures(m_previous_texture_modifier);
                }
        }
-       if(!getParent() && fabs(m_prop.automatic_rotate) > 0.001)
-       {
+       if (!getParent() && std::fabs(m_prop.automatic_rotate) > 0.001) {
                m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
+               yaw_translator.val_current = m_yaw;
                updateNodePos();
        }
 
@@ -919,14 +950,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                                + m_prop.automatic_face_movement_dir_offset;
                float max_rotation_delta =
                                dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
-               float delta = wrapDegrees_0_360(target_yaw - m_yaw);
 
-               if (delta > max_rotation_delta && 360 - delta > max_rotation_delta) {
-                       m_yaw += (delta < 180) ? max_rotation_delta : -max_rotation_delta;
-                       m_yaw = wrapDegrees_0_360(m_yaw);
-               } else {
-                       m_yaw = target_yaw;
-               }
+               wrappedApproachShortest(m_yaw, target_yaw, max_rotation_delta, 360.f);
+               yaw_translator.val_current = m_yaw;
                updateNodePos();
        }
 }
@@ -946,25 +972,23 @@ void GenericCAO::updateTexturePos()
                int row = m_tx_basepos.Y;
                int col = m_tx_basepos.X;
 
-               if(m_tx_select_horiz_by_yawpitch)
-               {
-                       if(cam_to_entity.Y > 0.75)
+               if (m_tx_select_horiz_by_yawpitch) {
+                       if (cam_to_entity.Y > 0.75)
                                col += 5;
-                       else if(cam_to_entity.Y < -0.75)
+                       else if (cam_to_entity.Y < -0.75)
                                col += 4;
-                       else{
+                       else {
                                float mob_dir =
                                                atan2(cam_to_entity.Z, cam_to_entity.X) / M_PI * 180.;
                                float dir = mob_dir - m_yaw;
                                dir = wrapDegrees_180(dir);
-                               //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
-                               if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
+                               if (std::fabs(wrapDegrees_180(dir - 0)) <= 45.1f)
                                        col += 2;
-                               else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
+                               else if(std::fabs(wrapDegrees_180(dir - 90)) <= 45.1f)
                                        col += 3;
-                               else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
+                               else if(std::fabs(wrapDegrees_180(dir - 180)) <= 45.1f)
                                        col += 0;
-                               else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
+                               else if(std::fabs(wrapDegrees_180(dir + 90)) <= 45.1f)
                                        col += 1;
                                else
                                        col += 4;
@@ -976,8 +1000,7 @@ void GenericCAO::updateTexturePos()
 
                float txs = m_tx_size.X;
                float tys = m_tx_size.Y;
-               setBillboardTextureMatrix(m_spritenode,
-                               txs, tys, col, row);
+               setBillboardTextureMatrix(m_spritenode, txs, tys, col, row);
        }
 }
 
@@ -993,12 +1016,16 @@ void GenericCAO::updateTextures(std::string mod)
        m_current_texture_modifier = mod;
        m_glow = m_prop.glow;
 
+       video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
+               video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+
        if (m_spritenode) {
                if (m_prop.visual == "sprite") {
                        std::string texturestring = "unknown_node.png";
                        if (!m_prop.textures.empty())
                                texturestring = m_prop.textures[0];
                        texturestring += mod;
+                       m_spritenode->getMaterial(0).MaterialType = material_type;
                        m_spritenode->setMaterialTexture(0,
                                        tsrc->getTextureForMesh(texturestring));
 
@@ -1033,9 +1060,11 @@ void GenericCAO::updateTextures(std::string mod)
 
                                // Set material flags and texture
                                video::SMaterial& material = m_animated_meshnode->getMaterial(i);
+                               material.MaterialType = material_type;
                                material.TextureLayer[0].Texture = texture;
                                material.setFlag(video::EMF_LIGHTING, true);
                                material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                               material.setFlag(video::EMF_BACK_FACE_CULLING, m_prop.backface_culling);
 
                                // don't filter low-res textures, makes them look blurry
                                // player models have a res of 64
@@ -1077,6 +1106,7 @@ void GenericCAO::updateTextures(std::string mod)
 
                                // Set material flags and texture
                                video::SMaterial& material = m_meshnode->getMaterial(i);
+                               material.MaterialType = material_type;
                                material.setFlag(video::EMF_LIGHTING, false);
                                material.setFlag(video::EMF_BILINEAR_FILTER, false);
                                material.setTexture(0,
@@ -1177,7 +1207,7 @@ void GenericCAO::updateAnimationSpeed()
 {
        if (!m_animated_meshnode)
                return;
-        
+
        m_animated_meshnode->setAnimationSpeed(m_animation_speed);
 }
 
@@ -1284,10 +1314,11 @@ void GenericCAO::processMessage(const std::string &data)
                m_position = readV3F1000(is);
                m_velocity = readV3F1000(is);
                m_acceleration = readV3F1000(is);
-               if(fabs(m_prop.automatic_rotate) < 0.001)
+               if (std::fabs(m_prop.automatic_rotate) < 0.001f)
                        m_yaw = readF1000(is);
                else
                        readF1000(is);
+               m_yaw = wrapDegrees_0_360(m_yaw);
                bool do_interpolate = readU8(is);
                bool is_end_position = readU8(is);
                float update_interval = readF1000(is);
@@ -1307,6 +1338,7 @@ void GenericCAO::processMessage(const std::string &data)
                } else {
                        pos_translator.init(m_position);
                }
+               yaw_translator.update(m_yaw, false, update_interval);
                updateNodePos();
        } else if (cmd == GENERIC_CMD_SET_TEXTURE_MOD) {
                std::string mod = deSerializeString(is);
@@ -1394,17 +1426,18 @@ void GenericCAO::processMessage(const std::string &data)
 
                updateBonePosition();
        } else if (cmd == GENERIC_CMD_ATTACH_TO) {
-               u16 parentID = readS16(is);
-               u16 oldparent = m_env->attachement_parent_ids[getId()];
-               if (oldparent) {
-                       m_children.erase(std::remove(m_children.begin(), m_children.end(),
-                               getId()), m_children.end());
-               }
-               m_env->attachement_parent_ids[getId()] = parentID;
-               GenericCAO *parentobj = m_env->getGenericCAO(parentID);
+               u16 parent_id = readS16(is);
+               u16 &old_parent_id = m_env->attachement_parent_ids[getId()];
+               if (parent_id != old_parent_id) {
+                       if (GenericCAO *old_parent = m_env->getGenericCAO(old_parent_id)) {
+                               old_parent->m_children.erase(std::remove(
+                                       m_children.begin(), m_children.end(),
+                                       getId()), m_children.end());
+                       }
+                       if (GenericCAO *new_parent = m_env->getGenericCAO(parent_id))
+                               new_parent->m_children.push_back(getId());
 
-               if (parentobj) {
-                       parentobj->m_children.push_back(getId());
+                       old_parent_id = parent_id;
                }
 
                m_attachment_bone = deSerializeString(is);