From baf7da9d4a7fc0566840b159903999d76d99a228 Mon Sep 17 00:00:00 2001 From: Kahrl Date: Thu, 8 Sep 2011 01:08:47 +0200 Subject: [PATCH] Collected and moved existing camera infrastructure from game.cpp to camera.cpp and camera.h. Introduced configuration settings 'fov' which chooses the camera's (vertical) field of view and 'view_bobbing' which currently does nothing. Other code refactored to not expect the FOV to be a build time constant. --- src/CMakeLists.txt | 1 + src/camera.cpp | 243 ++++++++++++++++++++++++++++++++++++++++ src/camera.h | 141 +++++++++++++++++++++++ src/client.cpp | 14 +-- src/client.h | 4 +- src/constants.h | 3 - src/defaultsettings.cpp | 2 + src/game.cpp | 205 ++++----------------------------- src/map.cpp | 7 +- src/map.h | 4 +- src/server.cpp | 2 +- src/utility.cpp | 7 +- src/utility.h | 4 +- 13 files changed, 428 insertions(+), 209 deletions(-) create mode 100644 src/camera.cpp create mode 100644 src/camera.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c3b096..80ee0fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -142,6 +142,7 @@ set(minetest_SRCS mapblock_mesh.cpp farmesh.cpp keycode.cpp + camera.cpp clouds.cpp clientobject.cpp guiMainMenu.cpp diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..30df439 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,243 @@ +/* +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 +(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. + +You should have received a copy of the GNU 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. +*/ + +#include "camera.h" +#include "debug.h" +#include "main.h" // for g_settings +#include "map.h" +#include "player.h" +#include "utility.h" +#include + +Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control): + m_smgr(smgr), + m_playernode(NULL), + m_cameranode(NULL), + m_draw_control(draw_control), + m_viewing_range_min(5.0), + m_viewing_range_max(5.0), + + m_camera_position(0,0,0), + m_camera_direction(0,0,0), + + m_aspect(1.0), + 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), + m_frametime_old(0), + m_frametime_counter(0), + m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range + + m_view_bobbing_anim(0), + m_view_bobbing_anim_left(0) +{ + dstream<<__FUNCTION_NAME<addEmptySceneNode(smgr->getRootSceneNode()); + m_cameranode = smgr->addCameraSceneNode(m_playernode); + + updateSettings(); +} + +Camera::~Camera() +{ +} + +void Camera::step(f32 dtime) +{ +} + +void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize) +{ + if (m_playernode == NULL || m_cameranode == NULL) + return; + + // FOV and and aspect ratio + m_aspect = (f32)screensize.X / (f32) screensize.Y; + 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); + + m_camera_position = player->getEyePosition(); // TODO bobbing + m_cameranode->setPosition(m_camera_position); + + m_camera_direction = v3f(0,0,1); + m_camera_direction.rotateYZBy(player->getPitch()); + m_camera_direction.rotateXZBy(player->getYaw()); + // *100.0 helps in large map coordinates + m_cameranode->setTarget(m_camera_position + m_camera_direction * 100.0); + + // Render distance feedback loop + updateViewingRange(frametime); + + // Check if view bobbing is active + v3f speed = player->getSpeed(); + f32 epsilon = BS / 1000.0; + if (speed.X * speed.X + speed.Z * speed.Z > epsilon*epsilon && + speed.Y < epsilon && + g_settings.getBool("view_bobbing") == true && + g_settings.getBool("free_move") == false) + { + // The player seems to be walking on solid ground. + // Enable view bobbing. + //dstream << "View bobbing active" << std::endl; + } + else + { + //dstream << "View bobbing inactive" << std::endl; + } +} + +void Camera::updateViewingRange(f32 frametime_in) +{ + if (m_draw_control.range_all) + return; + + m_added_frametime += frametime_in; + m_added_frames += 1; + + // Actually this counter kind of sucks because frametime is busytime + m_frametime_counter -= frametime_in; + if (m_frametime_counter > 0) + return; + m_frametime_counter = 0.2; + + dstream<<__FUNCTION_NAME + <<": Collected "< + +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 +(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. + +You should have received a copy of the GNU 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. +*/ + +#ifndef CAMERA_HEADER +#define CAMERA_HEADER + +#include "common_irrlicht.h" +#include "utility.h" + +class LocalPlayer; +class MapDrawControl; + +/* + Client camera class, manages the player and camera scene nodes, the viewing distance + and performs view bobbing etc. +*/ +class Camera +{ +public: + Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control); + ~Camera(); + + // Get player scene node. + // This node is positioned at the player's torso (without any view bobbing), + // as given by Player::m_position, Player::m_pitch and Player::m_yaw. + // Things like wielded tools should be positioned relative to this node. + inline scene::ISceneNode* getPlayerNode() const + { + return m_playernode; + } + + // Get camera scene node. + // The camera node is a child of the player node. + // It has the eye transformation and view bobbing applied. + inline scene::ICameraSceneNode* getCameraNode() const + { + return m_cameranode; + } + + // Get the camera position (in absolute scene coordinates). + // This has view bobbing applied. + inline v3f getPosition() const + { + return m_camera_position; + } + + // Get the camera direction (in absolute camera coordinates). + // This has view bobbing applied. + inline v3f getDirection() const + { + return m_camera_direction; + } + + // Horizontal field of view + inline f32 getFovX() const + { + return m_fov_x; + } + + // Vertical field of view + inline f32 getFovY() const + { + return m_fov_y; + } + + // Get maximum of getFovX() and getFovY() + inline f32 getFovMax() const + { + return MYMAX(m_fov_x, m_fov_y); + } + + // Step the camera: updates the viewing range and view bobbing. + void step(f32 dtime); + + // Update the camera from the local player's position. + // frametime is used to adjust the viewing range. + void update(LocalPlayer* player, f32 frametime, v2u32 screensize); + + // Render distance feedback loop + void updateViewingRange(f32 frametime_in); + + // Update settings from g_settings + void updateSettings(); + +private: + // Scene manager and nodes + scene::ISceneManager* m_smgr; + scene::ISceneNode* m_playernode; + scene::ICameraSceneNode* m_cameranode; + + // draw control + MapDrawControl& m_draw_control; + + // viewing_range_min_nodes setting + f32 m_viewing_range_min; + // viewing_range_max_nodes setting + f32 m_viewing_range_max; + + // Absolute camera position + v3f m_camera_position; + // Absolute camera direction + v3f m_camera_direction; + + // Field of view and aspect ratio stuff + f32 m_aspect; + f32 m_fov_x; + f32 m_fov_y; + + // Stuff for viewing range calculations + f32 m_wanted_frametime; + f32 m_added_frametime; + s16 m_added_frames; + f32 m_range_old; + f32 m_frametime_old; + f32 m_frametime_counter; + f32 m_time_per_range; + + // View bobbing animation frame (0 <= m_view_bobbing < 0x10000) + u32 m_view_bobbing_anim; + // Number of frames to continue the view bobbing animation. + u32 m_view_bobbing_anim_left; +}; + +#endif + diff --git a/src/client.cpp b/src/client.cpp index df792d1..81dedd1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1978,9 +1978,9 @@ void Client::addNode(v3s16 p, MapNode n) } } -void Client::updateCamera(v3f pos, v3f dir) +void Client::updateCamera(v3f pos, v3f dir, f32 fov) { - m_env.getClientMap().updateCamera(pos, dir); + m_env.getClientMap().updateCamera(pos, dir, fov); } void Client::renderPostFx() @@ -2004,16 +2004,6 @@ LocalPlayer* Client::getLocalPlayer() return m_env.getLocalPlayer(); } -v3f Client::getPlayerPosition(v3f *eye_position) -{ - //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); - if (eye_position) - *eye_position = player->getEyePosition(); - return player->getPosition(); -} - void Client::setPlayerControl(PlayerControl &control) { //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out diff --git a/src/client.h b/src/client.h index 9c942ff..930987c 100644 --- a/src/client.h +++ b/src/client.h @@ -199,7 +199,7 @@ public: // locks envlock void addNode(v3s16 p, MapNode n); - void updateCamera(v3f pos, v3f dir); + void updateCamera(v3f pos, v3f dir, f32 fov); void renderPostFx(); @@ -210,8 +210,6 @@ public: LocalPlayer* getLocalPlayer(); - v3f getPlayerPosition(v3f *eye_position); - void setPlayerControl(PlayerControl &control); void selectPlayerItem(u16 item); diff --git a/src/constants.h b/src/constants.h index 1af5f1f..9ba10b5 100644 --- a/src/constants.h +++ b/src/constants.h @@ -44,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PI 3.14159 -// This is the same as in minecraft and everything else -#define FOV_ANGLE (PI/2.5) - // The absolute working limit is (2^15 - viewing_range). // I really don't want to make every algorithm to check if it's // going near the limit or not, so this is lower. diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 1e17f2f..163ed08 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -59,6 +59,8 @@ void set_default_settings() g_settings.setDefault("random_input", "false"); g_settings.setDefault("client_unload_unused_data_timeout", "600"); g_settings.setDefault("enable_fog", "true"); + g_settings.setDefault("fov", "72"); + g_settings.setDefault("view_bobbing", "true"); g_settings.setDefault("new_style_water", "false"); g_settings.setDefault("new_style_leaves", "true"); g_settings.setDefault("smooth_lighting", "true"); diff --git a/src/game.cpp b/src/game.cpp index afe1ce8..fc1486b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "materials.h" #include "config.h" #include "clouds.h" +#include "camera.h" #include "farmesh.h" #include "mapblock.h" @@ -49,8 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define FIELD_OF_VIEW_TEST 0 -MapDrawControl draw_control; - // Chat data struct ChatLine { @@ -143,144 +142,6 @@ struct TextDestSignNode : public TextDest Client *m_client; }; -/* - Render distance feedback loop -*/ -void updateViewingRange(f32 frametime_in, Client *client) -{ - if(draw_control.range_all == true) - return; - - static f32 added_frametime = 0; - static s16 added_frames = 0; - - added_frametime += frametime_in; - added_frames += 1; - - // Actually this counter kind of sucks because frametime is busytime - static f32 counter = 0; - counter -= frametime_in; - if(counter > 0) - return; - //counter = 0.1; - counter = 0.2; - - /*dstream<<__FUNCTION_NAME - <<": Collected "< range_max) - new_range = range_max; - - /*dstream<<"new_range="<addCameraSceneNode( - 0, // Camera parent - v3f(BS*100, BS*2, BS*100), // Look from - v3f(BS*100+1, BS*2, BS*100), // Look to - -1 // Camera ID - ); - - if(camera == NULL) + Camera camera(smgr, draw_control); + if (camera.getPlayerNode() == NULL) + { + error_message = L"Failed to create the player node"; + return; + } + if (camera.getCameraNode() == NULL) { error_message = L"Failed to create the camera node"; return; } - camera->setFOV(FOV_ANGLE); - - // Just so big a value that everything rendered is visible - camera->setFarValue(100000*BS); - f32 camera_yaw = 0; // "right/left" f32 camera_pitch = 0; // "up/down" @@ -1168,12 +1023,6 @@ void the_game( // Necessary for device->getTimer()->getTime() device->run(); - /* - Viewing range - */ - - updateViewingRange(busytime, &client); - /* FPS limiter */ @@ -1565,10 +1414,6 @@ void the_game( } } - // Get player position - v3f camera_position; - v3f player_position = client.getPlayerPosition(&camera_position); - //TimeTaker //timer2("//timer2"); /* @@ -1621,25 +1466,25 @@ void the_game( first_loop_after_window_activation = true; } - camera_yaw = wrapDegrees(camera_yaw); - camera_pitch = wrapDegrees(camera_pitch); - - v3f camera_direction = v3f(0,0,1); - camera_direction.rotateYZBy(camera_pitch); - camera_direction.rotateXZBy(camera_yaw); + LocalPlayer* player = client.getLocalPlayer(); + camera.update(player, busytime, screensize); + camera.step(dtime); - camera->setPosition(camera_position); - // *100.0 helps in large map coordinates - camera->setTarget(camera_position + camera_direction * 100.0); + v3f player_position = player->getPosition(); + v3f camera_position = camera.getPosition(); + v3f camera_direction = camera.getDirection(); + f32 camera_fov = camera.getFovMax(); - if(FIELD_OF_VIEW_TEST){ - client.updateCamera(v3f(0,0,0), v3f(0,0,1)); + if(FIELD_OF_VIEW_TEST) + { + client.updateCamera(v3f(0,0,0), v3f(0,0,1), M_PI); } - else{ - //TimeTaker timer("client.updateCamera"); - client.updateCamera(camera_position, camera_direction); + else + { + client.updateCamera(camera_position, + camera_direction, camera_fov); } - + //timer2.stop(); //TimeTaker //timer3("//timer3"); @@ -2010,8 +1855,6 @@ void the_game( Calculate stuff for drawing */ - camera->setAspectRatio((f32)screensize.X / (f32)screensize.Y); - u32 daynight_ratio = client.getDayNightRatio(); u8 l = decode_light((daynight_ratio * LIGHT_SUN) / 1000); video::SColor bgcolor = video::SColor( diff --git a/src/map.cpp b/src/map.cpp index 6f22498..b1908fe 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3604,7 +3604,8 @@ ClientMap::ClientMap( m_client(client), m_control(control), m_camera_position(0,0,0), - m_camera_direction(0,0,1) + m_camera_direction(0,0,1), + m_camera_fov(M_PI) { m_camera_mutex.Init(); assert(m_camera_mutex.IsInitialized()); @@ -3713,6 +3714,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) m_camera_mutex.Lock(); v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; + f32 camera_fov = m_camera_fov; m_camera_mutex.Unlock(); /* @@ -3805,7 +3807,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) float d = 0.0; if(isBlockInSight(block->getPos(), camera_position, - camera_direction, range, &d) == false) + camera_direction, camera_fov, + range, &d) == false) { continue; } diff --git a/src/map.h b/src/map.h index 5bea4a1..cb649ad 100644 --- a/src/map.h +++ b/src/map.h @@ -518,11 +518,12 @@ public: ISceneNode::drop(); } - void updateCamera(v3f pos, v3f dir) + void updateCamera(v3f pos, v3f dir, f32 fov) { JMutexAutoLock lock(m_camera_mutex); m_camera_position = pos; m_camera_direction = dir; + m_camera_fov = fov; } /* @@ -603,6 +604,7 @@ private: v3f m_camera_position; v3f m_camera_direction; + f32 m_camera_fov; JMutex m_camera_mutex; core::map m_last_drawn_sectors; diff --git a/src/server.cpp b/src/server.cpp index 14d8942..fd93d75 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -584,7 +584,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, Don't generate or send if not in sight */ - if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false) + if(isBlockInSight(p, camera_pos, camera_dir, M_PI, 10000*BS) == false) { continue; } diff --git a/src/utility.cpp b/src/utility.cpp index 0721100..9c1edc8 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -162,8 +162,8 @@ void mysrand(unsigned seed) camera_dir: an unit vector pointing to camera direction range: viewing range */ -bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range, - f32 *distance_ptr) +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, + f32 camera_fov, f32 range, f32 *distance_ptr) { v3s16 blockpos_nodes = blockpos_b * MAP_BLOCKSIZE; @@ -211,8 +211,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range, cosangle += block_max_radius / dforward; // If block is not in the field of view, skip it - //if(cosangle < cos(FOV_ANGLE/2)) - if(cosangle < cos(FOV_ANGLE/2. * 4./3.)) + if(cosangle < cos(camera_fov / 2)) return false; } diff --git a/src/utility.h b/src/utility.h index ea7c118..d331baf 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1765,8 +1765,8 @@ inline int myrand_range(int min, int max) Miscellaneous functions */ -bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range, - f32 *distance_ptr=NULL); +bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, + f32 camera_fov, f32 range, f32 *distance_ptr=NULL); /* Queue with unique values with fast checking of value existence