summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/camera.cpp291
-rw-r--r--src/camera.h142
-rw-r--r--src/client.cpp22
-rw-r--r--src/client.h20
-rw-r--r--src/constants.h3
-rw-r--r--src/content_mapnode.cpp9
-rw-r--r--src/defaultsettings.cpp2
-rw-r--r--src/environment.cpp23
-rw-r--r--src/environment.h3
-rw-r--r--src/game.cpp228
-rw-r--r--src/map.cpp36
-rw-r--r--src/map.h6
-rw-r--r--src/mapnode.h3
-rw-r--r--src/server.cpp2
-rw-r--r--src/tile.cpp12
-rw-r--r--src/utility.cpp7
-rw-r--r--src/utility.h4
18 files changed, 550 insertions, 264 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9c3b0960a..80ee0fc64 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 000000000..7c3dfda3c
--- /dev/null
+++ b/src/camera.cpp
@@ -0,0 +1,291 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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 <cmath>
+
+const s32 BOBFRAMES = 0x1000000; // must be a power of two
+
+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_state(0)
+{
+ //dstream<<__FUNCTION_NAME<<std::endl;
+
+ // 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());
+ m_cameranode = smgr->addCameraSceneNode(smgr->getRootSceneNode());
+ m_cameranode->bindTargetAndRotation(true);
+
+ updateSettings();
+}
+
+Camera::~Camera()
+{
+}
+
+void Camera::step(f32 dtime)
+{
+ if (m_view_bobbing_state != 0)
+ {
+ s32 offset = MYMAX(dtime * BOBFRAMES, 1);
+ if (m_view_bobbing_state == 2)
+ {
+ // Animation is getting turned off
+ s32 subanim = (m_view_bobbing_anim & (BOBFRAMES/2-1));
+ if (subanim < BOBFRAMES/4)
+ offset = -1 * MYMIN(offset, subanim);
+ else
+ offset = MYMIN(offset, BOBFRAMES/2 - subanim);
+ }
+ m_view_bobbing_anim = (m_view_bobbing_anim + offset) & (BOBFRAMES-1);
+ }
+}
+
+void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
+{
+ if (m_playernode == NULL || m_cameranode == NULL)
+ return;
+
+ // Set player node transformation
+ m_playernode->setPosition(player->getPosition());
+ //m_playernode->setRotation(v3f(player->getPitch(), -1 * player->getYaw(), 0));
+ m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
+ m_playernode->updateAbsolutePosition();
+
+ // Compute relative camera position and target
+ v3f relative_cam_pos = player->getEyePosition() - player->getPosition();
+ v3f relative_cam_target = v3f(0,0,1);
+ relative_cam_target.rotateYZBy(player->getPitch());
+ relative_cam_target += relative_cam_pos;
+
+ if ((m_view_bobbing_anim & (BOBFRAMES/2-1)) != 0)
+ {
+ f32 bobamount = cos(player->getPitch() * M_PI / 180);
+ bobamount = 2 * MYMIN(bobamount, 0.5);
+
+ f32 bobangle = m_view_bobbing_anim * 2 * M_PI / BOBFRAMES;
+ f32 bobangle_s = sin(bobangle);
+ f32 bobangle_c = cos(bobangle);
+ f32 bobwidth = 0.02 * bobamount / (bobangle_c * bobangle_c + 1);
+ f32 bobheight = 1.5 * bobwidth;
+
+ relative_cam_pos.X += bobwidth * bobangle_s;
+ relative_cam_pos.Y += bobheight * bobangle_s * bobangle_c;
+ }
+
+ // Compute absolute camera position and target
+ m_playernode->getAbsoluteTransformation().transformVect(m_camera_position, relative_cam_pos);
+ m_playernode->getAbsoluteTransformation().transformVect(m_camera_direction, relative_cam_target);
+ m_camera_direction -= m_camera_position;
+
+ // Set camera node transformation
+ m_cameranode->setPosition(m_camera_position);
+ // *100.0 helps in large map coordinates
+ m_cameranode->setTarget(m_camera_position + 100.0 * m_camera_direction);
+
+ // 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);
+
+ // Render distance feedback loop
+ updateViewingRange(frametime);
+
+ // If the player seems to be walking on solid ground,
+ // view bobbing is enabled and free_move is off,
+ // start (or continue) the view bobbing animation.
+ v3f speed = player->getSpeed();
+ //dstream<<"speed: ("<<speed.X<<","<<speed.Y<<","<<speed.Z<<")"<<std::endl;
+ if ((hypot(speed.X, speed.Z) > BS) &&
+ (fabs(speed.Y) < BS/10) &&
+ (g_settings.getBool("view_bobbing") == true) &&
+ (g_settings.getBool("free_move") == false))
+ {
+ // Start animation
+ m_view_bobbing_state = 1;
+ }
+ else if (m_view_bobbing_state == 1)
+ {
+ // Stop animation
+ m_view_bobbing_state = 2;
+ }
+}
+
+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 "<<m_added_frames<<" frames, total of "
+ <<m_added_frametime<<"s."<<std::endl;
+
+ dstream<<"m_draw_control.blocks_drawn="
+ <<m_draw_control.blocks_drawn
+ <<", m_draw_control.blocks_would_have_drawn="
+ <<m_draw_control.blocks_would_have_drawn
+ <<std::endl;*/
+
+ m_draw_control.wanted_min_range = m_viewing_range_min;
+ m_draw_control.wanted_max_blocks = (1.5*m_draw_control.blocks_would_have_drawn)+1;
+ if (m_draw_control.wanted_max_blocks < 10)
+ m_draw_control.wanted_max_blocks = 10;
+
+ f32 block_draw_ratio = 1.0;
+ if (m_draw_control.blocks_would_have_drawn != 0)
+ {
+ block_draw_ratio = (f32)m_draw_control.blocks_drawn
+ / (f32)m_draw_control.blocks_would_have_drawn;
+ }
+
+ // Calculate the average frametime in the case that all wanted
+ // blocks had been drawn
+ f32 frametime = m_added_frametime / m_added_frames / block_draw_ratio;
+
+ m_added_frametime = 0.0;
+ m_added_frames = 0;
+
+ f32 wanted_frametime_change = m_wanted_frametime - frametime;
+ //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
+
+ // If needed frametime change is small, just return
+ if (fabs(wanted_frametime_change) < m_wanted_frametime*0.4)
+ {
+ //dstream<<"ignoring small wanted_frametime_change"<<std::endl;
+ return;
+ }
+
+ f32 range = m_draw_control.wanted_range;
+ f32 new_range = range;
+
+ f32 d_range = range - m_range_old;
+ f32 d_frametime = frametime - m_frametime_old;
+ if (d_range != 0)
+ {
+ m_time_per_range = d_frametime / d_range;
+ }
+
+ // The minimum allowed calculated frametime-range derivative:
+ // Practically this sets the maximum speed of changing the range.
+ // The lower this value, the higher the maximum changing speed.
+ // A low value here results in wobbly range (0.001)
+ // A high value here results in slow changing range (0.0025)
+ // SUGG: This could be dynamically adjusted so that when
+ // the camera is turning, this is lower
+ //f32 min_time_per_range = 0.0015;
+ f32 min_time_per_range = 0.0010;
+ //f32 min_time_per_range = 0.05 / range;
+ if(m_time_per_range < min_time_per_range)
+ {
+ m_time_per_range = min_time_per_range;
+ //dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
+ }
+ else
+ {
+ //dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
+ }
+
+ f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
+ // Dampen the change a bit to kill oscillations
+ //wanted_range_change *= 0.9;
+ //wanted_range_change *= 0.75;
+ wanted_range_change *= 0.5;
+ //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
+
+ // If needed range change is very small, just return
+ if(fabs(wanted_range_change) < 0.001)
+ {
+ //dstream<<"ignoring small wanted_range_change"<<std::endl;
+ return;
+ }
+
+ new_range += wanted_range_change;
+
+ //f32 new_range_unclamped = new_range;
+ new_range = MYMAX(new_range, m_viewing_range_min);
+ new_range = MYMIN(new_range, m_viewing_range_max);
+ /*dstream<<"new_range="<<new_range_unclamped
+ <<", clamped to "<<new_range<<std::endl;*/
+
+ m_draw_control.wanted_range = new_range;
+
+ m_range_old = new_range;
+ m_frametime_old = frametime;
+}
+
+void Camera::updateSettings()
+{
+ m_viewing_range_min = g_settings.getS16("viewing_range_nodes_min");
+ m_viewing_range_min = MYMAX(5.0, m_viewing_range_min);
+
+ m_viewing_range_max = g_settings.getS16("viewing_range_nodes_max");
+ m_viewing_range_max = MYMAX(m_viewing_range_min, m_viewing_range_max);
+
+ f32 fov_degrees = g_settings.getFloat("fov");
+ fov_degrees = MYMAX(fov_degrees, 10.0);
+ fov_degrees = MYMIN(fov_degrees, 170.0);
+ m_fov_y = fov_degrees * M_PI / 180.0;
+
+ f32 wanted_fps = g_settings.getFloat("wanted_fps");
+ wanted_fps = MYMAX(wanted_fps, 1.0);
+ m_wanted_frametime = 1.0 / wanted_fps;
+}
+
diff --git a/src/camera.h b/src/camera.h
new file mode 100644
index 000000000..500168f3d
--- /dev/null
+++ b/src/camera.h
@@ -0,0 +1,142 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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. Yaw is applied but not pitch.
+ // Things like wielded tools should be positioned relative to this node.
+ inline scene::ISceneNode* getPlayerNode() const
+ {
+ return m_playernode;
+ }
+
+ // Get camera scene 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 < 0x1000000)
+ s32 m_view_bobbing_anim;
+ // If 0, view bobbing is off (e.g. player is standing).
+ // If 1, view bobbing is on (player is walking).
+ // If 2, view bobbing is getting switched off.
+ s32 m_view_bobbing_state;
+};
+
+#endif
+
diff --git a/src/client.cpp b/src/client.cpp
index d491f9d36..71a826a1f 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -189,8 +189,6 @@ Client::Client(
),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_device(device),
- camera_position(0,0,0),
- camera_direction(0,0,1),
m_server_ser_ver(SER_FMT_VER_INVALID),
m_inventory_updated(false),
m_time_of_day(0),
@@ -1980,11 +1978,14 @@ 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);
- camera_position = pos;
- camera_direction = dir;
+ m_env.getClientMap().updateCamera(pos, dir, fov);
+}
+
+void Client::renderPostFx()
+{
+ m_env.getClientMap().renderPostFx();
}
MapNode Client::getNode(v3s16 p)
@@ -1998,14 +1999,9 @@ NodeMetadata* Client::getNodeMetadata(v3s16 p)
return m_env.getMap().getNodeMetadata(p);
}
-v3f Client::getPlayerPosition(v3f *eye_position)
+LocalPlayer* Client::getLocalPlayer()
{
- //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();
+ return m_env.getLocalPlayer();
}
void Client::setPlayerWield(scene::ISceneNode *wield)
diff --git a/src/client.h b/src/client.h
index 398a3b849..e7a81a111 100644
--- a/src/client.h
+++ b/src/client.h
@@ -199,16 +199,16 @@ 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();
// Returns InvalidPositionException if not found
MapNode getNode(v3s16 p);
// Wrapper to Map
NodeMetadata* getNodeMetadata(v3s16 p);
- // Get the player position, and optionally put the
- // eye position in *eye_position
- v3f getPlayerPosition(v3f *eye_position=NULL);
+ LocalPlayer* getLocalPlayer();
void setPlayerWield(scene::ISceneNode *wield);
void setPlayerControl(PlayerControl &control);
@@ -303,15 +303,6 @@ public:
{
return m_access_denied_reason;
}
-
- /*
- This should only be used for calling the special drawing stuff in
- ClientEnvironment
- */
- ClientEnvironment * getEnv()
- {
- return &m_env;
- }
private:
@@ -343,9 +334,6 @@ private:
IrrlichtDevice *m_device;
- v3f camera_position;
- v3f camera_direction;
-
// Server serialization version
u8 m_server_ser_ver;
diff --git a/src/constants.h b/src/constants.h
index 1af5f1f1b..9ba10b51c 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/content_mapnode.cpp b/src/content_mapnode.cpp
index e18112ae4..89171755e 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -36,6 +36,11 @@ void setStoneLikeDiggingProperties(DiggingPropertiesList &list, float toughness)
void setDirtLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
void setWoodLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
+/*
+ A conversion table for backwards compatibility.
+ Maps <=v19 content types to current ones.
+ Should never be touched.
+*/
content_t trans_table_19[21][2] = {
{CONTENT_GRASS, 1},
{CONTENT_TREE, 4},
@@ -380,6 +385,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
+ f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
@@ -428,6 +434,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_WATERSOURCE;
f->liquid_viscosity = WATER_VISC;
f->vertex_alpha = WATER_ALPHA;
+ f->post_effect_color = video::SColor(64, 100, 100, 200);
if(f->special_material == NULL && g_texturesource)
{
// Flowing water material
@@ -460,6 +467,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
+ f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material
@@ -509,6 +517,7 @@ void content_mapnode_init()
f->liquid_alternative_source = CONTENT_LAVASOURCE;
f->liquid_viscosity = LAVA_VISC;
f->damage_per_second = 4*2;
+ f->post_effect_color = video::SColor(192, 255, 64, 0);
if(f->special_material == NULL && g_texturesource)
{
// Flowing lava material
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 1e17f2f3a..163ed0884 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/environment.cpp b/src/environment.cpp
index 8103b7110..80f41f9fd 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -1940,29 +1940,6 @@ ClientEnvEvent ClientEnvironment::getClientEvent()
return m_client_event_queue.pop_front();
}
-void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
-{
- /*LocalPlayer *player = getLocalPlayer();
- assert(player);
- v3f pos_f = player->getPosition() + v3f(0,BS*1.625,0);*/
- v3f pos_f = camera_pos;
- v3s16 p_nodes = floatToInt(pos_f, BS);
- MapNode n = m_map->getNodeNoEx(p_nodes);
- if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
- {
- v2u32 ss = driver->getScreenSize();
- core::rect<s32> rect(0,0, ss.X, ss.Y);
- driver->draw2DRectangle(video::SColor(64, 100, 100, 200), rect);
- }
- else if(content_features(n).solidness == 2 &&
- g_settings.getBool("free_move") == false)
- {
- v2u32 ss = driver->getScreenSize();
- core::rect<s32> rect(0,0, ss.X, ss.Y);
- driver->draw2DRectangle(video::SColor(255, 0, 0, 0), rect);
- }
-}
-
#endif // #ifndef SERVER
diff --git a/src/environment.h b/src/environment.h
index d9248d2ad..055e2b1f6 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -406,9 +406,6 @@ public:
// Get event from queue. CEE_NONE is returned if queue is empty.
ClientEnvEvent getClientEvent();
-
- // Post effects
- void drawPostFx(video::IVideoDriver* driver, v3f camera_pos);
private:
ClientMap *m_map;
diff --git a/src/game.cpp b/src/game.cpp
index 86f1939c3..af4886137 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
{
@@ -144,144 +143,6 @@ struct TextDestSignNode : public TextDest
};
/*
- 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 "<<added_frames<<" frames, total of "
- <<added_frametime<<"s."<<std::endl;*/
-
- /*dstream<<"draw_control.blocks_drawn="
- <<draw_control.blocks_drawn
- <<", draw_control.blocks_would_have_drawn="
- <<draw_control.blocks_would_have_drawn
- <<std::endl;*/
-
- float range_min = g_settings.getS16("viewing_range_nodes_min");
- float range_max = g_settings.getS16("viewing_range_nodes_max");
-
- // Limit minimum to keep the feedback loop stable
- if(range_min < 5)
- range_min = 5;
-
- draw_control.wanted_min_range = range_min;
- //draw_control.wanted_max_blocks = (1.5*draw_control.blocks_drawn)+1;
- draw_control.wanted_max_blocks = (1.5*draw_control.blocks_would_have_drawn)+1;
- if(draw_control.wanted_max_blocks < 10)
- draw_control.wanted_max_blocks = 10;
-
- float block_draw_ratio = 1.0;
- if(draw_control.blocks_would_have_drawn != 0)
- {
- block_draw_ratio = (float)draw_control.blocks_drawn
- / (float)draw_control.blocks_would_have_drawn;
- }
-
- // Calculate the average frametime in the case that all wanted
- // blocks had been drawn
- f32 frametime = added_frametime / added_frames / block_draw_ratio;
-
- added_frametime = 0.0;
- added_frames = 0;
-
- float wanted_fps = g_settings.getFloat("wanted_fps");
- float wanted_frametime = 1.0 / wanted_fps;
-
- f32 wanted_frametime_change = wanted_frametime - frametime;
- //dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
-
- // If needed frametime change is small, just return
- if(fabs(wanted_frametime_change) < wanted_frametime*0.4)
- {
- //dstream<<"ignoring small wanted_frametime_change"<<std::endl;
- return;
- }
-
- float range = draw_control.wanted_range;
- float new_range = range;
-
- static s16 range_old = 0;
- static f32 frametime_old = 0;
-
- float d_range = range - range_old;
- f32 d_frametime = frametime - frametime_old;
- // A sane default of 30ms per 50 nodes of range
- static f32 time_per_range = 30. / 50;
- if(d_range != 0)
- {
- time_per_range = d_frametime / d_range;
- }
-
- // The minimum allowed calculated frametime-range derivative:
- // Practically this sets the maximum speed of changing the range.
- // The lower this value, the higher the maximum changing speed.
- // A low value here results in wobbly range (0.001)
- // A high value here results in slow changing range (0.0025)
- // SUGG: This could be dynamically adjusted so that when
- // the camera is turning, this is lower
- //float min_time_per_range = 0.0015;
- float min_time_per_range = 0.0010;
- //float min_time_per_range = 0.05 / range;
- if(time_per_range < min_time_per_range)
- {
- time_per_range = min_time_per_range;
- //dstream<<"time_per_range="<<time_per_range<<" (min)"<<std::endl;
- }
- else
- {
- //dstream<<"time_per_range="<<time_per_range<<std::endl;
- }
-
- f32 wanted_range_change = wanted_frametime_change / time_per_range;
- // Dampen the change a bit to kill oscillations
- //wanted_range_change *= 0.9;
- //wanted_range_change *= 0.75;
- wanted_range_change *= 0.5;
- //dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
-
- // If needed range change is very small, just return
- if(fabs(wanted_range_change) < 0.001)
- {
- //dstream<<"ignoring small wanted_range_change"<<std::endl;
- return;
- }
-
- new_range += wanted_range_change;
-
- //float new_range_unclamped = new_range;
- if(new_range < range_min)
- new_range = range_min;
- if(new_range > range_max)
- new_range = range_max;
-
- /*dstream<<"new_range="<<new_range_unclamped
- <<", clamped to "<<new_range<<std::endl;*/
-
- draw_control.wanted_range = new_range;
-
- range_old = new_range;
- frametime_old = frametime;
-}
-
-/*
Hotbar draw routine
*/
void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
@@ -847,6 +708,7 @@ void the_game(
draw_load_screen(L"Creating client...", driver, font);
std::cout<<DTIME<<"Creating client"<<std::endl;
+ MapDrawControl draw_control;
Client client(device, playername.c_str(), password, draw_control);
draw_load_screen(L"Resolving address...", driver, font);
@@ -950,28 +812,18 @@ void the_game(
/*
Create the camera node
*/
-
- scene::ICameraSceneNode* camera = smgr->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
- );
-
- // Do this so children rotate accordingly (tool)
- camera->bindTargetAndRotation(true);
-
- 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"
@@ -979,7 +831,7 @@ void the_game(
Tool
*/
- v3f tool_wield_position(0.6, -0.6, 1.0);
+ v3f tool_wield_position(0.06*BS, 1.619*BS, 0.1*BS);
v3f tool_wield_rotation(-25, 180, -25);
float tool_wield_animation = 0.0;
scene::IMeshSceneNode *tool_wield;
@@ -1004,7 +856,7 @@ void the_game(
mesh->addMeshBuffer(buf);
buf->drop();
- tool_wield = smgr->addMeshSceneNode(mesh, camera);
+ tool_wield = smgr->addMeshSceneNode(mesh, camera.getPlayerNode());
mesh->drop();
}
tool_wield->setVisible(false);
@@ -1210,12 +1062,6 @@ void the_game(
device->run();
/*
- Viewing range
- */
-
- updateViewingRange(busytime, &client);
-
- /*
FPS limiter
*/
@@ -1606,10 +1452,6 @@ void the_game(
}
}
- // Get player position
- v3f camera_position;
- v3f player_position = client.getPlayerPosition(&camera_position);
-
//TimeTaker //timer2("//timer2");
/*
@@ -1662,25 +1504,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), camera_fov);
}
- 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");
@@ -2060,8 +1902,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(
@@ -2082,7 +1922,7 @@ void the_game(
update_skybox(driver, smgr, skybox, brightness);
/*
- Update coulds
+ Update clouds
*/
if(clouds)
{
@@ -2372,6 +2212,13 @@ void the_game(
}
/*
+ Post effects
+ */
+ {
+ client.renderPostFx();
+ }
+
+ /*
Frametime log
*/
if(g_settings.getBool("frametime_graph") == true)
@@ -2411,13 +2258,6 @@ void the_game(
guienv->drawAll();
/*
- Environment post fx
- */
- {
- client.getEnv()->drawPostFx(driver, camera_position);
- }
-
- /*
Draw hotbar
*/
{
diff --git a/src/map.cpp b/src/map.cpp
index 7de79c75d..b1908fe2e 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;
}
@@ -3925,6 +3928,35 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
<<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
}
+void ClientMap::renderPostFx()
+{
+ // Sadly ISceneManager has no "post effects" render pass, in that case we
+ // could just register for that and handle it in renderMap().
+
+ m_camera_mutex.Lock();
+ v3f camera_position = m_camera_position;
+ m_camera_mutex.Unlock();
+
+ MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
+
+ // - If the player is in a solid node, make everything black.
+ // - If the player is in liquid, draw a semi-transparent overlay.
+ ContentFeatures& features = content_features(n);
+ video::SColor post_effect_color = features.post_effect_color;
+ if(features.solidness == 2 && g_settings.getBool("free_move") == false)
+ {
+ post_effect_color = video::SColor(255, 0, 0, 0);
+ }
+ if (post_effect_color.getAlpha() != 0)
+ {
+ // Draw a full-screen rectangle
+ video::IVideoDriver* driver = SceneManager->getVideoDriver();
+ v2u32 ss = driver->getScreenSize();
+ core::rect<s32> rect(0,0, ss.X, ss.Y);
+ driver->draw2DRectangle(post_effect_color, rect);
+ }
+}
+
bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
core::map<v3s16, MapBlock*> *affected_blocks)
{
diff --git a/src/map.h b/src/map.h
index e0b67eb6e..cb649addd 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;
}
/*
@@ -552,6 +553,8 @@ public:
void renderMap(video::IVideoDriver* driver, s32 pass);
+ void renderPostFx();
+
/*
Methods for setting temporary modifications to nodes for
drawing.
@@ -601,6 +604,7 @@ private:
v3f m_camera_position;
v3f m_camera_direction;
+ f32 m_camera_fov;
JMutex m_camera_mutex;
core::map<v2s16, bool> m_last_drawn_sectors;
diff --git a/src/mapnode.h b/src/mapnode.h
index 3ad67aaf6..19dfb2802 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -160,6 +160,8 @@ struct ContentFeatures
u8 liquid_viscosity;
// Used currently for flowing liquids
u8 vertex_alpha;
+ // Post effect color, drawn when the camera is inside the node.
+ video::SColor post_effect_color;
// Special irrlicht material, used sometimes
video::SMaterial *special_material;
AtlasPointer *special_atlas;
@@ -197,6 +199,7 @@ struct ContentFeatures
liquid_alternative_source = CONTENT_IGNORE;
liquid_viscosity = 0;
vertex_alpha = 255;
+ post_effect_color = video::SColor(0, 0, 0, 0);
special_material = NULL;
special_atlas = NULL;
light_source = 0;
diff --git a/src/server.cpp b/src/server.cpp
index 14d8942cb..fd93d7523 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/tile.cpp b/src/tile.cpp
index d4244bd42..73f2a85ea 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -504,8 +504,16 @@ void TextureSource::buildMainAtlas()
}
/*
- A list of stuff to add. This should contain as much of the
- stuff shown in game as possible, to minimize texture changes.
+ A list of stuff to include in the texture atlas.
+
+ It is a single-dimensional texture atlas due to the need to tile
+ textures.
+
+ It should contain as much of the stuff shown in game as possible,
+ to minimize texture changes.
+
+ It fills up quickly, so do not add anything that isn't contained
+ in most MapBlocks. E.g. mese isn't suitable but stone is.
*/
core::array<std::string> sourcelist;
diff --git a/src/utility.cpp b/src/utility.cpp
index 0721100cb..9c1edc8a9 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 ea7c11846..d331bafbb 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