]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/content_cao.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / client / content_cao.cpp
index 5d8a597a2c41618c4a8743edd58b5a444fc2e075..ec1fd1c2affadd2c718ab8207a1728d9b3889bd4 100644 (file)
@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client/sound.h"
 #include "client/tile.h"
 #include "util/basic_macros.h"
-#include "util/numeric.h" // For IntervalLimiter & setPitchYawRoll
+#include "util/numeric.h"
 #include "util/serialize.h"
 #include "camera.h" // CameraModes
 #include "collision.h"
@@ -172,6 +172,20 @@ static void updatePositionRecursive(scene::ISceneNode *node)
        node->updateAbsolutePosition();
 }
 
+static bool logOnce(const std::ostringstream &from, std::ostream &log_to)
+{
+       thread_local std::vector<u64> logged;
+
+       std::string message = from.str();
+       u64 hash = murmur_hash_64_ua(message.data(), message.length(), 0xBADBABE);
+
+       if (std::find(logged.begin(), logged.end(), hash) != logged.end())
+               return false;
+       logged.push_back(hash);
+       log_to << message << std::endl;
+       return true;
+}
+
 /*
        TestCAO
 */
@@ -422,7 +436,7 @@ const v3f GenericCAO::getPosition() const
        return m_position;
 }
 
-const bool GenericCAO::isImmortal()
+bool GenericCAO::isImmortal() const
 {
        return itemgroup_get(getGroups(), "immortal");
 }
@@ -651,7 +665,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
                                m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
                m_spritenode->grab();
                m_spritenode->setMaterialTexture(0,
-                               tsrc->getTextureForMesh("unknown_node.png"));
+                               tsrc->getTextureForMesh("no_texture.png"));
 
                setSceneNodeMaterial(m_spritenode);
 
@@ -735,9 +749,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
                m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
                m_meshnode->grab();
                mesh->drop();
-               // Set it to use the materials of the meshbuffers directly.
-               // This is needed for changing the texture in the future
-               m_meshnode->setReadOnlyMaterials(true);
        } else if (m_prop.visual == "cube") {
                grabMatrixNode();
                scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
@@ -754,10 +765,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
                grabMatrixNode();
                scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
                if (mesh) {
-                       m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode);
-                       m_animated_meshnode->grab();
-                       mesh->drop(); // The scene node took hold of it
-
                        if (!checkMeshNormals(mesh)) {
                                infostream << "GenericCAO: recalculating normals for mesh "
                                        << m_prop.mesh << std::endl;
@@ -765,6 +772,9 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
                                                recalculateNormals(mesh, true, false);
                        }
 
+                       m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode);
+                       m_animated_meshnode->grab();
+                       mesh->drop(); // The scene node took hold of it
                        m_animated_meshnode->animateJoints(); // Needed for some animations
                        m_animated_meshnode->setScale(m_prop.visual_size);
 
@@ -827,12 +837,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
        setNodeLight(m_last_light);
        updateMeshCulling();
 
+       if (m_animated_meshnode) {
+               u32 mat_count = m_animated_meshnode->getMaterialCount();
+               if (mat_count == 0 || m_prop.textures.empty()) {
+                       // nothing
+               } else if (mat_count > m_prop.textures.size()) {
+                       std::ostringstream oss;
+                       oss << "GenericCAO::addToScene(): Model "
+                               << m_prop.mesh << " loaded with " << mat_count
+                               << " mesh buffers but only " << m_prop.textures.size()
+                               << " texture(s) specifed, this is deprecated.";
+                       logOnce(oss, warningstream);
+
+                       video::ITexture *last = m_animated_meshnode->getMaterial(0).TextureLayer[0].Texture;
+                       for (u32 i = 1; i < mat_count; i++) {
+                               auto &layer = m_animated_meshnode->getMaterial(i).TextureLayer[0];
+                               if (!layer.Texture)
+                                       layer.Texture = last;
+                               last = layer.Texture;
+                       }
+               }
+       }
+
        if (m_client->modsLoaded() && m_client->getScript()->on_object_add(m_id)) {
                removeFromScene(false);
                return;
        }
 
-
        if (m_client->modsLoaded())
                m_client->getScript()->on_object_properties_change(m_id);
 }
