diff --git a/src/gameui/camera/CSimpleCamera.cpp b/src/gameui/camera/CSimpleCamera.cpp index 6b48a67..cbcd5a2 100644 --- a/src/gameui/camera/CSimpleCamera.cpp +++ b/src/gameui/camera/CSimpleCamera.cpp @@ -1,6 +1,87 @@ #include "CSimpleCamera.hpp" #include +#include +#include + +#include "gx/Transform.hpp" + + +static void FaceDirection(const C3Vector& direction, C3Vector* xprime, C3Vector* yprime, C3Vector* zprime) { + STORM_ASSERT(!CMath::fequal(direction.SquaredMag(), 0.0)); + + *xprime = direction; + + yprime->x = -xprime->y; + yprime->y = xprime->x; + yprime->z = 0.0f; + + if (yprime->x == 0.0 && yprime->y == 0.0) { + yprime->y = 1.1920929e-7f; + } + + CMath::normalize(yprime->x, yprime->y); + + zprime->x = -xprime->z * yprime->y; + zprime->y = xprime->z * yprime->x; + zprime->z = xprime->x * yprime->y - xprime->y * yprime->x; +} + +static void FaceDirectionWithRoll(const C3Vector& direction, const C3Vector& up, C3Vector* xprime, C3Vector* yprime, C3Vector* zprime) { + STORM_ASSERT(!CMath::fequal(direction.SquaredMag(), 0.0)); + + *xprime = direction; + + float dot = CMath::fabs(C3Vector::Dot(up, *xprime)); + if (CMath::fequal(dot, 1.0)) { + yprime->x = 1.0f; + yprime->y = 0.0f; + yprime->z = 0.0f; + } else { + *yprime = C3Vector::Cross(up, *xprime); + yprime->Normalize(); + } + + *zprime = C3Vector::Cross(*xprime, *yprime); +} + +static void BuildBillboardMatrix(const C3Vector& direction, C33Matrix* rotation) { + C3Vector xprime; + C3Vector yprime; + C3Vector zprime; + FaceDirection(direction, &xprime, &yprime, &zprime); + + rotation->a0 = xprime.x; + rotation->a1 = xprime.y; + rotation->a2 = xprime.z; + + rotation->b0 = yprime.x; + rotation->b1 = yprime.y; + rotation->b2 = yprime.z; + + rotation->c0 = zprime.x; + rotation->c1 = zprime.y; + rotation->c2 = zprime.z; +} + +static void BuildBillboardMatrixWithRoll(const C3Vector& direction, const C3Vector& up, C33Matrix* rotation) { + C3Vector xprime; + C3Vector yprime; + C3Vector zprime; + FaceDirectionWithRoll(direction, up, &xprime, &yprime, &zprime); + + rotation->a0 = xprime.x; + rotation->a1 = xprime.y; + rotation->a2 = xprime.z; + + rotation->b0 = yprime.x; + rotation->b1 = yprime.y; + rotation->b2 = yprime.z; + + rotation->c0 = zprime.x; + rotation->c1 = zprime.y; + rotation->c2 = zprime.z; +} CSimpleCamera::CSimpleCamera() : m_position() @@ -49,17 +130,25 @@ C3Vector CSimpleCamera::Up() { } void CSimpleCamera::SetFacing(float yaw, float pitch, float roll) { - // TODO + this->m_facing.FromEulerAnglesZYX(yaw, pitch, roll); } void CSimpleCamera::SetFacing(const C3Vector& forward, const C3Vector& up) { - // TODO + BuildBillboardMatrixWithRoll(forward, up, &this->m_facing); } void CSimpleCamera::SetFacing(const C3Vector& forward) { - // TODO + BuildBillboardMatrix(forward, &this->m_facing); } void CSimpleCamera::SetGxProjectionAndView(const CRect& projectionRect) { - // TODO + this->m_aspect = (projectionRect.maxX - projectionRect.minX) / (projectionRect.maxY - projectionRect.minY); + + C44Matrix mProj; + GxuXformCreateProjection_SG(this->m_fov, this->m_aspect, this->m_nearZ, this->m_farZ, mProj); + GxXformSetProjection(mProj); + + C44Matrix mView; + GxuXformCreateLookAtSgCompat(C3Vector(), Forward(), Up(), mView); + GxXformSetView(mView); } diff --git a/src/gameui/camera/CSimpleCamera.hpp b/src/gameui/camera/CSimpleCamera.hpp index 5618f85..be0f59c 100644 --- a/src/gameui/camera/CSimpleCamera.hpp +++ b/src/gameui/camera/CSimpleCamera.hpp @@ -19,9 +19,9 @@ class CSimpleCamera { float FOV() { this->m_fov; }; float Aspect() { this->m_aspect; }; - C3Vector Forward(); - C3Vector Right(); - C3Vector Up(); + virtual C3Vector Forward(); + virtual C3Vector Right(); + virtual C3Vector Up(); void SetPosition(const C3Vector& position) { this->m_position = position; }; void SetPosition(float x, float y, float z) { this->m_position = C3Vector(x, y, z); };