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:
hikerstk 2010-06-28 23:33:07 +00:00
parent f1c187d5d5
commit c1c7daf2fa
6 changed files with 193 additions and 57 deletions

View File

@ -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.

View File

@ -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). */

View File

@ -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)

View File

@ -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

View File

@ -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",

View File

@ -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);