Fix rendering glitches when far from the center of the map

This commit is contained in:
Novatux 2014-01-26 11:40:21 +01:00
parent 8e15179e7d
commit 062de11b4c
17 changed files with 112 additions and 35 deletions

@ -36,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "profiler.h" #include "profiler.h"
#include "util/numeric.h" #include "util/numeric.h"
#include "util/mathconstants.h" #include "util/mathconstants.h"
#include "constants.h"
#define CAMERA_OFFSET_STEP 200
Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
IGameDef *gamedef): IGameDef *gamedef):
@ -53,6 +56,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
m_camera_position(0,0,0), m_camera_position(0,0,0),
m_camera_direction(0,0,0), m_camera_direction(0,0,0),
m_camera_offset(0,0,0),
m_aspect(1.0), m_aspect(1.0),
m_fov_x(1.0), m_fov_x(1.0),
@ -348,11 +352,19 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime,
v3f abs_cam_up; v3f abs_cam_up;
m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_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 // 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); m_cameranode->setUpVector(abs_cam_up);
// *100.0 helps in large map coordinates // *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 // Get FOV setting
f32 fov_degrees = g_settings->getFloat("fov"); f32 fov_degrees = g_settings->getFloat("fov");

@ -79,6 +79,12 @@ public:
{ {
return m_camera_direction; return m_camera_direction;
} }
// Get the camera offset
inline v3s16 getOffset() const
{
return m_camera_offset;
}
// Horizontal field of view // Horizontal field of view
inline f32 getFovX() const inline f32 getFovX() const
@ -144,6 +150,8 @@ private:
v3f m_camera_position; v3f m_camera_position;
// Absolute camera direction // Absolute camera direction
v3f m_camera_direction; v3f m_camera_direction;
// Camera offset
v3s16 m_camera_offset;
// Field of view and aspect ratio stuff // Field of view and aspect ratio stuff
f32 m_aspect; f32 m_aspect;

@ -179,7 +179,7 @@ void * MeshUpdateThread::Thread()
ScopeProfiler sp(g_profiler, "Client: Mesh making"); 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) if(mesh_new->getMesh()->getMeshBufferCount() == 0)
{ {
delete mesh_new; delete mesh_new;

@ -119,6 +119,8 @@ public:
MutexedQueue<MeshUpdateResult> m_queue_out; MutexedQueue<MeshUpdateResult> m_queue_out;
IGameDef *m_gamedef; IGameDef *m_gamedef;
v3s16 m_camera_offset;
}; };
enum ClientEventType enum ClientEventType
@ -406,6 +408,8 @@ public:
// Including blocks at appropriate edges // Including blocks at appropriate edges
void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false); 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 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. // Get event from queue. CE_NONE is returned if queue is empty.
ClientEvent getClientEvent(); ClientEvent getClientEvent();

@ -175,6 +175,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
v3f camera_position = m_camera_position; v3f camera_position = m_camera_position;
v3f camera_direction = m_camera_direction; v3f camera_direction = m_camera_direction;
f32 camera_fov = m_camera_fov; f32 camera_fov = m_camera_fov;
v3s16 camera_offset = m_camera_offset;
m_camera_mutex.Unlock(); m_camera_mutex.Unlock();
// Use a higher fov to accomodate faster camera movements. // 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 not seen on display
*/ */
if (block->mesh != NULL)
block->mesh->updateCameraOffset(m_camera_offset);
float range = 100000 * BS; float range = 100000 * BS;
if(m_control.range_all == false) if(m_control.range_all == false)
range = m_control.wanted_range * BS; range = m_control.wanted_range * BS;