@@ -842,7 +873,8 @@ void GenericCAO::updateLight(u32 day_night_ratio)
        if (m_glow < 0)
                return;
 
-       u8 light_at_pos = 0;
+       u16 light_at_pos = 0;
+       u8 light_at_pos_intensity = 0;
        bool pos_ok = false;
 
        v3s16 pos[3];
@@ -851,30 +883,36 @@ void GenericCAO::updateLight(u32 day_night_ratio)
                bool this_ok;
                MapNode n = m_env->getMap().getNode(pos[i], &this_ok);
                if (this_ok) {
-                       u8 this_light = n.getLightBlend(day_night_ratio, m_client->ndef());
-                       light_at_pos = MYMAX(light_at_pos, this_light);
+                       u16 this_light = getInteriorLight(n, 0, m_client->ndef());
+                       u8 this_light_intensity = MYMAX(this_light & 0xFF, (this_light >> 8) && 0xFF);
+                       if (this_light_intensity > light_at_pos_intensity) {
+                               light_at_pos = this_light;
+                               light_at_pos_intensity = this_light_intensity;
+                       }
                        pos_ok = true;
                }
        }
        if (!pos_ok)
-               light_at_pos = blend_light(day_night_ratio, LIGHT_SUN, 0);
+               light_at_pos = LIGHT_SUN;
+
+       video::SColor light = encode_light(light_at_pos, m_glow);
+       if (!m_enable_shaders)
+               final_color_blend(&light, light_at_pos, day_night_ratio);
 
-       u8 light = decode_light(light_at_pos + m_glow);
        if (g_settings->getBool("fullbright"))
-               light = 255;
+               light = video::SColor(0xFFFFFFFF);
+
        if (light != m_last_light) {
                m_last_light = light;
                setNodeLight(light);
        }
 }
 
-void GenericCAO::setNodeLight(u8 light)
+void GenericCAO::setNodeLight(const video::SColor &light_color)
 {
-       video::SColor color(255, light, light, light);
-
        if (m_prop.visual == "wielditem" || m_prop.visual == "item") {
                if (m_wield_meshnode)
-                       m_wield_meshnode->setNodeLightColor(color);
+                       m_wield_meshnode->setNodeLightColor(light_color);
                return;
        }
 
@@ -886,7 +924,7 @@ void GenericCAO::setNodeLight(u8 light)
                        scene::IMesh *mesh = m_meshnode->getMesh();
                        for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
                                scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
-                               buf->getMaterial().EmissiveColor = color;
+                               buf->getMaterial().EmissiveColor = light_color;
                        }
                } else {
                        scene::ISceneNode *node = getSceneNode();
@@ -895,16 +933,16 @@ void GenericCAO::setNodeLight(u8 light)
 
                        for (u32 i = 0; i < node->getMaterialCount(); ++i) {
                                video::SMaterial &material = node->getMaterial(i);
-                               material.EmissiveColor = color;
+                               material.EmissiveColor = light_color;
                        }
                }
        } else {
                if (m_meshnode) {
-                       setMeshColor(m_meshnode->getMesh(), color);
+                       setMeshColor(m_meshnode->getMesh(), light_color);
                } else if (m_animated_meshnode) {
-                       setAnimatedMeshColor(m_animated_meshnode, color);
+                       setAnimatedMeshColor(m_animated_meshnode, light_color);
                } else if (m_spritenode) {
-                       m_spritenode->setColor(color);
+                       m_spritenode->setColor(light_color);
                }
        }
 }
@@ -1014,12 +1052,14 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        m_velocity = v3f(0,0,0);
                        m_acceleration = v3f(0,0,0);
                        const PlayerControl &controls = player->getPlayerControl();
+                       f32 new_speed = player->local_animation_speed;
 
                        bool walking = false;
-                       if (controls.movement_speed > 0.001f && ! g_settings->getBool("freecam"))
+                       if (controls.movement_speed > 0.001f && ! g_settings->getBool("freecam")) {
+                               new_speed *= controls.movement_speed;
                                walking = true;
+                       }
 
-                       f32 new_speed = player->local_animation_speed;
                        v2s32 new_anim = v2s32(0,0);
                        bool allow_update = false;
 
