X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcamera.cpp;h=33e85d06926e9568c4e02de64723e01cf23ba517;hb=9f1ae4084d945adb6281eaddc2ae56f488691d8b;hp=a9497152b44f29d33c1303d7eacbdad116f417a2;hpb=54f3796f9105cb220c95aa6c2e80516cdd4e4a00;p=dragonfireclient.git diff --git a/src/camera.cpp b/src/camera.cpp index a9497152b..33e85d069 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -3,16 +3,16 @@ Minetest-c55 Copyright (C) 2010-2011 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -22,19 +22,33 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "main.h" // for g_settings #include "map.h" +#include "clientmap.h" // MapDrawControl +#include "mesh.h" #include "player.h" +#include "tile.h" #include - -const s32 BOBFRAMES = 0x1000000; // must be a power of two - -Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): +#include "settings.h" +#include "itemdef.h" // For wield visualization +#include "noise.h" // easeCurve +#include "gamedef.h" +#include "sound.h" +#include "event.h" +#include "util/numeric.h" +#include "util/mathconstants.h" + +Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, + IGameDef *gamedef): m_smgr(smgr), m_playernode(NULL), m_headnode(NULL), m_cameranode(NULL), + + m_wieldmgr(NULL), + m_wieldnode(NULL), + m_wieldlight(0), + m_draw_control(draw_control), - m_viewing_range_min(5.0), - m_viewing_range_max(5.0), + m_gamedef(gamedef), m_camera_position(0,0,0), m_camera_direction(0,0,0), @@ -43,7 +57,6 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): m_fov_x(1.0), m_fov_y(1.0), - m_wanted_frametime(0.0), m_added_frametime(0), m_added_frames(0), m_range_old(0), @@ -53,7 +66,10 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): m_view_bobbing_anim(0), m_view_bobbing_state(0), - m_view_bobbing_speed(0) + m_view_bobbing_speed(0), + + m_digging_anim(0), + m_digging_button(-1) { //dstream<<__FUNCTION_NAME<addCameraSceneNode(smgr->getRootSceneNode()); m_cameranode->bindTargetAndRotation(true); - updateSettings(); + // This needs to be in its own scene manager. It is drawn after + // all other 3D scene nodes and before the GUI. + m_wieldmgr = smgr->createNewSceneManager(); + m_wieldmgr->addCameraSceneNode(); + m_wieldnode = m_wieldmgr->addMeshSceneNode(createCubeMesh(v3f(1,1,1)), NULL); // need a dummy mesh } Camera::~Camera() { + m_wieldnode->setMesh(NULL); + m_wieldmgr->drop(); } bool Camera::successfullyCreated(std::wstring& error_message) @@ -88,38 +110,135 @@ bool Camera::successfullyCreated(std::wstring& error_message) error_message = L"Failed to create the camera scene node"; return false; } + if (m_wieldmgr == NULL) + { + error_message = L"Failed to create the wielded item scene manager"; + return false; + } + if (m_wieldnode == NULL) + { + error_message = L"Failed to create the wielded item scene node"; + return false; + } return true; } +// Returns the fractional part of x +inline f32 my_modf(f32 x) +{ + double dummy; + return modf(x, &dummy); +} + void Camera::step(f32 dtime) { if (m_view_bobbing_state != 0) { - s32 offset = MYMAX(dtime * m_view_bobbing_speed * 0.035 * BOBFRAMES, 1); + //f32 offset = dtime * m_view_bobbing_speed * 0.035; + f32 offset = dtime * m_view_bobbing_speed * 0.030; if (m_view_bobbing_state == 2) { +#if 0 // Animation is getting turned off - s32 subanim = (m_view_bobbing_anim & (BOBFRAMES/2-1)); - if (subanim < BOBFRAMES/4) - offset = -1 * MYMIN(offset, subanim); + if (m_view_bobbing_anim < 0.5) + m_view_bobbing_anim -= offset; else - offset = MYMIN(offset, BOBFRAMES/2 - subanim); + m_view_bobbing_anim += offset; + if (m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1) + { + m_view_bobbing_anim = 0; + m_view_bobbing_state = 0; + } +#endif +#if 1 + // Animation is getting turned off + if(m_view_bobbing_anim < 0.25){ + m_view_bobbing_anim -= offset; + } else if(m_view_bobbing_anim > 0.75){ + m_view_bobbing_anim += offset; + } if(m_view_bobbing_anim < 0.5){ + m_view_bobbing_anim += offset; + if(m_view_bobbing_anim > 0.5) + m_view_bobbing_anim = 0.5; + } else { + m_view_bobbing_anim -= offset; + if(m_view_bobbing_anim < 0.5) + m_view_bobbing_anim = 0.5; + } + if(m_view_bobbing_anim <= 0 || m_view_bobbing_anim >= 1 || + fabs(m_view_bobbing_anim - 0.5) < 0.01) + { + m_view_bobbing_anim = 0; + m_view_bobbing_state = 0; + } +#endif + } + else + { + float was = m_view_bobbing_anim; + m_view_bobbing_anim = my_modf(m_view_bobbing_anim + offset); + bool step = (was == 0 || + (was < 0.5f && m_view_bobbing_anim >= 0.5f) || + (was > 0.5f && m_view_bobbing_anim <= 0.5f)); + if(step){ + MtEvent *e = new SimpleTriggerEvent("ViewBobbingStep"); + m_gamedef->event()->put(e); + } + } + } + + if (m_digging_button != -1) + { + f32 offset = dtime * 3.5; + float m_digging_anim_was = m_digging_anim; + m_digging_anim += offset; + if (m_digging_anim >= 1) + { + m_digging_anim = 0; + m_digging_button = -1; + } + float lim = 0.15; + if(m_digging_anim_was < lim && m_digging_anim >= lim) + { + if(m_digging_button == 0){ + MtEvent *e = new SimpleTriggerEvent("CameraPunchLeft"); + m_gamedef->event()->put(e); + } else if(m_digging_button == 1){ + MtEvent *e = new SimpleTriggerEvent("CameraPunchRight"); + m_gamedef->event()->put(e); + } } - m_view_bobbing_anim = (m_view_bobbing_anim + offset) & (BOBFRAMES-1); } } -void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize) +void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize, + f32 tool_reload_ratio) { + // Get player position + // Smooth the movement when walking up stairs + v3f old_player_position = m_playernode->getPosition(); + v3f player_position = player->getPosition(); + //if(player->touching_ground && player_position.Y > old_player_position.Y) + if(player->touching_ground && + player_position.Y > old_player_position.Y) + { + f32 oldy = old_player_position.Y; + f32 newy = player_position.Y; + f32 t = exp(-23*frametime); + player_position.Y = oldy * t + newy * (1-t); + } + // Set player node transformation - m_playernode->setPosition(player->getPosition()); + m_playernode->setPosition(player_position); m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0)); m_playernode->updateAbsolutePosition(); + //Get camera tilt timer (hurt animation) + float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75); + // Set head node transformation - v3f eye_offset = player->getEyePosition() - player->getPosition(); - m_headnode->setPosition(eye_offset); - m_headnode->setRotation(v3f(player->getPitch(), 0, 0)); + m_headnode->setPosition(player->getEyeOffset()+v3f(0,cameratilt*-player->hurt_tilt_strength,0)); + m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength)); m_headnode->updateAbsolutePosition(); // Compute relative camera position and target @@ -127,46 +246,119 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize) v3f rel_cam_target = v3f(0,0,1); v3f rel_cam_up = v3f(0,1,0); - s32 bobframe = m_view_bobbing_anim & (BOBFRAMES/2-1); - if (bobframe != 0) + if (m_view_bobbing_anim != 0) { - f32 bobfrac = (f32) bobframe / (BOBFRAMES/2); - f32 bobdir = (m_view_bobbing_anim < (BOBFRAMES/2)) ? 1.0 : -1.0; + f32 bobfrac = my_modf(m_view_bobbing_anim * 2); + f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0; + #if 1 f32 bobknob = 1.2; - f32 bobtmp = sin(pow(bobfrac, bobknob) * PI); + f32 bobtmp = sin(pow(bobfrac, bobknob) * M_PI); + //f32 bobtmp2 = cos(pow(bobfrac, bobknob) * M_PI); v3f bobvec = v3f( - 0.01 * bobdir * sin(bobfrac * PI), - 0.005 * bobtmp * bobtmp, + 0.3 * bobdir * sin(bobfrac * M_PI), + -0.28 * bobtmp * bobtmp, 0.); - rel_cam_pos += bobvec * 3.; - rel_cam_target += bobvec * 4.5; + //rel_cam_pos += 0.2 * bobvec; + //rel_cam_target += 0.03 * bobvec; + //rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * M_PI); + float f = 1.0; + f *= g_settings->getFloat("view_bobbing_amount"); + rel_cam_pos += bobvec * f; + //rel_cam_target += 0.995 * bobvec * f; + rel_cam_target += bobvec * f; + rel_cam_target.Z -= 0.005 * bobvec.Z * f; + //rel_cam_target.X -= 0.005 * bobvec.X * f; + //rel_cam_target.Y -= 0.005 * bobvec.Y * f; + rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * M_PI * f); + #else + f32 angle_deg = 1 * bobdir * sin(bobfrac * M_PI); + f32 angle_rad = angle_deg * M_PI / 180; + f32 r = 0.05; + v3f off = v3f( + r * sin(angle_rad), + r * (cos(angle_rad) - 1), + 0); + rel_cam_pos += off; + //rel_cam_target += off; + rel_cam_up.rotateXYBy(angle_deg); + #endif + } // Compute absolute camera position and target m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos); - m_headnode->getAbsoluteTransformation().transformVect(m_camera_direction, rel_cam_target); - m_camera_direction -= m_camera_position; + m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos); v3f abs_cam_up; - m_headnode->getAbsoluteTransformation().transformVect(abs_cam_up, rel_cam_pos + rel_cam_up); - abs_cam_up -= m_camera_position; + m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up); // Set camera node transformation m_cameranode->setPosition(m_camera_position); m_cameranode->setUpVector(abs_cam_up); - m_cameranode->setTarget(m_camera_position + m_camera_direction); + // *100.0 helps in large map coordinates + m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction); + + // Get FOV setting + f32 fov_degrees = g_settings->getFloat("fov"); + fov_degrees = MYMAX(fov_degrees, 10.0); + fov_degrees = MYMIN(fov_degrees, 170.0); - // FOV and and aspect ratio + // FOV and aspect ratio m_aspect = (f32)screensize.X / (f32) screensize.Y; + m_fov_y = 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))); + // WTF is this? It can't be right m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y)); m_cameranode->setAspectRatio(m_aspect); m_cameranode->setFOV(m_fov_y); - // Just so big a value that everything rendered is visible - // Some more allowance that m_viewing_range_max * BS because of active objects etc. - m_cameranode->setFarValue(m_viewing_range_max * BS * 10); + + // Position the wielded item + //v3f wield_position = v3f(45, -35, 65); + v3f wield_position = v3f(55, -35, 65); + //v3f wield_rotation = v3f(-100, 120, -100); + v3f wield_rotation = v3f(-100, 120, -100); + if(m_digging_anim < 0.05 || m_digging_anim > 0.5){ + f32 frac = 1.0; + if(m_digging_anim > 0.5) + frac = 2.0 * (m_digging_anim - 0.5); + // This value starts from 1 and settles to 0 + f32 ratiothing = pow((1.0f - tool_reload_ratio), 0.5f); + //f32 ratiothing2 = pow(ratiothing, 0.5f); + f32 ratiothing2 = (easeCurve(ratiothing*0.5))*2.0; + wield_position.Y -= frac * 25.0 * pow(ratiothing2, 1.7f); + //wield_position.Z += frac * 5.0 * ratiothing2; + wield_position.X -= frac * 35.0 * pow(ratiothing2, 1.1f); + wield_rotation.Y += frac * 70.0 * pow(ratiothing2, 1.4f); + //wield_rotation.X -= frac * 15.0 * pow(ratiothing2, 1.4f); + //wield_rotation.Z += frac * 15.0 * pow(ratiothing2, 1.0f); + } + if (m_digging_button != -1) + { + f32 digfrac = m_digging_anim; + wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI); + wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI); + wield_position.Z += 25 * 0.5; + + // Euler angles are PURE EVIL, so why not use quaternions? + core::quaternion quat_begin(wield_rotation * core::DEGTORAD); + core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD); + core::quaternion quat_slerp; + quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI)); + quat_slerp.toEuler(wield_rotation); + wield_rotation *= core::RADTODEG; + } + else { + f32 bobfrac = my_modf(m_view_bobbing_anim); + wield_position.X -= sin(bobfrac*M_PI*2.0) * 3.0; + wield_position.Y += sin(my_modf(bobfrac*2.0)*M_PI) * 3.0; + } + m_wieldnode->setPosition(wield_position); + m_wieldnode->setRotation(wield_rotation); + m_wieldlight = player->light; // Render distance feedback loop updateViewingRange(frametime); @@ -177,8 +369,9 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize) v3f speed = player->getSpeed(); if ((hypot(speed.X, speed.Z) > BS) && (player->touching_ground) && - (g_settings.getBool("view_bobbing") == true) && - (g_settings.getBool("free_move") == false)) + (g_settings->getBool("view_bobbing") == true) && + (g_settings->getBool("free_move") == false || + !m_gamedef->checkLocalPrivilege("fly"))) { // Start animation m_view_bobbing_state = 1; @@ -188,12 +381,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize) { // Stop animation m_view_bobbing_state = 2; - m_view_bobbing_speed = 100; - } - else if (m_view_bobbing_state == 2 && bobframe == 0) - { - // Stop animation completed - m_view_bobbing_state = 0; + m_view_bobbing_speed = 60; } } @@ -221,8 +409,33 @@ void Camera::updateViewingRange(f32 frametime_in) <getS16("viewing_range_nodes_min"); + viewing_range_min = MYMAX(5.0, viewing_range_min); + + f32 viewing_range_max = g_settings->getS16("viewing_range_nodes_max"); + viewing_range_max = MYMAX(viewing_range_min, viewing_range_max); + + // Immediately apply hard limits + if(m_draw_control.wanted_range < viewing_range_min) + m_draw_control.wanted_range = viewing_range_min; + if(m_draw_control.wanted_range > viewing_range_max) + m_draw_control.wanted_range = viewing_range_max; + + // Just so big a value that everything rendered is visible + // Some more allowance than viewing_range_max * BS because of clouds, + // active objects, etc. + if(viewing_range_max < 200*BS) + m_cameranode->setFarValue(200 * BS * 10); + else + m_cameranode->setFarValue(viewing_range_max * BS * 10); + + f32 wanted_fps = g_settings->getFloat("wanted_fps"); + wanted_fps = MYMAX(wanted_fps, 1.0); + f32 wanted_frametime = 1.0 / wanted_fps; + + m_draw_control.wanted_min_range = viewing_range_min; + m_draw_control.wanted_max_blocks = (2.0*m_draw_control.blocks_would_have_drawn)+1; if (m_draw_control.wanted_max_blocks < 10) m_draw_control.wanted_max_blocks = 10; @@ -240,11 +453,13 @@ void Camera::updateViewingRange(f32 frametime_in) m_added_frametime = 0.0; m_added_frames = 0; - f32 wanted_frametime_change = m_wanted_frametime - frametime; + f32 wanted_frametime_change = wanted_frametime - frametime; //dstream<<"wanted_frametime_change="<idef(); + scene::IMesh *wield_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef); + if(wield_mesh) + { + m_wieldnode->setMesh(wield_mesh); + m_wieldnode->setVisible(true); + } + else + { + m_wieldnode->setVisible(false); + } } +void Camera::drawWieldedTool() +{ + // Set vertex colors of wield mesh according to light level + u8 li = m_wieldlight; + video::SColor color(255,li,li,li); + setMeshColor(m_wieldnode->getMesh(), color); + + // Clear Z buffer + m_wieldmgr->getVideoDriver()->clearZBuffer(); + + // Draw the wielded node (in a separate scene manager) + scene::ICameraSceneNode* cam = m_wieldmgr->getActiveCamera(); + cam->setAspectRatio(m_cameranode->getAspectRatio()); + cam->setFOV(72.0*M_PI/180.0); + cam->setNearValue(0.1); + cam->setFarValue(100); + m_wieldmgr->drawAll(); +}