@ -86,12 +86,13 @@ public:
ISceneNode::drop(); 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); JMutexAutoLock lock(m_camera_mutex);
m_camera_position = pos; m_camera_position = pos;
m_camera_direction = dir; m_camera_direction = dir;
m_camera_fov = fov; m_camera_fov = fov;
m_camera_offset = offset;
} }
/* /*
@ -146,6 +147,7 @@ private:
v3f m_camera_position; v3f m_camera_position;
v3f m_camera_direction; v3f m_camera_direction;
f32 m_camera_fov; f32 m_camera_fov;
v3s16 m_camera_offset;
JMutex m_camera_mutex; JMutex m_camera_mutex;
std::map<v3s16, MapBlock*> m_drawlist; std::map<v3s16, MapBlock*> m_drawlist;

@ -65,6 +65,7 @@ public:
virtual bool isLocalPlayer(){return false;} virtual bool isLocalPlayer(){return false;}
virtual void setAttachments(){} virtual void setAttachments(){}
virtual bool doShowSelectionBox(){return true;} virtual bool doShowSelectionBox(){return true;}
virtual void updateCameraOffset(v3s16 camera_offset){};
// Step object in time // Step object in time
virtual void step(float dtime, ClientEnvironment *env){} virtual void step(float dtime, ClientEnvironment *env){}

@ -35,7 +35,8 @@ Clouds::Clouds(
scene::ISceneNode(parent, mgr, id), scene::ISceneNode(parent, mgr, id),
m_seed(seed), m_seed(seed),
m_camera_pos(0,0), 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_LIGHTING, false);
//m_material.setFlag(video::EMF_BACK_FACE_CULLING, 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); v3f pos(p0.X, m_cloud_y, p0.Y);
pos -= intToFloat(m_camera_offset, BS);
for(u16 i=0; i<4; i++) for(u16 i=0; i<4; i++)
v[i].Pos += pos; v[i].Pos += pos;

@ -66,6 +66,11 @@ public:
void step(float dtime); void step(float dtime);
void update(v2f camera_p, video::SColorf color); void update(v2f camera_p, video::SColorf color);
void updateCameraOffset(v3s16 camera_offset)
{
m_camera_offset = camera_offset;
}
private: private:
video::SMaterial m_material; video::SMaterial m_material;
@ -76,6 +81,7 @@ private:
u32 m_seed; u32 m_seed;
v2f m_camera_pos; v2f m_camera_pos;
float m_time; float m_time;
v3s16 m_camera_offset;
}; };

@ -1058,23 +1058,24 @@ public:
if(getParent() != NULL) if(getParent() != NULL)
return; return;
v3s16 camera_offset = m_env->getCameraOffset();
if(m_meshnode){ 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(); v3f rot = m_meshnode->getRotation();
rot.Y = -m_yaw; rot.Y = -m_yaw;
m_meshnode->setRotation(rot); m_meshnode->setRotation(rot);
} }
if(m_animated_meshnode){ 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(); v3f rot = m_animated_meshnode->getRotation();
rot.Y = -m_yaw; rot.Y = -m_yaw;
m_animated_meshnode->setRotation(rot); m_animated_meshnode->setRotation(rot);
} }
if(m_spritenode){ 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) void step(float dtime, ClientEnvironment *env)
{ {
if(m_visuals_expired && m_smgr && m_irr){ if(m_visuals_expired && m_smgr && m_irr){

@ -500,6 +500,10 @@ public:
{ m_player_names.push_back(name); } { m_player_names.push_back(name); }
void removePlayerName(std::string name) void removePlayerName(std::string name)
{ m_player_names.remove(name); } { m_player_names.remove(name); }
void updateCameraOffset(v3s16 camera_offset)
{ m_camera_offset = camera_offset; }
v3s16 getCameraOffset()
{ return m_camera_offset; }
private: private:
ClientMap *m_map; ClientMap *m_map;
@ -515,6 +519,7 @@ private:
IntervalLimiter m_drowning_interval; IntervalLimiter m_drowning_interval;
IntervalLimiter m_breathing_interval; IntervalLimiter m_breathing_interval;
std::list<std::string> m_player_names; std::list<std::string> m_player_names;
v3s16 m_camera_offset;
}; };
#endif #endif

@ -228,6 +228,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
core::line3d<f32> shootline, f32 d, core::line3d<f32> shootline, f32 d,
bool liquids_pointable, bool liquids_pointable,
bool look_for_object, bool look_for_object,
v3s16 camera_offset,
std::vector<aabb3f> &hilightboxes, std::vector<aabb3f> &hilightboxes,
ClientActiveObject *&selected_object) ClientActiveObject *&selected_object)
{ {
@ -258,8 +259,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
v3f pos = selected_object->getPosition(); v3f pos = selected_object->getPosition();
hilightboxes.push_back(aabb3f( hilightboxes.push_back(aabb3f(
selection_box->MinEdge + pos, selection_box->MinEdge + pos - intToFloat(camera_offset, BS),
selection_box->MaxEdge + pos)); selection_box->MaxEdge + pos - intToFloat(camera_offset, BS)));
} }
mindistance = (selected_object->getPosition() - camera_position).getLength(); mindistance = (selected_object->getPosition() - camera_position).getLength();
@ -361,8 +362,8 @@ PointedThing getPointedThing(Client *client, v3f player_position,
i2 != boxes.end(); i2++) i2 != boxes.end(); i2++)
{ {
aabb3f box = *i2; aabb3f box = *i2;
box.MinEdge += npf + v3f(-d,-d,-d); box.MinEdge += npf + v3f(-d,-d,-d) - intToFloat(camera_offset, BS);
box.MaxEdge += npf + v3f(d,d,d); box.MaxEdge += npf + v3f(d,d,d) - intToFloat(camera_offset, BS);
hilightboxes.push_back(box); hilightboxes.push_back(box);
} }
} }
@ -2541,6 +2542,8 @@ void the_game(
Update camera Update camera
*/ */
v3s16 old_camera_offset = camera.getOffset();
LocalPlayer* player = client.getEnv().getLocalPlayer(); LocalPlayer* player = client.getEnv().getLocalPlayer();
float full_punch_interval = playeritem_toolcap.full_punch_interval; float full_punch_interval = playeritem_toolcap.full_punch_interval;
float tool_reload_ratio = time_from_last_punch / 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_position = camera.getPosition();
v3f camera_direction = camera.getDirection(); v3f camera_direction = camera.getDirection();
f32 camera_fov = camera.getFovMax(); f32 camera_fov = camera.getFovMax();
v3s16 camera_offset = camera.getOffset();
bool camera_offset_changed = (camera_offset != old_camera_offset);
if(!disable_camera_update){ if(!disable_camera_update){
client.getEnv().getClientMap().updateCamera(camera_position, 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 // Update sound listener
@ -2600,6 +2612,7 @@ void the_game(
&client, player_position, camera_direction, &client, player_position, camera_direction,
camera_position, shootline, d, camera_position, shootline, d,
playeritem_def.liquids_pointable, !ldown_for_dig, playeritem_def.liquids_pointable, !ldown_for_dig,
camera_offset,
// output // output
hilightboxes, hilightboxes,
selected_object); selected_object);
@ -3030,7 +3043,7 @@ void the_game(
Update particles Update particles
*/ */
allparticles_step(dtime, client.getEnv()); allparticles_step(dtime);
allparticlespawners_step(dtime, client.getEnv()); allparticlespawners_step(dtime, client.getEnv());
/* /*
@ -3249,7 +3262,8 @@ void the_game(
*/ */
update_draw_list_timer += dtime; update_draw_list_timer += dtime;
if(update_draw_list_timer >= 0.2 || 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; update_draw_list_timer = 0;
client.getEnv().getClientMap().updateDrawList(driver); client.getEnv().getClientMap().updateDrawList(driver);
update_draw_list_last_cam_dir = camera_direction; update_draw_list_last_cam_dir = camera_direction;

@ -398,7 +398,7 @@ public:
MeshMakeData mesh_make_data(gamedef); MeshMakeData mesh_make_data(gamedef);
MapNode mesh_make_node(id, param1, 0); MapNode mesh_make_node(id, param1, 0);
mesh_make_data.fillSingleNode(&mesh_make_node); 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(); scene::IMesh *node_mesh = mapblock_mesh.getMesh();
assert(node_mesh); assert(node_mesh);
video::SColor c(255, 255, 255, 255); video::SColor c(255, 255, 255, 255);

@ -1030,7 +1030,7 @@ static void updateAllFastFaceRows(MeshMakeData *data,
MapBlockMesh MapBlockMesh
*/ */
MapBlockMesh::MapBlockMesh(MeshMakeData *data): MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
m_mesh(new scene::SMesh()), m_mesh(new scene::SMesh()),
m_gamedef(data->m_gamedef), m_gamedef(data->m_gamedef),
m_animation_force_timer(0), // force initial animation m_animation_force_timer(0), // force initial animation
@ -1248,11 +1248,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
&p.indices[0], p.indices.size()); &p.indices[0], p.indices.size());
} }
m_camera_offset = camera_offset;
/* /*
Do some stuff to the mesh 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) if(m_mesh)
{ {
@ -1415,6 +1417,14 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
return true; 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 MeshCollector
*/ */

@ -81,7 +81,7 @@ class MapBlockMesh
{ {
public: public:
// Builds the mesh given // Builds the mesh given
MapBlockMesh(MeshMakeData *data); MapBlockMesh(MeshMakeData *data, v3s16 camera_offset);
~MapBlockMesh(); ~MapBlockMesh();
// Main animation function, parameters: // Main animation function, parameters:
@ -107,6 +107,8 @@ public:
if(m_animation_force_timer > 0) if(m_animation_force_timer > 0)
m_animation_force_timer--; m_animation_force_timer--;
} }
void updateCameraOffset(v3s16 camera_offset);
private: private:
scene::SMesh *m_mesh; scene::SMesh *m_mesh;
@ -133,6 +135,9 @@ private:
u32 m_last_daynight_ratio; u32 m_last_daynight_ratio;
// For each meshbuffer, maps vertex indices to (day,night) pairs // For each meshbuffer, maps vertex indices to (day,night) pairs
std::map<u32, std::map<u32, std::pair<u8, u8> > > m_daynight_diffs; 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;
}; };

