3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU 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.
22 #include "main.h" // for g_settings
28 Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
32 m_draw_control(draw_control),
33 m_viewing_range_min(5.0),
34 m_viewing_range_max(5.0),
36 m_camera_position(0,0,0),
37 m_camera_direction(0,0,0),
43 m_wanted_frametime(0.0),
48 m_frametime_counter(0),
49 m_time_per_range(30. / 50), // a sane default of 30ms per 50 nodes of range
51 m_view_bobbing_anim(0),
52 m_view_bobbing_anim_left(0)
54 dstream<<__FUNCTION_NAME<<std::endl;
56 m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
57 m_cameranode = smgr->addCameraSceneNode(m_playernode);
66 void Camera::step(f32 dtime)
70 void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
72 if (m_playernode == NULL || m_cameranode == NULL)
75 // FOV and and aspect ratio
76 m_aspect = (f32)screensize.X / (f32) screensize.Y;
77 m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
78 m_cameranode->setAspectRatio(m_aspect);
79 m_cameranode->setFOV(m_fov_y);
81 // Just so big a value that everything rendered is visible
82 // Some more allowance that m_viewing_range_max * BS because of active objects etc.
83 m_cameranode->setFarValue(m_viewing_range_max * BS * 10);
85 m_camera_position = player->getEyePosition(); // TODO bobbing
86 m_cameranode->setPosition(m_camera_position);
88 m_camera_direction = v3f(0,0,1);
89 m_camera_direction.rotateYZBy(player->getPitch());
90 m_camera_direction.rotateXZBy(player->getYaw());
91 // *100.0 helps in large map coordinates
92 m_cameranode->setTarget(m_camera_position + m_camera_direction * 100.0);
94 // Render distance feedback loop
95 updateViewingRange(frametime);
97 // Check if view bobbing is active
98 v3f speed = player->getSpeed();
99 f32 epsilon = BS / 1000.0;
100 if (speed.X * speed.X + speed.Z * speed.Z > epsilon*epsilon &&
102 g_settings.getBool("view_bobbing") == true &&
103 g_settings.getBool("free_move") == false)
105 // The player seems to be walking on solid ground.
106 // Enable view bobbing.
107 //dstream << "View bobbing active" << std::endl;
111 //dstream << "View bobbing inactive" << std::endl;
115 void Camera::updateViewingRange(f32 frametime_in)
117 if (m_draw_control.range_all)
120 m_added_frametime += frametime_in;
123 // Actually this counter kind of sucks because frametime is busytime
124 m_frametime_counter -= frametime_in;
125 if (m_frametime_counter > 0)
127 m_frametime_counter = 0.2;
129 dstream<<__FUNCTION_NAME
130 <<": Collected "<<m_added_frames<<" frames, total of "
131 <<m_added_frametime<<"s."<<std::endl;
133 dstream<<"m_draw_control.blocks_drawn="
134 <<m_draw_control.blocks_drawn
135 <<", m_draw_control.blocks_would_have_drawn="
136 <<m_draw_control.blocks_would_have_drawn
139 m_draw_control.wanted_min_range = m_viewing_range_min;
140 m_draw_control.wanted_max_blocks = (1.5*m_draw_control.blocks_would_have_drawn)+1;
141 if (m_draw_control.wanted_max_blocks < 10)
142 m_draw_control.wanted_max_blocks = 10;
144 f32 block_draw_ratio = 1.0;
145 if (m_draw_control.blocks_would_have_drawn != 0)
147 block_draw_ratio = (f32)m_draw_control.blocks_drawn
148 / (f32)m_draw_control.blocks_would_have_drawn;
151 // Calculate the average frametime in the case that all wanted
152 // blocks had been drawn
153 f32 frametime = m_added_frametime / m_added_frames / block_draw_ratio;
155 m_added_frametime = 0.0;
158 f32 wanted_frametime_change = m_wanted_frametime - frametime;
159 dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
161 // If needed frametime change is small, just return
162 if (fabs(wanted_frametime_change) < m_wanted_frametime*0.4)
164 dstream<<"ignoring small wanted_frametime_change"<<std::endl;
168 f32 range = m_draw_control.wanted_range;
169 f32 new_range = range;
171 f32 d_range = range - m_range_old;
172 f32 d_frametime = frametime - m_frametime_old;
175 m_time_per_range = d_frametime / d_range;
178 // The minimum allowed calculated frametime-range derivative:
179 // Practically this sets the maximum speed of changing the range.
180 // The lower this value, the higher the maximum changing speed.
181 // A low value here results in wobbly range (0.001)
182 // A high value here results in slow changing range (0.0025)
183 // SUGG: This could be dynamically adjusted so that when
184 // the camera is turning, this is lower
185 //f32 min_time_per_range = 0.0015;
186 f32 min_time_per_range = 0.0010;
187 //f32 min_time_per_range = 0.05 / range;
188 if(m_time_per_range < min_time_per_range)
190 m_time_per_range = min_time_per_range;
191 dstream<<"m_time_per_range="<<m_time_per_range<<" (min)"<<std::endl;
195 dstream<<"m_time_per_range="<<m_time_per_range<<std::endl;
198 f32 wanted_range_change = wanted_frametime_change / m_time_per_range;
199 // Dampen the change a bit to kill oscillations
200 //wanted_range_change *= 0.9;
201 //wanted_range_change *= 0.75;
202 wanted_range_change *= 0.5;
203 dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
205 // If needed range change is very small, just return
206 if(fabs(wanted_range_change) < 0.001)
208 dstream<<"ignoring small wanted_range_change"<<std::endl;
212 new_range += wanted_range_change;
214 f32 new_range_unclamped = new_range;
215 new_range = MYMAX(new_range, m_viewing_range_min);
216 new_range = MYMIN(new_range, m_viewing_range_max);
217 dstream<<"new_range="<<new_range_unclamped
218 <<", clamped to "<<new_range<<std::endl;
220 m_draw_control.wanted_range = new_range;
222 m_range_old = new_range;
223 m_frametime_old = frametime;
226 void Camera::updateSettings()
228 m_viewing_range_min = g_settings.getS16("viewing_range_nodes_min");
229 m_viewing_range_min = MYMAX(5.0, m_viewing_range_min);
231 m_viewing_range_max = g_settings.getS16("viewing_range_nodes_max");
232 m_viewing_range_max = MYMAX(m_viewing_range_min, m_viewing_range_max);
234 f32 fov_degrees = g_settings.getFloat("fov");
235 fov_degrees = MYMAX(fov_degrees, 10.0);
236 fov_degrees = MYMIN(fov_degrees, 170.0);
237 m_fov_y = fov_degrees * M_PI / 180.0;
239 f32 wanted_fps = g_settings.getFloat("wanted_fps");
240 wanted_fps = MYMAX(wanted_fps, 1.0);
241 m_wanted_frametime = 1.0 / wanted_fps;