#include "DebugCameraController.h"
#include "Utils/CasualCoreCandidates.h"
#include "Utils/Plane.h"
#include <RKCamera.h>
using namespace bne;
namespace details
{
static Plane s_basePlane(RKVector(0, 0, 0, 0), RKVector(0, 1.f, 0, 0)); // RKVector::Zero, RKVector::Up - order of static initialisation issue
static const float c_rorationSpeed(1.0f);
static const float c_heightSpeed(10.0f);
static const float c_zoomSpeed(1.0f);
static const int c_panKey(17); // CTRL
static const int c_heightKey(16); // SHIFT
}
SERIALIZE_BEGIN(DebugCameraController)
SERIALIZE_END()
DebugCameraController::DebugCameraController()
: Parent()
, m_pinchRefScreenPoint(0, 0)
, m_vBoundaryCenter(0, 0, 0, 0)
, m_CameraDesiredTarget(0, 0, 0, 1)
, m_currentScreenPoint(0, 0)
, m_previousScreenPoint(0, 0)
, m_mode(Mode_Rotate)
, m_yaw(0.0f)
, m_pitch(0.0f)
{
}
DebugCameraController::~DebugCameraController()
{
RKCamera_SetDefault();
}
bool DebugCameraController::Init()
{
bool success = Parent::Init();
if (success)
{
SetUpdatable(true);
}
return success;
}
void DebugCameraController::Reset()
{
m_pinchRefScreenPoint.Set(0, 0);
}
void DebugCameraController::SetCameraControl(RKCamera* camera)
{
Parent::SetCameraControl(camera);
if (camera)
{
m_vBoundaryCenter = ScreenToWorld(RKVector2(0, 0));
m_CameraDesiredTarget = m_vBoundaryCenter;
camera->SetZoom(2.5f);
}
}
void DebugCameraController::UpdateFromCamera(RKCamera* camera)
{
if ((camera != nullptr) && (camera->IsOrtho()))
{
RKVector cameraLookAt = GetLookAtPoint(camera);
float currentZoom = (cameraLookAt - camera->GetWorldPosition()).Length();
RKVector controllerLookAt = GetLookAtPoint(this);
RKVector controllerDirection = GetWorldTransform().GetZAxis();
controllerDirection.w = 0;
controllerDirection.Normalize();
RKVector newControllerPos = controllerLookAt - (controllerDirection * currentZoom);
SetWorldPosition(newControllerPos);
}
}
void DebugCameraController::CopySettingFromCameraCtrl(CasualCore::CameraController* ctrl)
{
Parent::CopySettingFromCameraCtrl(ctrl);
if (ctrl)
{
SetWorldPosition(ctrl->GetWorldPosition());
SetWorldRotation(ctrl->GetWorldRotation());
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
UpdateCamera(camera);
}
}
}
void DebugCameraController::Update(float time)
{
}
bool DebugCameraController::OnKeyDown(int keycode)
{
switch (keycode)
{
case details::c_panKey:
m_mode = Mode_Pan;
break;
case details::c_heightKey:
m_mode = Mode_Height;
break;
default:
m_mode = Mode_Rotate;
break;
}
return true;
}
bool DebugCameraController::OnKeyUp(int keycode)
{
m_mode = Mode_Rotate;
return true;
}
void DebugCameraController::PanStarted(float x, float y)
{
m_currentScreenPoint = RKVector2(x, y);
m_previousScreenPoint = RKVector2(x, y);
switch (m_mode)
{
case Mode_Rotate:
RotateStarted(x, y);
break;
case Mode_Pan:
m_CameraDesiredTarget = ScreenToWorld(RKVector2(0, 0));
break;
case Mode_Height:
HeightStarted(x, y);
break;
default:
RKASSERT(false, "DebugCameraController: Mode not implemented.");
break;
}
}
void DebugCameraController::PanChanged(float x, float y)
{
m_previousScreenPoint = m_currentScreenPoint;
m_currentScreenPoint = RKVector2(x, y);
switch (m_mode)
{
case Mode_Rotate:
RotateChanged(x, y);
break;
case Mode_Pan:
if (GetCamera())
{
m_CameraDesiredTarget -= ScreenToWorld(RKVector2(x, y)) - ScreenToWorld(m_currentScreenPoint);
GetCamera()->MoveToLookAt(m_CameraDesiredTarget);
}
break;
case Mode_Height:
HeightChanged(x, y);
break;
default:
RKASSERT(false, "DebugCameraController: Mode not implemented.");
break;
}
}
void DebugCameraController::PanEnded(float x, float y)
{
switch (m_mode)
{
case Mode_Rotate:
RotateEnded(x, y);
break;
case Mode_Pan:
// nothing to do
break;
case Mode_Height:
break;
default:
RKASSERT(false, "DebugCameraController: Mode not implemented.");
break;
}
}
void DebugCameraController::RotateStarted(float x, float y)
{
}
void DebugCameraController::RotateChanged(float x, float y)
{
float deltaYaw = (m_previousScreenPoint.x - m_currentScreenPoint.x) * details::c_rorationSpeed;
float deltaPitch = (m_currentScreenPoint.y - m_previousScreenPoint.y) * details::c_rorationSpeed;
m_yaw += deltaYaw;
m_pitch += deltaPitch;
m_yaw = m_yaw < RKPI ? m_yaw : m_yaw - (2.0f * RKPI);
m_yaw = m_yaw > -RKPI ? m_yaw : m_yaw + (2.0f * RKPI);
m_pitch = RKCLAMP(-RKPI / 2.0f, RKPI / 2.0f, m_pitch);
RKLOG("yaw = %f", m_yaw);
RKLOG("pitch = %f", m_pitch);
RKQuaternion rotation;
rotation.FromEuler(m_pitch, m_yaw, 0.0f);
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
camera->SetRotation(rotation);
}
}
void DebugCameraController::HeightStarted(float x, float y)
{
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
m_initialPosition = camera->GetWorldPosition();
}
}
void DebugCameraController::HeightChanged(float x, float y)
{
float deltaHeight = (m_previousScreenPoint.y - m_currentScreenPoint.y) * details::c_heightSpeed;
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
camera->SetWorldPosition(m_initialPosition + RKVector(0.0f, deltaHeight, 0.0f, 0.0f));
}
}
void DebugCameraController::Pinch(float x, float y)
{
if (x > 1.0f)
{
ZoomBy(-1.0f);
}
else if (x < 1.0f)
{
ZoomBy(1.0f);
}
PinchEnded(x, y);
}
void DebugCameraController::UpdateZoomPoint(float x, float y)
{
m_pinchRefScreenPoint.Set(x, y);
}
void DebugCameraController::ZoomBy(float zoomFactor)
{
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
if (!camera->IsOrtho())
{
RKVector direction = camera->GetDirection();
RKVector position = camera->GetWorldPosition();
position += direction * details::c_zoomSpeed * zoomFactor;
camera->SetWorldPosition(position);
}
}
}
RKVector DebugCameraController::ScreenToWorld(const RKVector2 & position)
{
RKVector position_w(RKVector::Zero);
RKCamera* camera = GetCamera();
if (camera != nullptr)
{
RKVector origin, direction;
GetCamera()->GetWorldRay(position, origin, direction);
details::s_basePlane.Intersection(origin, direction, &position_w);
}
return position_w;
}
RKVector DebugCameraController::GetLookAtPoint(RKTransformObject* camera)
{
RKVector lookAtPoint(RKVector::Zero);
if (camera != nullptr)
{
RKVector direction = camera->GetWorldTransform().GetZAxis();
direction.w = 0;
direction.Normalize();
details::s_basePlane.Intersection(camera->GetWorldPosition(), direction, &lookAtPoint);
}
return lookAtPoint;
}