@ -66,6 +66,7 @@ Particle::Particle(
{ {
// Misc // Misc
m_gamedef = gamedef; m_gamedef = gamedef;
m_env = &env;
// Texture // Texture
m_material.setFlag(video::EMF_LIGHTING, false); m_material.setFlag(video::EMF_LIGHTING, false);
@ -95,7 +96,7 @@ Particle::Particle(
this->setAutomaticCulling(scene::EAC_OFF); this->setAutomaticCulling(scene::EAC_OFF);
// Init lighting // Init lighting
updateLight(env); updateLight();
// Init model // Init model
updateVertices(); updateVertices();
@ -134,7 +135,7 @@ void Particle::render()
scene::EPT_TRIANGLES, video::EIT_16BIT); scene::EPT_TRIANGLES, video::EIT_16BIT);
} }
void Particle::step(float dtime, ClientEnvironment &env) void Particle::step(float dtime)
{ {
m_time += dtime; m_time += dtime;
if (m_collisiondetection) if (m_collisiondetection)
@ -143,7 +144,7 @@ void Particle::step(float dtime, ClientEnvironment &env)
v3f p_pos = m_pos*BS; v3f p_pos = m_pos*BS;
v3f p_velocity = m_velocity*BS; v3f p_velocity = m_velocity*BS;
v3f p_acceleration = m_acceleration*BS; v3f p_acceleration = m_acceleration*BS;
collisionMoveSimple(&env, m_gamedef, collisionMoveSimple(m_env, m_gamedef,
BS*0.5, box, BS*0.5, box,
0, dtime, 0, dtime,
p_pos, p_velocity, p_acceleration); p_pos, p_velocity, p_acceleration);
@ -158,13 +159,13 @@ void Particle::step(float dtime, ClientEnvironment &env)
} }
// Update lighting // Update lighting
updateLight(env); updateLight();
// Update model // Update model
updateVertices(); updateVertices();
} }
void Particle::updateLight(ClientEnvironment &env) void Particle::updateLight()
{ {
u8 light = 0; u8 light = 0;
try{ try{
@ -173,11 +174,11 @@ void Particle::updateLight(ClientEnvironment &env)
floor(m_pos.Y+0.5), floor(m_pos.Y+0.5),
floor(m_pos.Z+0.5) floor(m_pos.Z+0.5)
); );
MapNode n = env.getClientMap().getNode(p); MapNode n = m_env->getClientMap().getNode(p);
light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef()); light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef());
} }
catch(InvalidPositionException &e){ 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_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, m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
c, tx0, ty0); c, tx0, ty0);
v3s16 camera_offset = m_env->getCameraOffset();
for(u16 i=0; i<4; i++) for(u16 i=0; i<4; i++)
{ {
if (m_vertical) { if (m_vertical) {
@ -209,17 +211,16 @@ void Particle::updateVertices()
m_vertices[i].Pos.rotateXZBy(m_player->getYaw()); m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
} }
m_box.addInternalPoint(m_vertices[i].Pos); 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 Helpers
*/ */
void allparticles_step (float dtime, ClientEnvironment &env) void allparticles_step (float dtime)
{ {
for(std::vector<Particle*>::iterator i = all_particles.begin(); for(std::vector<Particle*>::iterator i = all_particles.begin();
i != all_particles.end();) i != all_particles.end();)
@ -232,7 +233,7 @@ void allparticles_step (float dtime, ClientEnvironment &env)
} }
else else
{ {
(*i)->step(dtime, env); (*i)->step(dtime);
i++; i++;
} }
} }

