]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/camera.cpp
Remove unused ITextSceneNode header (#11476)
[dragonfireclient.git] / src / client / camera.cpp
index fb1c3ff56138ed1442b7b0683e7d53d5aaa9696f..2629a63590e4f3ad805d694d13cf15f607aa4c6d 100644 (file)
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "wieldmesh.h"
 #include "noise.h"         // easeCurve
 #include "sound.h"
-#include "event.h"
+#include "mtevent.h"
 #include "nodedef.h"
 #include "util/numeric.h"
 #include "constants.h"
@@ -43,11 +43,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define WIELDMESH_AMPLITUDE_X 7.0f
 #define WIELDMESH_AMPLITUDE_Y 10.0f
 
-Camera::Camera(MapDrawControl &draw_control, Client *client):
+Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine):
        m_draw_control(draw_control),
        m_client(client)
 {
-       scene::ISceneManager *smgr = RenderingEngine::get_scene_manager();
+       auto smgr = rendering_engine->get_scene_manager();
        // note: making the camera node a child of the player node
        // would lead to unexpected behaviour, so we don't do that.
        m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
@@ -79,6 +79,7 @@ Camera::Camera(MapDrawControl &draw_control, Client *client):
        m_cache_fov                 = std::fmax(g_settings->getFloat("fov"), 45.0f);
        m_arm_inertia               = g_settings->getBool("arm_inertia");
        m_nametags.clear();
+       m_show_nametag_backgrounds  = g_settings->getBool("show_nametag_backgrounds");
 }
 
 Camera::~Camera()
@@ -86,6 +87,51 @@ Camera::~Camera()
        m_wieldmgr->drop();
 }
 
