LCOV - code coverage report
Current view: top level - src - camera.cpp (source / functions) Hit Total Coverage
Test: report Lines: 229 314 72.9 %
Date: 2015-07-11 18:23:49 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "camera.h"
      21             : #include "debug.h"
      22             : #include "client.h"
      23             : #include "map.h"
      24             : #include "clientmap.h"     // MapDrawControl
      25             : #include "player.h"
      26             : #include <cmath>
      27             : #include "settings.h"
      28             : #include "wieldmesh.h"
      29             : #include "noise.h"         // easeCurve
      30             : #include "gamedef.h"
      31             : #include "sound.h"
      32             : #include "event.h"
      33             : #include "profiler.h"
      34             : #include "util/numeric.h"
      35             : #include "util/mathconstants.h"
      36             : #include "constants.h"
      37             : 
      38             : #define CAMERA_OFFSET_STEP 200
      39             : 
      40             : #include "nodedef.h"
      41             : 
      42           1 : Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
      43             :                 IGameDef *gamedef):
      44             :         m_playernode(NULL),
      45             :         m_headnode(NULL),
      46             :         m_cameranode(NULL),
      47             : 
      48             :         m_wieldmgr(NULL),
      49             :         m_wieldnode(NULL),
      50             : 
      51             :         m_draw_control(draw_control),
      52             :         m_gamedef(gamedef),
      53             : 
      54             :         m_camera_position(0,0,0),
      55             :         m_camera_direction(0,0,0),
      56             :         m_camera_offset(0,0,0),
      57             : 
      58             :         m_aspect(1.0),
      59             :         m_fov_x(1.0),
      60             :         m_fov_y(1.0),
      61             : 
      62             :         m_added_busytime(0),
      63             :         m_added_frames(0),
      64             :         m_range_old(0),
      65             :         m_busytime_old(0),
      66             :         m_frametime_counter(0),
      67             :         m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range
      68             : 
      69             :         m_view_bobbing_anim(0),
      70             :         m_view_bobbing_state(0),
      71             :         m_view_bobbing_speed(0),
      72             :         m_view_bobbing_fall(0),
      73             : 
      74             :         m_digging_anim(0),
      75             :         m_digging_button(-1),
      76             : 
      77             :         m_wield_change_timer(0.125),
      78             :         m_wield_item_next(),
      79             : 
      80           1 :         m_camera_mode(CAMERA_MODE_FIRST)
      81             : {
      82             :         //dstream<<__FUNCTION_NAME<<std::endl;
      83             : 
      84             :         // note: making the camera node a child of the player node
      85             :         // would lead to unexpected behaviour, so we don't do that.
      86           1 :         m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
      87           1 :         m_headnode = smgr->addEmptySceneNode(m_playernode);
      88           1 :         m_cameranode = smgr->addCameraSceneNode(smgr->getRootSceneNode());
      89           1 :         m_cameranode->bindTargetAndRotation(true);
      90             : 
      91             :         // This needs to be in its own scene manager. It is drawn after
      92             :         // all other 3D scene nodes and before the GUI.
      93           1 :         m_wieldmgr = smgr->createNewSceneManager();
      94           1 :         m_wieldmgr->addCameraSceneNode();
      95           1 :         m_wieldnode = new WieldMeshSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr, -1, true);
      96           1 :         m_wieldnode->setItem(ItemStack(), m_gamedef);
      97           1 :         m_wieldnode->drop(); // m_wieldmgr grabbed it
      98           1 :         m_wieldlightnode = m_wieldmgr->addLightSceneNode(NULL, v3f(0.0, 50.0, 0.0));
      99             : 
     100             :         /* TODO: Add a callback function so these can be updated when a setting
     101             :          *       changes.  At this point in time it doesn't matter (e.g. /set
     102             :          *       is documented to change server settings only)
     103             :          *
     104             :          * TODO: Local caching of settings is not optimal and should at some stage
     105             :          *       be updated to use a global settings object for getting thse values
     106             :          *       (as opposed to the this local caching). This can be addressed in
     107             :          *       a later release.
     108             :          */
     109           1 :         m_cache_fall_bobbing_amount = g_settings->getFloat("fall_bobbing_amount");
     110           1 :         m_cache_view_bobbing_amount = g_settings->getFloat("view_bobbing_amount");
     111           1 :         m_cache_wanted_fps          = g_settings->getFloat("wanted_fps");
     112           1 :         m_cache_fov                 = g_settings->getFloat("fov");
     113           1 :         m_cache_view_bobbing        = g_settings->getBool("view_bobbing");
     114           1 : }
     115             : 
     116           2 : Camera::~Camera()
     117             : {
     118           1 :         m_wieldmgr->drop();
     119           1 : }
     120             : 
     121           1 : bool Camera::successfullyCreated(std::string &error_message)
     122             : {
     123           1 :         if (!m_playernode) {
     124           0 :                 error_message = "Failed to create the player scene node";
     125           1 :         } else if (!m_headnode) {
     126           0 :                 error_message = "Failed to create the head scene node";
     127           1 :         } else if (!m_cameranode) {
     128           0 :                 error_message = "Failed to create the camera scene node";
     129           1 :         } else if (!m_wieldmgr) {
     130           0 :                 error_message = "Failed to create the wielded item scene manager";
     131           1 :         } else if (!m_wieldnode) {
     132           0 :                 error_message = "Failed to create the wielded item scene node";
     133             :         } else {
     134           1 :                 error_message.clear();
     135             :         }
     136           1 :         return error_message.empty();
     137             : }
     138             : 
     139             : // Returns the fractional part of x
     140        3603 : inline f32 my_modf(f32 x)
     141             : {
     142             :         double dummy;
     143        3603 :         return modf(x, &dummy);
     144             : }
     145             : 
     146        1166 : void Camera::step(f32 dtime)
     147             : {
     148        1166 :         if(m_view_bobbing_fall > 0)
     149             :         {
     150           0 :                 m_view_bobbing_fall -= 3 * dtime;
     151           0 :                 if(m_view_bobbing_fall <= 0)
     152           0 :                         m_view_bobbing_fall = -1; // Mark the effect as finished
     153             :         }
     154             : 
     155        1166 :         bool was_under_zero = m_wield_change_timer < 0;
     156        1166 :         m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
     157             : 
     158        1166 :         if (m_wield_change_timer >= 0 && was_under_zero)
     159          15 :                 m_wieldnode->setItem(m_wield_item_next, m_gamedef);
     160             : 
     161        1166 :         if (m_view_bobbing_state != 0)
     162             :         {
     163             :                 //f32 offset = dtime * m_view_bobbing_speed * 0.035;
     164         678 :                 f32 offset = dtime * m_view_bobbing_speed * 0.030;
     165         678 :                 if (m_view_bobbing_state == 2)
     166             :                 {
     167             : #if 0
     168             :                         // Animation is getting turned off
     169             :                         if (m_view_bobbing_anim < 0.5)
     170             :                                 m_view_bobbing_anim -= offset;
     171             :                         else
     172             :                                 m_view_bobbing_anim += offset;
     173             :                         if (m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1)
     174             :                         {
     175             :                                 m_view_bobbing_anim = 0;
     176             :                                 m_view_bobbing_state = 0;
     177             :                         }
     178             : #endif
     179             : #if 1
     180             :                         // Animation is getting turned off
     181          77 :                         if(m_view_bobbing_anim < 0.25)
     182             :                         {
     183          28 :                                 m_view_bobbing_anim -= offset;
     184          49 :                         } else if(m_view_bobbing_anim > 0.75) {
     185          20 :                                 m_view_bobbing_anim += offset;
     186             :                         }
     187          77 :                         if(m_view_bobbing_anim < 0.5)
     188             :                         {
     189          48 :                                 m_view_bobbing_anim += offset;
     190          48 :                                 if(m_view_bobbing_anim > 0.5)
     191           4 :                                         m_view_bobbing_anim = 0.5;
     192             :                         } else {
     193          29 :                                 m_view_bobbing_anim -= offset;
     194          29 :                                 if(m_view_bobbing_anim < 0.5)
     195           2 :                                         m_view_bobbing_anim = 0.5;
     196             :                         }
     197         154 :                         if(m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1 ||
     198          77 :                                         fabs(m_view_bobbing_anim - 0.5) < 0.01)
     199             :                         {
     200           8 :                                 m_view_bobbing_anim = 0;
     201           8 :                                 m_view_bobbing_state = 0;
     202             :                         }
     203             : #endif
     204             :                 }
     205             :                 else
     206             :                 {
     207         601 :                         float was = m_view_bobbing_anim;
     208         601 :                         m_view_bobbing_anim = my_modf(m_view_bobbing_anim + offset);
     209         593 :                         bool step = (was == 0 ||
     210         995 :                                         (was < 0.5f && m_view_bobbing_anim >= 0.5f) ||
     211         837 :                                         (was > 0.5f && m_view_bobbing_anim <= 0.5f));
     212         601 :                         if(step)
     213             :                         {
     214          37 :                                 MtEvent *e = new SimpleTriggerEvent("ViewBobbingStep");
     215          37 :                                 m_gamedef->event()->put(e);
     216             :                         }
     217             :                 }
     218             :         }
     219             : 
     220        1166 :         if (m_digging_button != -1)
     221             :         {
     222           0 :                 f32 offset = dtime * 3.5;
     223           0 :                 float m_digging_anim_was = m_digging_anim;
     224           0 :                 m_digging_anim += offset;
     225           0 :                 if (m_digging_anim >= 1)
     226             :                 {
     227           0 :                         m_digging_anim = 0;
     228           0 :                         m_digging_button = -1;
     229             :                 }
     230           0 :                 float lim = 0.15;
     231           0 :                 if(m_digging_anim_was < lim && m_digging_anim >= lim)
     232             :                 {
     233           0 :                         if(m_digging_button == 0)
     234             :                         {
     235           0 :                                 MtEvent *e = new SimpleTriggerEvent("CameraPunchLeft");
     236           0 :                                 m_gamedef->event()->put(e);
     237           0 :                         } else if(m_digging_button == 1) {
     238           0 :                                 MtEvent *e = new SimpleTriggerEvent("CameraPunchRight");
     239           0 :                                 m_gamedef->event()->put(e);
     240             :                         }
     241             :                 }
     242             :         }
     243        1166 : }
     244             : 
     245        1166 : void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
     246             :                 f32 tool_reload_ratio, ClientEnvironment &c_env)
     247             : {
     248             :         // Get player position
     249             :         // Smooth the movement when walking up stairs
     250        1166 :         v3f old_player_position = m_playernode->getPosition();
     251        1166 :         v3f player_position = player->getPosition();
     252        1166 :         if (player->isAttached && player->parent)
     253           0 :                 player_position = player->parent->getPosition();
     254             :         //if(player->touching_ground && player_position.Y > old_player_position.Y)
     255        2332 :         if(player->touching_ground &&
     256        1166 :                         player_position.Y > old_player_position.Y)
     257             :         {
     258           0 :                 f32 oldy = old_player_position.Y;
     259           0 :                 f32 newy = player_position.Y;
     260           0 :                 f32 t = exp(-23*frametime);
     261           0 :                 player_position.Y = oldy * t + newy * (1-t);
     262             :         }
     263             : 
     264             :         // Set player node transformation
     265        1166 :         m_playernode->setPosition(player_position);
     266        1166 :         m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
     267        1166 :         m_playernode->updateAbsolutePosition();
     268             : 
     269             :         // Get camera tilt timer (hurt animation)
     270        1166 :         float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75);
     271             : 
     272             :         // Fall bobbing animation
     273        1166 :         float fall_bobbing = 0;
     274        1166 :         if(player->camera_impact >= 1 && m_camera_mode < CAMERA_MODE_THIRD)
     275             :         {
     276           0 :                 if(m_view_bobbing_fall == -1) // Effect took place and has finished
     277           0 :                         player->camera_impact = m_view_bobbing_fall = 0;
     278           0 :                 else if(m_view_bobbing_fall == 0) // Initialize effect
     279           0 :                         m_view_bobbing_fall = 1;
     280             : 
     281             :                 // Convert 0 -> 1 to 0 -> 1 -> 0
     282           0 :                 fall_bobbing = m_view_bobbing_fall < 0.5 ? m_view_bobbing_fall * 2 : -(m_view_bobbing_fall - 0.5) * 2 + 1;
     283             :                 // Smoothen and invert the above
     284           0 :                 fall_bobbing = sin(fall_bobbing * 0.5 * M_PI) * -1;
     285             :                 // Amplify according to the intensity of the impact
     286           0 :                 fall_bobbing *= (1 - rangelim(50 / player->camera_impact, 0, 1)) * 5;
     287             : 
     288           0 :                 fall_bobbing *= m_cache_fall_bobbing_amount;
     289             :         }
     290             : 
     291             :         // Calculate players eye offset for different camera modes
     292        1166 :         v3f PlayerEyeOffset = player->getEyeOffset();
     293        1166 :         if (m_camera_mode == CAMERA_MODE_FIRST)
     294        1166 :                 PlayerEyeOffset += player->eye_offset_first;
     295             :         else
     296           0 :                 PlayerEyeOffset += player->eye_offset_third;
     297             : 
     298             :         // Set head node transformation
     299        1166 :         m_headnode->setPosition(PlayerEyeOffset+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0));
     300        1166 :         m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength));
     301        1166 :         m_headnode->updateAbsolutePosition();
     302             : 
     303             :         // Compute relative camera position and target
     304        1166 :         v3f rel_cam_pos = v3f(0,0,0);
     305        1166 :         v3f rel_cam_target = v3f(0,0,1);
     306        1166 :         v3f rel_cam_up = v3f(0,1,0);
     307             : 
     308        1166 :         if (m_view_bobbing_anim != 0 && m_camera_mode < CAMERA_MODE_THIRD)
     309             :         {
     310         670 :                 f32 bobfrac = my_modf(m_view_bobbing_anim * 2);
     311         670 :                 f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0;
     312             : 
     313             :                 #if 1
     314         670 :                 f32 bobknob = 1.2;
     315         670 :                 f32 bobtmp = sin(pow(bobfrac, bobknob) * M_PI);
     316             :                 //f32 bobtmp2 = cos(pow(bobfrac, bobknob) * M_PI);
     317             : 
     318             :                 v3f bobvec = v3f(
     319         670 :                         0.3 * bobdir * sin(bobfrac * M_PI),
     320         670 :                         -0.28 * bobtmp * bobtmp,
     321        1340 :                         0.);
     322             : 
     323             :                 //rel_cam_pos += 0.2 * bobvec;
     324             :                 //rel_cam_target += 0.03 * bobvec;
     325             :                 //rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * M_PI);
     326         670 :                 float f = 1.0;
     327         670 :                 f *= m_cache_view_bobbing_amount;
     328         670 :                 rel_cam_pos += bobvec * f;
     329             :                 //rel_cam_target += 0.995 * bobvec * f;
     330         670 :                 rel_cam_target += bobvec * f;
     331         670 :                 rel_cam_target.Z -= 0.005 * bobvec.Z * f;
     332             :                 //rel_cam_target.X -= 0.005 * bobvec.X * f;
     333             :                 //rel_cam_target.Y -= 0.005 * bobvec.Y * f;
     334         670 :                 rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * M_PI * f);
     335             :                 #else
     336             :                 f32 angle_deg = 1 * bobdir * sin(bobfrac * M_PI);
     337             :                 f32 angle_rad = angle_deg * M_PI / 180;
     338             :                 f32 r = 0.05;
     339             :                 v3f off = v3f(
     340             :                         r * sin(angle_rad),
     341             :                         r * (cos(angle_rad) - 1),
     342             :                         0);
     343             :                 rel_cam_pos += off;
     344             :                 //rel_cam_target += off;
     345             :                 rel_cam_up.rotateXYBy(angle_deg);
     346             :                 #endif
     347             : 
     348             :         }
     349             : 
     350             :         // Compute absolute camera position and target
     351        1166 :         m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos);
     352        1166 :         m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos);
     353             : 
     354        1166 :         v3f abs_cam_up;
     355        1166 :         m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);
     356             : 
     357             :         // Seperate camera position for calculation
     358        1166 :         v3f my_cp = m_camera_position;
     359             : 
     360             :         // Reposition the camera for third person view
     361        1166 :         if (m_camera_mode > CAMERA_MODE_FIRST)
     362             :         {
     363           0 :                 if (m_camera_mode == CAMERA_MODE_THIRD_FRONT)
     364           0 :                         m_camera_direction *= -1;
     365             : 
     366           0 :                 my_cp.Y += 2;
     367             : 
     368             :                 // Calculate new position
     369           0 :                 bool abort = false;
     370           0 :                 for (int i = BS; i <= BS*2.75; i++)
     371             :                 {
     372           0 :                         my_cp.X = m_camera_position.X + m_camera_direction.X*-i;
     373           0 :                         my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i;
     374           0 :                         if (i > 12)
     375           0 :                                 my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i);
     376             : 
     377             :                         // Prevent camera positioned inside nodes
     378           0 :                         INodeDefManager *nodemgr = m_gamedef->ndef();
     379           0 :                         MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS));
     380           0 :                         const ContentFeatures& features = nodemgr->get(n);
     381           0 :                         if(features.walkable)
     382             :                         {
     383           0 :                                 my_cp.X += m_camera_direction.X*-1*-BS/2;
     384           0 :                                 my_cp.Z += m_camera_direction.Z*-1*-BS/2;
     385           0 :                                 my_cp.Y += m_camera_direction.Y*-1*-BS/2;
     386           0 :                                 abort = true;
     387           0 :                                 break;
     388             :                         }
     389             :                 }
     390             : 
     391             :                 // If node blocks camera position don't move y to heigh
     392           0 :                 if (abort && my_cp.Y > player_position.Y+BS*2)
     393           0 :                         my_cp.Y = player_position.Y+BS*2;
     394             :         }
     395             : 
     396             :         // Update offset if too far away from the center of the map
     397             :         m_camera_offset.X += CAMERA_OFFSET_STEP*
     398        1166 :                         (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
     399             :         m_camera_offset.Y += CAMERA_OFFSET_STEP*
     400        1166 :                         (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
     401             :         m_camera_offset.Z += CAMERA_OFFSET_STEP*
     402        1166 :                         (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);
     403             : 
     404             :         // Set camera node transformation
     405        1166 :         m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS));
     406        1166 :         m_cameranode->setUpVector(abs_cam_up);
     407             :         // *100.0 helps in large map coordinates
     408        1166 :         m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
     409             : 
     410             :         // update the camera position in front-view mode to render blocks behind player
     411        1166 :         if (m_camera_mode == CAMERA_MODE_THIRD_FRONT)
     412           0 :                 m_camera_position = my_cp;
     413             : 
     414             :         // Get FOV setting
     415        1166 :         f32 fov_degrees = m_cache_fov;
     416        1166 :         fov_degrees = MYMAX(fov_degrees, 10.0);
     417        1166 :         fov_degrees = MYMIN(fov_degrees, 170.0);
     418             : 
     419             :         // FOV and aspect ratio
     420        1166 :         m_aspect = (f32) porting::getWindowSize().X / (f32) porting::getWindowSize().Y;
     421        1166 :         m_fov_y = fov_degrees * M_PI / 180.0;
     422             :         // Increase vertical FOV on lower aspect ratios (<16:10)
     423        1166 :         m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect)));
     424        1166 :         m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y));
     425        1166 :         m_cameranode->setAspectRatio(m_aspect);
     426        1166 :         m_cameranode->setFOV(m_fov_y);
     427             : 
     428             :         // Position the wielded item
     429             :         //v3f wield_position = v3f(45, -35, 65);
     430        1166 :         v3f wield_position = v3f(55, -35, 65);
     431             :         //v3f wield_rotation = v3f(-100, 120, -100);
     432        1166 :         v3f wield_rotation = v3f(-100, 120, -100);
     433        1166 :         wield_position.Y += fabs(m_wield_change_timer)*320 - 40;
     434        1166 :         if(m_digging_anim < 0.05 || m_digging_anim > 0.5)
     435             :         {
     436        1166 :                 f32 frac = 1.0;
     437        1166 :                 if(m_digging_anim > 0.5)
     438           0 :                         frac = 2.0 * (m_digging_anim - 0.5);
     439             :                 // This value starts from 1 and settles to 0
     440        1166 :                 f32 ratiothing = pow((1.0f - tool_reload_ratio), 0.5f);
     441             :                 //f32 ratiothing2 = pow(ratiothing, 0.5f);
     442        1166 :                 f32 ratiothing2 = (easeCurve(ratiothing*0.5))*2.0;
     443        1166 :                 wield_position.Y -= frac * 25.0 * pow(ratiothing2, 1.7f);
     444             :                 //wield_position.Z += frac * 5.0 * ratiothing2;
     445        1166 :                 wield_position.X -= frac * 35.0 * pow(ratiothing2, 1.1f);
     446        1166 :                 wield_rotation.Y += frac * 70.0 * pow(ratiothing2, 1.4f);
     447             :                 //wield_rotation.X -= frac * 15.0 * pow(ratiothing2, 1.4f);
     448             :                 //wield_rotation.Z += frac * 15.0 * pow(ratiothing2, 1.0f);
     449             :         }
     450        1166 :         if (m_digging_button != -1)
     451             :         {
     452           0 :                 f32 digfrac = m_digging_anim;
     453           0 :                 wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI);
     454           0 :                 wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI);
     455           0 :                 wield_position.Z += 25 * 0.5;
     456             : 
     457             :                 // Euler angles are PURE EVIL, so why not use quaternions?
     458           0 :                 core::quaternion quat_begin(wield_rotation * core::DEGTORAD);
     459           0 :                 core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD);
     460           0 :                 core::quaternion quat_slerp;
     461           0 :                 quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI));
     462           0 :                 quat_slerp.toEuler(wield_rotation);
     463           0 :                 wield_rotation *= core::RADTODEG;
     464             :         } else {
     465        1166 :                 f32 bobfrac = my_modf(m_view_bobbing_anim);
     466        1166 :                 wield_position.X -= sin(bobfrac*M_PI*2.0) * 3.0;
     467        1166 :                 wield_position.Y += sin(my_modf(bobfrac*2.0)*M_PI) * 3.0;
     468             :         }
     469        1166 :         m_wieldnode->setPosition(wield_position);
     470        1166 :         m_wieldnode->setRotation(wield_rotation);
     471             : 
     472             :         // Shine light upon the wield mesh
     473        1166 :         video::SColor black(255,0,0,0);
     474        1166 :         m_wieldmgr->setAmbientLight(player->light_color.getInterpolated(black, 0.7));
     475        1166 :         m_wieldlightnode->getLightData().DiffuseColor = player->light_color.getInterpolated(black, 0.3);
     476        1166 :         m_wieldlightnode->setPosition(v3f(30+5*sin(2*player->getYaw()*M_PI/180), -50, 0));
     477             : 
     478             :         // Render distance feedback loop
     479        1166 :         updateViewingRange(frametime, busytime);
     480             : 
     481             :         // If the player is walking, swimming, or climbing,
     482             :         // view bobbing is enabled and free_move is off,
     483             :         // start (or continue) the view bobbing animation.
     484        1166 :         v3f speed = player->getSpeed();
     485        1166 :         const bool movement_XZ = hypot(speed.X, speed.Z) > BS;
     486        1166 :         const bool movement_Y = abs(speed.Y) > BS;
     487             : 
     488        1166 :         const bool walking = movement_XZ && player->touching_ground;
     489        1166 :         const bool swimming = (movement_XZ || player->swimming_vertical) && player->in_liquid;
     490        1166 :         const bool climbing = movement_Y && player->is_climbing;
     491        4063 :         if ((walking || swimming || climbing) &&
     492        3570 :                         m_cache_view_bobbing &&
     493        2969 :                         (!g_settings->getBool("free_move") || !m_gamedef->checkLocalPrivilege("fly")))
     494             :         {
     495             :                 // Start animation
     496         601 :                 m_view_bobbing_state = 1;
     497         601 :                 m_view_bobbing_speed = MYMIN(speed.getLength(), 40);
     498             :         }
     499         565 :         else if (m_view_bobbing_state == 1)
     500             :         {
     501             :                 // Stop animation
     502          10 :                 m_view_bobbing_state = 2;
     503          10 :                 m_view_bobbing_speed = 60;
     504             :         }
     505        1166 : }
     506             : 
     507        1166 : void Camera::updateViewingRange(f32 frametime_in, f32 busytime_in)
     508             : {
     509        1166 :         if (m_draw_control.range_all)
     510           0 :                 return;
     511             : 
     512        1166 :         m_added_busytime += busytime_in;
     513        1166 :         m_added_frames += 1;
     514             : 
     515        1166 :         m_frametime_counter -= frametime_in;
     516        1166 :         if (m_frametime_counter > 0)
     517        1020 :                 return;
     518         146 :         m_frametime_counter = 0.2; // Same as ClientMap::updateDrawList interval
     519             : 
     520             :         /*dstream<<__FUNCTION_NAME
     521             :                         <<": Collected "<<m_added_frames<<" frames, total of "
     522             :                         <<m_added_busytime<<"s."<<std::endl;
     523             : 
     524             :         dstream<<"m_draw_control.blocks_drawn="
     525             :                         <<m_draw_control.blocks_drawn
     526             :                         <<", m_draw_control.blocks_would_have_drawn="
     527             :                         <<m_draw_control.blocks_would_have_drawn
     528             :                         <<std::endl;*/
     529             : 
     530             :         // Get current viewing range and FPS settings
     531         146 :         f32 viewing_range_min = g_settings->getFloat("viewing_range_nodes_min");
     532         146 :         viewing_range_min = MYMAX(15.0, viewing_range_min);
     533             : 
     534         146 :         f32 viewing_range_max = g_settings->getFloat("viewing_range_nodes_max");
     535         146 :         viewing_range_max = MYMAX(viewing_range_min, viewing_range_max);
     536             : 
     537             :         // Immediately apply hard limits
     538         146 :         if(m_draw_control.wanted_range < viewing_range_min)
     539           0 :                 m_draw_control.wanted_range = viewing_range_min;
     540         146 :         if(m_draw_control.wanted_range > viewing_range_max)
     541           0 :                 m_draw_control.wanted_range = viewing_range_max;
     542             : 
     543             :         // Just so big a value that everything rendered is visible
     544             :         // Some more allowance than viewing_range_max * BS because of clouds,
     545             :         // active objects, etc.
     546         146 :         if(viewing_range_max < 200*BS)
     547         146 :                 m_cameranode->setFarValue(200 * BS * 10);
     548             :         else
     549           0 :                 m_cameranode->setFarValue(viewing_range_max * BS * 10);
     550             : 
     551         146 :         f32 wanted_fps = m_cache_wanted_fps;
     552         146 :         wanted_fps = MYMAX(wanted_fps, 1.0);
     553         146 :         f32 wanted_frametime = 1.0 / wanted_fps;
     554             : 
     555         146 :         m_draw_control.wanted_min_range = viewing_range_min;
     556         146 :         m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1;
     557         146 :         if (m_draw_control.wanted_max_blocks < 10)
     558           2 :                 m_draw_control.wanted_max_blocks = 10;
     559             : 
     560         146 :         f32 block_draw_ratio = 1.0;
     561         146 :         if (m_draw_control.blocks_would_have_drawn != 0)
     562             :         {
     563         144 :                 block_draw_ratio = (f32)m_draw_control.blocks_drawn
     564         144 :                         / (f32)m_draw_control.blocks_would_have_drawn;
     565             :         }
     566             : 
     567             :         // Calculate the average frametime in the case that all wanted
     568             :         // blocks had been drawn
     569         146 :         f32 frametime = m_added_busytime / m_added_frames / block_draw_ratio;
     570             : 
     571         146 :         m_added_busytime = 0.0;
     572         146 :         m_added_frames = 0;
     573             : 
     574         146 :         f32 wanted_frametime_change = wanted_frametime - frametime;
     575             :         //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
     576         146 :         g_profiler->avg("wanted_frametime_change", wanted_frametime_change);
     577             : 
     578             :         // If needed frametime change is small, just return
     579             :         // This value was 0.4 for many months until 2011-10-18 by c55;
     580         146 :         if (fabs(wanted_frametime_change) < wanted_frametime*0.33)
     581             :         {
     582             :                 //dstream<<"ignoring small wanted_frametime_change"<<std::endl;
     583          75 :                 return;
     584             :         }
     585             : 
     586          71 :         f32 range = m_draw_control.wanted_range;
     587          71 :         f32 new_range = range;
     588             : 
     589          71 :         f32 d_range = range - m_range_old;
     590          71 :         f32 d_busytime = busytime_in - m_busytime_old;
     591          71 :         if (d_range != 0)
     592             :         {
     593          48 :                 m_time_per_range = d_busytime / d_range;
     594             :         }
     595             :         //dstream<<"time_per_range="<<m_time_per_range<<std::endl;
     596          71 :         g_profiler->avg("time_per_range", m_time_per_range);
     597             : 
     598             :         // The minimum allowed calculated frametime-range derivative:
     599             :         // Practically this sets the maximum speed of changing the range.
     600             :         // The lower this value, the higher the maximum changing speed.
     601             :         // A low value here results in wobbly range (0.001)
     602             :         // A low value can cause oscillation in very nonlinear time/range curves.
     603             :         // A high value here results in slow changing range (0.0025)
     604             :         // SUGG: This could be dynamically adjusted so that when
     605             :         //       the camera is turning, this is lower
     606             :         //f32 min_time_per_range = 0.0010; // Up to 0.4.7
     607          71 :         f32 min_time_per_range = 0.0005;
     608          71 :         if(m_time_per_range < min_time_per_range)
     609             :         {
     610          34 :                 m_time_per_range = min_time_per_range;
     611             :                 //dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
     612             :         }
     613             :         else
     614             :         {
     615             :                 //dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
     616             :         }
     617             : 
     618          71 :         f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
     619             :         // Dampen the change a bit to kill oscillations
     620             :         //wanted_range_change *= 0.9;
     621             :         //wanted_range_change *= 0.75;
     622          71 :         wanted_range_change *= 0.5;
     623             :         //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
     624             : 
     625             :         // If needed range change is very small, just return
     626          71 :         if(fabs(wanted_range_change) < 0.001)
     627             :         {
     628             :                 //dstream<<"ignoring small wanted_range_change"<<std::endl;
     629           0 :                 return;
     630             :         }
     631             : 
     632          71 :         new_range += wanted_range_change;
     633             : 
     634             :         //f32 new_range_unclamped = new_range;
     635          71 :         new_range = MYMAX(new_range, viewing_range_min);
     636          71 :         new_range = MYMIN(new_range, viewing_range_max);
     637             :         /*dstream<<"new_range="<<new_range_unclamped
     638             :                         <<", clamped to "<<new_range<<std::endl;*/
     639             : 
     640          71 :         m_range_old = m_draw_control.wanted_range;
     641          71 :         m_busytime_old = busytime_in;
     642             : 
     643          71 :         m_draw_control.wanted_range = new_range;
     644             : }
     645             : 
     646           0 : void Camera::setDigging(s32 button)
     647             : {
     648           0 :         if (m_digging_button == -1)
     649           0 :                 m_digging_button = button;
     650           0 : }
     651             : 
     652          24 : void Camera::wield(const ItemStack &item)
     653             : {
     654          24 :         if (item.name != m_wield_item_next.name) {
     655          21 :                 m_wield_item_next = item;
     656          21 :                 if (m_wield_change_timer > 0)
     657          15 :                         m_wield_change_timer = -m_wield_change_timer;
     658           6 :                 else if (m_wield_change_timer == 0)
     659           0 :                         m_wield_change_timer = -0.001;
     660             :         }
     661          24 : }
     662             : 
     663        1166 : void Camera::drawWieldedTool(irr::core::matrix4* translation)
     664             : {
     665             :         // Clear Z buffer so that the wielded tool stay in front of world geometry
     666        1166 :         m_wieldmgr->getVideoDriver()->clearZBuffer();
     667             : 
     668             :         // Draw the wielded node (in a separate scene manager)
     669        1166 :         scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera();
     670        1166 :         cam->setAspectRatio(m_cameranode->getAspectRatio());
     671        1166 :         cam->setFOV(72.0*M_PI/180.0);
     672        1166 :         cam->setNearValue(0.1);
     673        1166 :         cam->setFarValue(1000);
     674        1166 :         if (translation != NULL)
     675             :         {
     676           0 :                 irr::core::matrix4 startMatrix = cam->getAbsoluteTransformation();
     677           0 :                 irr::core::vector3df focusPoint = (cam->getTarget()
     678           0 :                                 - cam->getAbsolutePosition()).setLength(1)
     679           0 :                                 + cam->getAbsolutePosition();
     680             : 
     681             :                 irr::core::vector3df camera_pos =
     682           0 :                                 (startMatrix * *translation).getTranslation();
     683           0 :                 cam->setPosition(camera_pos);
     684           0 :                 cam->setTarget(focusPoint);
     685             :         }
     686        1166 :         m_wieldmgr->drawAll();
     687        1169 : }

Generated by: LCOV version 1.11