@ -67,19 +67,20 @@ class Particle : public scene::ISceneNode
virtual void OnRegisterSceneNode(); virtual void OnRegisterSceneNode();
virtual void render(); virtual void render();
void step(float dtime, ClientEnvironment &env); void step(float dtime);
bool get_expired () bool get_expired ()
{ return m_expiration < m_time; } { return m_expiration < m_time; }
private: private:
void updateLight(ClientEnvironment &env); void updateLight();
void updateVertices(); void updateVertices();
video::S3DVertex m_vertices[4]; video::S3DVertex m_vertices[4];
float m_time; float m_time;
float m_expiration; float m_expiration;
ClientEnvironment *m_env;
IGameDef *m_gamedef; IGameDef *m_gamedef;
core::aabbox3d<f32> m_box; core::aabbox3d<f32> m_box;
core::aabbox3d<f32> m_collisionbox; core::aabbox3d<f32> m_collisionbox;
@ -94,6 +95,7 @@ private:
u8 m_light; u8 m_light;
bool m_collisiondetection; bool m_collisiondetection;
bool m_vertical; bool m_vertical;
v3s16 m_camera_offset;
}; };
class ParticleSpawner class ParticleSpawner
@ -144,7 +146,7 @@ class ParticleSpawner
bool m_vertical; bool m_vertical;
}; };
void allparticles_step (float dtime, ClientEnvironment &env); void allparticles_step (float dtime);
void allparticlespawners_step (float dtime, ClientEnvironment &env); void allparticlespawners_step (float dtime, ClientEnvironment &env);
void delete_particlespawner (u32 id); void delete_particlespawner (u32 id);