X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Fcontent_cao.cpp;h=d89bb53b31881a7123bd0328268f275dd50557b2;hb=a89afe1229e327da3c397a3912b2d43d2196ea2b;hp=2e58e19cfb83e0c5bd646f8a805a7fb979ec1d62;hpb=f30dcdb504adb02724e3a5faa30a951eb907b33f;p=minetest.git diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 2e58e19cf..d89bb53b3 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -20,14 +20,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_cao.h" #include #include -#include #include #include #include "client/client.h" +#include "client/renderingengine.h" #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" @@ -171,6 +171,20 @@ static void updatePositionRecursive(scene::ISceneNode *node) node->updateAbsolutePosition(); } +static bool logOnce(const std::ostringstream &from, std::ostream &log_to) +{ + thread_local std::vector 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 */ @@ -421,7 +435,7 @@ const v3f GenericCAO::getPosition() const return m_position; } -const bool GenericCAO::isImmortal() +bool GenericCAO::isImmortal() const { return itemgroup_get(getGroups(), "immortal"); } @@ -555,6 +569,9 @@ void GenericCAO::removeFromScene(bool permanent) clearParentAttachment(); } + if (auto shadow = RenderingEngine::get_shadow_renderer()) + shadow->removeNodeFromShadowList(getSceneNode()); + if (m_meshnode) { m_meshnode->remove(); m_meshnode->drop(); @@ -644,7 +661,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); @@ -728,9 +745,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)); @@ -747,10 +761,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; @@ -758,6 +768,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); @@ -803,10 +816,13 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) if (m_reset_textures_timer < 0) updateTextures(m_current_texture_modifier); - scene::ISceneNode *node = getSceneNode(); + if (scene::ISceneNode *node = getSceneNode()) { + if (m_matrixnode) + node->setParent(m_matrixnode); - if (node && m_matrixnode) - node->setParent(m_matrixnode); + if (auto shadow = RenderingEngine::get_shadow_renderer()) + shadow->addNodeToShadowList(node); + } updateNametag(); updateMarker(); @@ -816,6 +832,28 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) updateAttachments(); 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; + } + } + } } void GenericCAO::updateLight(u32 day_night_ratio) @@ -823,7 +861,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]; @@ -832,28 +871,33 @@ 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 (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; } @@ -865,7 +909,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(); @@ -874,16 +918,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); } } } @@ -990,14 +1034,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.up || controls.down || controls.left || controls.right || - controls.forw_move_joystick_axis != 0.f || - controls.sidew_move_joystick_axis != 0.f) + if (controls.movement_speed > 0.001f) { + new_speed *= controls.movement_speed; walking = true; + } - f32 new_speed = player->local_animation_speed; v2s32 new_anim = v2s32(0,0); bool allow_update = false; @@ -1009,7 +1053,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) g_settings->getBool("free_move") && m_client->checkLocalPrivilege("fly")))) new_speed *= 1.5; - // slowdown speed if sneeking + // slowdown speed if sneaking if (controls.sneak && walking) new_speed /= 2; @@ -1281,9 +1325,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; @@ -1291,6 +1341,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 @@ -1326,6 +1377,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); @@ -1362,7 +1414,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; @@ -1376,6 +1428,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 @@ -1395,54 +1448,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) @@ -1716,6 +1771,7 @@ void GenericCAO::processMessage(const std::string &data) m_tx_basepos = p; m_anim_num_frames = num_frames; + m_anim_frame = 0; m_anim_framelength = framelength; m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch; @@ -1773,6 +1829,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); @@ -1817,6 +1874,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); } } @@ -1864,7 +1923,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) { @@ -1884,6 +1944,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); } } @@ -1912,20 +1974,17 @@ void GenericCAO::updateMeshCulling() const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST; - 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