Fix rendering glitches when far from the center of the map
authorNovatux <nathanael.courant@laposte.net>
Sun, 26 Jan 2014 10:40:21 +0000 (11:40 +0100)
committerNovatux <nathanael.courant@laposte.net>
Tue, 4 Mar 2014 19:12:10 +0000 (20:12 +0100)
17 files changed:
src/camera.cpp
src/camera.h
src/client.cpp
src/client.h
src/clientmap.cpp
src/clientmap.h
src/clientobject.h
src/clouds.cpp
src/clouds.h
src/content_cao.cpp
src/environment.h
src/game.cpp
src/itemdef.cpp
src/mapblock_mesh.cpp
src/mapblock_mesh.h
src/particles.cpp
src/particles.h

index 937ba38af2ac065ed053b4d9bc580ab56278a7a8..783ae84c475eb1b973a5c830787b7507103291ac 100644 (file)
@@ -36,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #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):
@@ -53,6 +56,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
 
        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),
@@ -348,11 +352,19 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
        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");
index aa9139148e60b6d8cf5ad4e624b3accda12fcceb..df40e3b9f02229503ebcf6a987b00b3729c5ad65 100644 (file)
@@ -79,6 +79,12 @@ public:
        {
                return m_camera_direction;
        }
+       
+       // Get the camera offset
+       inline v3s16 getOffset() const
+       {
+               return m_camera_offset;
+       }
 
        // Horizontal field of view
        inline f32 getFovX() const
@@ -144,6 +150,8 @@ private:
        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;
index fb3f9b861d7733d574e7777aafa54e41e86aea5a..4d6c0cb9907337c6dc56d95e4935d64636640fa4 100644 (file)
@@ -179,7 +179,7 @@ void * MeshUpdateThread::Thread()
 
                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;
index 52d285ac41626a7be2ee8a32dfc9ae3624f26338..01cd3a01c6904dbdcf2d2ebed09a26026696980a 100644 (file)
@@ -119,6 +119,8 @@ public:
        MutexedQueue<MeshUpdateResult> m_queue_out;
 
        IGameDef *m_gamedef;
+       
+       v3s16 m_camera_offset;
 };
 
 enum ClientEventType
@@ -406,6 +408,8 @@ public:
        // 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();
index df6c2822c209ce4467d15ad862b2ce7f0129037d..20a59f266a4d12328eec5403496c0ef2b8dd252d 100644 (file)
@@ -175,6 +175,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
        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.
@@ -250,6 +251,9 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                                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;
index f36e6127c1ff5a704fd9d86a333f6087f8f26546..e695411be593916695a4616c03449e95ac2e8524 100644 (file)
@@ -86,12 +86,13 @@ public:
                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;
        }
 
        /*
@@ -146,6 +147,7 @@ private:
        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;
index fb5cb29f463bd86253a023ed40707e120a92b3ac..613c635a2dcf2df84a495f6eeb87489230bc23f6 100644 (file)
@@ -65,6 +65,7 @@ public:
        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){}
index 55ec8965ad6683b8b146f4ec7e907702c790d66c..1bf6dc9c1170d46318ee97431c3e6558da505e1f 100644 (file)
@@ -35,7 +35,8 @@ Clouds::Clouds(
        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);
@@ -318,6 +319,7 @@ void Clouds::render()
                        }
 
                        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;
index 8f8b19faf77c63bb58a0348f8a22e7bfeb8f384f..d718e56bf355241107e2ddadc4bc26efae9e9081 100644 (file)
@@ -66,6 +66,11 @@ public:
        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;
@@ -76,6 +81,7 @@ private:
        u32 m_seed;
        v2f m_camera_pos;
        float m_time;
+       v3s16 m_camera_offset;
 };
 
 
index 840103cc74644f7406ae98e569258b4c7bdad3e7..84ec3e1430701014e3ee3791f958e558c50c1490 100644 (file)
@@ -1058,23 +1058,24 @@ public:
                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){
index 9e282476fd82a34399c10f06ac6d0e2cf7b4d462..8cc0bcd7e732e9e666253395431e5403e541f9cf 100644 (file)
@@ -500,6 +500,10 @@ public:
        { 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;
@@ -515,6 +519,7 @@ private:
        IntervalLimiter m_drowning_interval;
        IntervalLimiter m_breathing_interval;
        std::list<std::string> m_player_names;
+       v3s16 m_camera_offset;
 };
 
 #endif
index 196d1e316d44e3629aee5e01a6b149be9479b52c..18e69c132acc64ffa5ca5744392d122741ca3a71 100644 (file)
@@ -228,6 +228,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
                core::line3d<f32> shootline, f32 d,
                bool liquids_pointable,
                bool look_for_object,
+               v3s16 camera_offset,
                std::vector<aabb3f> &hilightboxes,
                ClientActiveObject *&selected_object)
 {
@@ -258,8 +259,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
 
                                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();
@@ -361,8 +362,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
                                                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);
                                }
                        }
@@ -2541,6 +2542,8 @@ void the_game(
                        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;
@@ -2554,10 +2557,19 @@ void the_game(
                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
@@ -2600,6 +2612,7 @@ void the_game(
                                &client, player_position, camera_direction,
                                camera_position, shootline, d,
                                playeritem_def.liquids_pointable, !ldown_for_dig,
+                               camera_offset,
                                // output
                                hilightboxes,
                                selected_object);
@@ -3030,7 +3043,7 @@ void the_game(
                        Update particles
                */
 
