1) Added support for new camera mode: end camera positions and types
can now be specified in the scene file. Currently supported are: - normal 'ahead of kart' camera (which is what we used so far) - fixed camera: camera is at a fixed position, always looking at the kart. 2) Removed camera.hpp dependency from kart.hpp. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@5585 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
f1c187d5d5
commit
c1c7daf2fa
@ -29,12 +29,15 @@
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "karts/kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
std::vector<Camera::EndCameraInformation> Camera::m_end_cameras;
|
||||
|
||||
Camera::Camera(int camera_index, const Kart* kart)
|
||||
{
|
||||
m_mode = CM_NORMAL;
|
||||
@ -64,6 +67,23 @@ Camera::~Camera()
|
||||
irr_driver->removeCameraSceneNode(m_camera);
|
||||
} // ~Camera
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Reads the information about the end camera. This information is shared
|
||||
* between all cameras, so this is a static function.
|
||||
* \param node The XML node containing all end camera informations
|
||||
*/
|
||||
void Camera::readEndCamera(const XMLNode &root)
|
||||
{
|
||||
m_end_cameras.clear();
|
||||
for(unsigned int i=0; i<root.getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *node = root.getNode(i);
|
||||
EndCameraInformation eci;
|
||||
if(!eci.readXML(*node)) continue;
|
||||
m_end_cameras.push_back(eci);
|
||||
} // for i<getNumNodes()
|
||||
} // readEndCamera
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Sets up the viewport, aspect ratio, field of view, and scaling for this
|
||||
* camera.
|
||||
@ -154,6 +174,7 @@ void Camera::setMode(Mode mode)
|
||||
computeNormalCameraPosition(&wanted_position, &wanted_target);
|
||||
m_camera->setPosition(wanted_position.toIrrVector());
|
||||
m_camera->setTarget(wanted_target.toIrrVector());
|
||||
|
||||
assert(!isnan(m_camera->getPosition().X));
|
||||
assert(!isnan(m_camera->getPosition().Y));
|
||||
assert(!isnan(m_camera->getPosition().Z));
|
||||
@ -161,12 +182,15 @@ void Camera::setMode(Mode mode)
|
||||
}
|
||||
if(mode==CM_FINAL)
|
||||
{
|
||||
#undef NEW_FINAL_CAMERA
|
||||
#ifdef NEW_FINAL_CAMERA
|
||||
m_camera->setPosition(core::vector3df(-2, 1, 10));
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
#endif
|
||||
}
|
||||
m_next_end_camera = m_end_cameras.size()>1 ? 1 : 0;
|
||||
m_current_end_camera = 0;
|
||||
if(m_end_cameras.size()>0 &&
|
||||
m_end_cameras[0].m_type==EndCameraInformation::EC_STATIC_FOLLOW_KART)
|
||||
{
|
||||
m_camera->setPosition(m_end_cameras[0].m_position.toIrrVector());
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
}
|
||||
} // mode==CM_FINAL
|
||||
|
||||
m_mode = mode;
|
||||
} // setMode
|
||||
@ -199,7 +223,8 @@ void Camera::setInitialTransform()
|
||||
+ core::vector3df(0, 25, -50) );
|
||||
m_camera->setRotation(core::vector3df(0, 0, 0));
|
||||
m_camera->setRotation( core::vector3df( 0.0f, 0.0f, 0.0f ) );
|
||||
|
||||
m_camera->setFOV(m_fov);
|
||||
|
||||
assert(!isnan(m_camera->getPosition().X));
|
||||
assert(!isnan(m_camera->getPosition().Y));
|
||||
assert(!isnan(m_camera->getPosition().Z));
|
||||
@ -296,48 +321,14 @@ void Camera::update(float dt)
|
||||
break;
|
||||
}
|
||||
case CM_FINAL:
|
||||
#ifdef NEW_FINAL_CAMERA
|
||||
{
|
||||
const core::vector3df &cp = m_camera->getAbsolutePosition();
|
||||
const Vec3 &kp = m_kart->getXYZ();
|
||||
// Estimate the fov, assuming that the vector from the camera to
|
||||
// the kart and the kart length are orthogonal to each other
|
||||
// --> tan (fov) = kart_length / camera_kart_distance
|
||||
// In order to show a little bit of the surrounding of the kart
|
||||
// the kart length is multiplied by 3 (experimentally found, but
|
||||
// this way we have approx one kart length on the left and right
|
||||
// side of the screen for the surroundings)
|
||||
float fov = atan2(3*m_kart->getKartLength(),
|
||||
(cp-kp.toIrrVector()).getLength());
|
||||
m_camera->setFOV(fov);
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
handleEndCamera(dt);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
{
|
||||
wanted_target.setY(wanted_target.getY()+ 0.75f);
|
||||
float angle_around = m_kart->getHeading()
|
||||
//+ m_rotation_range * m_kart->getSteerPercent()
|
||||
//* m_kart->getSkidding()
|
||||
;
|
||||
float angle_up = m_kart->getPitch() + 30.0f*DEGREE_TO_RAD;
|
||||
wanted_position.setX( sin(angle_around));
|
||||
wanted_position.setY( sin(angle_up) );
|
||||
wanted_position.setZ( cos(angle_around));
|
||||
wanted_position *= m_distance * 2.0f;
|
||||
wanted_position += wanted_target;
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
m_camera->setPosition(wanted_position.toIrrVector());
|
||||
m_camera->setTarget(wanted_target.toIrrVector());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case CM_REVERSE: // Same as CM_NORMAL except it looks backwards
|
||||
{
|
||||
wanted_target.setY(wanted_target.getY()+ 0.75f);
|
||||
float angle_around = m_kart->getHeading()
|
||||
+ m_rotation_range * m_kart->getSteerPercent()
|
||||
* m_kart->getSkidding();
|
||||
float angle_around = m_kart->getHeading();
|
||||
float angle_up = m_kart->getPitch() + 30.0f*DEGREE_TO_RAD;
|
||||
wanted_position.setX( sin(angle_around));
|
||||
wanted_position.setY( sin(angle_up) );
|
||||
@ -389,6 +380,73 @@ void Camera::update(float dt)
|
||||
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function handles the end camera. It adjusts the camera position
|
||||
* according to the current camera type, and checks if a switch to the
|
||||
* next camera should be made.
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void Camera::handleEndCamera(float dt)
|
||||
{
|
||||
switch(m_end_cameras[m_current_end_camera].m_type)
|
||||
{
|
||||
case EndCameraInformation::EC_STATIC_FOLLOW_KART:
|
||||
{
|
||||
const core::vector3df &cp = m_camera->getAbsolutePosition();
|
||||
const Vec3 &kp = m_kart->getXYZ();
|
||||
// Estimate the fov, assuming that the vector from the camera to
|
||||
// the kart and the kart length are orthogonal to each other
|
||||
// --> tan (fov) = kart_length / camera_kart_distance
|
||||
// In order to show a little bit of the surrounding of the kart
|
||||
// the kart length is multiplied by 3 (experimentally found, but
|
||||
// this way we have approx one kart length on the left and right
|
||||
// side of the screen for the surroundings)
|
||||
float fov = 3*atan2(m_kart->getKartLength(),
|
||||
(cp-kp.toIrrVector()).getLength());
|
||||
m_camera->setFOV(fov);
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
break;
|
||||
}
|
||||
case EndCameraInformation::EC_AHEAD_OF_KART:
|
||||
{
|
||||
Vec3 wanted_target = m_kart->getXYZ();
|
||||
wanted_target.setY(wanted_target.getY()+ 0.75f);
|
||||
float angle_around = m_kart->getHeading()
|
||||
//+ m_rotation_range * m_kart->getSteerPercent()
|
||||
//* m_kart->getSkidding()
|
||||
;
|
||||
float angle_up = m_kart->getPitch() + 30.0f*DEGREE_TO_RAD;
|
||||
Vec3 wanted_position;
|
||||
wanted_position.setX( sin(angle_around));
|
||||
wanted_position.setY( sin(angle_up) );
|
||||
wanted_position.setZ( cos(angle_around));
|
||||
wanted_position *= m_distance * 2.0f;
|
||||
wanted_position += wanted_target;
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
m_camera->setPosition(wanted_position.toIrrVector());
|
||||
m_camera->setTarget(wanted_target.toIrrVector());
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
} // switch
|
||||
|
||||
// Now test if the kart is close enough to the next end camera, and
|
||||
// if so activate it.
|
||||
if( m_end_cameras.size()>0 &&
|
||||
m_end_cameras[m_next_end_camera].isReached(m_kart->getXYZ()))
|
||||
{
|
||||
m_current_end_camera = m_next_end_camera;
|
||||
if(m_end_cameras[m_current_end_camera].m_type
|
||||
==EndCameraInformation::EC_STATIC_FOLLOW_KART)
|
||||
m_camera->setPosition(
|
||||
m_end_cameras[m_current_end_camera].m_position.toIrrVector()
|
||||
);
|
||||
m_camera->setFOV(m_fov);
|
||||
m_next_end_camera++;
|
||||
if(m_next_end_camera>=m_end_cameras.size()) m_next_end_camera = 0;
|
||||
}
|
||||
} // handleEndCamera
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets viewport etc. for this camera. Called from irr_driver just before
|
||||
* rendering the view for this kart.
|
||||
|
@ -22,15 +22,19 @@
|
||||
#ifndef HEADER_CAMERA_HPP
|
||||
#define HEADER_CAMERA_HPP
|
||||
|
||||
#include "utils/vec3.hpp"
|
||||
#include <vector>
|
||||
|
||||
#include "irrlicht.h"
|
||||
using namespace irr;
|
||||
|
||||
#include "io/xml_node.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
class Kart;
|
||||
|
||||
/**
|
||||
* \brief Handles the game camera
|
||||
* \ingroup graphics
|
||||
* \ingroup graphicsp"
|
||||
*/
|
||||
class Camera
|
||||
{
|
||||
@ -91,14 +95,82 @@ private:
|
||||
/** Velocity of the target of the camera, only used for end camera. */
|
||||
core::vector3df m_target_velocity;
|
||||
|
||||
/** A class that stores information about the different end cameras
|
||||
* which can be specified in the scene.xml file. */
|
||||
class EndCameraInformation
|
||||
{
|
||||
public:
|
||||
/** The camera type:
|
||||
EC_STATIC_FOLLOW_KART A static camera that always points at the
|
||||
kart.
|
||||
EC_AHEAD_OF_KART A camera that flies ahead of the kart
|
||||
always pointing at the kart.
|
||||
*/
|
||||
enum {EC_STATIC_FOLLOW_KART,
|
||||
EC_AHEAD_OF_KART}
|
||||
m_type;
|
||||
|
||||
/** Position of the end camera. */
|
||||
Vec3 m_position;
|
||||
|
||||
/** Distance to kart by which this camera is activated. */
|
||||
float m_distance2;
|
||||
|
||||
/** Reads end camera information from XML. Returns false if an
|
||||
* error occurred.
|
||||
* \param node XML Node with the end camera information. */
|
||||
bool readXML(const XMLNode &node)
|
||||
{
|
||||
std::string s;
|
||||
node.get("type", &s);
|
||||
if(s=="static_follow_kart")
|
||||
m_type = EC_STATIC_FOLLOW_KART;
|
||||
else if(s=="ahead_of_kart")
|
||||
m_type = EC_AHEAD_OF_KART;
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Invalid camera type '%s' - camera is ignored.\n",
|
||||
s.c_str());
|
||||
return false;
|
||||
}
|
||||
node.get("xyz", &m_position);
|
||||
node.get("distance", &m_distance2);
|
||||
// Store the squared value
|
||||
m_distance2 *= m_distance2;
|
||||
return true;
|
||||
} // readXML
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns true if the specified position is close enough to this
|
||||
* camera, so that this camera should become the next end camera.
|
||||
* \param xyz Position to test for distance.
|
||||
* \returns True if xyz is close enough to this camera.
|
||||
*/
|
||||
bool isReached(const Vec3 &xyz)
|
||||
{ return (xyz-m_position).length2() < m_distance2; }
|
||||
}; // EndCameraInformation
|
||||
|
||||
/** List of all end camera information. This information is shared
|
||||
* between all cameras, so it's static. */
|
||||
static std::vector<EndCameraInformation> m_end_cameras;
|
||||
|
||||
/** Index of the current end camera. */
|
||||
unsigned int m_current_end_camera;
|
||||
|
||||
/** The next end camera to be activated. */
|
||||
unsigned int m_next_end_camera;
|
||||
|
||||
void setupCamera();
|
||||
void smoothMoveCamera(float dt, const Vec3 &wanted_position,
|
||||
const Vec3 &wanted_target);
|
||||
void computeNormalCameraPosition(Vec3 *wanted_position,
|
||||
Vec3 *wanted_target);
|
||||
void handleEndCamera(float dt);
|
||||
|
||||
public:
|
||||
Camera (int camera_index, const Kart* kart);
|
||||
~Camera ();
|
||||
static void readEndCamera(const XMLNode &root);
|
||||
void setMode (Mode mode_); /** Set the camera to the given mode */
|
||||
Mode getMode();
|
||||
/** Returns the camera index (or player kart index, which is the same). */
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/nitro.hpp"
|
||||
#include "graphics/shadow.hpp"
|
||||
@ -481,7 +482,7 @@ void Kart::finishedRace(float time)
|
||||
m_kart_properties->getKartModel()->setAnimation(KartModel::AF_LOSE_START);
|
||||
|
||||
// Not all karts have a camera
|
||||
if (m_camera) m_camera->setMode(Camera::CM_REVERSE);
|
||||
if (m_camera) m_camera->setMode(Camera::CM_FINAL);
|
||||
|
||||
RaceGUI* m = World::getWorld()->getRaceGUI();
|
||||
if(m)
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include "graphics/camera.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "karts/emergency_animation.hpp"
|
||||
@ -36,19 +35,20 @@
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "tracks/terrain_info.hpp"
|
||||
|
||||
class SkidMarks;
|
||||
class Shadow;
|
||||
class Item;
|
||||
class Smoke;
|
||||
class WaterSplash;
|
||||
class Nitro;
|
||||
class SlipStream;
|
||||
class SFXBase;
|
||||
class btUprightConstraint;
|
||||
class btKart;
|
||||
class btUprightConstraint;
|
||||
class btVehicleTuning;
|
||||
class Camera;
|
||||
class Item;
|
||||
class Nitro;
|
||||
class Quad;
|
||||
class Shadow;
|
||||
class SFXBase;
|
||||
class SkidMarks;
|
||||
class SlipStream;
|
||||
class Smoke;
|
||||
class Stars;
|
||||
class WaterSplash;
|
||||
|
||||
/** The main kart class. All type of karts are of this object, but with
|
||||
* different controllers. The controllers are what turn a kart into a
|
||||
|
@ -31,6 +31,7 @@ using namespace irr;
|
||||
#include "audio/music_manager.hpp"
|
||||
#include "config/stk_config.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "graphics/CBatchingMesh.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
@ -814,6 +815,10 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
{
|
||||
handleSky(*node, path);
|
||||
}
|
||||
else if(name=="end-cameras")
|
||||
{
|
||||
Camera::readEndCamera(*node);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Warning: while loading track '%s', element '%s' was met but is unknown.\n",
|
||||
|
@ -360,7 +360,7 @@ namespace StringUtils
|
||||
*/
|
||||
std::string timeToString(float time)
|
||||
{
|
||||
int int_time = time*100.0f+0.5f;
|
||||
int int_time = (int)(time*100.0f+0.5f);
|
||||
int min = int_time / 6000;
|
||||
int sec = (int_time-min*6000)/100;
|
||||
int hundredths = (int_time - min*6000-sec*100);
|
||||
|
Loading…
x
Reference in New Issue
Block a user