diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 34a481f47..cddafd81a 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -28,6 +28,7 @@ #include "audio/music_manager.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/rain.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "karts/explosion_animation.hpp" @@ -39,16 +40,20 @@ #include "utils/aligned_array.hpp" #include "utils/constants.hpp" -#include -#include +#include "ICameraSceneNode.h" +#include "ISceneManager.h" AlignedArray Camera::m_end_cameras; +std::vector Camera::m_all_cameras; -Camera::Camera(int camera_index, AbstractKart* kart) +// ============================================================================ +Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) { - m_mode = CM_NORMAL; - m_index = camera_index; - m_camera = irr_driver->addCameraSceneNode(); + m_mode = CM_NORMAL; + m_index = camera_index; + m_rain = NULL; + m_original_kart = kart; + m_camera = irr_driver->addCameraSceneNode(); #ifdef DEBUG m_camera->setName(core::stringc("Camera for ") + kart->getKartProperties()->getName()); @@ -56,7 +61,7 @@ Camera::Camera(int camera_index, AbstractKart* kart) setupCamera(); m_distance = kart->getKartProperties()->getCameraDistance(); - m_kart = kart; + setKart(kart); m_ambient_light = World::getWorld()->getTrack()->getDefaultAmbientColor(); // TODO: Put these values into a config file @@ -83,6 +88,7 @@ Camera::Camera(int camera_index, AbstractKart* kart) */ Camera::~Camera() { + if(m_rain) delete m_rain; irr_driver->removeCameraSceneNode(m_camera); } // ~Camera @@ -90,12 +96,16 @@ Camera::~Camera() /** Changes the owner of this camera to the new kart. * \param new_kart The new kart to use this camera. */ -void Camera::changeOwner(AbstractKart *new_kart) +void Camera::setKart(AbstractKart *new_kart) { - m_kart->setCamera(NULL); m_kart = new_kart; - new_kart->setCamera(this); -} // changeOwner +#ifdef DEBUG + std::string name = new_kart->getIdent()+"'s camera"; + if(new_kart) + getCameraSceneNode()->setName(name.c_str() ); +#endif + +} // setKart //----------------------------------------------------------------------------- /** This function clears all end camera data structure. This is necessary @@ -203,7 +213,14 @@ void Camera::setupCamera() m_camera->setFOV(m_fov); m_camera->setAspectRatio(m_aspect); m_camera->setFarValue(World::getWorld()->getTrack()->getCameraFar()); - } // setupCamera + + if (UserConfigParams::m_weather_effects && + World::getWorld()->getTrack()->getWeatherType() == WEATHER_RAIN) + { + m_rain = new Rain(this, NULL); + } + +} // setupCamera // ---------------------------------------------------------------------------- /** Sets the mode of the camera. @@ -252,6 +269,7 @@ Camera::Mode Camera::getMode() */ void Camera::reset() { + m_kart = m_original_kart; setMode(CM_NORMAL); setInitialTransform(); } // reset @@ -422,6 +440,16 @@ void Camera::getCameraSettings(float *above_kart, float *cam_angle, */ void Camera::update(float dt) { + if (UserConfigParams::m_graphical_effects) + { + if (m_rain) + { + m_rain->setPosition( getCameraSceneNode()->getPosition() ); + m_rain->update(dt); + } + } // UserConfigParams::m_graphical_effects + + // The following settings give a debug camera which shows the track from // high above the kart straight down. if(UserConfigParams::m_camera_debug) diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index c1bdcc1ba..1aa27d908 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -21,23 +21,26 @@ #ifndef HEADER_CAMERA_HPP #define HEADER_CAMERA_HPP +#include "io/xml_node.hpp" +#include "utils/no_copy.hpp" +#include "utils/aligned_array.hpp" +#include "utils/leak_check.hpp" +#include "utils/vec3.hpp" + +#include "SColor.h" +#include "vector2d.h" +#include "rect.h" + #include -#include -#include -#include namespace irr { namespace scene { class ICameraSceneNode; } } using namespace irr; -#include "io/xml_node.hpp" -#include "utils/no_copy.hpp" -#include "utils/aligned_array.hpp" -#include "utils/vec3.hpp" - class AbstractKart; +class Rain; /** * \brief Handles the game camera @@ -91,6 +94,11 @@ private: * since in profile mode the camera might change its owner. */ AbstractKart *m_kart; + /** A pointer to the original kart the camera was pointing at when it + * was created. Used when restarting a race (since the camera might + * get attached to another kart if a kart is elimiated). */ + AbstractKart *m_original_kart; + /** The list of viewports for this cameras. */ core::recti m_viewport; @@ -112,7 +120,14 @@ private: /* Whether we should use the pre-0.7 camera style or the * modern style. Should default to modern. */ Style m_camera_style; - + + /** List of all cameras. */ + static std::vector m_all_cameras; + + /** Used to show rain graphical effects. */ + Rain *m_rain; + + /** A class that stores information about the different end cameras * which can be specified in the scene.xml file. */ class EndCameraInformation @@ -190,9 +205,41 @@ private: bool *smoothing); void positionCamera(float dt, float above_kart, float cam_angle, float side_way, float distance, float smoothing); + + Camera(int camera_index, AbstractKart* kart); + ~Camera(); public: - Camera (int camera_index, AbstractKart* kart); - ~Camera (); + LEAK_CHECK() + + /** Returns the number of cameras used. */ + static unsigned int getNumCameras() { return m_all_cameras.size(); } + + // ------------------------------------------------------------------------ + /** Returns a camera. */ + static Camera *getCamera(unsigned int n) { return m_all_cameras[n]; } + + // ------------------------------------------------------------------------ + /** Remove all cameras. */ + static void removeAllCameras() + { + for(unsigned int i=0; iupdate(dt); - for(unsigned int i=0; igetNumKarts(); i++) + for(unsigned int i=0; igetKart(i); - if(!kart->getCamera()) continue; + Camera *camera = Camera::getCamera(i); + #ifdef ENABLE_PROFILER std::ostringstream oss; oss << "drawAll() for kart " << i << std::flush; PROFILER_PUSH_CPU_MARKER(oss.str().c_str(), (i+1)*60, 0x00, 0x00); #endif - kart->getCamera()->activate(); - rg->preRenderCallback(*kart); // adjusts start referee + camera->activate(); + rg->preRenderCallback(camera); // adjusts start referee m_scene_manager->drawAll(); PROFILER_POP_CPU_MARKER(); @@ -1692,15 +1690,14 @@ void IrrDriver::update(float dt) UserConfigParams::m_width, UserConfigParams::m_height)); - for(unsigned int i=0; igetNumKarts(); i++) + for(unsigned int i=0; igetKart(i); - if(!kart->getCamera()) continue; + Camera *camera = Camera::getCamera(i); char marker_name[100]; sprintf(marker_name, "renderPlayerView() for kart %d", i); PROFILER_PUSH_CPU_MARKER(marker_name, 0x00, 0x00, (i+1)*60); - rg->renderPlayerView(kart, dt); + rg->renderPlayerView(camera, dt); PROFILER_POP_CPU_MARKER(); } // for igetIndex()==0; - if (lightning) m_thunder_sound = sfx_manager->createSoundSource("thunder"); + if (m_lightning) + m_thunder_sound = sfx_manager->createSoundSource("thunder"); Material* m = material_manager->getMaterial("rain.png"); assert(m != NULL); @@ -108,7 +109,9 @@ Rain::Rain(irr::scene::ICameraSceneNode* camera, irr::scene::ISceneNode* parent, mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); - m_node[r] = irr_driver->addPerCameraMesh(mesh, camera, parent); + m_node[r] = irr_driver->addPerCameraMesh(mesh, + camera->getCameraSceneNode(), + parent); mesh->drop(); buffer->drop(); diff --git a/src/graphics/rain.hpp b/src/graphics/rain.hpp index 42483b402..4dafed01d 100644 --- a/src/graphics/rain.hpp +++ b/src/graphics/rain.hpp @@ -19,6 +19,7 @@ #ifndef HEADER_RAIN_HPP #define HEADER_RAIN_HPP +class Camera; class PerCameraNode; #include @@ -47,7 +48,7 @@ class Rain SFXBase* m_thunder_sound; public: - Rain(irr::scene::ICameraSceneNode* camera, irr::scene::ISceneNode* parent, bool lightning); + Rain(Camera* camera, irr::scene::ISceneNode* parent); ~Rain(); void update(float dt); diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index df50e9971..1d53ce23c 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -118,15 +118,7 @@ void InputManager::handleStaticAction(int key, int value) if(!ProfileWorld::isProfileMode() || !world) break; int kart_id = key - KEY_KEY_1; if(kart_id<0 || kart_id>=(int)world->getNumKarts()) break; - for(unsigned int i=0; igetNumKarts(); i++) - { - if(world->getKart(i)->getCamera()) - { - world->getKart(i)->getCamera() - ->changeOwner(world->getKart(kart_id)); - - } - } + Camera::getCamera(0)->setKart(world->getKart(kart_id)); break; } #endif diff --git a/src/karts/abstract_kart.hpp b/src/karts/abstract_kart.hpp index bbb6d72fc..9bd0997a2 100644 --- a/src/karts/abstract_kart.hpp +++ b/src/karts/abstract_kart.hpp @@ -29,7 +29,6 @@ class Attachment; class btKart; class btQuaternion; class btUprightConstraint; -class Camera; class Controller; class Item; class KartModel; @@ -81,7 +80,7 @@ public: int position, const btTransform& init_transform); virtual ~AbstractKart(); virtual void reset(); - virtual void init(RaceManager::KartType type, bool is_first_kart) = 0; + virtual void init(RaceManager::KartType type) = 0; // ======================================================================== // Functions related to controlling the kart // ------------------------------------------------------------------------ @@ -280,18 +279,6 @@ public: /** Activates a slipstream effect, atm that is display some nitro. */ virtual void setSlipstreamEffect(float f) = 0; // ------------------------------------------------------------------------ - /** Sets the camera for this kart. Takes ownership of the camera and - * will delete it. */ - virtual void setCamera(Camera *camera) = 0; - // ------------------------------------------------------------------------ - /** Returns the camera of this kart (or NULL if no camera is attached - * to this kart). */ - virtual Camera* getCamera() = 0; - // ------------------------------------------------------------------------ - /** Returns the camera of this kart (or NULL if no camera is attached - * to this kart). */ - virtual const Camera* getCamera() const = 0; - // ------------------------------------------------------------------------ /** Plays a beep sfx. */ virtual void beep() = 0; // ------------------------------------------------------------------------ diff --git a/src/karts/controller/ai_base_controller.hpp b/src/karts/controller/ai_base_controller.hpp index d9c4baca3..3fbeda17c 100644 --- a/src/karts/controller/ai_base_controller.hpp +++ b/src/karts/controller/ai_base_controller.hpp @@ -88,6 +88,9 @@ protected: void computePath(); virtual bool doSkid(float steer_fraction); // ------------------------------------------------------------------------ + /** Nothing special to do when the race is finished. */ + virtual void raceFinished() {}; + // ------------------------------------------------------------------------ /** This can be called to detect if the kart is stuck (i.e. repeatedly * hitting part of the track). */ bool isStuck() const { return m_stuck_trigger_rescue; } diff --git a/src/karts/controller/controller.hpp b/src/karts/controller/controller.hpp index a4a23aa52..a981176d2 100644 --- a/src/karts/controller/controller.hpp +++ b/src/karts/controller/controller.hpp @@ -69,7 +69,6 @@ public: virtual void crashed (const AbstractKart *k) = 0; virtual void crashed (const Material *m) = 0; virtual void setPosition (int p) = 0; - virtual void finishedRace (float time) = 0; virtual bool isPlayerController () const = 0; virtual bool isNetworkController() const = 0; virtual bool disableSlipstreamBonus() const = 0; @@ -98,6 +97,10 @@ public: virtual void newLap(int lap) = 0; // ------------------------------------------------------------------------ virtual void skidBonusTriggered() = 0; + // ------------------------------------------------------------------------ + /** Called whan this controller's kart finishes the last lap. */ + virtual void finishedRace(float time) = 0; + // ------------------------------------------------------------------------ }; // Controller #endif diff --git a/src/karts/controller/end_controller.cpp b/src/karts/controller/end_controller.cpp index 6312d216a..465b7a4d9 100644 --- a/src/karts/controller/end_controller.cpp +++ b/src/karts/controller/end_controller.cpp @@ -54,6 +54,7 @@ EndController::EndController(AbstractKart *kart, StateManager::ActivePlayer *pla Controller *prev_controller) : AIBaseController(kart, player) { + m_previous_controller = prev_controller; if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES) { // Overwrite the random selected default path from AIBaseController @@ -150,9 +151,10 @@ void EndController::reset() */ void EndController::newLap(int lap) { - // This will implicitely trigger setting the first end camera to be active. - if(m_kart->getCamera()) - m_kart->getCamera()->setMode(Camera::CM_FINAL); + // Forward the call to the original controller. This will implicitely + // trigger setting the first end camera to be active if the controller + // is a player controller. + m_previous_controller->newLap(lap); } // newLap //----------------------------------------------------------------------------- diff --git a/src/karts/controller/end_controller.hpp b/src/karts/controller/end_controller.hpp index 035949674..c2c09ecab 100644 --- a/src/karts/controller/end_controller.hpp +++ b/src/karts/controller/end_controller.hpp @@ -23,6 +23,7 @@ #include "karts/controller/ai_base_controller.hpp" +class Camera; class LinearWorld; class QuadGraph; class Track; @@ -62,6 +63,9 @@ private: float m_time_since_stuck; + /** Stores a pointer to the original controller. */ + Controller *m_previous_controller; + /** For debugging purpose: a sphere indicating where the AI * is targeting at. */ irr::scene::ISceneNode *m_debug_sphere; diff --git a/src/karts/controller/player_controller.cpp b/src/karts/controller/player_controller.cpp index fdb64e628..840fd9dbc 100644 --- a/src/karts/controller/player_controller.cpp +++ b/src/karts/controller/player_controller.cpp @@ -56,14 +56,14 @@ PlayerController::PlayerController(AbstractKart *kart, m_player = player; m_player->setKart(kart); m_penalty_time = 0.0f; - kart->setCamera(new Camera(player_index, kart)); - kart->getCamera()->setMode(Camera::CM_NORMAL); - - m_bzzt_sound = sfx_manager->createSoundSource( "bzzt" ); - m_wee_sound = sfx_manager->createSoundSource( "wee" ); - m_ugh_sound = sfx_manager->createSoundSource( "ugh" ); - m_grab_sound = sfx_manager->createSoundSource( "grab_collectable" ); - m_full_sound = sfx_manager->createSoundSource( "energy_bar_full" ); + // Keep a pointer to the camera to remove the need to search for + // the right camera once per frame later. + m_camera = Camera::createCamera(kart); + m_bzzt_sound = sfx_manager->createSoundSource( "bzzt" ); + m_wee_sound = sfx_manager->createSoundSource( "wee" ); + m_ugh_sound = sfx_manager->createSoundSource( "ugh" ); + m_grab_sound = sfx_manager->createSoundSource( "grab_collectable" ); + m_full_sound = sfx_manager->createSoundSource( "energy_bar_full" ); reset(); } // PlayerController @@ -365,17 +365,17 @@ void PlayerController::update(float dt) // look backward when the player requests or // if automatic reverse camera is active - if (m_kart->getCamera()->getMode() != Camera::CM_FINAL) + if (m_camera->getMode() != Camera::CM_FINAL) { if (m_controls->m_look_back || (UserConfigParams::m_reverse_look_threshold>0 && m_kart->getSpeed()<-UserConfigParams::m_reverse_look_threshold)) { - m_kart->getCamera()->setMode(Camera::CM_REVERSE); + m_camera->setMode(Camera::CM_REVERSE); } else { - if (m_kart->getCamera()->getMode() == Camera::CM_REVERSE) - m_kart->getCamera()->setMode(Camera::CM_NORMAL); + if (m_camera->getMode() == Camera::CM_REVERSE) + m_camera->setMode(Camera::CM_NORMAL); } } @@ -422,9 +422,12 @@ void PlayerController::setPosition(int p) //----------------------------------------------------------------------------- /** Called when a kart finishes race. * /param time Finishing time for this kart. - */ + d*/ void PlayerController::finishedRace(float time) { + // This will implicitely trigger setting the first end camera to be active + m_camera->setMode(Camera::CM_FINAL); + } // finishedRace //----------------------------------------------------------------------------- diff --git a/src/karts/controller/player_controller.hpp b/src/karts/controller/player_controller.hpp index 7c50cb35e..cd43bcbba 100644 --- a/src/karts/controller/player_controller.hpp +++ b/src/karts/controller/player_controller.hpp @@ -43,6 +43,10 @@ private: float m_penalty_time; + /** The camera attached to the kart for this controller. The camera + * object is managed in the Camera class, so no need to free it. */ + Camera *m_camera; + SFXBase *m_bzzt_sound; SFXBase *m_wee_sound; SFXBase *m_ugh_sound; @@ -62,20 +66,21 @@ public: float previous_energy=0); virtual void skidBonusTriggered(); virtual void setPosition (int p); - virtual void finishedRace (float time); virtual bool isPlayerController() const {return true;} virtual bool isNetworkController() const { return false; } virtual void reset (); void resetInputState (); + virtual void finishedRace (float time); virtual void crashed (const AbstractKart *k) {} virtual void crashed (const Material *m) {} // ------------------------------------------------------------------------ + /** Callback whenever a new lap is triggered. Used by the AI + * to trigger a recomputation of the way to use, not used for players. */ + virtual void newLap(int lap) {} + // ------------------------------------------------------------------------ /** Player will always be able to get a slipstream bonus. */ virtual bool disableSlipstreamBonus() const { return false; } - // ------------------------------------------------------------------------ - /** Callback whenever a new lap is triggered. Used by the AI - * to trigger a recomputation of the way to use. */ - virtual void newLap(int lap) {} -}; + +}; // PlayerController #endif diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index b3247ec0a..39928ae8b 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -114,9 +114,12 @@ ExplosionAnimation::~ExplosionAnimation() { m_kart->getBody()->setLinearVelocity(btVector3(0,0,0)); m_kart->getBody()->setAngularVelocity(btVector3(0,0,0)); - if(m_kart->getCamera() && - m_kart->getCamera()->getMode() != Camera::CM_FINAL) - m_kart->getCamera()->setMode(Camera::CM_NORMAL); + for(unsigned int i=0; igetMode() != Camera::CM_FINAL) + camera->setMode(Camera::CM_NORMAL); + } } } // ~KartAnimation diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 4c95572af..e39f7f609 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -36,7 +36,6 @@ #include "graphics/particle_emitter.hpp" #include "graphics/particle_kind.hpp" #include "graphics/particle_kind_manager.hpp" -#include "graphics/rain.hpp" #include "graphics/shadow.hpp" #include "graphics/skid_marks.hpp" #include "graphics/slip_stream.hpp" @@ -83,7 +82,6 @@ * \param ident The identifier for the kart model to use. * \param position The position (or rank) for this kart (between 1 and * number of karts). This is used to determine the start position. - * \param is_first_kart Indicates whether this is the first *player* kart * \param init_transform The initial position and rotation for this kart. */ Kart::Kart (const std::string& ident, unsigned int world_kart_id, @@ -113,11 +111,9 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, m_collision_particles = NULL; m_slipstream = NULL; m_skidmarks = NULL; - m_camera = NULL; m_controller = NULL; m_saved_controller = NULL; m_flying = false; - m_rain = NULL; m_sky_particles_emitter= NULL; m_stars_effect = NULL; @@ -161,8 +157,9 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, // ----------------------------------------------------------------------------- /** This is a second initialisation phase, necessary since in the constructor * virtual functions are not called for any superclasses. - */ -void Kart::init(RaceManager::KartType type, bool is_first_kart) + * \param type Type of the kart. +*/ +void Kart::init(RaceManager::KartType type) { // In multiplayer mode, sounds are NOT positional if (race_manager->getNumLocalPlayers() > 1) @@ -201,7 +198,7 @@ void Kart::init(RaceManager::KartType type, bool is_first_kart) { animations = false; } - loadData(type, is_first_kart, animations); + loadData(type, animations); m_kart_gfx = new KartGFX(this); m_skidding = new Skidding(this, @@ -242,7 +239,6 @@ Kart::~Kart() if(m_previous_terrain_sound) sfx_manager->deleteSFX(m_previous_terrain_sound); if(m_collision_particles) delete m_collision_particles; if(m_slipstream) delete m_slipstream; - if(m_rain) delete m_rain; if(m_sky_particles_emitter) delete m_sky_particles_emitter; if(m_attachment) delete m_attachment; if (m_stars_effect) delete m_stars_effect; @@ -273,7 +269,6 @@ Kart::~Kart() delete m_controller; if(m_saved_controller) delete m_saved_controller; - if (m_camera) delete m_camera; } // ~Kart //----------------------------------------------------------------------------- @@ -299,12 +294,6 @@ void Kart::reset() m_max_speed->reset(); m_powerup->reset(); - if (m_camera) - { - m_camera->reset(); - m_camera->setInitialTransform(); - } - // Reset animations and wheels m_kart_model->reset(); @@ -800,9 +789,6 @@ void Kart::finishedRace(float time) else m_kart_model->setAnimation(KartModel::AF_LOSE_START); - // Not all karts have a camera - if (m_camera) m_camera->setMode(Camera::CM_FINAL); - RaceGUIBase* m = World::getWorld()->getRaceGUI(); if(m) { @@ -820,9 +806,6 @@ void Kart::finishedRace(float time) else if(m_race_position>=0.7f*race_manager->getNumberOfKarts()) m_kart_model->setAnimation(KartModel::AF_LOSE_START); - // Not all karts have a camera - if (m_camera) m_camera->setMode(Camera::CM_REVERSE); - RaceGUIBase* m = World::getWorld()->getRaceGUI(); if(m) { @@ -1015,8 +998,6 @@ void Kart::update(float dt) if(!history->replayHistory()) m_controller->update(dt); - if(m_camera) - m_camera->update(dt); // if its view is blocked by plunger, decrease remaining time if(m_view_blocked_by_plunger > 0) m_view_blocked_by_plunger -= dt; @@ -1082,16 +1063,6 @@ void Kart::update(float dt) m_attachment->update(dt); - //smoke drawing control point - if (UserConfigParams::m_graphical_effects) - { - if (m_rain) - { - m_rain->setPosition( getCamera()->getCameraSceneNode()->getPosition() ); - m_rain->update(dt); - } - } // UserConfigParams::m_graphical_effects - m_kart_gfx->update(dt); if (m_collision_particles) m_collision_particles->update(dt); @@ -1377,17 +1348,22 @@ void Kart::handleMaterialGFX() // has the 'below surface' flag set. Detect if there is a surface // on top of the kart. // -------------------------------------------------------------- - if (m_camera && m_camera->getMode() != Camera::CM_FINAL) + if (m_controller->isPlayerController() && !hasFinishedRace()) { - if (material && material->hasFallingEffect() && !m_flying) + for(unsigned int i=0; isetMode(Camera::CM_FALLING); - } - else if (m_camera->getMode() != Camera::CM_NORMAL && - m_camera->getMode() != Camera::CM_REVERSE) - { - m_camera->setMode(Camera::CM_NORMAL); - } + Camera *camera = Camera::getCamera(i); + + if (material && material->hasFallingEffect() && !m_flying) + { + Camera::getCamera(i)->setMode(Camera::CM_FALLING); + } + else if (camera->getMode() != Camera::CM_NORMAL && + camera->getMode() != Camera::CM_REVERSE) + { + camera->setMode(Camera::CM_NORMAL); + } + } // for i in all cameras for this kart } // camera != final camera if (!UserConfigParams::m_graphical_effects) @@ -1444,30 +1420,6 @@ void Kart::handleMaterialGFX() } // handleMaterialGFX -//----------------------------------------------------------------------------- -/** Sets or reset the camera attached to a kart. In profile mode even AI karts - * can have a camera attached. - * \params camera The camera to attach to this kart (or NULL if no camera - * is to be used - */ -void Kart::setCamera(Camera *camera) -{ - m_camera = camera; - if(!camera) - return; - -#ifdef DEBUG - m_camera->getCameraSceneNode() - ->setName((getIdent() + "'s camera").c_str()); -#endif - - // Handle camera-specific nodes for now if in multiplayer - if (m_rain && race_manager->getNumLocalPlayers() > 1) - { - m_rain->setCamera( camera->getCameraSceneNode() ); - } -} // setCamera - //----------------------------------------------------------------------------- /** Sets zipper time, and apply one time additional speed boost. It can be * used with a specific material, in which case the zipper parmaters are @@ -2149,9 +2101,10 @@ void Kart::updateFlying() // ---------------------------------------------------------------------------- /** Attaches the right model, creates the physics and loads all special * effects (particle systems etc.) + * \param type Type of the kart. + * \param is_animated_model True if the model is animated. */ -void Kart::loadData(RaceManager::KartType type, bool is_first_kart, - bool is_animated_model) +void Kart::loadData(RaceManager::KartType type, bool is_animated_model) { m_node = m_kart_model->attachModel(is_animated_model); @@ -2185,14 +2138,7 @@ void Kart::loadData(RaceManager::KartType type, bool is_first_kart, // of the heightmap being calculated and kept in memory m_sky_particles_emitter->addHeightMapAffector(track); } - - if (UserConfigParams::m_weather_effects && track->getWeatherType() == WEATHER_RAIN && - type == RaceManager::KT_PLAYER) - { - // camera not yet available at this point - m_rain = new Rain(NULL, NULL, is_first_kart); - } - + Vec3 position(0, getKartHeight()*0.35f, -getKartLength()*0.35f); m_slipstream = new SlipStream(this); diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index 1e8f1ef6a..8f7577f79 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -38,7 +38,6 @@ class btKart; class btUprightConstraint; class Attachment; -class Camera; class Controller; class Item; class AbstractKartAnimation; @@ -46,7 +45,6 @@ class KartGFX; class MaxSpeed; class ParticleEmitter; class ParticleKind; -class Rain; class SFXBase; class Shadow; class Skidding; @@ -110,14 +108,6 @@ private: /** For stars rotating around head effect */ Stars *m_stars_effect; - -protected: // Used by the AI atm - /** The camera for each kart. Not all karts have cameras (e.g. AI karts - * usually don't), but there are exceptions: e.g. after the end of a - * race an AI kart is replacing the kart for a player. - */ - Camera *m_camera; - private: /** True if the kart hasn't moved since 'ready-set-go' - used to * determine startup boost. */ @@ -174,8 +164,6 @@ private: /** Handles all slipstreaming. */ SlipStream *m_slipstream; - Rain *m_rain; - /** Rotation compared to the start position, same for all wheels */ float m_wheel_rotation; @@ -221,14 +209,13 @@ private: void updateNitro(float dt); float getActualWheelForce(); void crashed(); - void loadData(RaceManager::KartType type, bool is_first_kart, - bool animatedModel); + void loadData(RaceManager::KartType type, bool animatedModel); public: Kart(const std::string& ident, unsigned int world_kart_id, int position, const btTransform& init_transform); virtual ~Kart(); - virtual void init(RaceManager::KartType type, bool is_first_kart); + virtual void init(RaceManager::KartType type); virtual void updateGraphics(float dt, const Vec3& off_xyz, const btQuaternion& off_rotation); virtual void createPhysics (); @@ -290,18 +277,6 @@ public: /** Returns a points to this kart's graphical effects. */ KartGFX* getKartGFX() { return m_kart_gfx; } // ------------------------------------------------------------------------ - /** Returns the camera of this kart (or NULL if no camera is attached - * to this kart). */ - virtual Camera* getCamera () {return m_camera;} - // ------------------------------------------------------------------------ - /** Returns the camera of this kart (or NULL if no camera is attached - * to this kart) - const version. */ - virtual const Camera* getCamera () const {return m_camera;} - // ------------------------------------------------------------------------ - /** Sets the camera for this kart. Takes ownership of the camera and - * will delete it. */ - virtual void setCamera(Camera *camera); - // ------------------------------------------------------------------------ /** Returns the remaining collected energy. */ virtual float getEnergy () const { return m_collected_energy; } // ------------------------------------------------------------------------ diff --git a/src/karts/rescue_animation.cpp b/src/karts/rescue_animation.cpp index dd96bc80c..bfd718170 100644 --- a/src/karts/rescue_animation.cpp +++ b/src/karts/rescue_animation.cpp @@ -77,9 +77,13 @@ RescueAnimation::~RescueAnimation() m_kart->getBody()->setLinearVelocity(btVector3(0,0,0)); m_kart->getBody()->setAngularVelocity(btVector3(0,0,0)); World::getWorld()->getPhysics()->addKart(m_kart); - if (m_kart->getCamera() && - m_kart->getCamera()->getMode() != Camera::CM_FINAL) - m_kart->getCamera()->setMode(Camera::CM_NORMAL); + for(unsigned int i=0; igetKart()==m_kart && + camera->getMode() != Camera::CM_FINAL) + camera->setMode(Camera::CM_NORMAL); + } } } // ~RescueAnimation diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index 9c9964387..489f1de2a 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -125,7 +125,19 @@ void FollowTheLeaderRace::countdownReachedZero() } // Time doesn't make any sense in FTL (and it is not displayed) kart->finishedRace(-1.0f); - } + + // Move any camera for this kart to the leader, facing backwards, + // so that the eliminated player has something to watch. + for(unsigned int i=0; igetKart()==kart) + { + camera->setMode(Camera::CM_LEADER_MODE); + camera->setKart(getKart(0)); + } + } // for iinit(RaceManager::KT_AI, /*is_first_kart*/false); + new_kart->init(RaceManager::KT_AI); Controller *controller = loadAIController(new_kart); new_kart->setController(controller); @@ -118,7 +118,8 @@ AbstractKart *ProfileWorld::createKart(const std::string &kart_ident, int index, // karts can be seen. if (index == (int)race_manager->getNumberOfKarts()-1) { - new_kart->setCamera(new Camera(index, new_kart)); + // The camera keeps track of all cameras and will free them + Camera::createCamera(new_kart); } return new_kart; } // createKart diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index 522d142f6..78434dd43 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -151,6 +151,35 @@ void ThreeStrikesBattle::kartHit(const int kart_id) if(wheels[2]) wheels[2]->setVisible(false); if(wheels[3]) wheels[3]->setVisible(false); eliminateKart(kart_id, /*notify_of_elimination*/ true); + // Find a camera of the kart with the most lives ("leader"), and + // attach all cameras for this kart to the leader. + int max_lives = 0; + AbstractKart *leader = NULL; + for(unsigned int i=0; iisEliminated() || kart->hasFinishedRace() || + kart->getWorldKartId()==kart_id) continue; + if(m_kart_info[i].m_lives > max_lives) + { + leader = kart; + max_lives = m_kart_info[i].m_lives; + } + } + // leader could be 0 if the last two karts hit each other in + // the same frame + if(leader) + { + for(unsigned int i=0; igetKart()->getWorldKartId()==kart_id) + { + camera->setMode(Camera::CM_NORMAL); + camera->setKart(leader); + } + } // for in < number of cameras + } // if leader m_insert_tire = 4; } diff --git a/src/modes/world.cpp b/src/modes/world.cpp index b91695059..fd18517fd 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -211,7 +211,7 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index, int position = index+1; btTransform init_pos = m_track->getStartTransform(index); AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos); - new_kart->init(race_manager->getKartType(index), (local_player_id == 0)); + new_kart->init(race_manager->getKartType(index)); Controller *controller = NULL; switch(kart_type) { @@ -303,6 +303,8 @@ World::~World() delete m_karts[i]; m_karts.clear(); + Camera::removeAllCameras(); + projectile_manager->cleanup(); // In case that the track is not found, m_physics is still undefined. if(m_physics) @@ -553,14 +555,16 @@ void World::resetAllKarts() // Now store the current (i.e. in rest) suspension length for each // kart, so that the karts can visualise the suspension. (*i)->setSuspensionLength(); - // Initialise the camera (if available), now that the correct - // kart position is set - if((*i)->getCamera()) - (*i)->getCamera()->setInitialTransform(); // Update the kart transforms with the newly computed position // after all karts are reset (*i)->setTrans((*i)->getBody()->getWorldTransform()); } + + // Initialise the cameras, now that the correct kart positions are set + for(unsigned int i=0; isetInitialTransform(); + } } // resetAllKarts // ---------------------------------------------------------------------------- @@ -723,6 +727,11 @@ void World::update(float dt) if(!m_karts[i]->isEliminated()) m_karts[i]->update(dt) ; } + for(unsigned int i=0; iupdate(dt); + } + projectile_manager->update(dt); PROFILER_POP_CPU_MARKER(); @@ -881,53 +890,43 @@ AbstractKart *World::getPlayerKart(unsigned int n) const */ AbstractKart *World::getLocalPlayerKart(unsigned int n) const { - int count=-1; - const int kart_count = m_karts.size(); - for(int i=0; igetCamera() && - (m_karts[i]->getController()->isPlayerController() || - ProfileWorld::isProfileMode() ) ) - { - count++; - if(count == (int)n) return m_karts[i]; - } - } - return NULL; + if(n>=Camera::getNumCameras()) return NULL; + return Camera::getCamera(n)->getKart(); } // getLocalPlayerKart //----------------------------------------------------------------------------- /** Remove (eliminate) a kart from the race */ -void World::eliminateKart(int kart_number, bool notify_of_elimination) +void World::eliminateKart(int kart_id, bool notify_of_elimination) { - AbstractKart *kart = m_karts[kart_number]; + AbstractKart *kart = m_karts[kart_id]; - // Display a message about the eliminated kart in the race gui + // Display a message about the eliminated kart in the race guia if (notify_of_elimination) { - for (KartList::iterator i = m_karts.begin(); i != m_karts.end(); i++ ) + for(unsigned int i=0; igetCamera()) continue; - if(*i==kart) - { - m_race_gui->addMessage(_("You have been eliminated!"), *i, + Camera *camera = Camera::getCamera(i); + if(camera->getKart()==kart) + m_race_gui->addMessage(_("You have been eliminated!"), kart, 2.0f); - } else - { m_race_gui->addMessage(_("'%s' has been eliminated.", - core::stringw(kart->getName())), *i, + core::stringw(kart->getName())), + camera->getKart(), 2.0f); - } - } // for i in kart - } + } // for i < number of cameras + } // if notify_of_elimination if(kart->getController()->isPlayerController()) { - // Change the camera so that it will be attached to the leader - // and facing backwards. - Camera* camera=kart->getCamera(); - camera->setMode(Camera::CM_LEADER_MODE); + for(unsigned int i=0; igetKart()==kart) + camera->setMode(Camera::CM_LEADER_MODE); + } m_eliminated_players++; } @@ -981,6 +980,12 @@ void World::restartRace() { (*i)->reset(); } + + for(unsigned int i=0; ireset(); + } + if(ReplayPlay::get()) ReplayPlay::get()->reset(); resetAllKarts(); diff --git a/src/replay/replay_play.cpp b/src/replay/replay_play.cpp index 92ba28a6e..facddf79f 100644 --- a/src/replay/replay_play.cpp +++ b/src/replay/replay_play.cpp @@ -182,8 +182,7 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line) exit(-2); } m_ghost_karts.push_back(new GhostKart(std::string(s))); - m_ghost_karts[m_ghost_karts.size()-1].init(RaceManager::KT_GHOST, - /*is_first_kart*/false); + m_ghost_karts[m_ghost_karts.size()-1].init(RaceManager::KT_GHOST); fgets(s, 1023, fd); unsigned int size; diff --git a/src/states_screens/minimal_race_gui.cpp b/src/states_screens/minimal_race_gui.cpp index 42c3177e5..9848a8677 100644 --- a/src/states_screens/minimal_race_gui.cpp +++ b/src/states_screens/minimal_race_gui.cpp @@ -198,16 +198,19 @@ void MinimalRaceGUI::renderGlobal(float dt) * collectibles, ... * \param kart Pointer to the kart for which to render the view. */ -void MinimalRaceGUI::renderPlayerView(const AbstractKart *kart, float dt) +void MinimalRaceGUI::renderPlayerView(const Camera *camera, float dt) { if (!m_enabled) return; - const core::recti &viewport = kart->getCamera()->getViewport(); - core::vector2df scaling = kart->getCamera()->getScaling(); + const core::recti &viewport = camera->getViewport(); + core::vector2df scaling = camera->getScaling(); scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size - drawPlungerInFace(kart, dt); + const AbstractKart *kart = camera->getKart(); + if(!kart) return; + + drawPlungerInFace(camera, dt); drawAllMessages (kart, viewport, scaling); if(!World::getWorld()->isRacePhase()) return; @@ -215,7 +218,7 @@ void MinimalRaceGUI::renderPlayerView(const AbstractKart *kart, float dt) drawEnergyMeter (kart, viewport, scaling); drawRankLap (kart, viewport); - RaceGUIBase::renderPlayerView(kart, dt); + RaceGUIBase::renderPlayerView(camera, dt); } // renderPlayerView //----------------------------------------------------------------------------- diff --git a/src/states_screens/minimal_race_gui.hpp b/src/states_screens/minimal_race_gui.hpp index 92f25dc96..a3f8ab151 100644 --- a/src/states_screens/minimal_race_gui.hpp +++ b/src/states_screens/minimal_race_gui.hpp @@ -118,7 +118,7 @@ public: MinimalRaceGUI(); ~MinimalRaceGUI(); virtual void renderGlobal(float dt); - virtual void renderPlayerView(const AbstractKart *kart, float dt); + virtual void renderPlayerView(const Camera *camera, float dt); /** Returns the size of the texture on which to render the minimap to. */ virtual const core::dimension2du getMiniMapSize() const diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index 290834a3d..cb8d65012 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -184,15 +184,17 @@ void RaceGUI::renderGlobal(float dt) * collectibles, ... * \param kart Pointer to the kart for which to render the view. */ -void RaceGUI::renderPlayerView(const AbstractKart *kart, float dt) +void RaceGUI::renderPlayerView(const Camera *camera, float dt) { if (!m_enabled) return; - const core::recti &viewport = kart->getCamera()->getViewport(); + const core::recti &viewport = camera->getViewport(); - core::vector2df scaling = kart->getCamera()->getScaling(); + core::vector2df scaling = camera->getScaling(); + const AbstractKart *kart = camera->getKart(); + if(!kart) return; - drawPlungerInFace(kart, dt); + drawPlungerInFace(camera, dt); scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size drawAllMessages (kart, viewport, scaling); @@ -205,7 +207,7 @@ void RaceGUI::renderPlayerView(const AbstractKart *kart, float dt) if (!m_is_tutorial) drawRankLap (kart, viewport); - RaceGUIBase::renderPlayerView(kart, dt); + RaceGUIBase::renderPlayerView(camera, dt); } // renderPlayerView //----------------------------------------------------------------------------- diff --git a/src/states_screens/race_gui.hpp b/src/states_screens/race_gui.hpp index 1abd92390..ff456c8bf 100644 --- a/src/states_screens/race_gui.hpp +++ b/src/states_screens/race_gui.hpp @@ -111,7 +111,7 @@ public: RaceGUI(); ~RaceGUI(); virtual void renderGlobal(float dt); - virtual void renderPlayerView(const AbstractKart *kart, float dt); + virtual void renderPlayerView(const Camera *camera, float dt); /** Returns the size of the texture on which to render the minimap to. */ virtual const core::dimension2du getMiniMapSize() const diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index b92b3e7da..490b91a8d 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -474,21 +474,22 @@ void RaceGUIBase::update(float dt) * is used here to display the referee during the ready-set-go phase. * \param kart The kart whose view is rendered next. */ -void RaceGUIBase::preRenderCallback(const AbstractKart &kart) +void RaceGUIBase::preRenderCallback(const Camera *camera) { - if(m_referee) + if(m_referee && camera->getKart()) { - Vec3 xyz = m_referee_pos[kart.getWorldKartId()]; + unsigned int world_id = camera->getKart()->getWorldKartId(); + Vec3 xyz = m_referee_pos[world_id]; xyz.setY(xyz.getY()+m_referee_height); m_referee->setPosition(xyz); - m_referee->setRotation(m_referee_rotation[kart.getWorldKartId()]); + m_referee->setRotation(m_referee_rotation[world_id]); } } // preRenderCallback // ---------------------------------------------------------------------------- -void RaceGUIBase::renderPlayerView(const AbstractKart *kart, float dt) +void RaceGUIBase::renderPlayerView(const Camera *camera, float dt) { - const core::recti &viewport = kart->getCamera()->getViewport(); + const core::recti &viewport = camera->getViewport(); if (m_lightning > 0.0f) { @@ -1030,15 +1031,16 @@ void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin) /** Draws the plunger-in-face if necessary. Does nothing if there is no * plunger in face atm. */ -void RaceGUIBase::drawPlungerInFace(const AbstractKart *kart, float dt) +void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt) { + const AbstractKart *kart = camera->getKart(); if (kart->getBlockedByPlungerTime()<=0) { m_plunger_state = PLUNGER_STATE_INIT; return; } - const core::recti &viewport = kart->getCamera()->getViewport(); + const core::recti &viewport = camera->getViewport(); const int screen_width = viewport.LowerRightCorner.X - viewport.UpperLeftCorner.X; diff --git a/src/states_screens/race_gui_base.hpp b/src/states_screens/race_gui_base.hpp index bbe6ad4a5..6bf41186d 100644 --- a/src/states_screens/race_gui_base.hpp +++ b/src/states_screens/race_gui_base.hpp @@ -36,6 +36,7 @@ using namespace irr; #include "utils/vec3.hpp" class AbstractKart; +class Camera; class Material; class Referee; @@ -194,7 +195,7 @@ protected: const core::vector2df &scaling); void drawGlobalMusicDescription(); void drawGlobalReadySetGo (); - void drawPlungerInFace(const AbstractKart *kart, float dt); + void drawPlungerInFace(const Camera *camera, float dt); /** Instructs the base gui to ignore unimportant messages (like * item messages). */ @@ -220,7 +221,7 @@ public: virtual void renderGlobal(float dt); virtual void init(); virtual void restartRace(); - virtual void renderPlayerView(const AbstractKart *kart, float dt); + virtual void renderPlayerView(const Camera *camera, float dt); virtual void addMessage(const irr::core::stringw &m, const AbstractKart *kart, float time, const video::SColor &color= @@ -228,7 +229,7 @@ public: bool important=true, bool big_font=false); virtual void update(float dt); - virtual void preRenderCallback(const AbstractKart &kart); + virtual void preRenderCallback(const Camera *camera); // ------------------------------------------------------------------------ /** Returns the size of the texture on which to render the minimap to. */ virtual const core::dimension2du diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp index 444582533..ccc5950cc 100644 --- a/src/states_screens/race_gui_overworld.cpp +++ b/src/states_screens/race_gui_overworld.cpp @@ -178,13 +178,14 @@ void RaceGUIOverworld::renderGlobal(float dt) * collectibles, ... * \param kart Pointer to the kart for which to render the view. */ -void RaceGUIOverworld::renderPlayerView(const AbstractKart *kart, float dt) +void RaceGUIOverworld::renderPlayerView(const Camera *camera, float dt) { if (!m_enabled) return; + const AbstractKart *kart = camera->getKart(); + if(!kart) return; - const core::recti &viewport = kart->getCamera()->getViewport(); - - core::vector2df scaling = kart->getCamera()->getScaling(); + const core::recti &viewport = camera->getViewport(); + core::vector2df scaling = camera->getScaling(); //std::cout << "Applied ratio : " << viewport.getWidth()/800.0f << std::endl; scaling *= viewport.getWidth()/800.0f; // scale race GUI along screen size @@ -197,7 +198,7 @@ void RaceGUIOverworld::renderPlayerView(const AbstractKart *kart, float dt) drawPowerupIcons (kart, viewport, scaling); - RaceGUIBase::renderPlayerView(kart, dt); + RaceGUIBase::renderPlayerView(camera, dt); } // renderPlayerView //----------------------------------------------------------------------------- diff --git a/src/states_screens/race_gui_overworld.hpp b/src/states_screens/race_gui_overworld.hpp index 2c950c2e1..3cb0fc3a3 100644 --- a/src/states_screens/race_gui_overworld.hpp +++ b/src/states_screens/race_gui_overworld.hpp @@ -120,7 +120,7 @@ public: RaceGUIOverworld(); ~RaceGUIOverworld(); virtual void renderGlobal(float dt); - virtual void renderPlayerView(const AbstractKart *kart, float dt); + virtual void renderPlayerView(const Camera *camera, float dt); // ------------------------------------------------------------------------ /** Returns the currently selected challenge data (or NULL if no is diff --git a/src/tracks/ambient_light_sphere.cpp b/src/tracks/ambient_light_sphere.cpp index 639a1e9d0..c09783622 100644 --- a/src/tracks/ambient_light_sphere.cpp +++ b/src/tracks/ambient_light_sphere.cpp @@ -48,10 +48,11 @@ void AmbientLightSphere::update(float dt) CheckStructure::update(dt); World *world = World::getWorld(); - for(unsigned int i=0; igetNumKarts(); i++) + for(unsigned int i=0; igetKart(i); - if(!kart->getCamera()) continue; + Camera *camera = Camera::getCamera(i); + const AbstractKart *kart=camera->getKart(); + if(!kart) continue; if(isInside(i)) { float d2=getDistance2ForKart(i); @@ -67,7 +68,7 @@ void AmbientLightSphere::update(float dt) const video::SColor &def = track->getDefaultAmbientColor(); color = m_ambient_color.getInterpolated(def, f); } - kart->getCamera()->setAmbientLight(color); + camera->setAmbientLight(color); } // if active } // for igetKart(indx)->getCamera()) return false; - return CheckSphere::isTriggered(old_pos, new_pos, indx); + for(unsigned int i=0; igetKart()->getWorldKartId()==indx) + return CheckSphere::isTriggered(old_pos, new_pos, indx); + } + return false; } // isTriggered diff --git a/src/tracks/track_sector.hpp b/src/tracks/track_sector.hpp index da804a767..af6edf129 100644 --- a/src/tracks/track_sector.hpp +++ b/src/tracks/track_sector.hpp @@ -22,7 +22,6 @@ #include "utils/vec3.hpp" class Track; -class Kart; /** This object keeps track of which sector an object is on. A sector is * actually just the graph node (it's called sector to better distinguish