-               allparticles_step(dtime, client.getEnv());
+               allparticles_step(dtime);
                allparticlespawners_step(dtime, client.getEnv());
                
                /*
@@ -3249,7 +3262,8 @@ void the_game(
                */
                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;
index d5e03f7b367242d29471d13790779a81b74a6088..0187c73877cdf02398140e87cd709e020250b127 100644 (file)
@@ -398,7 +398,7 @@ public:
                        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);
index afea3dcce2e9224d3d894b69c366834ae99d20ec..ef05acbb7ceaf8772f31416111c52a1263c1089f 100644 (file)
@@ -1030,7 +1030,7 @@ static void updateAllFastFaceRows(MeshMakeData *data,
        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
@@ -1248,11 +1248,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                                &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)
        {
@@ -1415,6 +1417,14 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
        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
 */
index c75984021e32f62331e5f1afd114839ba635fa39..021309d9931798442332a6aa56dd814d71dd85f0 100644 (file)
@@ -81,7 +81,7 @@ class MapBlockMesh
 {
 public:
        // Builds the mesh given
-       MapBlockMesh(MeshMakeData *data);
+       MapBlockMesh(MeshMakeData *data, v3s16 camera_offset);
        ~MapBlockMesh();
 
        // Main animation function, parameters:
@@ -107,6 +107,8 @@ public:
                if(m_animation_force_timer > 0)
                        m_animation_force_timer--;
        }
+       
+       void updateCameraOffset(v3s16 camera_offset);
 
 private:
        scene::SMesh *m_mesh;
@@ -133,6 +135,9 @@ private:
        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;
 };
 
 
index 19bdaf1215f7c5258f168f39ecc514ea1954fedd..5a3056c324dc1242815b4a9e0030a8c1479c2378 100644 (file)
@@ -66,6 +66,7 @@ Particle::Particle(
 {
        // Misc
        m_gamedef = gamedef;
+       m_env = &env;
 
        // Texture
        m_material.setFlag(video::EMF_LIGHTING, false);
@@ -95,7 +96,7 @@ Particle::Particle(
        this->setAutomaticCulling(scene::EAC_OFF);
 
        // Init lighting
-       updateLight(env);
+       updateLight();
 
        // Init model
        updateVertices();
@@ -134,7 +135,7 @@ void Particle::render()
                        scene::EPT_TRIANGLES, video::EIT_16BIT);
 }
 
-void Particle::step(float dtime, ClientEnvironment &env)
+void Particle::step(float dtime)
 {
        m_time += dtime;
        if (m_collisiondetection)
@@ -143,7 +144,7 @@ void Particle::step(float dtime, ClientEnvironment &env)
                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);
@@ -158,13 +159,13 @@ void Particle::step(float dtime, ClientEnvironment &env)
        }
 
        // Update lighting
-       updateLight(env);
+       updateLight();
 
        // Update model
        updateVertices();
 }
 
-void Particle::updateLight(ClientEnvironment &env)
+void Particle::updateLight()
 {
        u8 light = 0;
        try{
@@ -173,11 +174,11 @@ void Particle::updateLight(ClientEnvironment &env)
                        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);
 }
@@ -199,6 +200,7 @@ void Particle::updateVertices()
        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) {
@@ -209,17 +211,16 @@ void Particle::updateVertices()
                        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();)
@@ -232,7 +233,7 @@ void allparticles_step (float dtime, ClientEnvironment &env)
                }
                else
                {
-                       (*i)->step(dtime, env);
+                       (*i)->step(dtime);
                        i++;
                }
        }
index 7c89a79bfd80afbacc594e9021292c68a3f4f8cd..101fc49ce145cb8cb5a0bd72f8e8315318ec6543 100644 (file)
@@ -67,19 +67,20 @@ class Particle : public scene::ISceneNode
        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;
@@ -94,6 +95,7 @@ private:
        u8 m_light;
        bool m_collisiondetection;
        bool m_vertical;
+       v3s16 m_camera_offset;
 };
 
 class ParticleSpawner
@@ -144,7 +146,7 @@ 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);