@@ -1034,7 +1074,6 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
                        // slowdown speed if sneaking
                        if (controls.sneak && walking && ! g_settings->getBool("no_slow"))
                                new_speed /= 2;
-                       new_speed *= controls.movement_speed;
 
                        if (walking && (controls.dig || controls.place)) {
                                new_anim = player->local_animations[3];
@@ -1304,9 +1343,15 @@ void GenericCAO::updateTextures(std::string mod)
        m_current_texture_modifier = mod;
        m_glow = m_prop.glow;
 
+       video::ITexture *shadow_texture = nullptr;
+       if (auto shadow = RenderingEngine::get_shadow_renderer())
+               shadow_texture = shadow->get_texture();
+
+       const u32 TEXTURE_LAYER_SHADOW = 3;
+
        if (m_spritenode) {
                if (m_prop.visual == "sprite") {
-                       std::string texturestring = "unknown_node.png";
+                       std::string texturestring = "no_texture.png";
                        if (!m_prop.textures.empty())
                                texturestring = m_prop.textures[0];
                        texturestring += mod;
@@ -1314,6 +1359,7 @@ void GenericCAO::updateTextures(std::string mod)
                        m_spritenode->getMaterial(0).MaterialTypeParam = 0.5f;
                        m_spritenode->setMaterialTexture(0,
                                        tsrc->getTextureForMesh(texturestring));
+                       m_spritenode->setMaterialTexture(TEXTURE_LAYER_SHADOW, shadow_texture);
 
                        // This allows setting per-material colors. However, until a real lighting
                        // system is added, the code below will have no effect. Once MineTest
@@ -1349,6 +1395,7 @@ void GenericCAO::updateTextures(std::string mod)
                                material.MaterialType = m_material_type;
                                material.MaterialTypeParam = 0.5f;
                                material.TextureLayer[0].Texture = texture;
+                               material.TextureLayer[TEXTURE_LAYER_SHADOW].Texture = shadow_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);
@@ -1385,7 +1432,7 @@ void GenericCAO::updateTextures(std::string mod)
                {
                        for (u32 i = 0; i < 6; ++i)
                        {
-                               std::string texturestring = "unknown_node.png";
+                               std::string texturestring = "no_texture.png";
                                if(m_prop.textures.size() > i)
                                        texturestring = m_prop.textures[i];
                                texturestring += mod;
@@ -1399,6 +1446,7 @@ void GenericCAO::updateTextures(std::string mod)
                                material.setFlag(video::EMF_BILINEAR_FILTER, false);
                                material.setTexture(0,
                                                tsrc->getTextureForMesh(texturestring));
+                               material.setTexture(TEXTURE_LAYER_SHADOW, shadow_texture);
                                material.getTextureMatrix(0).makeIdentity();
 
                                // This allows setting per-material colors. However, until a real lighting
@@ -1418,54 +1466,56 @@ void GenericCAO::updateTextures(std::string mod)
                } else if (m_prop.visual == "upright_sprite") {
                        scene::IMesh *mesh = m_meshnode->getMesh();
                        {
-                               std::string tname = "unknown_object.png";
+                               std::string tname = "no_texture.png";
                                if (!m_prop.textures.empty())
                                        tname = m_prop.textures[0];
                                tname += mod;
-                               scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
-                               buf->getMaterial().setTexture(0,
+                               auto& material = m_meshnode->getMaterial(0);
+                               material.setTexture(0,
                                                tsrc->getTextureForMesh(tname));
+                               material.setTexture(TEXTURE_LAYER_SHADOW, shadow_texture);
 
                                // This allows setting per-material colors. However, until a real lighting
                                // system is added, the code below will have no effect. Once MineTest
                                // has directional lighting, it should work automatically.
                                if(!m_prop.colors.empty()) {
-                                       buf->getMaterial().AmbientColor = m_prop.colors[0];
-                                       buf->getMaterial().DiffuseColor = m_prop.colors[0];
-                                       buf->getMaterial().SpecularColor = m_prop.colors[0];
+                                       material.AmbientColor = m_prop.colors[0];
+                                       material.DiffuseColor = m_prop.colors[0];
+                                       material.SpecularColor = m_prop.colors[0];
                                }
 
-                               buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
+                               material.setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
+                               material.setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
+                               material.setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
                        }
                        {
-                               std::string tname = "unknown_object.png";
+                               std::string tname = "no_texture.png";
                                if (m_prop.textures.size() >= 2)
                                        tname = m_prop.textures[1];
                                else if (!m_prop.textures.empty())
                                        tname = m_prop.textures[0];
                                tname += mod;
-                               scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
-                               buf->getMaterial().setTexture(0,
+                               auto& material = m_meshnode->getMaterial(1);
+                               material.setTexture(0,
                                                tsrc->getTextureForMesh(tname));
+                               material.setTexture(TEXTURE_LAYER_SHADOW, shadow_texture);
 
                                // This allows setting per-material colors. However, until a real lighting
                                // system is added, the code below will have no effect. Once MineTest
                                // has directional lighting, it should work automatically.
                                if (m_prop.colors.size() >= 2) {
-                                       buf->getMaterial().AmbientColor = m_prop.colors[1];
-                                       buf->getMaterial().DiffuseColor = m_prop.colors[1];
-                                       buf->getMaterial().SpecularColor = m_prop.colors[1];
+                                       material.AmbientColor = m_prop.colors[1];
+                                       material.DiffuseColor = m_prop.colors[1];
+                                       material.SpecularColor = m_prop.colors[1];
                                } else if (!m_prop.colors.empty()) {
-                                       buf->getMaterial().AmbientColor = m_prop.colors[0];
-                                       buf->getMaterial().DiffuseColor = m_prop.colors[0];
-                                       buf->getMaterial().SpecularColor = m_prop.colors[0];
+                                       material.AmbientColor = m_prop.colors[0];
+                                       material.DiffuseColor = m_prop.colors[0];
+                                       material.SpecularColor = m_prop.colors[0];
                                }
 
-                               buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
+                               material.setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
+                               material.setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
+                               material.setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
                        }
                        // Set mesh color (only if lighting is disabled)
                        if (!m_prop.colors.empty() && m_glow < 0)
@@ -1811,6 +1861,7 @@ void GenericCAO::processMessage(const std::string &data)
                        {
                                        updateAnimation();
                        }
+                       // FIXME: ^ This code is trash. It's also broken.
                }
        } else if (cmd == AO_CMD_SET_ANIMATION_SPEED) {
                m_animation_speed = readF32(is);
@@ -1855,6 +1906,8 @@ void GenericCAO::processMessage(const std::string &data)
                                m_reset_textures_timer = 0.05;
                                if(damage >= 2)
                                        m_reset_textures_timer += 0.05 * damage;
+                               // Cap damage overlay to 1 second
+                               m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
                                updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
                        }
                }
@@ -1905,7 +1958,8 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
                        m_armor_groups,
                        toolcap,
                        punchitem,
-                       time_from_last_punch);
+                       time_from_last_punch,
+                       punchitem->wear);
 
        if(result.did_punch && result.damage != 0)
        {
@@ -1925,6 +1979,8 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
                        m_reset_textures_timer = 0.05;
                        if (result.damage >= 2)
                                m_reset_textures_timer += 0.05 * result.damage;
+                       // Cap damage overlay to 1 second
+                       m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
                        updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
                }
        }
@@ -1953,20 +2009,17 @@ void GenericCAO::updateMeshCulling()
 
        const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST && ! g_settings->getBool("freecam");
 
-       if (m_meshnode && m_prop.visual == "upright_sprite") {
-               u32 buffers = m_meshnode->getMesh()->getMeshBufferCount();
-               for (u32 i = 0; i < buffers; i++) {
-                       video::SMaterial &mat = m_meshnode->getMesh()->getMeshBuffer(i)->getMaterial();
-                       // upright sprite has no backface culling
-                       mat.setFlag(video::EMF_FRONT_FACE_CULLING, hidden);
-               }
-               return;
-       }
-
        scene::ISceneNode *node = getSceneNode();
+
        if (!node)
                return;
 
+       if (m_prop.visual == "upright_sprite") {
+               // upright sprite has no backface culling
+               node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING, hidden);
+               return;
+       }
+
        if (hidden) {
                // Hide the mesh by culling both front and
                // back faces. Serious hackyness but it works for our