#include "profiler.h"
#include "util/numeric.h"
#include "util/mathconstants.h"
+#include "constants.h"
+
+#define CAMERA_OFFSET_STEP 200
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
IGameDef *gamedef):
m_camera_position(0,0,0),
m_camera_direction(0,0,0),
+ m_camera_offset(0,0,0),
m_aspect(1.0),
m_fov_x(1.0),
v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up);
+ // Update offset if too far away from the center of the map
+ m_camera_offset.X += CAMERA_OFFSET_STEP*
+ (((s16)(m_camera_position.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP);
+ m_camera_offset.Y += CAMERA_OFFSET_STEP*
+ (((s16)(m_camera_position.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP);
+ m_camera_offset.Z += CAMERA_OFFSET_STEP*
+ (((s16)(m_camera_position.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP);
+
// Set camera node transformation
- m_cameranode->setPosition(m_camera_position);
+ m_cameranode->setPosition(m_camera_position-intToFloat(m_camera_offset, BS));
m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates
- m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction);
+ m_cameranode->setTarget(m_camera_position-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction);
// Get FOV setting
f32 fov_degrees = g_settings->getFloat("fov");
{
return m_camera_direction;
}
+
+ // Get the camera offset
+ inline v3s16 getOffset() const
+ {
+ return m_camera_offset;
+ }
// Horizontal field of view
inline f32 getFovX() const
v3f m_camera_position;
// Absolute camera direction
v3f m_camera_direction;
+ // Camera offset
+ v3s16 m_camera_offset;
// Field of view and aspect ratio stuff
f32 m_aspect;
ScopeProfiler sp(g_profiler, "Client: Mesh making");
- MapBlockMesh *mesh_new = new MapBlockMesh(q->data);
+ MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
if(mesh_new->getMesh()->getMeshBufferCount() == 0)
{
delete mesh_new;
MutexedQueue<MeshUpdateResult> m_queue_out;
IGameDef *m_gamedef;
+
+ v3s16 m_camera_offset;
};
enum ClientEventType
// Including blocks at appropriate edges
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false);
void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false);
+
+ void updateCameraOffset(v3s16 camera_offset){ m_mesh_update_thread.m_camera_offset = camera_offset; }
// Get event from queue. CE_NONE is returned if queue is empty.
ClientEvent getClientEvent();
v3f camera_position = m_camera_position;
v3f camera_direction = m_camera_direction;
f32 camera_fov = m_camera_fov;
+ v3s16 camera_offset = m_camera_offset;
m_camera_mutex.Unlock();
// Use a higher fov to accomodate faster camera movements.
if not seen on display
*/
+ if (block->mesh != NULL)
+ block->mesh->updateCameraOffset(m_camera_offset);
+
float range = 100000 * BS;
if(m_control.range_all == false)
range = m_control.wanted_range * BS;
ISceneNode::drop();
}
- void updateCamera(v3f pos, v3f dir, f32 fov)
+ void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset)
{
JMutexAutoLock lock(m_camera_mutex);
m_camera_position = pos;
m_camera_direction = dir;
m_camera_fov = fov;
+ m_camera_offset = offset;
}
/*
v3f m_camera_position;
v3f m_camera_direction;
f32 m_camera_fov;
+ v3s16 m_camera_offset;
JMutex m_camera_mutex;
std::map<v3s16, MapBlock*> m_drawlist;
virtual bool isLocalPlayer(){return false;}
virtual void setAttachments(){}
virtual bool doShowSelectionBox(){return true;}
+ virtual void updateCameraOffset(v3s16 camera_offset){};
// Step object in time
virtual void step(float dtime, ClientEnvironment *env){}
scene::ISceneNode(parent, mgr, id),
m_seed(seed),
m_camera_pos(0,0),
- m_time(0)
+ m_time(0),
+ m_camera_offset(0,0,0)
{
m_material.setFlag(video::EMF_LIGHTING, false);
//m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
}
v3f pos(p0.X, m_cloud_y, p0.Y);
+ pos -= intToFloat(m_camera_offset, BS);
for(u16 i=0; i<4; i++)
v[i].Pos += pos;
void step(float dtime);
void update(v2f camera_p, video::SColorf color);
+
+ void updateCameraOffset(v3s16 camera_offset)
+ {
+ m_camera_offset = camera_offset;
+ }
private:
video::SMaterial m_material;
u32 m_seed;
v2f m_camera_pos;
float m_time;
+ v3s16 m_camera_offset;
};
if(getParent() != NULL)
return;
+ v3s16 camera_offset = m_env->getCameraOffset();
if(m_meshnode){
- m_meshnode->setPosition(pos_translator.vect_show);
+ m_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
v3f rot = m_meshnode->getRotation();
rot.Y = -m_yaw;
m_meshnode->setRotation(rot);
}
if(m_animated_meshnode){
- m_animated_meshnode->setPosition(pos_translator.vect_show);
+ m_animated_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
v3f rot = m_animated_meshnode->getRotation();
rot.Y = -m_yaw;
m_animated_meshnode->setRotation(rot);
}
if(m_spritenode){
- m_spritenode->setPosition(pos_translator.vect_show);
+ m_spritenode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS));
}
}
-
+
void step(float dtime, ClientEnvironment *env)
{
if(m_visuals_expired && m_smgr && m_irr){
{ m_player_names.push_back(name); }
void removePlayerName(std::string name)
{ m_player_names.remove(name); }
+ void updateCameraOffset(v3s16 camera_offset)
+ { m_camera_offset = camera_offset; }
+ v3s16 getCameraOffset()
+ { return m_camera_offset; }
private:
ClientMap *m_map;
IntervalLimiter m_drowning_interval;
IntervalLimiter m_breathing_interval;
std::list<std::string> m_player_names;
+ v3s16 m_camera_offset;
};
#endif
core::line3d<f32> shootline, f32 d,
bool liquids_pointable,
bool look_for_object,
+ v3s16 camera_offset,
std::vector<aabb3f> &hilightboxes,
ClientActiveObject *&selected_object)
{
v3f pos = selected_object->getPosition();
hilightboxes.push_back(aabb3f(
- selection_box->MinEdge + pos,
- selection_box->MaxEdge + pos));
+ selection_box->MinEdge + pos - intToFloat(camera_offset, BS),
+ selection_box->MaxEdge + pos - intToFloat(camera_offset, BS)));
}
mindistance = (selected_object->getPosition() - camera_position).getLength();
i2 != boxes.end(); i2++)
{
aabb3f box = *i2;
- box.MinEdge += npf + v3f(-d,-d,-d);
- box.MaxEdge += npf + v3f(d,d,d);
+ box.MinEdge += npf + v3f(-d,-d,-d) - intToFloat(camera_offset, BS);
+ box.MaxEdge += npf + v3f(d,d,d) - intToFloat(camera_offset, BS);
hilightboxes.push_back(box);
}
}
Update camera
*/
+ v3s16 old_camera_offset = camera.getOffset();
+
LocalPlayer* player = client.getEnv().getLocalPlayer();
float full_punch_interval = playeritem_toolcap.full_punch_interval;
float tool_reload_ratio = time_from_last_punch / full_punch_interval;
v3f camera_position = camera.getPosition();
v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax();
+ v3s16 camera_offset = camera.getOffset();
+
+ bool camera_offset_changed = (camera_offset != old_camera_offset);
if(!disable_camera_update){
client.getEnv().getClientMap().updateCamera(camera_position,
- camera_direction, camera_fov);
+ camera_direction, camera_fov, camera_offset);
+ if (camera_offset_changed){
+ client.updateCameraOffset(camera_offset);
+ client.getEnv().updateCameraOffset(camera_offset);
+ if (clouds)
+ clouds->updateCameraOffset(camera_offset);
+ }
}
// Update sound listener
&client, player_position, camera_direction,
camera_position, shootline, d,
playeritem_def.liquids_pointable, !ldown_for_dig,
+ camera_offset,
// output
hilightboxes,
selected_object);
Update particles
*/
- allparticles_step(dtime, client.getEnv());
+ allparticles_step(dtime);
allparticlespawners_step(dtime, client.getEnv());
/*
*/
update_draw_list_timer += dtime;
if(update_draw_list_timer >= 0.2 ||
- update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){
+ update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2 ||
+ camera_offset_changed){
update_draw_list_timer = 0;
client.getEnv().getClientMap().updateDrawList(driver);
update_draw_list_last_cam_dir = camera_direction;
MeshMakeData mesh_make_data(gamedef);
MapNode mesh_make_node(id, param1, 0);
mesh_make_data.fillSingleNode(&mesh_make_node);
- MapBlockMesh mapblock_mesh(&mesh_make_data);
+ MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
scene::IMesh *node_mesh = mapblock_mesh.getMesh();
assert(node_mesh);
video::SColor c(255, 255, 255, 255);
MapBlockMesh
*/
-MapBlockMesh::MapBlockMesh(MeshMakeData *data):
+MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
m_mesh(new scene::SMesh()),
m_gamedef(data->m_gamedef),
m_animation_force_timer(0), // force initial animation
&p.indices[0], p.indices.size());
}
+ m_camera_offset = camera_offset;
+
/*
Do some stuff to the mesh
*/
- translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
+ translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
if(m_mesh)
{
return true;
}
+void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
+{
+ if (camera_offset != m_camera_offset) {
+ translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
+ m_camera_offset = camera_offset;
+ }
+}
+
/*
MeshCollector
*/
{
public:
// Builds the mesh given
- MapBlockMesh(MeshMakeData *data);
+ MapBlockMesh(MeshMakeData *data, v3s16 camera_offset);
~MapBlockMesh();
// Main animation function, parameters:
if(m_animation_force_timer > 0)
m_animation_force_timer--;
}
+
+ void updateCameraOffset(v3s16 camera_offset);
private:
scene::SMesh *m_mesh;
u32 m_last_daynight_ratio;
// For each meshbuffer, maps vertex indices to (day,night) pairs
std::map<u32, std::map<u32, std::pair<u8, u8> > > m_daynight_diffs;
+
+ // Camera offset info -> do we have to translate the mesh?
+ v3s16 m_camera_offset;
};
{
// Misc
m_gamedef = gamedef;
+ m_env = &env;
// Texture
m_material.setFlag(video::EMF_LIGHTING, false);
this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting
- updateLight(env);
+ updateLight();
// Init model
updateVertices();
scene::EPT_TRIANGLES, video::EIT_16BIT);
}
-void Particle::step(float dtime, ClientEnvironment &env)
+void Particle::step(float dtime)
{
m_time += dtime;
if (m_collisiondetection)
v3f p_pos = m_pos*BS;
v3f p_velocity = m_velocity*BS;
v3f p_acceleration = m_acceleration*BS;
- collisionMoveSimple(&env, m_gamedef,
+ collisionMoveSimple(m_env, m_gamedef,
BS*0.5, box,
0, dtime,
p_pos, p_velocity, p_acceleration);
}
// Update lighting
- updateLight(env);
+ updateLight();
// Update model
updateVertices();
}
-void Particle::updateLight(ClientEnvironment &env)
+void Particle::updateLight()
{
u8 light = 0;
try{
floor(m_pos.Y+0.5),
floor(m_pos.Z+0.5)
);
- MapNode n = env.getClientMap().getNode(p);
- light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef());
+ MapNode n = m_env->getClientMap().getNode(p);
+ light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef());
}
catch(InvalidPositionException &e){
- light = blend_light(env.getDayNightRatio(), LIGHT_SUN, 0);
+ light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
}
m_light = decode_light(light);
}
m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
c, tx0, ty0);
+ v3s16 camera_offset = m_env->getCameraOffset();
for(u16 i=0; i<4; i++)
{
if (m_vertical) {
m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
}
m_box.addInternalPoint(m_vertices[i].Pos);
- m_vertices[i].Pos += m_pos*BS;
+ m_vertices[i].Pos += m_pos*BS - intToFloat(camera_offset, BS);
}
}
-
/*
Helpers
*/
-void allparticles_step (float dtime, ClientEnvironment &env)
+void allparticles_step (float dtime)
{
for(std::vector<Particle*>::iterator i = all_particles.begin();
i != all_particles.end();)
}
else
{
- (*i)->step(dtime, env);
+ (*i)->step(dtime);
i++;
}
}
virtual void OnRegisterSceneNode();
virtual void render();
- void step(float dtime, ClientEnvironment &env);
+ void step(float dtime);
bool get_expired ()
{ return m_expiration < m_time; }
private:
- void updateLight(ClientEnvironment &env);
+ void updateLight();
void updateVertices();
video::S3DVertex m_vertices[4];
float m_time;
float m_expiration;
+ ClientEnvironment *m_env;
IGameDef *m_gamedef;
core::aabbox3d<f32> m_box;
core::aabbox3d<f32> m_collisionbox;
u8 m_light;
bool m_collisiondetection;
bool m_vertical;
+ v3s16 m_camera_offset;
};
class ParticleSpawner
bool m_vertical;
};
-void allparticles_step (float dtime, ClientEnvironment &env);
+void allparticles_step (float dtime);
void allparticlespawners_step (float dtime, ClientEnvironment &env);
void delete_particlespawner (u32 id);