diff --git a/sources.cmake b/sources.cmake index ddc029d4f..dfc0e3774 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 98c2162e3..630f108e0 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -23,6 +23,10 @@ #include "audio/sfx_manager.hpp" #include "config/user_config.hpp" +#include "graphics/camera_debug.hpp" +#include "graphics/camera_end.hpp" +#include "graphics/camera_fps.hpp" +#include "graphics/camera_normal.hpp" #include "graphics/irr_driver.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" @@ -38,20 +42,68 @@ #include "utils/constants.hpp" #include "utils/vs.hpp" -#include "ICameraSceneNode.h" #include "ISceneManager.h" -AlignedArray Camera::m_end_cameras; -std::vector Camera::m_all_cameras; +std::vector Camera::m_all_cameras; +Camera* Camera::s_active_camera = NULL; +Camera::CameraType Camera::m_default_type = Camera::CM_TYPE_NORMAL; -Camera* Camera::s_active_camera = NULL; -Camera::DebugMode Camera::m_debug_mode = Camera::CM_DEBUG_NONE; +// ------------------------------------------------------------------------ +/** Creates a new camera and adds it to the list of all cameras. Also the + * camera index (which determines which viewport to use in split screen) + * is set. + */ +Camera* Camera::createCamera(AbstractKart* kart) +{ + Camera *camera = createCamera(m_all_cameras.size(), m_default_type, kart); + m_all_cameras.push_back(camera); + return camera; +} // createCamera(kart) -// ============================================================================ +// ---------------------------------------------------------------------------- +/** Creates a camera of the specified type, but does not add it to the list + * of all cameras. This is a helper function for other static functions. + * \paran index Index this camera has in the list of all cameras. + * \param type The camera type of the camera to create. + * \param kart To which kart the camera is attached (NULL if a free camera). + */ +Camera* Camera::createCamera(unsigned int index, CameraType type, + AbstractKart* kart) +{ + Camera *camera = NULL; + switch (type) + { + case CM_TYPE_NORMAL: camera = new CameraNormal(index, kart); break; + case CM_TYPE_DEBUG: camera = new CameraDebug (index, kart); break; + case CM_TYPE_FPS: camera = new CameraFPS (index, kart); break; + case CM_TYPE_END: camera = new CameraEnd (index, kart); break; + } // switch type + + return camera; +} // createCamera + +// ---------------------------------------------------------------------------- +void Camera::changeCamera(unsigned int camera_index, CameraType type) +{ + assert(camera_indexgetType()==type) return; + + Camera *new_camera = createCamera(old_camera->getIndex(), type, + old_camera->m_kart ); + // Replace the previous camera + m_all_cameras[camera_index] = new_camera; + if(s_active_camera == old_camera) + s_active_camera == new_camera; + delete old_camera; +} // changeCamera + +// ---------------------------------------------------------------------------- Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) { - m_smooth = false; - m_attached = false; m_mode = CM_NORMAL; m_index = camera_index; m_original_kart = kart; @@ -60,31 +112,8 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL) setupCamera(); setKart(kart); - m_distance = kart ? kart->getKartProperties()->getCameraDistance() : 1000.0f; m_ambient_light = World::getWorld()->getTrack()->getDefaultAmbientColor(); - // TODO: Put these values into a config file - // Global or per split screen zone? - // Either global or per user (for instance, some users may not like - // the extra camera rotation so they could set m_rotation_range to - // zero to disable it for themselves). - m_position_speed = 8.0f; - m_target_speed = 10.0f; - m_rotation_range = 0.4f; - m_rotation_range = 0.0f; - m_lin_velocity = core::vector3df(0, 0, 0); - m_target_velocity = core::vector3df(0, 0, 0); - m_target_direction = core::vector3df(0, 0, 1); - m_target_up_vector = core::vector3df(0, 1, 0); - m_direction_velocity = core::vector3df(0, 0, 0); - - m_local_position = core::vector3df(0, 0, 0); - m_local_direction = core::vector3df(0, 0, 1); - m_local_up = core::vector3df(0, 1, 0); - - m_angular_velocity = 0; - m_target_angular_velocity = 0; - m_max_velocity = 15; reset(); } // Camera @@ -99,53 +128,6 @@ Camera::~Camera() s_active_camera = NULL; } // ~Camera -//----------------------------------------------------------------------------- -/** Applies mouse movement to the first person camera. - * \param x The horizontal difference of the mouse position. - * \param y The vertical difference of the mouse position. - */ -void Camera::applyMouseMovement (float x, float y) -{ - vector3df direction(m_target_direction); - vector3df up(m_camera->getUpVector()); - - // Set local values if the camera is attached to the kart - if (m_attached) - up = m_local_up; - - direction.normalize(); - up.normalize(); - - vector3df side(direction.crossProduct(up)); - side.normalize(); - core::quaternion quat; - quat.fromAngleAxis(y, side); - - core::quaternion quat_x; - quat_x.fromAngleAxis(x, up); - quat *= quat_x; - - direction = quat * direction; - // Try to prevent toppling over - // If the camera would topple over with the next movement, the vertical - // movement gets reset close to the up vector - if ((direction - up).getLengthSQ() + (m_target_direction - up).getLengthSQ() - <= (direction - m_target_direction).getLengthSQ()) - direction = quat_x * ((m_target_direction - up).setLength(0.02f) + up); - // Prevent toppling under - else if ((direction + up).getLengthSQ() + (m_target_direction + up).getLengthSQ() - <= (direction - m_target_direction).getLengthSQ()) - direction = quat_x * ((m_target_direction + up).setLength(0.02f) - up); - m_target_direction = direction; - - // Don't do that because it looks ugly and is bad to handle ;) - /*side = direction.crossProduct(up); - // Compute new up vector - up = side.crossProduct(direction); - up.normalize(); - cam->setUpVector(up);*/ -} - //----------------------------------------------------------------------------- /** Changes the owner of this camera to the new kart. * \param new_kart The new kart to use this camera. @@ -161,46 +143,14 @@ void Camera::setKart(AbstractKart *new_kart) } // setKart -//----------------------------------------------------------------------------- -/** This function clears all end camera data structure. This is necessary - * since all end cameras are shared between all camera instances (i.e. are - * static), otherwise (if no end camera is defined for a track) the old - * end camera structure would be used. - */ -void Camera::clearEndCameras() -{ - m_end_cameras.clear(); -} // clearEndCameras - -//----------------------------------------------------------------------------- -/** 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; iisReverse()) - index = root.getNumNodes() - 1 - i; - const XMLNode *node = root.getNode(index); - EndCameraInformation eci; - if(!eci.readXML(*node)) continue; - m_end_cameras.push_back(eci); - } // for igetActualScreenSize().Width)/irr_driver->getActualScreenSize().Height; + m_aspect = (float)(irr_driver->getActualScreenSize().Width) + / irr_driver->getActualScreenSize().Height; switch(race_manager->getNumLocalPlayers()) { case 1: m_viewport = core::recti(0, 0, @@ -277,21 +227,18 @@ void Camera::setMode(Mode mode) { // If we switch from reverse view, move the camera immediately to the // correct position. - if((m_mode==CM_REVERSE && mode==CM_NORMAL) || (m_mode==CM_FALLING && mode==CM_NORMAL)) + if( (m_mode==CM_REVERSE && mode==CM_NORMAL) || + (m_mode==CM_FALLING && mode==CM_NORMAL) ) { Vec3 start_offset(0, 1.6f, -3); Vec3 current_position = m_kart->getTrans()(start_offset); - m_camera->setPosition( current_position.toIrrVector()); + m_camera->setPosition(current_position.toIrrVector()); m_camera->setTarget(m_camera->getPosition()); } - if(mode==CM_FINAL) + + if(mode==CM_TYPE_END) { - if(m_end_cameras.size()>0) - m_camera->setPosition(m_end_cameras[0].m_position.toIrrVector()); - m_next_end_camera = m_end_cameras.size()>1 ? 1 : 0; - m_current_end_camera = 0; - m_camera->setFOV(m_fov); - handleEndCamera(0); + printf(""); } // mode==CM_FINAL m_mode = mode; @@ -303,7 +250,7 @@ void Camera::setMode(Mode mode) Camera::Mode Camera::getMode() { return m_mode; -} +} // getMode //----------------------------------------------------------------------------- /** Reset is called when a new race starts. Make sure that the camera @@ -327,6 +274,9 @@ void Camera::setInitialTransform() if (m_kart == NULL) return; Vec3 start_offset(0, 1.6f, -3); Vec3 current_position = m_kart->getTrans()(start_offset); + assert(!std::isnan(current_position.getX())); + assert(!std::isnan(current_position.getY())); + assert(!std::isnan(current_position.getZ())); m_camera->setPosition( current_position.toIrrVector()); // Reset the target from the previous target (in case of a restart // of a race) - otherwise the camera will initially point in the wrong @@ -337,179 +287,15 @@ void Camera::setInitialTransform() 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(!std::isnan(m_camera->getPosition().X)); - assert(!std::isnan(m_camera->getPosition().Y)); - assert(!std::isnan(m_camera->getPosition().Z)); } // setInitialTransform -//----------------------------------------------------------------------------- -/** Moves the camera smoothly from the current camera position (and target) - * to the new position and target. - * \param wanted_position The position the camera wanted to reach. - * \param wanted_target The point the camera wants to point to. - */ -void Camera::smoothMoveCamera(float dt) -{ - Kart *kart = dynamic_cast(m_kart); - if (kart->isFlying()) - { - Vec3 vec3 = m_kart->getXYZ() + Vec3(sin(m_kart->getHeading()) * -4.0f, 0.5f, cos(m_kart->getHeading()) * -4.0f); - m_camera->setTarget(m_kart->getXYZ().toIrrVector()); - m_camera->setPosition(vec3.toIrrVector()); - return; - } - - - core::vector3df current_position = m_camera->getPosition(); - // Smoothly interpolate towards the position and target - const KartProperties *kp = m_kart->getKartProperties(); - float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease(); - float max_speed_without_zipper = kp->getEngineMaxSpeed(); - float current_speed = m_kart->getSpeed(); - - const Skidding *ks = m_kart->getSkidding(); - float skid_factor = ks->getVisualSkidRotation(); - - float skid_angle = asin(skid_factor); - float ratio = (current_speed - max_speed_without_zipper) / max_increase_with_zipper; - ratio = ratio > -0.12f ? ratio : -0.12f; - float camera_distance = -3 * (0.5f + ratio);// distance of camera from kart in x and z plane - if (camera_distance > -2.0f) camera_distance = -2.0f; - Vec3 camera_offset(camera_distance * sin(skid_angle / 2), - 1.1f * (1 + ratio / 2), - camera_distance * cos(skid_angle / 2));// defines how far camera should be from player kart. - Vec3 m_kart_camera_position_with_offset = m_kart->getTrans()(camera_offset); - - - - core::vector3df current_target = m_kart->getXYZ().toIrrVector();// next target - current_target.Y += 0.5f; - core::vector3df wanted_position = m_kart_camera_position_with_offset.toIrrVector();// new required position of camera - - if ((m_kart->getSpeed() > 5 ) || (m_kart->getSpeed() < 0 )) - { - current_position += ((wanted_position - current_position) * dt - * (m_kart->getSpeed()>0 ? m_kart->getSpeed()/3 + 1.0f - : -1.5f * m_kart->getSpeed() + 2.0f)); - } - else - { - current_position += (wanted_position - current_position) * dt * 5; - } - - // Avoid camera crash: if the speed is negative, the current_position - // can oscillate between plus and minus, getting bigger and bigger. If - // this happens often enough, floating point overflow happens (large - // negative speeds can happen when the kart is tumbling/falling) - // To avoid this, we just move the camera to the wanted position if - // the distance becomes too large (see #1356). - if( (current_position - wanted_position).getLengthSQ() > 100) - { - Log::debug("camera", "Resetting camera position to avoid crash"); - current_position = wanted_position; - } - - if(m_mode!=CM_FALLING) - m_camera->setPosition(current_position); - m_camera->setTarget(current_target);//set new target - - assert(!std::isnan(m_camera->getPosition().X)); - assert(!std::isnan(m_camera->getPosition().Y)); - assert(!std::isnan(m_camera->getPosition().Z)); - -} // smoothMoveCamera - -//----------------------------------------------------------------------------- -/** Determine the camera settings for the current frame. - * \param above_kart How far above the camera should aim at. - * \param cam_angle Angle above the kart plane for the camera. - * \param sideway Sideway movement of the camera. - * \param distance Distance from kart. - */ -void Camera::getCameraSettings(float *above_kart, float *cam_angle, - float *sideway, float *distance, - bool *smoothing) -{ - const KartProperties *kp = m_kart->getKartProperties(); - - switch(m_mode) - { - case CM_NORMAL: - case CM_FALLING: - { - if(m_debug_mode==CM_DEBUG_GROUND) - { - *above_kart = 0; - *cam_angle = 0; - *distance = -m_kart->getKartModel()->getLength()-1.0f; - } - else if(m_debug_mode==CM_DEBUG_BEHIND_KART) - { - *above_kart = 0; - *cam_angle = 0; - *distance = -0.5f*m_kart->getKartModel()->getLength()-1.0f; - *smoothing = false; - } - else - { - *above_kart = 0.75f; - *cam_angle = kp->getCameraForwardUpAngle() * DEGREE_TO_RAD; - *distance = -m_distance; - } - float steering = m_kart->getSteerPercent() - * (1.0f + (m_kart->getSkidding()->getSkidFactor() - - 1.0f)/2.3f ); - // quadratically to dampen small variations (but keep sign) - float dampened_steer = fabsf(steering) * steering; - *sideway = -m_rotation_range*dampened_steer*0.5f; - *smoothing = true; - break; - } // CM_FALLING - case CM_REVERSE: // Same as CM_NORMAL except it looks backwards - { - *above_kart = 0.75f; - *cam_angle = kp->getCameraBackwardUpAngle() * DEGREE_TO_RAD; - *sideway = 0; - *distance = 2.0f*m_distance; - *smoothing = false; - break; - } - case CM_CLOSEUP: // Lower to the ground and closer to the kart - { - *above_kart = 0.75f; - *cam_angle = 20.0f*DEGREE_TO_RAD; - *sideway = m_rotation_range - * m_kart->getSteerPercent() - * m_kart->getSkidding()->getSkidFactor(); - *distance = -0.5f*m_distance; - *smoothing = false; - break; - } - case CM_LEADER_MODE: - { - *above_kart = 0.0f; - *cam_angle = 40*DEGREE_TO_RAD; - *sideway = 0; - *distance = 2.0f*m_distance; - *smoothing = true; - break; - } - case CM_FINAL: - case CM_SIMPLE_REPLAY: - // TODO: Implement - break; - } - -} // getCameraSettings - //----------------------------------------------------------------------------- /** Called once per time frame to move the camera to the right position. * \param dt Time step. */ void Camera::update(float dt) { - if (m_kart == NULL) + if (!m_kart) { if (race_manager->getNumLocalPlayers() < 2) { @@ -526,320 +312,11 @@ void Camera::update(float dt) { Vec3 heading(sin(m_kart->getHeading()), 0.0f, cos(m_kart->getHeading())); SFXManager::get()->positionListener(m_kart->getXYZ(), - heading, - Vec3(0, 1, 0)); - } - - float above_kart, cam_angle, side_way, distance; - bool smoothing; - - // To view inside tunnels in top mode, increase near value - m_camera->setNearValue(m_debug_mode==CM_DEBUG_TOP_OF_KART ? 27.0f : 1.0f); - - // The following settings give a debug camera which shows the track from - // high above the kart straight down. - if (m_debug_mode==CM_DEBUG_TOP_OF_KART) - { - core::vector3df xyz = m_kart->getXYZ().toIrrVector(); - m_camera->setTarget(xyz); - xyz.Y = xyz.Y+55; - xyz.Z -= 5.0f; - m_camera->setPosition(xyz); - } - else if (m_debug_mode==CM_DEBUG_SIDE_OF_KART) - { - core::vector3df xyz = m_kart->getXYZ().toIrrVector(); - Vec3 offset(3, 0, 0); - offset = m_kart->getTrans()(offset); - m_camera->setTarget(xyz); - m_camera->setPosition(offset.toIrrVector()); - } - // Update the first person camera - else if (m_debug_mode == CM_DEBUG_FPS) - { - vector3df direction(m_camera->getTarget() - m_camera->getPosition()); - vector3df up(m_camera->getUpVector()); - vector3df side(direction.crossProduct(up)); - vector3df pos = m_camera->getPosition(); - - // Set local values if the camera is attached to the kart - if (m_attached) - { - direction = m_local_direction; - up = m_local_up; - pos = m_local_position; - } - - // Update smooth movement - if (m_smooth) - { - // Angular velocity - if (m_angular_velocity < m_target_angular_velocity) - { - m_angular_velocity += UserConfigParams::m_fpscam_angular_velocity; - if (m_angular_velocity > m_target_angular_velocity) - m_angular_velocity = m_target_angular_velocity; - } - else if (m_angular_velocity > m_target_angular_velocity) - { - m_angular_velocity -= UserConfigParams::m_fpscam_angular_velocity; - if (m_angular_velocity < m_target_angular_velocity) - m_angular_velocity = m_target_angular_velocity; - } - - // Linear velocity - core::vector3df diff(m_target_velocity - m_lin_velocity); - if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) - { - if (diff.getLengthSQ() > 1) - diff.setLength(1); - m_lin_velocity += diff; - } - - // Camera direction - diff = m_target_direction - direction; - if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) - { - diff.setLength(UserConfigParams::m_fpscam_direction_speed); - m_direction_velocity += diff; - if (m_direction_velocity.getLengthSQ() > - UserConfigParams::m_fpscam_smooth_direction_max_speed * - UserConfigParams::m_fpscam_smooth_direction_max_speed) - m_direction_velocity.setLength( - UserConfigParams::m_fpscam_smooth_direction_max_speed); - direction += m_direction_velocity; - m_target_direction = direction; - } - - // Camera rotation - diff = m_target_up_vector - up; - if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) - { - if (diff.getLengthSQ() > - UserConfigParams::m_fpscam_angular_velocity * - UserConfigParams::m_fpscam_angular_velocity) - diff.setLength(UserConfigParams::m_fpscam_angular_velocity); - up += diff; - } - } - else - { - direction = m_target_direction; - up = m_target_up_vector; - side = direction.crossProduct(up); - } - - // Rotate camera - core::quaternion quat; - quat.fromAngleAxis(m_angular_velocity * dt, direction); - up = quat * up; - m_target_up_vector = quat * up; - direction.normalize(); - up.normalize(); - side.normalize(); - - // Top vector is the real up vector, not the one used by the camera - vector3df top(side.crossProduct(direction)); - - // Move camera - vector3df movement(direction * m_lin_velocity.Z + - top * m_lin_velocity.Y + side * m_lin_velocity.X); - pos = pos + movement * dt; - - if (m_attached) - { - // Save current values - m_local_position = pos; - m_local_direction = direction; - m_local_up = up; - - // Move the camera with the kart - btTransform t = m_kart->getTrans(); - if (stk_config->m_camera_follow_skid && - m_kart->getSkidding()->getVisualSkidRotation() != 0) - { - // If the camera should follow the graphical skid, add the - // visual rotation to the relative vector: - btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0); - t.setBasis(t.getBasis() * btMatrix3x3(q)); - } - pos = Vec3(t(Vec3(pos))).toIrrVector(); - - btQuaternion q = t.getRotation(); - btMatrix3x3 mat(q); - direction = Vec3(mat * Vec3(direction)).toIrrVector(); - up = Vec3(mat * Vec3(up)).toIrrVector(); - } - - // Set camera attributes - m_camera->setPosition(pos); - m_camera->setTarget(pos + direction); - m_camera->setUpVector(up); - } - else if (m_mode==CM_FINAL) - { - handleEndCamera(dt); - } - // If an explosion is happening, stop moving the camera, - // but keep it target on the kart. - else if (dynamic_cast(m_kart->getKartAnimation())) - { - getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); - // The camera target needs to be 'smooth moved', otherwise - // there will be a noticable jump in the first frame - - // Aim at the usual same position of the kart (i.e. slightly - // above the kart). - // Note: this code is replicated from smoothMoveCamera so that - // the camera keeps on pointing to the same spot. - core::vector3df current_target = (m_kart->getXYZ().toIrrVector()+core::vector3df(0, above_kart, 0)); - m_camera->setTarget(current_target); - } - else - { - getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); - positionCamera(dt, above_kart, cam_angle, side_way, distance, smoothing); + heading, + Vec3(0, 1, 0)); } } // update -// ---------------------------------------------------------------------------- -/** Actually sets the camera based on the given parameter. - * \param above_kart How far above the camera should aim at. - * \param cam_angle Angle above the kart plane for the camera. - * \param sideway Sideway movement of the camera. - * \param distance Distance from kart. -*/ -void Camera::positionCamera(float dt, float above_kart, float cam_angle, - float side_way, float distance, float smoothing) -{ - Vec3 wanted_position; - Vec3 wanted_target = m_kart->getXYZ(); - if(m_debug_mode==CM_DEBUG_GROUND) - { - const btWheelInfo &w = m_kart->getVehicle()->getWheelInfo(2); - wanted_target.setY(w.m_raycastInfo.m_contactPointWS.getY()); - } - else - wanted_target.setY(wanted_target.getY()+above_kart); - float tan_up = tan(cam_angle); - Vec3 relative_position(side_way, - fabsf(distance)*tan_up+above_kart, - distance); - btTransform t=m_kart->getTrans(); - if(stk_config->m_camera_follow_skid && - m_kart->getSkidding()->getVisualSkidRotation()!=0) - { - // If the camera should follow the graphical skid, add the - // visual rotation to the relative vector: - btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0); - t.setBasis(t.getBasis() * btMatrix3x3(q)); - } - if (m_debug_mode == CM_DEBUG_GROUND) - { - wanted_position = t(relative_position); - // Make sure that the Y position is a the same height as the wheel. - wanted_position.setY(wanted_target.getY()); - } - else - wanted_position = t(relative_position); - - if (smoothing && !isDebug()) - { - smoothMoveCamera(dt); - } - else - { - if (m_mode!=CM_FALLING) - m_camera->setPosition(wanted_position.toIrrVector()); - m_camera->setTarget(wanted_target.toIrrVector()); - - if (race_manager->getNumLocalPlayers() < 2) - { - SFXManager::get()->positionListener(m_camera->getPosition(), - wanted_target - m_camera->getPosition(), - Vec3(0, 1, 0)); - } - } - - Kart *kart = dynamic_cast(m_kart); - if (kart && !kart->isFlying()) - { - // Rotate the up vector (0,1,0) by the rotation ... which is just column 1 - Vec3 up = m_kart->getTrans().getBasis().getColumn(1); - float f = 0.04f; // weight for new up vector to reduce shaking - m_camera->setUpVector( f * up.toIrrVector() + - (1.0f - f) * m_camera->getUpVector()); - } // kart && !flying - else - m_camera->setUpVector(core::vector3df(0, 1, 0)); -} // positionCamera - -// ---------------------------------------------------------------------------- -/** 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) -{ - // First 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>=(unsigned)m_end_cameras.size()) - m_next_end_camera = 0; - } - - EndCameraInformation::EndCameraType info - = m_end_cameras.size()==0 ? EndCameraInformation::EC_AHEAD_OF_KART - : m_end_cameras[m_current_end_camera].m_type; - - switch(info) - { - case EndCameraInformation::EC_STATIC_FOLLOW_KART: - { - // Since the camera has no parents, we can use the relative - // position here (otherwise we need to call updateAbsolutePosition - // after changing the relative position in order to get the right - // position here). - const core::vector3df &cp = m_camera->getPosition(); - 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 6 (experimentally found) - float fov = 6*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: - { - float cam_angle = m_kart->getKartProperties()->getCameraBackwardUpAngle() * DEGREE_TO_RAD; - - positionCamera(dt, /*above_kart*/0.75f, - cam_angle, /*side_way*/0, - 2.0f*m_distance, /*smoothing*/false); - break; - } - default: break; - } // switch - -} // handleEndCamera - // ---------------------------------------------------------------------------- /** Sets viewport etc. for this camera. Called from irr_driver just before * rendering the view for this kart. @@ -855,43 +332,3 @@ void Camera::activate(bool alsoActivateInIrrlicht) } } // activate -// ---------------------------------------------------------------------------- -/** Sets the angular velocity for this camera. */ -void Camera::setAngularVelocity(float vel) -{ - if (m_smooth) - m_target_angular_velocity = vel; - else - m_angular_velocity = vel; -} // setAngularVelocity - -// ---------------------------------------------------------------------------- -/** Returns the current target angular velocity. */ -float Camera::getAngularVelocity() -{ - if (m_smooth) - return m_target_angular_velocity; - else - return m_angular_velocity; -} // getAngularVelocity - -// ---------------------------------------------------------------------------- -/** Sets the linear velocity for this camera. */ -void Camera::setLinearVelocity(core::vector3df vel) -{ - if (m_smooth) - m_target_velocity = vel; - else - m_lin_velocity = vel; -} // setLinearVelocity - -// ---------------------------------------------------------------------------- -/** Returns the current linear velocity. */ -const core::vector3df &Camera::getLinearVelocity() -{ - if (m_smooth) - return m_target_velocity; - else - return m_lin_velocity; -} // getLinearVelocity - diff --git a/src/graphics/camera.hpp b/src/graphics/camera.hpp index fb641791d..73a64d72e 100644 --- a/src/graphics/camera.hpp +++ b/src/graphics/camera.hpp @@ -35,11 +35,7 @@ #include -namespace irr -{ - namespace scene { class ICameraSceneNode; } -} -using namespace irr; +#include "ICameraSceneNode.h" class AbstractKart; @@ -55,37 +51,34 @@ public: CM_CLOSEUP, //!< Closer to kart CM_REVERSE, //!< Looking backwards CM_LEADER_MODE, //!< for deleted player karts in follow the leader - CM_FINAL, //!< Final camera CM_SIMPLE_REPLAY, CM_FALLING }; // Mode - enum DebugMode { - CM_DEBUG_NONE, - CM_DEBUG_TOP_OF_KART, //!< Camera hovering over kart - CM_DEBUG_GROUND, //!< Camera at ground level, wheel debugging - CM_DEBUG_FPS, //!< FPS Camera - CM_DEBUG_BEHIND_KART, //!< Camera straight behind kart - CM_DEBUG_SIDE_OF_KART,//!< Camera to the right of the kart - }; // DebugMode + enum CameraType { + CM_TYPE_NORMAL, + CM_TYPE_DEBUG, //!< A debug camera. + CM_TYPE_FPS, //!< FPS Camera + CM_TYPE_END //!< End camera + }; // CameraType private: static Camera* s_active_camera; - /** Special debug camera: 0: normal camera; 1: being high over the kart; - 2: on ground level; 3: free first person camera; - 4: straight behind kart */ - static DebugMode m_debug_mode; - - /** The camera scene node. */ - scene::ICameraSceneNode *m_camera; /** The project-view matrix of the previous frame, used for the blur shader. */ core::matrix4 m_previous_pv_matrix; /** Camera's mode. */ Mode m_mode; + /** The type of the camera. */ + CameraType m_type; + + /** The default type for any newly created camera. Used to store command + * line parameters. */ + static CameraType m_default_type; + /** The index of this camera which is the index of the kart it is * attached to. */ unsigned int m_index; @@ -93,24 +86,6 @@ private: /** Current ambient light for this camera. */ video::SColor m_ambient_light; - /** Distance between the camera and the kart. */ - float m_distance; - - /** The speed at which the camera changes position. */ - float m_position_speed; - - /** The speed at which the camera target changes position. */ - float m_target_speed; - - /** Factor of the effects of steering in camera aim. */ - float m_rotation_range; - - /** The kart that the camera follows. It can't be const, - * since in profile mode the camera might change its owner. - * May be NULL (example: cutscene camera) - */ - 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). */ @@ -128,136 +103,55 @@ private: /** Aspect ratio for camera. */ float m_aspect; - /** Smooth acceleration with the first person camera. */ - bool m_smooth; - - /** Attache the first person camera to a kart. - That means moving the kart also moves the camera. */ - bool m_attached; - - /** The speed at which the up-vector rotates, only used for the first person camera. */ - float m_angular_velocity; - - /** Target angular velocity. Used for smooth movement in fps perpective. */ - float m_target_angular_velocity; - - /** Maximum velocity for fps camera. */ - float m_max_velocity; - - /** Linear velocity of the camera, used for end and first person camera. - It's stored relative to the camera direction for the first person view. */ - core::vector3df m_lin_velocity; - - /** Velocity of the target of the camera, used for end and first person camera. */ - core::vector3df m_target_velocity; - - /** The target direction for the camera, only used for the first person camera. */ - core::vector3df m_target_direction; - - /** The speed at which the direction changes, only used for the first person camera. */ - core::vector3df m_direction_velocity; - - /** The up vector the camera should have, only used for the first person camera. */ - core::vector3df m_target_up_vector; - - /** Save the local position if the first person camera is attached to the kart. */ - core::vector3df m_local_position; - - /** Save the local direction if the first person camera is attached to the kart. */ - core::vector3df m_local_direction; - - /** Save the local up vector if the first person camera is attached to the kart. */ - core::vector3df m_local_up; /** List of all cameras. */ static std::vector m_all_cameras; - /** 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. - */ - typedef enum {EC_STATIC_FOLLOW_KART, - EC_AHEAD_OF_KART} EndCameraType; - EndCameraType 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 - { - Log::warn("Camera", "Invalid camera type '%s' - camera is ignored.", - 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 AlignedArray 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); - void handleEndCamera(float dt); - void getCameraSettings(float *above_kart, float *cam_angle, - float *side_way, float *distance, - 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(); +protected: + /** The camera scene node. */ + scene::ICameraSceneNode *m_camera; + + /** The kart that the camera follows. It can't be const, + * since in profile mode the camera might change its owner. + * May be NULL (example: cutscene camera) + */ + AbstractKart *m_kart; + + static Camera* createCamera(unsigned int index, CameraType type, + AbstractKart* kart); + + Camera(int camera_index, AbstractKart* kart); + virtual ~Camera(); public: LEAK_CHECK() - /** Returns the number of cameras used. */ - static unsigned int getNumCameras() { return (unsigned int)m_all_cameras.size(); } + // ======================================================================== + // Static functions + static Camera* createCamera(AbstractKart* kart); + static void changeCamera(unsigned int camera_index, CameraType type); + // ------------------------------------------------------------------------ + /** Sets the default type for each camera that will be created. Used for + * command line parameters to select a debug etc camera. */ + static void setDefaultCameraType(CameraType type) { m_default_type = type;} + // ------------------------------------------------------------------------ + /** Returns the default type for each camera that will be created. Used + * for command line parameters to select a debug etc camera. */ + static CameraType getDefaultCameraType() { return m_default_type;} + // ------------------------------------------------------------------------ + /** Returns the number of cameras used. */ + static unsigned int getNumCameras() + { + return (unsigned int)m_all_cameras.size(); + } // getNumCameras // ------------------------------------------------------------------------ /** Returns a camera. */ static Camera *getCamera(unsigned int n) { return m_all_cameras[n]; } - + // ------------------------------------------------------------------------ + /** Returns the currently active camera. */ + static Camera* getActiveCamera() { return s_active_camera; } // ------------------------------------------------------------------------ /** Remove all cameras. */ static void removeAllCameras() @@ -267,37 +161,21 @@ public: m_all_cameras.clear(); } // removeAllCameras - // ------------------------------------------------------------------------ - /** Creates a camera and adds it to the list of all cameras. Also the - * camera index (which determines which viewport to use in split screen) - * is set. - */ - static Camera* createCamera(AbstractKart* kart) - { - Camera *c = new Camera((int)m_all_cameras.size(), kart); - m_all_cameras.push_back(c); - return c; - } // createCamera - // ------------------------------------------------------------------------ - - static void readEndCamera(const XMLNode &root); - static void clearEndCameras(); - // ------------------------------------------------------------------------ - static void setDebugMode(DebugMode debug_mode) { m_debug_mode = debug_mode;} - // ------------------------------------------------------------------------ - static bool isDebug() { return m_debug_mode != CM_DEBUG_NONE; } - // ------------------------------------------------------------------------ - static bool isFPS() { return m_debug_mode == CM_DEBUG_FPS; } - // ------------------------------------------------------------------------ + // ======================================================================== void setMode(Mode mode); /** Set the camera to the given mode */ Mode getMode(); - void reset(); - void setInitialTransform(); - void activate(bool alsoActivateInIrrlicht=true); - void update(float dt); void setKart(AbstractKart *new_kart); - + virtual void reset(); + virtual void setInitialTransform(); + virtual void activate(bool alsoActivateInIrrlicht=true); + virtual void update(float dt); + // ------------------------------------------------------------------------ + /** Returns the type of this camera. */ + CameraType getType() { return m_type; } + // ------------------------------------------------------------------------ + /** Sets the field of view for the irrlicht camera. */ + void setFoV() { m_camera->setFOV(m_fov); } // ------------------------------------------------------------------------ /** Returns the camera index (or player kart index, which is the same). */ int getIndex() const {return m_index;} @@ -317,66 +195,6 @@ public: /** Returns the kart to which this camera is attached. */ AbstractKart* getKart() { return m_kart; } - // ------------------------------------------------------------------------ - /** Applies mouse movement to the first person camera. */ - void applyMouseMovement (float x, float y); - - // ------------------------------------------------------------------------ - /** Sets if the first person camera should be moved smooth. */ - void setSmoothMovement (bool value) { m_smooth = value; } - - // ------------------------------------------------------------------------ - /** If the first person camera should be moved smooth. */ - bool getSmoothMovement () { return m_smooth; } - - // ------------------------------------------------------------------------ - /** Sets if the first person camera should be moved with the kart. */ - void setAttachedFpsCam (bool value) { m_attached = value; } - - // ------------------------------------------------------------------------ - /** If the first person camera should be moved with the kart. */ - bool getAttachedFpsCam () { return m_attached; } - - // ------------------------------------------------------------------------ - /** Sets the angular velocity for this camera. */ - void setMaximumVelocity (float vel) { m_max_velocity = vel; } - - // ------------------------------------------------------------------------ - /** Returns the current angular velocity. */ - float getMaximumVelocity () { return m_max_velocity; } - - // ------------------------------------------------------------------------ - /** Sets the vector, the first person camera should look at. */ - void setDirection (core::vector3df target) { m_target_direction = target; } - - // ------------------------------------------------------------------------ - /** Gets the vector, the first person camera should look at. */ - const core::vector3df &getDirection () { return m_target_direction; } - - // ------------------------------------------------------------------------ - /** Sets the up vector, the first person camera should use. */ - void setUpVector (core::vector3df target) { m_target_up_vector = target; } - - // ------------------------------------------------------------------------ - /** Gets the up vector, the first person camera should use. */ - const core::vector3df &getUpVector () { return m_target_up_vector; } - - // ------------------------------------------------------------------------ - /** Sets the angular velocity for this camera. */ - void setAngularVelocity (float vel); - - // ------------------------------------------------------------------------ - /** Returns the current target angular velocity. */ - float getAngularVelocity (); - - // ------------------------------------------------------------------------ - /** Sets the linear velocity for this camera. */ - void setLinearVelocity (core::vector3df vel); - - // ------------------------------------------------------------------------ - /** Returns the current linear velocity. */ - const core::vector3df &getLinearVelocity (); - // ------------------------------------------------------------------------ /** Sets the ambient light for this camera. */ void setAmbientLight(const video::SColor &color) { m_ambient_light=color; } @@ -396,9 +214,9 @@ public: // ------------------------------------------------------------------------ /** Returns the camera scene node. */ scene::ICameraSceneNode *getCameraSceneNode() { return m_camera; } - // ------------------------------------------------------------------------ - static Camera* getActiveCamera() { return s_active_camera; } + /** Returs the absolute position of the camera. */ + Vec3 getXYZ() { return Vec3(m_camera->getPosition()); } } ; #endif diff --git a/src/graphics/camera_debug.cpp b/src/graphics/camera_debug.cpp new file mode 100644 index 000000000..35dfcdc9a --- /dev/null +++ b/src/graphics/camera_debug.cpp @@ -0,0 +1,217 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/camera_debug.hpp" + +#include "config/stk_config.hpp" +#include "karts/abstract_kart.hpp" +#include "karts/explosion_animation.hpp" +#include "karts/kart.hpp" +#include "karts/kart_properties.hpp" +#include "karts/skidding.hpp" +#include "physics/btKart.hpp" + +CameraDebug::CameraDebugType CameraDebug::m_default_debug_Type = + CameraDebug::CM_DEBUG_TOP_OF_KART; + +// ============================================================================ +CameraDebug::CameraDebug(int camera_index, AbstractKart* kart) + : CameraNormal(camera_index, kart) +{ + reset(); +} // Camera + +// ---------------------------------------------------------------------------- +/** Removes the camera scene node from the scene. + */ +CameraDebug::~CameraDebug() +{ +} // ~CameraDebug + +//----------------------------------------------------------------------------- +/** Determine the camera settings for the current frame. + * \param above_kart How far above the camera should aim at. + * \param cam_angle Angle above the kart plane for the camera. + * \param sideway Sideway movement of the camera. + * \param distance Distance from kart. + */ +void CameraDebug::getCameraSettings(float *above_kart, float *cam_angle, + float *sideway, float *distance, + bool *smoothing) +{ + const KartProperties *kp = getKart()->getKartProperties(); + + // Set some default values + float steering = m_kart->getSteerPercent() + * (1.0f + (m_kart->getSkidding()->getSkidFactor() + - 1.0f) / 2.3f); + // quadratically to dampen small variations (but keep sign) + float dampened_steer = fabsf(steering) * steering; + *sideway = -m_rotation_range*dampened_steer*0.5f; + *above_kart = 0; + *cam_angle = 0; + *smoothing = true; + + switch(m_default_debug_Type) + { + case CM_DEBUG_BEHIND_KART: + *distance = -0.5f*m_kart->getKartModel()->getLength()-1.0f; + break; + case CM_DEBUG_GROUND: + *distance = -m_kart->getKartModel()->getLength()-1.0f; + break; + case CM_DEBUG_SIDE_OF_KART: + case CM_DEBUG_TOP_OF_KART: + *above_kart = 0.75f; + *cam_angle = kp->getCameraForwardUpAngle() * DEGREE_TO_RAD; + *distance = -m_distance; + break; + } // switch + +} // getCameraSettings + +//----------------------------------------------------------------------------- +/** Called once per time frame to move the camera to the right position. + * \param dt Time step. + */ +void CameraDebug::update(float dt) +{ + Camera::update(dt); + + // To view inside tunnels in top mode, increase near value + m_camera->setNearValue(m_default_debug_Type==CM_DEBUG_TOP_OF_KART + ? 27.0f : 1.0f); + + float above_kart, cam_angle, side_way, distance; + bool smoothing; + + // The following settings give a debug camera which shows the track from + // high above the kart straight down. + if (m_default_debug_Type==CM_DEBUG_TOP_OF_KART) + { + core::vector3df xyz = m_kart->getXYZ().toIrrVector(); + m_camera->setTarget(xyz); + xyz.Y = xyz.Y+55; + xyz.Z -= 5.0f; + m_camera->setPosition(xyz); + } + else if (m_default_debug_Type==CM_DEBUG_SIDE_OF_KART) + { + core::vector3df xyz = m_kart->getXYZ().toIrrVector(); + Vec3 offset(3, 0, 0); + offset = m_kart->getTrans()(offset); + m_camera->setTarget(xyz); + m_camera->setPosition(offset.toIrrVector()); + } + // Update the first person camera + // If an explosion is happening, stop moving the camera, + // but keep it target on the kart. + else if (dynamic_cast(m_kart->getKartAnimation())) + { + getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); + // The camera target needs to be 'smooth moved', otherwise + // there will be a noticable jump in the first frame + + // Aim at the usual same position of the kart (i.e. slightly + // above the kart). + // Note: this code is replicated from smoothMoveCamera so that + // the camera keeps on pointing to the same spot. + core::vector3df current_target = (m_kart->getXYZ().toIrrVector()+core::vector3df(0, above_kart, 0)); + m_camera->setTarget(current_target); + } + else + { + getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); + positionCamera(dt, above_kart, cam_angle, side_way, distance, smoothing); + } +} // update + +// ---------------------------------------------------------------------------- +/** Actually sets the camera based on the given parameter. + * \param above_kart How far above the camera should aim at. + * \param cam_angle Angle above the kart plane for the camera. + * \param sideway Sideway movement of the camera. + * \param distance Distance from kart. +*/ +void CameraDebug::positionCamera(float dt, float above_kart, float cam_angle, + float side_way, float distance, + float smoothing) +{ + Vec3 wanted_position; + Vec3 wanted_target = m_kart->getXYZ(); + if(m_default_debug_Type==CM_DEBUG_GROUND) + { + const btWheelInfo &w = m_kart->getVehicle()->getWheelInfo(2); + wanted_target.setY(w.m_raycastInfo.m_contactPointWS.getY()); + } + else + wanted_target.setY(wanted_target.getY()+above_kart); + float tan_up = tan(cam_angle); + Vec3 relative_position(side_way, + fabsf(distance)*tan_up+above_kart, + distance); + btTransform t=m_kart->getTrans(); + if(stk_config->m_camera_follow_skid && + m_kart->getSkidding()->getVisualSkidRotation()!=0) + { + // If the camera should follow the graphical skid, add the + // visual rotation to the relative vector: + btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0); + t.setBasis(t.getBasis() * btMatrix3x3(q)); + } + if (m_default_debug_Type == CM_DEBUG_GROUND) + { + wanted_position = t(relative_position); + // Make sure that the Y position is a the same height as the wheel. + wanted_position.setY(wanted_target.getY()); + } + else + wanted_position = t(relative_position); + + if (smoothing && !isDebug()) + { + smoothMoveCamera(dt); + } + else + { + if (getMode()!=CM_FALLING) + m_camera->setPosition(wanted_position.toIrrVector()); + m_camera->setTarget(wanted_target.toIrrVector()); + + if (race_manager->getNumLocalPlayers() < 2) + { + SFXManager::get()->positionListener(m_camera->getPosition(), + wanted_target - m_camera->getPosition(), + Vec3(0, 1, 0)); + } + } + + Kart *kart = dynamic_cast(m_kart); + if (kart && !kart->isFlying()) + { + // Rotate the up vector (0,1,0) by the rotation ... which is just column 1 + Vec3 up = m_kart->getTrans().getBasis().getColumn(1); + float f = 0.04f; // weight for new up vector to reduce shaking + m_camera->setUpVector( f * up.toIrrVector() + + (1.0f - f) * m_camera->getUpVector()); + } // kart && !flying + else + m_camera->setUpVector(core::vector3df(0, 1, 0)); +} // positionCamera + diff --git a/src/graphics/camera_debug.hpp b/src/graphics/camera_debug.hpp new file mode 100644 index 000000000..c61782b72 --- /dev/null +++ b/src/graphics/camera_debug.hpp @@ -0,0 +1,70 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_CAMERA_DEBUG_HPP +#define HEADER_CAMERA_DEBUG_HPP + +#include "graphics/camera_normal.hpp" + +class AbstractKart; + +/** + * Handles the debug camera. Inherits from CameraNormal to make use + * of the smoothing function. + * \ingroup graphics + */ +class CameraDebug : public CameraNormal +{ +public: + enum CameraDebugType { + CM_DEBUG_TOP_OF_KART, //!< Camera hovering over kart + CM_DEBUG_GROUND, //!< Camera at ground level, wheel debugging + CM_DEBUG_BEHIND_KART, //!< Camera straight behind kart + CM_DEBUG_SIDE_OF_KART, //!< Camera to the right of the kart + }; // CameraDebugType + +private: + + static CameraDebugType m_default_debug_Type; + + void getCameraSettings(float *above_kart, float *cam_angle, + float *side_way, float *distance, + bool *smoothing); + void positionCamera(float dt, float above_kart, float cam_angle, + float side_way, float distance, float smoothing); + + friend class Camera; + CameraDebug(int camera_index, AbstractKart* kart); + virtual ~CameraDebug(); +public: + + void update(float dt); + // ------------------------------------------------------------------------ + /** Sets the debug type for all cameras. */ + static void setDebugType(CameraDebugType type) + { + m_default_debug_Type = type; + } // setDebugType + +}; // CameraDebug + +#endif + +/* EOF */ diff --git a/src/graphics/camera_end.cpp b/src/graphics/camera_end.cpp new file mode 100644 index 000000000..d5f868747 --- /dev/null +++ b/src/graphics/camera_end.cpp @@ -0,0 +1,144 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2006-2016 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/camera_end.hpp" + +#include "karts/abstract_kart.hpp" +#include "karts/kart_properties.hpp" +#include "tracks/quad_graph.hpp" + +#include "ICameraSceneNode.h" + +AlignedArray CameraEnd::m_end_cameras; +// ============================================================================ +CameraEnd::CameraEnd(int camera_index, AbstractKart* kart) + : CameraNormal(camera_index, kart) +{ + reset(); + if(m_end_cameras.size()>0) + m_camera->setPosition(m_end_cameras[0].m_position.toIrrVector()); + m_next_end_camera = m_end_cameras.size()>1 ? 1 : 0; + m_current_end_camera = 0; + setFoV(); + update(0); +} // Camera + +//----------------------------------------------------------------------------- +/** This function clears all end camera data structure. This is necessary + * since all end cameras are shared between all camera instances (i.e. are + * static), otherwise (if no end camera is defined for a track) the old + * end camera structure would be used. + */ +void CameraEnd::clearEndCameras() +{ + m_end_cameras.clear(); +} // clearEndCameras + +//----------------------------------------------------------------------------- +/** 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 CameraEnd::readEndCamera(const XMLNode &root) +{ + m_end_cameras.clear(); + for(unsigned int i=0; iisReverse()) + index = root.getNumNodes() - 1 - i; + const XMLNode *node = root.getNode(index); + EndCameraInformation eci; + if(!eci.readXML(*node)) continue; + m_end_cameras.push_back(eci); + } // for isetNearValue(1.0f); + + // First 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() + ); + } + setFoV(); + m_next_end_camera++; + if(m_next_end_camera>=(unsigned)m_end_cameras.size()) + m_next_end_camera = 0; + } + + EndCameraInformation::EndCameraType info + = m_end_cameras.size()==0 ? EndCameraInformation::EC_AHEAD_OF_KART + : m_end_cameras[m_current_end_camera].m_type; + + switch(info) + { + case EndCameraInformation::EC_STATIC_FOLLOW_KART: + { + // Since the camera has no parents, we can use the relative + // position here (otherwise we need to call updateAbsolutePosition + // after changing the relative position in order to get the right + // position here). + const core::vector3df &cp = m_camera->getPosition(); + 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 6 (experimentally found) + float fov = 6*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: + { + float cam_angle = m_kart->getKartProperties()->getCameraBackwardUpAngle() + * DEGREE_TO_RAD; + + positionCamera(dt, /*above_kart*/0.75f, + cam_angle, /*side_way*/0, + 2.0f*getDistanceToKart(), /*smoothing*/false); + break; + } + default: break; + } // switch + +} // update diff --git a/src/graphics/camera_end.hpp b/src/graphics/camera_end.hpp new file mode 100644 index 000000000..b1bd51de3 --- /dev/null +++ b/src/graphics/camera_end.hpp @@ -0,0 +1,115 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_CAMERA_END_HPP +#define HEADER_CAMERA_END_HPP + +#include "graphics/camera_normal.hpp" + +#include "utils/cpp2011.hpp" + +/** + * Handles the end race camera. It inherits from CameraNormal to make + * use of the normal camera implementation of a reverse camera. + * \ingroup graphics + */ +class CameraEnd : public CameraNormal +{ +private: + /** 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. + */ + typedef enum {EC_STATIC_FOLLOW_KART, + EC_AHEAD_OF_KART} EndCameraType; + EndCameraType 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 + { + Log::warn("Camera", "Invalid camera type '%s' - camera is ignored.", + 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 AlignedArray 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 handleEndCamera(float dt); + + friend class Camera; // Give Camera access to constructor + CameraEnd(int camera_index, AbstractKart* kart); + virtual ~CameraEnd() {} +public: + + static void readEndCamera(const XMLNode &root); + static void clearEndCameras(); + virtual void update(float dt) OVERRIDE; +}; // class CameraEnd + +#endif + +/* EOF */ diff --git a/src/graphics/camera_fps.cpp b/src/graphics/camera_fps.cpp new file mode 100644 index 000000000..477e17d90 --- /dev/null +++ b/src/graphics/camera_fps.cpp @@ -0,0 +1,289 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/camera_fps.hpp" + +#include "config/stk_config.hpp" +#include "config/user_config.hpp" +#include "karts/abstract_kart.hpp" +#include "karts/skidding.hpp" + +#include "vector3d.h" + +using namespace irr; + +// ============================================================================ +CameraFPS::CameraFPS(int camera_index, AbstractKart* kart) + : Camera(camera_index, kart) +{ + m_attached = false; + + // TODO: Put these values into a config file + // Global or per split screen zone? + // Either global or per user (for instance, some users may not like + // the extra camera rotation so they could set m_rotation_range to + // zero to disable it for themselves). + m_position_speed = 8.0f; + m_target_speed = 10.0f; + m_rotation_range = 0.4f; + m_rotation_range = 0.0f; + m_lin_velocity = core::vector3df(0, 0, 0); + m_target_velocity = core::vector3df(0, 0, 0); + m_target_direction = core::vector3df(0, 0, 1); + m_target_up_vector = core::vector3df(0, 1, 0); + m_direction_velocity = core::vector3df(0, 0, 0); + + m_local_position = core::vector3df(0, 0, 0); + m_local_direction = core::vector3df(0, 0, 1); + m_local_up = core::vector3df(0, 1, 0); + + m_angular_velocity = 0; + m_target_angular_velocity = 0; + m_max_velocity = 15; + reset(); +} // Camera + +// ---------------------------------------------------------------------------- +/** Removes the camera scene node from the scene. + */ +CameraFPS::~CameraFPS() +{ +} // ~Camera + +//----------------------------------------------------------------------------- +/** Applies mouse movement to the first person camera. + * \param x The horizontal difference of the mouse position. + * \param y The vertical difference of the mouse position. + */ +void CameraFPS::applyMouseMovement (float x, float y) +{ + core::vector3df direction(m_target_direction); + core::vector3df up(m_camera->getUpVector()); + + // Set local values if the camera is attached to the kart + if (m_attached) + up = m_local_up; + + direction.normalize(); + up.normalize(); + + core::vector3df side(direction.crossProduct(up)); + side.normalize(); + core::quaternion quat; + quat.fromAngleAxis(y, side); + + core::quaternion quat_x; + quat_x.fromAngleAxis(x, up); + quat *= quat_x; + + direction = quat * direction; + // Try to prevent toppling over + // If the camera would topple over with the next movement, the vertical + // movement gets reset close to the up vector + if ((direction - up).getLengthSQ() + (m_target_direction - up).getLengthSQ() + <= (direction - m_target_direction).getLengthSQ()) + direction = quat_x * ((m_target_direction - up).setLength(0.02f) + up); + // Prevent toppling under + else if ((direction + up).getLengthSQ() + (m_target_direction + up).getLengthSQ() + <= (direction - m_target_direction).getLengthSQ()) + direction = quat_x * ((m_target_direction + up).setLength(0.02f) - up); + m_target_direction = direction; + + // Don't do that because it looks ugly and is bad to handle ;) + /*side = direction.crossProduct(up); + // Compute new up vector + up = side.crossProduct(direction); + up.normalize(); + cam->setUpVector(up);*/ +} // applyMouseMovement + +//----------------------------------------------------------------------------- +/** Called once per time frame to move the camera to the right position. + * \param dt Time step. + */ +void CameraFPS::update(float dt) +{ + Camera::update(dt); + + // To view inside tunnels in top mode, increase near value + m_camera->setNearValue(1.0f); + + core::vector3df direction(m_camera->getTarget() - m_camera->getPosition()); + core::vector3df up(m_camera->getUpVector()); + core::vector3df side(direction.crossProduct(up)); + core::vector3df pos = m_camera->getPosition(); + + // Set local values if the camera is attached to the kart + if (m_attached) + { + direction = m_local_direction; + up = m_local_up; + pos = m_local_position; + } + + // Update smooth movement + if (m_smooth) + { + // Angular velocity + if (m_angular_velocity < m_target_angular_velocity) + { + m_angular_velocity += UserConfigParams::m_fpscam_angular_velocity; + if (m_angular_velocity > m_target_angular_velocity) + m_angular_velocity = m_target_angular_velocity; + } + else if (m_angular_velocity > m_target_angular_velocity) + { + m_angular_velocity -= UserConfigParams::m_fpscam_angular_velocity; + if (m_angular_velocity < m_target_angular_velocity) + m_angular_velocity = m_target_angular_velocity; + } + + // Linear velocity + core::vector3df diff(m_target_velocity - m_lin_velocity); + if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) + { + if (diff.getLengthSQ() > 1) diff.setLength(1); + m_lin_velocity += diff; + } + + // Camera direction + diff = m_target_direction - direction; + if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) + { + diff.setLength(UserConfigParams::m_fpscam_direction_speed); + m_direction_velocity += diff; + if (m_direction_velocity.getLengthSQ() > + UserConfigParams::m_fpscam_smooth_direction_max_speed * + UserConfigParams::m_fpscam_smooth_direction_max_speed) + { + m_direction_velocity.setLength( + UserConfigParams::m_fpscam_smooth_direction_max_speed); + } + direction += m_direction_velocity; + m_target_direction = direction; + } // if diff is no 0 + + // Camera rotation + diff = m_target_up_vector - up; + if (diff.X != 0 || diff.Y != 0 || diff.Z != 0) + { + if (diff.getLengthSQ() > + UserConfigParams::m_fpscam_angular_velocity * + UserConfigParams::m_fpscam_angular_velocity) + { + diff.setLength(UserConfigParams::m_fpscam_angular_velocity); + } + up += diff; + } + } + else + { + direction = m_target_direction; + up = m_target_up_vector; + side = direction.crossProduct(up); + } + + // Rotate camera + core::quaternion quat; + quat.fromAngleAxis(m_angular_velocity * dt, direction); + up = quat * up; + m_target_up_vector = quat * up; + direction.normalize(); + up.normalize(); + side.normalize(); + + // Top vector is the real up vector, not the one used by the camera + core::vector3df top(side.crossProduct(direction)); + + // Move camera + core::vector3df movement(direction * m_lin_velocity.Z + + top * m_lin_velocity.Y + side * m_lin_velocity.X); + pos = pos + movement * dt; + + if (m_attached) + { + // Save current values + m_local_position = pos; + m_local_direction = direction; + m_local_up = up; + + // Move the camera with the kart + btTransform t = m_kart->getTrans(); + if (stk_config->m_camera_follow_skid && + m_kart->getSkidding()->getVisualSkidRotation() != 0) + { + // If the camera should follow the graphical skid, add the + // visual rotation to the relative vector: + btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0); + t.setBasis(t.getBasis() * btMatrix3x3(q)); + } + pos = Vec3(t(Vec3(pos))).toIrrVector(); + + btQuaternion q = t.getRotation(); + btMatrix3x3 mat(q); + direction = Vec3(mat * Vec3(direction)).toIrrVector(); + up = Vec3(mat * Vec3(up)).toIrrVector(); + } + + // Set camera attributes + m_camera->setPosition(pos); + m_camera->setTarget(pos + direction); + m_camera->setUpVector(up); +} // update + +// ---------------------------------------------------------------------------- +/** Sets the angular velocity for this camera. */ +void CameraFPS::setAngularVelocity(float vel) +{ + if (m_smooth) + m_target_angular_velocity = vel; + else + m_angular_velocity = vel; +} // setAngularVelocity + +// ---------------------------------------------------------------------------- +/** Returns the current target angular velocity. */ +float CameraFPS::getAngularVelocity() +{ + if (m_smooth) + return m_target_angular_velocity; + else + return m_angular_velocity; +} // getAngularVelocity + +// ---------------------------------------------------------------------------- +/** Sets the linear velocity for this camera. */ +void CameraFPS::setLinearVelocity(core::vector3df vel) +{ + if (m_smooth) + m_target_velocity = vel; + else + m_lin_velocity = vel; +} // setLinearVelocity + +// ---------------------------------------------------------------------------- +/** Returns the current linear velocity. */ +const core::vector3df &CameraFPS::getLinearVelocity() +{ + if (m_smooth) + return m_target_velocity; + else + return m_lin_velocity; +} // getLinearVelocity + diff --git a/src/graphics/camera_fps.hpp b/src/graphics/camera_fps.hpp new file mode 100644 index 000000000..9d24d3d04 --- /dev/null +++ b/src/graphics/camera_fps.hpp @@ -0,0 +1,165 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_CAMERA_FPS_HPP +#define HEADER_CAMERA_FPS_HPP + +#include "graphics/camera.hpp" + +#include "utils/cpp2011.hpp" + +class AbstractKart; + +/** + * \brief Handles the game camera + * \ingroup graphics + */ +class CameraFPS : public Camera +{ +private: + /** The speed at which the camera changes position. */ + float m_position_speed; + + /** The speed at which the camera target changes position. */ + float m_target_speed; + + /** Factor of the effects of steering in camera aim. */ + float m_rotation_range; + + /** Smooth acceleration with the first person camera. */ + bool m_smooth; + + /** Attache the first person camera to a kart. + That means moving the kart also moves the camera. */ + bool m_attached; + + /** The speed at which the up-vector rotates, only used for the first person camera. */ + float m_angular_velocity; + + /** Target angular velocity. Used for smooth movement in fps perpective. */ + float m_target_angular_velocity; + + /** Maximum velocity for fps camera. */ + float m_max_velocity; + + /** Linear velocity of the camera, used for end and first person camera. + It's stored relative to the camera direction for the first person view. */ + core::vector3df m_lin_velocity; + + /** Velocity of the target of the camera, used for end and first person camera. */ + core::vector3df m_target_velocity; + + /** The target direction for the camera, only used for the first person camera. */ + core::vector3df m_target_direction; + + /** The speed at which the direction changes, only used for the first person camera. */ + core::vector3df m_direction_velocity; + + /** The up vector the camera should have, only used for the first person camera. */ + core::vector3df m_target_up_vector; + + /** Save the local position if the first person camera is attached to the kart. */ + core::vector3df m_local_position; + + /** Save the local direction if the first person camera is attached to the kart. */ + core::vector3df m_local_direction; + + /** Save the local up vector if the first person camera is attached to the kart. */ + core::vector3df m_local_up; + + + + void positionCamera(float dt, float above_kart, float cam_angle, + float side_way, float distance, float smoothing); + + friend class Camera; + CameraFPS(int camera_index, AbstractKart* kart); + virtual ~CameraFPS(); +public: + // ------------------------------------------------------------------------ + static bool isFPS() { return true; } + // ------------------------------------------------------------------------ + + virtual void update(float dt) OVERRIDE; + // ------------------------------------------------------------------------ + /** Applies mouse movement to the first person camera. */ + void applyMouseMovement (float x, float y); + + // ------------------------------------------------------------------------ + /** Sets if the first person camera should be moved smooth. */ + void setSmoothMovement (bool value) { m_smooth = value; } + + // ------------------------------------------------------------------------ + /** If the first person camera should be moved smooth. */ + bool getSmoothMovement () { return m_smooth; } + + // ------------------------------------------------------------------------ + /** Sets if the first person camera should be moved with the kart. */ + void setAttachedFpsCam (bool value) { m_attached = value; } + + // ------------------------------------------------------------------------ + /** If the first person camera should be moved with the kart. */ + bool getAttachedFpsCam () { return m_attached; } + + // ------------------------------------------------------------------------ + /** Sets the angular velocity for this camera. */ + void setMaximumVelocity (float vel) { m_max_velocity = vel; } + + // ------------------------------------------------------------------------ + /** Returns the current angular velocity. */ + float getMaximumVelocity () { return m_max_velocity; } + + // ------------------------------------------------------------------------ + /** Sets the vector, the first person camera should look at. */ + void setDirection (core::vector3df target) { m_target_direction = target; } + + // ------------------------------------------------------------------------ + /** Gets the vector, the first person camera should look at. */ + const core::vector3df &getDirection () { return m_target_direction; } + + // ------------------------------------------------------------------------ + /** Sets the up vector, the first person camera should use. */ + void setUpVector (core::vector3df target) { m_target_up_vector = target; } + + // ------------------------------------------------------------------------ + /** Gets the up vector, the first person camera should use. */ + const core::vector3df &getUpVector () { return m_target_up_vector; } + + // ------------------------------------------------------------------------ + /** Sets the angular velocity for this camera. */ + void setAngularVelocity (float vel); + + // ------------------------------------------------------------------------ + /** Returns the current target angular velocity. */ + float getAngularVelocity (); + + // ------------------------------------------------------------------------ + /** Sets the linear velocity for this camera. */ + void setLinearVelocity (core::vector3df vel); + + // ------------------------------------------------------------------------ + /** Returns the current linear velocity. */ + const core::vector3df &getLinearVelocity (); + +}; // class CameraFPS + +#endif + +/* EOF */ diff --git a/src/graphics/camera_normal.cpp b/src/graphics/camera_normal.cpp new file mode 100644 index 000000000..cc5231bb2 --- /dev/null +++ b/src/graphics/camera_normal.cpp @@ -0,0 +1,293 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "graphics/camera_normal.hpp" + +#include "karts/abstract_kart.hpp" +#include "karts/explosion_animation.hpp" +#include "karts/kart.hpp" +#include "karts/kart_properties.hpp" +#include "karts/skidding.hpp" +#include "modes/world.hpp" +#include "tracks/track.hpp" + +// ============================================================================ +CameraNormal::CameraNormal(int camera_index, AbstractKart* kart) + : Camera(camera_index, kart) +{ + m_distance = kart ? kart->getKartProperties()->getCameraDistance() : 1000.0f; + m_ambient_light = World::getWorld()->getTrack()->getDefaultAmbientColor(); + + // TODO: Put these values into a config file + // Global or per split screen zone? + // Either global or per user (for instance, some users may not like + // the extra camera rotation so they could set m_rotation_range to + // zero to disable it for themselves). + m_position_speed = 8.0f; + m_target_speed = 10.0f; + m_rotation_range = 0.4f; + m_rotation_range = 0.0f; + reset(); + m_camera->setNearValue(1.0f); +} // Camera + +//----------------------------------------------------------------------------- +/** Moves the camera smoothly from the current camera position (and target) + * to the new position and target. + * \param wanted_position The position the camera wanted to reach. + * \param wanted_target The point the camera wants to point to. + */ +void CameraNormal::smoothMoveCamera(float dt) +{ + Kart *kart = dynamic_cast(m_kart); + if (kart->isFlying()) + { + Vec3 vec3 = m_kart->getXYZ() + Vec3(sin(m_kart->getHeading()) * -4.0f, + 0.5f, + cos(m_kart->getHeading()) * -4.0f); + m_camera->setTarget(m_kart->getXYZ().toIrrVector()); + m_camera->setPosition(vec3.toIrrVector()); + return; + } // kart is flying + + + core::vector3df current_position = m_camera->getPosition(); + // Smoothly interpolate towards the position and target + const KartProperties *kp = m_kart->getKartProperties(); + float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease(); + float max_speed_without_zipper = kp->getEngineMaxSpeed(); + float current_speed = m_kart->getSpeed(); + + const Skidding *ks = m_kart->getSkidding(); + float skid_factor = ks->getVisualSkidRotation(); + + float skid_angle = asin(skid_factor); + float ratio = (current_speed - max_speed_without_zipper) / max_increase_with_zipper; + ratio = ratio > -0.12f ? ratio : -0.12f; + + // distance of camera from kart in x and z plane + float camera_distance = -3 * (0.5f + ratio); + if (camera_distance > -2.0f) camera_distance = -2.0f; + + // Defines how far camera should be from player kart. + Vec3 camera_offset(camera_distance * sin(skid_angle / 2), + 1.1f * (1 + ratio / 2), + camera_distance * cos(skid_angle / 2)); + Vec3 m_kart_camera_position_with_offset = m_kart->getTrans()(camera_offset); + + // next target + core::vector3df current_target = m_kart->getXYZ().toIrrVector(); + current_target.Y += 0.5f; + // new required position of camera + core::vector3df wanted_position = m_kart_camera_position_with_offset.toIrrVector(); + + float f = 5.0f; + if ((m_kart->getSpeed() > 5 ) || (m_kart->getSpeed() < 0 )) + { + f = m_kart->getSpeed()>0 ? m_kart->getSpeed()/3 + 1.0f + : -1.5f * m_kart->getSpeed() + 2.0f; + } + current_position += (wanted_position - current_position) * (dt *f); + + // Avoid camera crash: if the speed is negative, the current_position + // can oscillate between plus and minus, getting bigger and bigger. If + // this happens often enough, floating point overflow happens (large + // negative speeds can happen when the kart is tumbling/falling) + // To avoid this, we just move the camera to the wanted position if + // the distance becomes too large (see #1356). + if( (current_position - wanted_position).getLengthSQ() > 100) + { + Log::debug("camera", "Resetting camera position to avoid crash"); + current_position = wanted_position; + } + + if(getMode()!=CM_FALLING) + m_camera->setPosition(current_position); + m_camera->setTarget(current_target);//set new target + + assert(!std::isnan(m_camera->getPosition().X)); + assert(!std::isnan(m_camera->getPosition().Y)); + assert(!std::isnan(m_camera->getPosition().Z)); + +} // smoothMoveCamera + +//----------------------------------------------------------------------------- +/** Determine the camera settings for the current frame. + * \param above_kart How far above the camera should aim at. + * \param cam_angle Angle above the kart plane for the camera. + * \param sideway Sideway movement of the camera. + * \param distance Distance from kart. + */ +void CameraNormal::getCameraSettings(float *above_kart, float *cam_angle, + float *sideway, float *distance, + bool *smoothing) +{ + const KartProperties *kp = m_kart->getKartProperties(); + + switch(getMode()) + { + case CM_NORMAL: + case CM_FALLING: + { + *above_kart = 0.75f; + *cam_angle = kp->getCameraForwardUpAngle() * DEGREE_TO_RAD; + *distance = -m_distance; + float steering = m_kart->getSteerPercent() + * (1.0f + (m_kart->getSkidding()->getSkidFactor() + - 1.0f)/2.3f ); + // quadratically to dampen small variations (but keep sign) + float dampened_steer = fabsf(steering) * steering; + *sideway = -m_rotation_range*dampened_steer*0.5f; + *smoothing = true; + break; + } // CM_FALLING + case CM_REVERSE: // Same as CM_NORMAL except it looks backwards + { + *above_kart = 0.75f; + *cam_angle = kp->getCameraBackwardUpAngle() * DEGREE_TO_RAD; + *sideway = 0; + *distance = 2.0f*m_distance; + *smoothing = false; + break; + } + case CM_CLOSEUP: // Lower to the ground and closer to the kart + { + *above_kart = 0.75f; + *cam_angle = 20.0f*DEGREE_TO_RAD; + *sideway = m_rotation_range + * m_kart->getSteerPercent() + * m_kart->getSkidding()->getSkidFactor(); + *distance = -0.5f*m_distance; + *smoothing = false; + break; + } + case CM_LEADER_MODE: + { + *above_kart = 0.0f; + *cam_angle = 40*DEGREE_TO_RAD; + *sideway = 0; + *distance = 2.0f*m_distance; + *smoothing = true; + break; + } + case CM_SIMPLE_REPLAY: + // TODO: Implement + break; + } + +} // getCameraSettings + +//----------------------------------------------------------------------------- +/** Called once per time frame to move the camera to the right position. + * \param dt Time step. + */ +void CameraNormal::update(float dt) +{ + Camera::update(dt); + if(!m_kart) return; + + m_camera->setNearValue(1.0f); + + // If an explosion is happening, stop moving the camera, + // but keep it target on the kart. + if (dynamic_cast(m_kart->getKartAnimation())) + { + float above_kart, cam_angle, side_way, distance; + bool smoothing; + + getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); + // The camera target needs to be 'smooth moved', otherwise + // there will be a noticable jump in the first frame + + // Aim at the usual same position of the kart (i.e. slightly + // above the kart). + // Note: this code is replicated from smoothMoveCamera so that + // the camera keeps on pointing to the same spot. + core::vector3df current_target = (m_kart->getXYZ().toIrrVector() + + core::vector3df(0, above_kart, 0)); + m_camera->setTarget(current_target); + } + else // no kart animation + { + float above_kart, cam_angle, side_way, distance; + bool smoothing; + getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing); + positionCamera(dt, above_kart, cam_angle, side_way, distance, smoothing); + } +} // update + +// ---------------------------------------------------------------------------- +/** Actually sets the camera based on the given parameter. + * \param above_kart How far above the camera should aim at. + * \param cam_angle Angle above the kart plane for the camera. + * \param sideway Sideway movement of the camera. + * \param distance Distance from kart. +*/ +void CameraNormal::positionCamera(float dt, float above_kart, float cam_angle, + float side_way, float distance, float smoothing) +{ + Vec3 wanted_position; + Vec3 wanted_target = m_kart->getXYZ(); + wanted_target.setY(wanted_target.getY() + above_kart); + + float tan_up = tan(cam_angle); + Vec3 relative_position(side_way, + fabsf(distance)*tan_up+above_kart, + distance); + btTransform t=m_kart->getTrans(); + if(stk_config->m_camera_follow_skid && + m_kart->getSkidding()->getVisualSkidRotation()!=0) + { + // If the camera should follow the graphical skid, add the + // visual rotation to the relative vector: + btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0); + t.setBasis(t.getBasis() * btMatrix3x3(q)); + } + wanted_position = t(relative_position); + + if (smoothing) + { + smoothMoveCamera(dt); + } + else + { + if (getMode()!=CM_FALLING) + m_camera->setPosition(wanted_position.toIrrVector()); + m_camera->setTarget(wanted_target.toIrrVector()); + + if (race_manager->getNumLocalPlayers() < 2) + { + SFXManager::get()->positionListener(m_camera->getPosition(), + wanted_target - m_camera->getPosition(), + Vec3(0, 1, 0)); + } + } + + Kart *kart = dynamic_cast(m_kart); + if (kart && !kart->isFlying()) + { + // Rotate the up vector (0,1,0) by the rotation ... which is just column 1 + Vec3 up = m_kart->getTrans().getBasis().getColumn(1); + float f = 0.04f; // weight for new up vector to reduce shaking + m_camera->setUpVector( f * up.toIrrVector() + + (1.0f - f) * m_camera->getUpVector()); + } // kart && !flying + else + m_camera->setUpVector(core::vector3df(0, 1, 0)); +} // positionCamera diff --git a/src/graphics/camera_normal.hpp b/src/graphics/camera_normal.hpp new file mode 100644 index 000000000..24edea3bc --- /dev/null +++ b/src/graphics/camera_normal.hpp @@ -0,0 +1,85 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2015 Steve Baker +// Copyright (C) 2006-2015 SuperTuxKart-Team, Steve Baker +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_CAMERA_NORMAL_HPP +#define HEADER_CAMERA_NORMAL_HPP + +#include "graphics/camera.hpp" + +#include "utils/cpp2011.hpp" + +/** + * \brief Handles the normal racing camera + * \ingroup graphics + */ +class CameraNormal : public Camera +{ + +private: + + /** Current ambient light for this camera. */ + video::SColor m_ambient_light; + + /** Distance between the camera and the kart. */ + float m_distance; + + /** The speed at which the camera changes position. */ + float m_position_speed; + + /** The speed at which the camera target changes position. */ + float m_target_speed; + + /** Factor of the effects of steering in camera aim. */ + float m_rotation_range; + + void smoothMoveCamera(float dt); + void handleEndCamera(float dt); + void getCameraSettings(float *above_kart, float *cam_angle, + float *side_way, float *distance, + bool *smoothing); + void positionCamera(float dt, float above_kart, float cam_angle, + float side_way, float distance, float smoothing); + + // Give a few classes access to the constructor (mostly for inheritance) + friend class Camera; + friend class CameraDebug; + friend class CameraEnd; + CameraNormal(int camera_index, AbstractKart* kart); + virtual ~CameraNormal() {} +public: + bool isDebug() { return false; } + // ------------------------------------------------------------------------ + bool isFPS() { return false; } + // ------------------------------------------------------------------------ + virtual void update(float dt) OVERRIDE; + // ------------------------------------------------------------------------ + /** Sets the ambient light for this camera. */ + void setAmbientLight(const video::SColor &color) { m_ambient_light=color; } + // ------------------------------------------------------------------------ + float getDistanceToKart() const { return m_distance; } + // ------------------------------------------------------------------------ + /** Returns the current ambient light. */ + const video::SColor &getAmbientLight() const {return m_ambient_light; } + +}; // class CameraNormal + +#endif + +/* EOF */ diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index 9a2e3ced0..adc6e7e03 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -19,7 +19,7 @@ #include "input/input_manager.hpp" #include "config/user_config.hpp" -#include "graphics/camera.hpp" +#include "graphics/camera_fps.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/event_handler.hpp" @@ -174,10 +174,9 @@ void InputManager::handleStaticAction(int key, int value) // Moving the first person camera case KEY_KEY_W: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam ) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.Z = value ? cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -186,10 +185,9 @@ void InputManager::handleStaticAction(int key, int value) } case KEY_KEY_S: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.Z = value ? -cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -198,10 +196,9 @@ void InputManager::handleStaticAction(int key, int value) } case KEY_KEY_D: { - if (world && !UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && !UserConfigParams::m_artist_debug_mode && cam) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.X = value ? -cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -210,10 +207,9 @@ void InputManager::handleStaticAction(int key, int value) } case KEY_KEY_A: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.X = value ? cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -222,10 +218,9 @@ void InputManager::handleStaticAction(int key, int value) } case KEY_KEY_R: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.Y = value ? cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -234,10 +229,9 @@ void InputManager::handleStaticAction(int key, int value) } case KEY_KEY_F: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam) { - Camera *cam = Camera::getActiveCamera(); core::vector3df vel(cam->getLinearVelocity()); vel.Y = value ? -cam->getMaximumVelocity() : 0; cam->setLinearVelocity(vel); @@ -247,22 +241,20 @@ void InputManager::handleStaticAction(int key, int value) // Rotating the first person camera case KEY_KEY_Q: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam ) { - Camera *active_cam = Camera::getActiveCamera(); - active_cam->setAngularVelocity(value ? + cam->setAngularVelocity(value ? UserConfigParams::m_fpscam_max_angular_velocity : 0.0f); } break; } case KEY_KEY_E: { - if (world && UserConfigParams::m_artist_debug_mode && - Camera::isFPS() ) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (world && UserConfigParams::m_artist_debug_mode && cam) { - Camera *active_cam = Camera::getActiveCamera(); - active_cam->setAngularVelocity(value ? + cam->setAngularVelocity(value ? -UserConfigParams::m_fpscam_max_angular_velocity : 0); } break; @@ -1009,9 +1001,9 @@ EventPropagation InputManager::input(const SEvent& event) if (type == EMIE_MOUSE_MOVED) { - if (Camera::isFPS()) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (cam) { - Camera *cam = Camera::getActiveCamera(); // Center of the screen core::vector2df screen_size = irr_driver->getCurrentScreenSize(); int mid_x = (int) screen_size.X / 2; @@ -1064,12 +1056,12 @@ EventPropagation InputManager::input(const SEvent& event) } else if (type == EMIE_MOUSE_WHEEL) { - if (Camera::isFPS()) + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if (cam) { // Use scrolling to change the maximum speed // Only test if it's more or less than 0 as it seems to be not // reliable accross more platforms. - Camera *cam = Camera::getActiveCamera(); if (event.MouseInput.Wheel < 0) { float vel = cam->getMaximumVelocity() - 3; diff --git a/src/karts/controller/ai_base_controller.cpp b/src/karts/controller/ai_base_controller.cpp index b504286ae..ee82538f7 100644 --- a/src/karts/controller/ai_base_controller.cpp +++ b/src/karts/controller/ai_base_controller.cpp @@ -66,7 +66,7 @@ void AIBaseController::update(float dt) void AIBaseController::setControllerName(const std::string &name) { #ifdef DEBUG - if(m_ai_debug && !Camera::isDebug()) + if(m_ai_debug && Camera::getActiveCamera()->getType()==Camera::CM_NORMAL) m_kart->setOnScreenText(core::stringw(name.c_str()).c_str()); #endif Controller::setControllerName(name); diff --git a/src/karts/controller/ghost_controller.cpp b/src/karts/controller/ghost_controller.cpp index 19f3ac2bf..4ebf0690a 100644 --- a/src/karts/controller/ghost_controller.cpp +++ b/src/karts/controller/ghost_controller.cpp @@ -16,7 +16,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "graphics/camera.hpp" +#include "graphics/camera_fps.hpp" #include "karts/controller/ghost_controller.hpp" #include "karts/controller/kart_control.hpp" #include "modes/world.hpp" @@ -48,19 +48,23 @@ void GhostController::update(float dt) } // Watching replay use only - Camera *camera = Camera::getActiveCamera(); - if (camera != NULL && camera->getMode() != Camera::CM_FINAL) + for(unsigned int i=0; im_look_back) + Camera *camera = Camera::getCamera(i); + if(camera->getKart()!=m_kart) continue; + if (camera->getType() != Camera::CM_TYPE_END) { - camera->setMode(Camera::CM_REVERSE); - } - else - { - if (camera->getMode() == Camera::CM_REVERSE) - camera->setMode(Camera::CM_NORMAL); - } - } + if (m_controls->m_look_back) + { + camera->setMode(Camera::CM_REVERSE); + } + else + { + if (camera->getMode() == Camera::CM_REVERSE) + camera->setMode(Camera::CM_NORMAL); + } + } // if camera mode != END + } // for i in all cameras } // update diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index b48a3622d..36e8e626f 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -61,7 +61,8 @@ LocalPlayerController::LocalPlayerController(AbstractKart *kart, // 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); + Camera *camera = Camera::createCamera(kart); + m_camera_index = camera->getIndex(); m_bzzt_sound = SFXManager::get()->createSoundSource("bzzt"); m_wee_sound = SFXManager::get()->createSoundSource("wee"); m_ugh_sound = SFXManager::get()->createSoundSource("ugh"); @@ -166,17 +167,18 @@ void LocalPlayerController::update(float dt) // look backward when the player requests or // if automatic reverse camera is active - if (m_camera->getMode() != Camera::CM_FINAL) + Camera *camera = Camera::getCamera(m_camera_index); + if (camera->getType() != Camera::CM_TYPE_END) { if (m_controls->m_look_back || (UserConfigParams::m_reverse_look_threshold > 0 && m_kart->getSpeed() < -UserConfigParams::m_reverse_look_threshold)) { - m_camera->setMode(Camera::CM_REVERSE); + camera->setMode(Camera::CM_REVERSE); } else { - if (m_camera->getMode() == Camera::CM_REVERSE) - m_camera->setMode(Camera::CM_NORMAL); + if (camera->getMode() == Camera::CM_REVERSE) + camera->setMode(Camera::CM_NORMAL); } } @@ -242,8 +244,7 @@ void LocalPlayerController::setPosition(int p) void LocalPlayerController::finishedRace(float time) { // This will implicitely trigger setting the first end camera to be active - m_camera->setMode(Camera::CM_FINAL); - + Camera::changeCamera(m_camera_index, Camera::CM_TYPE_END); } // finishedRace //----------------------------------------------------------------------------- @@ -263,7 +264,7 @@ void LocalPlayerController::handleZipper(bool play_sound) } // Apply the motion blur according to the speed of the kart - irr_driver->getPostProcessing()->giveBoost(m_camera->getIndex()); + irr_driver->getPostProcessing()->giveBoost(m_camera_index); } // handleZipper diff --git a/src/karts/controller/local_player_controller.hpp b/src/karts/controller/local_player_controller.hpp index 932b11f8d..e082fbaae 100644 --- a/src/karts/controller/local_player_controller.hpp +++ b/src/karts/controller/local_player_controller.hpp @@ -24,7 +24,6 @@ #include "karts/controller/player_controller.hpp" class AbstractKart; -class Camera; class Player; class SFXBase; @@ -42,9 +41,10 @@ private: bool m_sound_schedule; - /** 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; + + /** The index of the camera attached to the kart for this controller. The + * camera object is managed in the Camera class, so no need to free it. */ + int m_camera_index; SFXBase *m_bzzt_sound; SFXBase *m_wee_sound; diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index a0c622cce..3d2ff01d1 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -127,7 +127,7 @@ ExplosionAnimation::~ExplosionAnimation() for(unsigned int i=0; igetMode() != Camera::CM_FINAL) + if(camera->getType() != Camera::CM_TYPE_END) camera->setMode(Camera::CM_NORMAL); } } diff --git a/src/karts/rescue_animation.cpp b/src/karts/rescue_animation.cpp index 29e2bcee9..7ddfcb232 100644 --- a/src/karts/rescue_animation.cpp +++ b/src/karts/rescue_animation.cpp @@ -83,7 +83,7 @@ RescueAnimation::~RescueAnimation() { Camera *camera = Camera::getCamera(i); if(camera && camera->getKart()==m_kart && - camera->getMode() != Camera::CM_FINAL) + camera->getType() != Camera::CM_TYPE_END) camera->setMode(Camera::CM_NORMAL); } } diff --git a/src/main.cpp b/src/main.cpp index 8024eca18..248e9e89e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,6 +151,7 @@ #include "config/stk_config.hpp" #include "config/user_config.hpp" #include "graphics/camera.hpp" +#include "graphics/camera_debug.hpp" #include "graphics/central_settings.hpp" #include "graphics/graphics_restrictions.hpp" #include "graphics/irr_driver.hpp" @@ -761,14 +762,23 @@ int handleCmdLine() if (CommandLine::has("--fps-debug")) UserConfigParams::m_fps_debug = true; - if(UserConfigParams::m_artist_debug_mode) + if (UserConfigParams::m_artist_debug_mode) { - if(CommandLine::has("--camera-wheel-debug")) - Camera::setDebugMode(Camera::CM_DEBUG_GROUND); + if (CommandLine::has("--camera-wheel-debug")) + { + Camera::setDefaultCameraType(Camera::CM_TYPE_DEBUG); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_GROUND); + } if(CommandLine::has("--camera-debug")) - Camera::setDebugMode(Camera::CM_DEBUG_TOP_OF_KART); + { + Camera::setDefaultCameraType(Camera::CM_TYPE_DEBUG); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_TOP_OF_KART); + } if(CommandLine::has("--camera-kart-debug")) - Camera::setDebugMode(Camera::CM_DEBUG_BEHIND_KART); + { + Camera::setDefaultCameraType(Camera::CM_TYPE_DEBUG); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_BEHIND_KART); + } if(CommandLine::has("--physics-debug")) UserConfigParams::m_physics_debug=1; if(CommandLine::has("--check-debug")) diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 1ac81bdd5..e3f2c219d 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -26,7 +26,7 @@ #include "config/player_manager.hpp" #include "config/stk_config.hpp" #include "config/user_config.hpp" -#include "graphics/camera.hpp" +#include "graphics/camera_end.hpp" #include "graphics/CBatchingMesh.hpp" #include "graphics/central_settings.hpp" #include "graphics/glwrap.hpp" @@ -1606,7 +1606,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) #endif } - Camera::clearEndCameras(); + CameraEnd::clearEndCameras(); m_sky_type = SKY_NONE; m_track_object_manager = new TrackObjectManager(); @@ -1761,7 +1761,8 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) // It's important to execute this BEFORE the code that creates the skycube, // otherwise the skycube node could be modified to have fog enabled, which // we don't want - if (m_use_fog && !Camera::isDebug() && !CVS->isGLSL()) + if (m_use_fog && Camera::getDefaultCameraType()!=Camera::CM_TYPE_DEBUG && + !CVS->isGLSL()) { /* NOTE: if LINEAR type, density does not matter, if EXP or EXP2, start and end do not matter */ @@ -2003,7 +2004,7 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, ModelDefin } else if (name == "end-cameras") { - Camera::readEndCamera(*node); + CameraEnd::readEndCamera(*node); } else if (name == "light") { diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index d8f776a47..17e3025ec 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -19,7 +19,8 @@ #include "debug.hpp" #include "config/user_config.hpp" -#include "graphics/camera.hpp" +#include "graphics/camera_debug.hpp" +#include "graphics/camera_fps.hpp" #include "graphics/irr_driver.hpp" #include "graphics/light.hpp" #include "graphics/shaders.hpp" @@ -440,47 +441,58 @@ bool handleContextMenuAction(s32 cmdID) } else if (cmdID == DEBUG_GUI_CAM_TOP) { - Camera::setDebugMode(Camera::CM_DEBUG_TOP_OF_KART); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_TOP_OF_KART); irr_driver->getDevice()->getCursorControl()->setVisible(true); } else if (cmdID == DEBUG_GUI_CAM_WHEEL) { - Camera::setDebugMode(Camera::CM_DEBUG_GROUND); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_GROUND); irr_driver->getDevice()->getCursorControl()->setVisible(true); } else if (cmdID == DEBUG_GUI_CAM_BEHIND_KART) { - Camera::setDebugMode(Camera::CM_DEBUG_BEHIND_KART); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_BEHIND_KART); irr_driver->getDevice()->getCursorControl()->setVisible(true); } else if (cmdID == DEBUG_GUI_CAM_SIDE_OF_KART) { - Camera::setDebugMode(Camera::CM_DEBUG_SIDE_OF_KART); + CameraDebug::setDebugType(CameraDebug::CM_DEBUG_SIDE_OF_KART); irr_driver->getDevice()->getCursorControl()->setVisible(true); } else if (cmdID == DEBUG_GUI_CAM_FREE) { - Camera::setDebugMode(Camera::CM_DEBUG_FPS); + Camera *camera = Camera::getActiveCamera(); + Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_FPS); irr_driver->getDevice()->getCursorControl()->setVisible(false); // Reset camera rotation - Camera *cam = Camera::getActiveCamera(); - cam->setDirection(vector3df(0, 0, 1)); - cam->setUpVector(vector3df(0, 1, 0)); + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if(cam) + { + cam->setDirection(vector3df(0, 0, 1)); + cam->setUpVector(vector3df(0, 1, 0)); + } } else if (cmdID == DEBUG_GUI_CAM_NORMAL) { - Camera::setDebugMode(Camera::CM_DEBUG_NONE); + Camera *camera = Camera::getActiveCamera(); + Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_NORMAL); irr_driver->getDevice()->getCursorControl()->setVisible(true); } else if (cmdID == DEBUG_GUI_CAM_SMOOTH) { - Camera *cam = Camera::getActiveCamera(); - cam->setSmoothMovement(!cam->getSmoothMovement()); + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if(cam) + { + cam->setSmoothMovement(!cam->getSmoothMovement()); + } } else if (cmdID == DEBUG_GUI_CAM_ATTACH) { - Camera *cam = Camera::getActiveCamera(); - cam->setAttachedFpsCam(!cam->getAttachedFpsCam()); + CameraFPS *cam = dynamic_cast(Camera::getActiveCamera()); + if(cam) + { + cam->setAttachedFpsCam(!cam->getAttachedFpsCam()); + } } else if (cmdID == DEBUG_VIEW_KART_ONE) {