+void Camera::notifyFovChange()
+{
+       LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+       assert(player);
+
+       PlayerFovSpec spec = player->getFov();
+
+       /*
+        * Update m_old_fov_degrees first - it serves as the starting point of the
+        * upcoming transition.
+        *
+        * If an FOV transition is already active, mark current FOV as the start of
+        * the new transition. If not, set it to the previous transition's target FOV.
+        */
+       if (m_fov_transition_active)
+               m_old_fov_degrees = m_curr_fov_degrees;
+       else
+               m_old_fov_degrees = m_server_sent_fov ? m_target_fov_degrees : m_cache_fov;
+
+       /*
+        * Update m_server_sent_fov next - it corresponds to the target FOV of the
+        * upcoming transition.
+        *
+        * Set it to m_cache_fov, if server-sent FOV is 0. Otherwise check if
+        * server-sent FOV is a multiplier, and multiply it with m_cache_fov instead
+        * of overriding.
+        */
+       if (spec.fov == 0.0f) {
+               m_server_sent_fov = false;
+               m_target_fov_degrees = m_cache_fov;
+       } else {
+               m_server_sent_fov = true;
+               m_target_fov_degrees = spec.is_multiplier ? m_cache_fov * spec.fov : spec.fov;
+       }
+
+       if (spec.transition_time > 0.0f)
+               m_fov_transition_active = true;
+
+       // If FOV smooth transition is active, initialize required variables
+       if (m_fov_transition_active) {
+               m_transition_time = spec.transition_time;
+               m_fov_diff = m_target_fov_degrees - m_old_fov_degrees;
+       }
+}
+
 bool Camera::successfullyCreated(std::string &error_message)
 {
        if (!m_playernode) {
@@ -297,9 +343,13 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
        if (player->getParent())
                player_position = player->getParent()->getPosition();
 
-       if(player->touching_ground &&
-                       player_position.Y > old_player_position.Y)
-       {
+       // Smooth the camera movement when the player instantly moves upward due to stepheight.
+       // To smooth the 'not touching_ground' stepheight, smoothing is necessary when jumping
+       // or swimming (for when moving from liquid to land).
+       // Disable smoothing if climbing or flying, to avoid upwards offset of player model
+       // when seen in 3rd person view.
+       bool flying = g_settings->getBool("free_move") && m_client->checkLocalPrivilege("fly");
+       if (player_position.Y > old_player_position.Y && !player->is_climbing && !flying) {
                f32 oldy = old_player_position.Y;
                f32 newy = player_position.Y;
                f32 t = std::exp(-23 * frametime);
@@ -462,35 +512,40 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
                m_camera_position = my_cp;
 
        /*
-        * Apply server-sent FOV. If server doesn't enforce FOV,
-        * check for zoom and set to zoom FOV.
-        * Otherwise, default to m_cache_fov
+        * Apply server-sent FOV, instantaneous or smooth transition.
+        * If not, check for zoom and set to zoom FOV.
+        * Otherwise, default to m_cache_fov.
         */
-
-       f32 fov_degrees;
-       PlayerFovSpec fov_spec = player->getFov();
-       if (fov_spec.fov > 0.0f) {
-               // If server-sent FOV is a multiplier, multiply
-               // it with m_cache_fov instead of overriding
-               if (fov_spec.is_multiplier)
-                       fov_degrees = m_cache_fov * fov_spec.fov;
-               else
-                       fov_degrees = fov_spec.fov;
+       if (m_fov_transition_active) {
+               // Smooth FOV transition
+               // Dynamically calculate FOV delta based on frametimes
+               f32 delta = (frametime / m_transition_time) * m_fov_diff;
+               m_curr_fov_degrees += delta;
+
+               // Mark transition as complete if target FOV has been reached
+               if ((m_fov_diff > 0.0f && m_curr_fov_degrees >= m_target_fov_degrees) ||
+                               (m_fov_diff < 0.0f && m_curr_fov_degrees <= m_target_fov_degrees)) {
+                       m_fov_transition_active = false;
+                       m_curr_fov_degrees = m_target_fov_degrees;
+               }
+       } else if (m_server_sent_fov) {
+               // Instantaneous FOV change
+               m_curr_fov_degrees = m_target_fov_degrees;
        } else if (player->getPlayerControl().zoom && player->getZoomFOV() > 0.001f) {
                // Player requests zoom, apply zoom FOV
-               fov_degrees = player->getZoomFOV();
+               m_curr_fov_degrees = player->getZoomFOV();
        } else {
                // Set to client's selected FOV
-               fov_degrees = m_cache_fov;
+               m_curr_fov_degrees = m_cache_fov;
        }
-       fov_degrees = rangelim(fov_degrees, 1.0f, 160.0f);
+       m_curr_fov_degrees = rangelim(m_curr_fov_degrees, 1.0f, 160.0f);
 
        // FOV and aspect ratio
-       const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+       const v2u32 &window_size = RenderingEngine::getWindowSize();
        m_aspect = (f32) window_size.X / (f32) window_size.Y;
-       m_fov_y = fov_degrees * M_PI / 180.0;
+       m_fov_y = m_curr_fov_degrees * M_PI / 180.0;
        // Increase vertical FOV on lower aspect ratios (<16:10)
-       m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
+       m_fov_y *= core::clamp(sqrt(16./10. / m_aspect), 1.0, 1.4);
        m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
        m_cameranode->setAspectRatio(m_aspect);
        m_cameranode->setFOV(m_fov_y);
@@ -542,7 +597,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
        m_wieldnode->setPosition(wield_position);
        m_wieldnode->setRotation(wield_rotation);
 
-       m_wieldnode->setColor(player->light_color);
+       m_wieldnode->setNodeLightColor(player->light_color);
 
        // Set render distance
        updateViewingRange();
@@ -557,14 +612,11 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
        const bool walking = movement_XZ && player->touching_ground;
        const bool swimming = (movement_XZ || player->swimming_vertical) && player->in_liquid;
        const bool climbing = movement_Y && player->is_climbing;
-       if ((walking || swimming || climbing) &&
-                       (!g_settings->getBool("free_move") || !m_client->checkLocalPrivilege("fly"))) {
+       if ((walking || swimming || climbing) && !flying) {
                // Start animation
                m_view_bobbing_state = 1;
                m_view_bobbing_speed = MYMIN(speed.getLength(), 70);
-       }
-       else if (m_view_bobbing_state == 1)
-       {
+       } else if (m_view_bobbing_state == 1) {
                // Stop animation
                m_view_bobbing_state = 2;
                m_view_bobbing_speed = 60;
@@ -612,7 +664,7 @@ void Camera::wield(const ItemStack &item)
 void Camera::drawWieldedTool(irr::core::matrix4* translation)
 {
        // Clear Z buffer so that the wielded tool stays in front of world geometry
-       m_wieldmgr->getVideoDriver()->clearZBuffer();
+       m_wieldmgr->getVideoDriver()->clearBuffers(video::ECBF_DEPTH);
 
        // Draw the wielded node (in a separate scene manager)
        scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
@@ -640,46 +692,47 @@ void Camera::drawNametags()
        core::matrix4 trans = m_cameranode->getProjectionMatrix();
        trans *= m_cameranode->getViewMatrix();
 
-       for (std::list<Nametag *>::const_iterator
-                       i = m_nametags.begin();
-                       i != m_nametags.end(); ++i) {
-               Nametag *nametag = *i;
-               if (nametag->nametag_color.getAlpha() == 0) {
-                       // Enforce hiding nametag,
-                       // because if freetype is enabled, a grey
-                       // shadow can remain.
-                       continue;
-               }
-               v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->nametag_pos * BS;
+       gui::IGUIFont *font = g_fontengine->getFont();
+       video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+       v2u32 screensize = driver->getScreenSize();
+
+       for (const Nametag *nametag : m_nametags) {
+               // Nametags are hidden in GenericCAO::updateNametag()
+
+               v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->pos * BS;
                f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f };
                trans.multiplyWith1x4Matrix(transformed_pos);
                if (transformed_pos[3] > 0) {
                        std::wstring nametag_colorless =
-                               unescape_translate(utf8_to_wide(nametag->nametag_text));
-                       core::dimension2d<u32> textsize =
-                               g_fontengine->getFont()->getDimension(
+                               unescape_translate(utf8_to_wide(nametag->text));
+                       core::dimension2d<u32> textsize = font->getDimension(
                                nametag_colorless.c_str());
                        f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
                                core::reciprocal(transformed_pos[3]);
-                       v2u32 screensize = RenderingEngine::get_video_driver()->getScreenSize();
                        v2s32 screen_pos;
                        screen_pos.X = screensize.X *
                                (0.5 * transformed_pos[0] * zDiv + 0.5) - textsize.Width / 2;
                        screen_pos.Y = screensize.Y *
                                (0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
                        core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
-                       g_fontengine->getFont()->draw(
-                               translate_string(utf8_to_wide(nametag->nametag_text)).c_str(),
-                               size + screen_pos, nametag->nametag_color);
+                       core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+
+                       auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds);
+                       if (bgcolor.getAlpha() != 0)
+                               driver->draw2DRectangle(bgcolor, bg_size + screen_pos);
+
+                       font->draw(
+                               translate_string(utf8_to_wide(nametag->text)).c_str(),
+                               size + screen_pos, nametag->textcolor);
                }
        }
 }
 
 Nametag *Camera::addNametag(scene::ISceneNode *parent_node,
-               const std::string &nametag_text, video::SColor nametag_color,
-               const v3f &pos)
+               const std::string &text, video::SColor textcolor,
+               Optional<video::SColor> bgcolor, const v3f &pos)
 {
-       Nametag *nametag = new Nametag(parent_node, nametag_text, nametag_color, pos);
+       Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos);
        m_nametags.push_back(nametag);
        return nametag;
 }