Set up CCamera, CLight, and CSceneNode to use mutable members for caching; modified CSceneNode to allow subclasses to change how transform is calculated

This commit is contained in:
parax0 2015-12-06 21:23:52 -07:00
parent c260e547c9
commit 0da183b161
14 changed files with 291 additions and 234 deletions

View File

@ -13,36 +13,36 @@ CCamera::CCamera()
mYaw = -Math::skHalfPi; mYaw = -Math::skHalfPi;
mPitch = 0.0f; mPitch = 0.0f;
SetOrbit(CVector3f(0), 5.f); SetOrbit(CVector3f(0), 5.f);
Update();
mMoveSpeed = 1.f; mMoveSpeed = 1.f;
mLookSpeed = 1.f; mLookSpeed = 1.f;
mViewOutdated = true; mTransformDirty = true;
mProjectionOutdated = true; mViewDirty = true;
mFrustumPlanesOutdated = true; mProjectionDirty = true;
mFrustumPlanesDirty = true;
} }
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/) CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
{ {
// todo: make it actually look at the target! // todo: make it actually look at the target!
// don't actually use this constructor, it's unfinished and won't work properly
mMode = eFreeCamera; mMode = eFreeCamera;
mMoveSpeed = 1.f; mMoveSpeed = 1.f;
mLookSpeed = 1.f; mLookSpeed = 1.f;
mPosition = Position; mPosition = Position;
mYaw = -Math::skHalfPi; mYaw = -Math::skHalfPi;
mPitch = 0.0f; mPitch = 0.0f;
Update();
} }
void CCamera::Pan(float XAmount, float YAmount) void CCamera::Pan(float XAmount, float YAmount)
{ {
if (mMode == eFreeCamera) if (mMode == eFreeCamera)
{ {
Update();
mPosition += mRightVector * (XAmount * mMoveSpeed); mPosition += mRightVector * (XAmount * mMoveSpeed);
mPosition += mUpVector * (YAmount * mMoveSpeed); mPosition += mUpVector * (YAmount * mMoveSpeed);
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
mFrustumPlanesDirty = true;
} }
else else
@ -53,24 +53,26 @@ void CCamera::Rotate(float XAmount, float YAmount)
{ {
mYaw -= (XAmount * mLookSpeed * 0.3f); mYaw -= (XAmount * mLookSpeed * 0.3f);
mPitch -= (YAmount * mLookSpeed * 0.3f); mPitch -= (YAmount * mLookSpeed * 0.3f);
ValidatePitch();
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
mFrustumPlanesDirty = true;
} }
void CCamera::Zoom(float Amount) void CCamera::Zoom(float Amount)
{ {
if (mMode == eFreeCamera) if (mMode == eFreeCamera)
{
Update();
mPosition += mDirection * (Amount * mMoveSpeed); mPosition += mDirection * (Amount * mMoveSpeed);
}
else else
{
mOrbitDistance -= Amount * mMoveSpeed; mOrbitDistance -= Amount * mMoveSpeed;
mTransformDirty = true;
}
mViewOutdated = true; mViewDirty = true;
mFrustumPlanesOutdated = true; mFrustumPlanesDirty = true;
} }
void CCamera::Snap(CVector3f Position) void CCamera::Snap(CVector3f Position)
@ -78,9 +80,9 @@ void CCamera::Snap(CVector3f Position)
mPosition = Position; mPosition = Position;
mYaw = -Math::skHalfPi; mYaw = -Math::skHalfPi;
mPitch = 0.0f; mPitch = 0.0f;
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
Update(); mFrustumPlanesDirty = true;
} }
void CCamera::ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime) void CCamera::ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime)
@ -117,7 +119,7 @@ void CCamera::ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, fl
} }
} }
CRay CCamera::CastRay(CVector2f DeviceCoords) CRay CCamera::CastRay(CVector2f DeviceCoords) const
{ {
CMatrix4f InverseVP = (ViewMatrix().Transpose() * ProjectionMatrix().Transpose()).Inverse(); CMatrix4f InverseVP = (ViewMatrix().Transpose() * ProjectionMatrix().Transpose()).Inverse();
@ -134,8 +136,11 @@ CRay CCamera::CastRay(CVector2f DeviceCoords)
void CCamera::SetMoveMode(ECameraMoveMode Mode) void CCamera::SetMoveMode(ECameraMoveMode Mode)
{ {
mMode = Mode; mMode = Mode;
mViewOutdated = true; mViewDirty = true;
mFrustumPlanesOutdated = true; mFrustumPlanesDirty = true;
if (mMode == eOrbitCamera)
mTransformDirty = true;
} }
void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance) void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance)
@ -145,24 +150,34 @@ void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance)
if (mMode == eOrbitCamera) if (mMode == eOrbitCamera)
{ {
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
mFrustumPlanesDirty = true;
} }
} }
void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 2.5f*/) void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 4.f*/)
{ {
CVector3f Min = OrbitTarget.Min(); CVector3f Min = OrbitTarget.Min();
CVector3f Max = OrbitTarget.Max(); CVector3f Max = OrbitTarget.Max();
mOrbitTarget = OrbitTarget.Center(); mOrbitTarget = OrbitTarget.Center();
mOrbitDistance = ((Max.x - Min.x) + (Max.y - Min.y) + (Max.z - Min.z)) / 3.f;
mOrbitDistance *= DistScale; // Find largest extent
CVector3f Extent = (Max - Min) / 2.f;
float Dist = 0.f;
if (Extent.x >= Extent.y && Extent.x >= Extent.z) Dist = Extent.x;
else if (Extent.y >= Extent.x && Extent.y >= Extent.z) Dist = Extent.y;
else Dist = Extent.z;
mOrbitDistance = Dist * DistScale;
if (mMode == eOrbitCamera) if (mMode == eOrbitCamera)
{ {
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
mFrustumPlanesDirty = true;
} }
} }
@ -172,12 +187,13 @@ void CCamera::SetOrbitDistance(float Distance)
if (mMode == eOrbitCamera) if (mMode == eOrbitCamera)
{ {
mViewOutdated = true; mTransformDirty = true;
mFrustumPlanesOutdated = true; mViewDirty = true;
mFrustumPlanesDirty = true;
} }
} }
void CCamera::LoadMatrices() void CCamera::LoadMatrices() const
{ {
CGraphics::sMVPBlock.ViewMatrix = ViewMatrix(); CGraphics::sMVPBlock.ViewMatrix = ViewMatrix();
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix(); CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
@ -187,21 +203,25 @@ void CCamera::LoadMatrices()
// ************ GETTERS ************ // ************ GETTERS ************
CVector3f CCamera::Position() const CVector3f CCamera::Position() const
{ {
UpdateTransform();
return mPosition; return mPosition;
} }
CVector3f CCamera::Direction() const CVector3f CCamera::Direction() const
{ {
UpdateTransform();
return mDirection; return mDirection;
} }
CVector3f CCamera::UpVector() const CVector3f CCamera::UpVector() const
{ {
UpdateTransform();
return mUpVector; return mUpVector;
} }
CVector3f CCamera::RightVector() const CVector3f CCamera::RightVector() const
{ {
UpdateTransform();
return mRightVector; return mRightVector;
} }
@ -225,53 +245,36 @@ ECameraMoveMode CCamera::MoveMode() const
return mMode; return mMode;
} }
const CMatrix4f& CCamera::ViewMatrix() const CMatrix4f& CCamera::ViewMatrix() const
{ {
if (mViewOutdated) UpdateView();
UpdateView(); return mViewMatrix;
return mCachedViewMatrix;
} }
const CMatrix4f& CCamera::ProjectionMatrix() const CMatrix4f& CCamera::ProjectionMatrix() const
{ {
if (mProjectionOutdated) UpdateProjection();
UpdateProjection(); return mProjectionMatrix;
return mCachedProjectionMatrix;
} }
const CFrustumPlanes& CCamera::FrustumPlanes() const CFrustumPlanes& CCamera::FrustumPlanes() const
{ {
if (mFrustumPlanesOutdated) UpdateFrustum();
UpdateFrustum(); return mFrustumPlanes;
return mCachedFrustumPlanes;
} }
// ************ SETTERS ************ // ************ SETTERS ************
void CCamera::SetPosition(CVector3f Position)
{
mPosition = Position;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
}
void CCamera::SetDirection(CVector3f Direction)
{
mDirection = Direction;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
}
void CCamera::SetYaw(float Yaw) void CCamera::SetYaw(float Yaw)
{ {
mYaw = Yaw; mYaw = Yaw;
mTransformDirty = true;
} }
void CCamera::SetPitch(float Pitch) void CCamera::SetPitch(float Pitch)
{ {
mPitch = Pitch; mPitch = Pitch;
ValidatePitch();
mTransformDirty = true;
} }
void CCamera::SetMoveSpeed(float MoveSpeed) void CCamera::SetMoveSpeed(float MoveSpeed)
@ -287,62 +290,81 @@ void CCamera::SetLookSpeed(float LookSpeed)
void CCamera::SetAspectRatio(float AspectRatio) void CCamera::SetAspectRatio(float AspectRatio)
{ {
mAspectRatio = AspectRatio; mAspectRatio = AspectRatio;
mProjectionOutdated = true; mProjectionDirty = true;
mFrustumPlanesOutdated = true; mFrustumPlanesDirty = true;
} }
// ************ PRIVATE ************ // ************ PRIVATE ************
void CCamera::Update() void CCamera::ValidatePitch()
{ {
// Update direction // This function mainly just exists to ensure the camera doesn't flip upside down
if (mPitch > Math::skHalfPi) mPitch = Math::skHalfPi; if (mPitch > Math::skHalfPi) mPitch = Math::skHalfPi;
if (mPitch < -Math::skHalfPi) mPitch = -Math::skHalfPi; if (mPitch < -Math::skHalfPi) mPitch = -Math::skHalfPi;
mDirection = CVector3f(
cos(mPitch) * cos(mYaw),
cos(mPitch) * sin(mYaw),
sin(mPitch)
);
mRightVector = CVector3f(
cos(mYaw - Math::skHalfPi),
sin(mYaw - Math::skHalfPi),
0
);
mUpVector = mRightVector.Cross(mDirection);
// Update position
if (mMode == eOrbitCamera)
{
if (mOrbitDistance < 1.f) mOrbitDistance = 1.f;
mPosition = mOrbitTarget + (mDirection * -mOrbitDistance);
}
mViewOutdated = true;
mFrustumPlanesOutdated = true;
} }
void CCamera::UpdateView() void CCamera::UpdateTransform() const
{
// Transform should be marked dirty when pitch, yaw, or orbit target/distance are changed
if (mTransformDirty)
{
mDirection = CVector3f(
cos(mPitch) * cos(mYaw),
cos(mPitch) * sin(mYaw),
sin(mPitch)
);
mRightVector = CVector3f(
cos(mYaw - Math::skHalfPi),
sin(mYaw - Math::skHalfPi),
0
);
mUpVector = mRightVector.Cross(mDirection);
// Update position
if (mMode == eOrbitCamera)
{
if (mOrbitDistance < 1.f) mOrbitDistance = 1.f;
mPosition = mOrbitTarget + (mDirection * -mOrbitDistance);
}
mViewDirty = true;
mFrustumPlanesDirty = true;
mTransformDirty = false;
}
}
void CCamera::UpdateView() const
{ {
// todo: don't use glm // todo: don't use glm
Update(); UpdateTransform();
glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z); if (mViewDirty)
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z); {
glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z); glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z);
mCachedViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose(); glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z);
mViewOutdated = false; glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z);
mViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
mViewDirty = false;
}
} }
void CCamera::UpdateProjection() void CCamera::UpdateProjection() const
{ {
mCachedProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f); if (mProjectionDirty)
mProjectionOutdated = false; {
mProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f);
mProjectionDirty = false;
}
} }
void CCamera::UpdateFrustum() void CCamera::UpdateFrustum() const
{ {
mCachedFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f); UpdateTransform();
mFrustumPlanesOutdated = false;
if (mFrustumPlanesDirty)
{
mFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f);
mFrustumPlanesDirty = false;
}
} }

View File

@ -16,28 +16,38 @@ enum ECameraMoveMode
eFreeCamera, eOrbitCamera eFreeCamera, eOrbitCamera
}; };
/* This class uses a lot of mutable members as an optimization so that they can
* be updated as infrequently as possible (eg only when the values are requested
* the next time after changes are made) while still always returning the correct
* value via the const get functions. They are not modified in const functions
* beyond ensuring that all data is valid and synced with everything else (eg
* mPosition is only modified to ensure it's correct in orbit mode given the
* target/distance/pitch/yaw; it won't be modified as a camera snap in a const
* function). */
class CCamera class CCamera
{ {
ECameraMoveMode mMode; ECameraMoveMode mMode;
CVector3f mPosition; mutable CVector3f mPosition;
CVector3f mDirection; mutable CVector3f mDirection;
CVector3f mRightVector; mutable CVector3f mRightVector;
CVector3f mUpVector; mutable CVector3f mUpVector;
float mAspectRatio; float mAspectRatio;
float mYaw; float mYaw;
float mPitch; float mPitch;
CVector3f mOrbitTarget; CVector3f mOrbitTarget;
float mOrbitDistance; mutable float mOrbitDistance;
float mMoveSpeed; float mMoveSpeed;
float mLookSpeed; float mLookSpeed;
CMatrix4f mCachedViewMatrix; mutable CMatrix4f mViewMatrix;
CMatrix4f mCachedProjectionMatrix; mutable CMatrix4f mProjectionMatrix;
CFrustumPlanes mCachedFrustumPlanes; mutable CFrustumPlanes mFrustumPlanes;
bool mViewOutdated;
bool mProjectionOutdated; mutable bool mTransformDirty;
bool mFrustumPlanesOutdated; mutable bool mViewDirty;
mutable bool mProjectionDirty;
mutable bool mFrustumPlanesDirty;
public: public:
CCamera(); CCamera();
@ -49,12 +59,12 @@ public:
void Snap(CVector3f Position); void Snap(CVector3f Position);
void ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime); void ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime);
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement); void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
CRay CastRay(CVector2f DeviceCoords); CRay CastRay(CVector2f DeviceCoords) const;
void LoadMatrices(); void LoadMatrices() const;
void SetMoveMode(ECameraMoveMode Mode); void SetMoveMode(ECameraMoveMode Mode);
void SetOrbit(const CVector3f& OrbitTarget, float Distance); void SetOrbit(const CVector3f& OrbitTarget, float Distance);
void SetOrbit(const CAABox& OrbitTarget, float DistScale = 2.5f); void SetOrbit(const CAABox& OrbitTarget, float DistScale = 4.f);
void SetOrbitDistance(float Distance); void SetOrbitDistance(float Distance);
// Getters // Getters
@ -66,13 +76,11 @@ public:
float Pitch() const; float Pitch() const;
float FieldOfView() const; float FieldOfView() const;
ECameraMoveMode MoveMode() const; ECameraMoveMode MoveMode() const;
const CMatrix4f& ViewMatrix(); const CMatrix4f& ViewMatrix() const;
const CMatrix4f& ProjectionMatrix(); const CMatrix4f& ProjectionMatrix() const;
const CFrustumPlanes& FrustumPlanes(); const CFrustumPlanes& FrustumPlanes() const;
// Setters // Setters
void SetPosition(CVector3f Position);
void SetDirection(CVector3f Direction);
void SetYaw(float Yaw); void SetYaw(float Yaw);
void SetPitch(float Pitch); void SetPitch(float Pitch);
void SetMoveSpeed(float MoveSpeed); void SetMoveSpeed(float MoveSpeed);
@ -81,10 +89,11 @@ public:
// Private // Private
private: private:
void Update(); void ValidatePitch();
void UpdateView(); void UpdateTransform() const;
void UpdateProjection(); void UpdateView() const;
void UpdateFrustum(); void UpdateProjection() const;
void UpdateFrustum() const;
}; };
#endif // CCAMERA_H #endif // CCAMERA_H

View File

@ -12,15 +12,15 @@ CLight::CLight()
mDirection = skDefaultLightDir; mDirection = skDefaultLightDir;
mDistAttenCoefficients = CVector3f(0.f, 1.f, 0.f); mDistAttenCoefficients = CVector3f(0.f, 1.f, 0.f);
mAngleAttenCoefficients = CVector3f(0.f, 1.f, 0.f); mAngleAttenCoefficients = CVector3f(0.f, 1.f, 0.f);
mRadius = 0.f; mCachedRadius = 0.f;
mIntensity = 0.f; mCachedIntensity = 0.f;
mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; mDirtyFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY;
} }
// ************ DATA MANIPULATION ************ // ************ DATA MANIPULATION ************
// This function is reverse engineered from the kiosk demo's code // This function is reverse engineered from the kiosk demo's code
float CLight::CalculateRadius() float CLight::CalculateRadius() const
{ {
if ((mDistAttenCoefficients.y >= FLT_EPSILON) || if ((mDistAttenCoefficients.y >= FLT_EPSILON) ||
(mDistAttenCoefficients.z >= FLT_EPSILON)) (mDistAttenCoefficients.z >= FLT_EPSILON))
@ -53,7 +53,7 @@ float CLight::CalculateRadius()
} }
// This function is also reverse engineered from the kiosk demo's code // This function is also reverse engineered from the kiosk demo's code
float CLight::CalculateIntensity() float CLight::CalculateIntensity() const
{ {
float Multiplier = (mType == eCustom) ? mAngleAttenCoefficients.x : 1.0f; float Multiplier = (mType == eCustom) ? mAngleAttenCoefficients.x : 1.0f;
float ColorR = float(mColor.r) / 255.f; float ColorR = float(mColor.r) / 255.f;
@ -118,26 +118,26 @@ CVector3f CLight::GetAngleAttenuation() const
return mAngleAttenCoefficients; return mAngleAttenCoefficients;
} }
float CLight::GetRadius() float CLight::GetRadius() const
{ {
if (mFlags & CLIGHT_NO_RADIUS) if (mDirtyFlags & CLIGHT_NO_RADIUS)
{ {
mRadius = CalculateRadius(); mCachedRadius = CalculateRadius();
mFlags &= ~CLIGHT_NO_RADIUS; mDirtyFlags &= ~CLIGHT_NO_RADIUS;
} }
return mRadius * 2; return mCachedRadius * 2;
} }
float CLight::GetIntensity() float CLight::GetIntensity() const
{ {
if (mFlags & CLIGHT_NO_INTENSITY) if (mDirtyFlags & CLIGHT_NO_INTENSITY)
{ {
mIntensity = CalculateIntensity(); mCachedIntensity = CalculateIntensity();
mFlags &= ~CLIGHT_NO_INTENSITY; mDirtyFlags &= ~CLIGHT_NO_INTENSITY;
} }
return mIntensity; return mCachedIntensity;
} }
// ************ SETTERS ************ // ************ SETTERS ************
@ -159,7 +159,7 @@ void CLight::SetDirection(const CVector3f& Direction)
void CLight::SetColor(const CColor& Color) void CLight::SetColor(const CColor& Color)
{ {
mColor = Color; mColor = Color;
mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; mDirtyFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY;
} }
void CLight::SetSpotCutoff(float Cutoff) void CLight::SetSpotCutoff(float Cutoff)

View File

@ -6,12 +6,9 @@
#include <Common/CVector3f.h> #include <Common/CVector3f.h>
#include <GL/glew.h> #include <GL/glew.h>
/** /* CLight is currently heavily based on the lights system from Metroid Prime,
* CLight is currently heavily based on the lights system from Metroid Prime,
* including code reverse engineered from the game's executable. Not yet sure * including code reverse engineered from the game's executable. Not yet sure
* how much needs to be modified to properly support Prime 3 and DKCR; they * how much needs to be modified to properly support DKCR. */
* have a new light structure.
*/
enum ELightType enum ELightType
{ {
eLocalAmbient = 0, eLocalAmbient = 0,
@ -31,17 +28,17 @@ class CLight
CVector3f mDistAttenCoefficients; CVector3f mDistAttenCoefficients;
CVector3f mAngleAttenCoefficients; CVector3f mAngleAttenCoefficients;
float mRadius; mutable float mCachedRadius;
float mIntensity; mutable float mCachedIntensity;
u8 mFlags; mutable u8 mDirtyFlags;
public: public:
CLight(); CLight();
private: private:
// Data Manipulation // Data Manipulation
float CalculateRadius(); float CalculateRadius() const;
float CalculateIntensity(); float CalculateIntensity() const;
CVector3f CalculateSpotAngleAtten(); CVector3f CalculateSpotAngleAtten();
public: public:
@ -53,8 +50,8 @@ public:
CColor GetColor() const; CColor GetColor() const;
CVector3f GetDistAttenuation() const; CVector3f GetDistAttenuation() const;
CVector3f GetAngleAttenuation() const; CVector3f GetAngleAttenuation() const;
float GetRadius(); float GetRadius() const;
float GetIntensity(); float GetIntensity() const;
// Setters // Setters
void SetLayer(u32 index); void SetLayer(u32 index);

View File

@ -134,3 +134,9 @@ CVector2f CLightNode::BillboardScale()
{ {
return AbsoluteScale().xz() * 0.75f; return AbsoluteScale().xz() * 0.75f;
} }
void CLightNode::CalculateTransform(CTransform4f& rOut) const
{
// Billboards don't rotate and their scale is applied separately
rOut.Translate(AbsolutePosition());
}

View File

@ -17,6 +17,9 @@ public:
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo); SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
CLight* Light(); CLight* Light();
CVector2f BillboardScale(); CVector2f BillboardScale();
protected:
void CalculateTransform(CTransform4f& rOut) const;
}; };
#endif // CLIGHTNODE_H #endif // CLIGHTNODE_H

View File

@ -113,6 +113,8 @@ void CModelNode::SetModel(CModel *pModel)
SetName(pModel->Source()); SetName(pModel->Source());
mLocalAABox = mpModel->AABox(); mLocalAABox = mpModel->AABox();
} }
MarkTransformChanged();
} }
void CModelNode::ForceAlphaEnabled(bool Enable) void CModelNode::ForceAlphaEnabled(bool Enable)

View File

@ -21,8 +21,7 @@ CSceneNode::CSceneNode(CSceneManager *pScene, CSceneNode *pParent)
mPosition = CVector3f::skZero; mPosition = CVector3f::skZero;
mRotation = CQuaternion::skIdentity; mRotation = CQuaternion::skIdentity;
mScale = CVector3f::skOne; mScale = CVector3f::skOne;
mScaleMultiplier = CVector3f::skOne; _mTransformDirty = true;
_mTransformOutdated = true;
_mInheritsPosition = true; _mInheritsPosition = true;
_mInheritsRotation = true; _mInheritsRotation = true;
@ -208,7 +207,7 @@ void CSceneNode::LoadLights(const SViewInfo& ViewInfo)
CGraphics::UpdateLightBlock(); CGraphics::UpdateLightBlock();
} }
void CSceneNode::DrawBoundingBox() void CSceneNode::DrawBoundingBox() const
{ {
CDrawUtil::DrawWireCube(AABox(), CColor::skWhite); CDrawUtil::DrawWireCube(AABox(), CColor::skWhite);
} }
@ -267,52 +266,49 @@ void CSceneNode::Scale(const CVector3f& scale)
MarkTransformChanged(); MarkTransformChanged();
} }
void CSceneNode::UpdateTransform() void CSceneNode::ForceRecalculateTransform() const
{
if (_mTransformOutdated)
{
ForceRecalculateTransform();
_mTransformOutdated = false;
}
}
void CSceneNode::ForceRecalculateTransform()
{ {
_mCachedTransform = CTransform4f::skIdentity; _mCachedTransform = CTransform4f::skIdentity;
_mCachedTransform.Scale(AbsoluteScale()); CalculateTransform(_mCachedTransform);
_mCachedTransform.Rotate(AbsoluteRotation());
_mCachedTransform.Translate(AbsolutePosition());
_mCachedAABox = mLocalAABox.Transformed(_mCachedTransform); _mCachedAABox = mLocalAABox.Transformed(_mCachedTransform);
// Sync with children - only needed if caller hasn't marked transform changed already // Sync with children - only needed if caller hasn't marked transform changed already
// If so, the children will already be marked // If so, the children will already be marked
if (!_mTransformOutdated) if (!_mTransformDirty)
{ {
for (auto it = mChildren.begin(); it != mChildren.end(); it++) for (auto it = mChildren.begin(); it != mChildren.end(); it++)
(*it)->MarkTransformChanged(); (*it)->MarkTransformChanged();
} }
_mTransformOutdated = false; _mTransformDirty = false;
} }
void CSceneNode::MarkTransformChanged() void CSceneNode::MarkTransformChanged() const
{ {
if (!_mTransformOutdated) if (!_mTransformDirty)
{ {
for (auto it = mChildren.begin(); it != mChildren.end(); it++) for (auto it = mChildren.begin(); it != mChildren.end(); it++)
(*it)->MarkTransformChanged(); (*it)->MarkTransformChanged();
} }
_mTransformOutdated = true; _mTransformDirty = true;
} }
const CTransform4f& CSceneNode::Transform() const CTransform4f& CSceneNode::Transform() const
{ {
if (_mTransformOutdated) if (_mTransformDirty)
ForceRecalculateTransform(); ForceRecalculateTransform();
return _mCachedTransform; return _mCachedTransform;
} }
void CSceneNode::CalculateTransform(CTransform4f& rOut) const
{
// Default implementation for virtual function
rOut.Scale(AbsoluteScale());
rOut.Rotate(AbsoluteRotation());
rOut.Translate(AbsolutePosition());
}
// ************ GETTERS ************ // ************ GETTERS ************
TString CSceneNode::Name() const TString CSceneNode::Name() const
{ {
@ -324,7 +320,7 @@ CSceneNode* CSceneNode::Parent() const
return mpParent; return mpParent;
} }
CSceneManager* CSceneNode::Scene() CSceneManager* CSceneNode::Scene() const
{ {
return mpScene; return mpScene;
} }
@ -366,7 +362,7 @@ CVector3f CSceneNode::LocalScale() const
CVector3f CSceneNode::AbsoluteScale() const CVector3f CSceneNode::AbsoluteScale() const
{ {
CVector3f ret = mScale * mScaleMultiplier; CVector3f ret = mScale;
if ((mpParent) && (InheritsScale())) if ((mpParent) && (InheritsScale()))
ret *= mpParent->AbsoluteScale(); ret *= mpParent->AbsoluteScale();
@ -374,15 +370,15 @@ CVector3f CSceneNode::AbsoluteScale() const
return ret; return ret;
} }
CAABox CSceneNode::AABox() CAABox CSceneNode::AABox() const
{ {
if (_mTransformOutdated) if (_mTransformDirty)
ForceRecalculateTransform(); ForceRecalculateTransform();
return _mCachedAABox; return _mCachedAABox;
} }
CVector3f CSceneNode::CenterPoint() CVector3f CSceneNode::CenterPoint() const
{ {
return AABox().Center(); return AABox().Center();
} }

View File

@ -21,9 +21,9 @@ class CSceneManager;
class CSceneNode : public IRenderable class CSceneNode : public IRenderable
{ {
private: private:
CTransform4f _mCachedTransform; mutable CTransform4f _mCachedTransform;
CAABox _mCachedAABox; mutable CAABox _mCachedAABox;
bool _mTransformOutdated; mutable bool _mTransformDirty;
bool _mInheritsPosition; bool _mInheritsPosition;
bool _mInheritsRotation; bool _mInheritsRotation;
@ -38,7 +38,6 @@ protected:
CVector3f mPosition; CVector3f mPosition;
CQuaternion mRotation; CQuaternion mRotation;
CVector3f mScale; CVector3f mScale;
CVector3f mScaleMultiplier;
CAABox mLocalAABox; CAABox mLocalAABox;
bool mMouseHovering; bool mMouseHovering;
@ -70,30 +69,32 @@ public:
void LoadModelMatrix(); void LoadModelMatrix();
void BuildLightList(CGameArea *pArea); void BuildLightList(CGameArea *pArea);
void LoadLights(const SViewInfo& ViewInfo); void LoadLights(const SViewInfo& ViewInfo);
void DrawBoundingBox(); void DrawBoundingBox() const;
void AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& ViewInfo); void AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& ViewInfo);
// Transform // Transform
void Translate(const CVector3f& translation, ETransformSpace transformSpace); void Translate(const CVector3f& translation, ETransformSpace transformSpace);
void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace); void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace);
void Scale(const CVector3f& scale); void Scale(const CVector3f& scale);
void UpdateTransform(); const CTransform4f& Transform() const;
void ForceRecalculateTransform(); protected:
void MarkTransformChanged(); void MarkTransformChanged() const;
const CTransform4f& Transform(); void ForceRecalculateTransform() const;
virtual void CalculateTransform(CTransform4f& rOut) const;
public:
// Getters // Getters
TString Name() const; TString Name() const;
CSceneNode* Parent() const; CSceneNode* Parent() const;
CSceneManager* Scene(); CSceneManager* Scene() const;
CVector3f LocalPosition() const; CVector3f LocalPosition() const;
CVector3f AbsolutePosition() const; CVector3f AbsolutePosition() const;
CQuaternion LocalRotation() const; CQuaternion LocalRotation() const;
CQuaternion AbsoluteRotation() const; CQuaternion AbsoluteRotation() const;
CVector3f LocalScale() const; CVector3f LocalScale() const;
CVector3f AbsoluteScale() const; CVector3f AbsoluteScale() const;
CAABox AABox(); CAABox AABox() const;
CVector3f CenterPoint(); CVector3f CenterPoint() const;
u32 LightLayerIndex() const; u32 LightLayerIndex() const;
bool MarkedVisible() const; bool MarkedVisible() const;
bool IsMouseHovering() const; bool IsMouseHovering() const;

View File

@ -29,16 +29,12 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
// Determine transform // Determine transform
mPosition = mpInstance->Position(); mPosition = mpInstance->Position();
mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName()); mScale = mpInstance->Scale();
mScaleMultiplier = mpInstance->Template()->PreviewScale();
if (pTemp->ScaleType() == CScriptTemplate::eScaleEnabled)
{
mScale = mpInstance->Scale();
mScaleMultiplier = mpInstance->Template()->PreviewScale();
}
MarkTransformChanged(); MarkTransformChanged();
SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName());
// Determine display assets // Determine display assets
mpActiveModel = mpInstance->GetDisplayModel(); mpActiveModel = mpInstance->GetDisplayModel();
mModelToken = CToken(mpActiveModel); mModelToken = CToken(mpActiveModel);
@ -72,8 +68,7 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
if (pVolumeModel) if (pVolumeModel)
{ {
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel);
mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), false); mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), true);
mpVolumePreviewNode->Scale(mpInstance->Scale());
mpVolumePreviewNode->ForceAlphaEnabled(true); mpVolumePreviewNode->ForceAlphaEnabled(true);
} }
} }
@ -162,7 +157,7 @@ void CScriptNode::Draw(ERenderOptions Options, int ComponentIndex, const SViewIn
if (!mpInstance) return; if (!mpInstance) return;
// Draw model // Draw model
if (mpActiveModel || !mpBillboard) if (UsesModel())
{ {
CGraphics::SetupAmbientColor(); CGraphics::SetupAmbientColor();
CGraphics::UpdateVertexBlock(); CGraphics::UpdateVertexBlock();
@ -204,7 +199,7 @@ void CScriptNode::DrawSelection()
glBlendFunc(GL_ONE, GL_ZERO); glBlendFunc(GL_ONE, GL_ZERO);
// Draw wireframe for models; billboards only get tinted // Draw wireframe for models; billboards only get tinted
if (mpActiveModel || !mpBillboard) if (UsesModel())
{ {
LoadModelMatrix(); LoadModelMatrix();
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
@ -258,7 +253,7 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester& Tester, const SView
// Otherwise, proceed with the ray test as normal... // Otherwise, proceed with the ray test as normal...
const CRay& Ray = Tester.Ray(); const CRay& Ray = Tester.Ray();
if (mpActiveModel || !mpBillboard) if (UsesModel())
{ {
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray); std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
@ -294,7 +289,7 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID,
if (options & eDrawObjects || ViewInfo.GameMode) if (options & eDrawObjects || ViewInfo.GameMode)
{ {
// Model test // Model test
if (mpActiveModel || !mpBillboard) if (UsesModel())
{ {
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
@ -381,21 +376,6 @@ CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const
return BaseColor; return BaseColor;
} }
CColor CScriptNode::WireframeColor() const
{
return CColor((u8) 12, 135, 194, 255);
}
CScriptObject* CScriptNode::Object()
{
return mpInstance;
}
CModel* CScriptNode::ActiveModel()
{
return mpActiveModel;
}
void CScriptNode::GeneratePosition() void CScriptNode::GeneratePosition()
{ {
if (!mHasValidPosition) if (!mHasValidPosition)
@ -457,12 +437,32 @@ void CScriptNode::GeneratePosition()
} }
} }
bool CScriptNode::HasPreviewVolume() CColor CScriptNode::WireframeColor() const
{
return CColor((u8) 12, 135, 194, 255);
}
CScriptObject* CScriptNode::Object() const
{
return mpInstance;
}
CModel* CScriptNode::ActiveModel() const
{
return mpActiveModel;
}
bool CScriptNode::UsesModel() const
{
return ((mpActiveModel != nullptr) || (mpBillboard == nullptr));
}
bool CScriptNode::HasPreviewVolume() const
{ {
return mHasVolumePreview; return mHasVolumePreview;
} }
CAABox CScriptNode::PreviewVolumeAABox() CAABox CScriptNode::PreviewVolumeAABox() const
{ {
if (!mHasVolumePreview) if (!mHasVolumePreview)
return CAABox::skZero; return CAABox::skZero;
@ -470,8 +470,25 @@ CAABox CScriptNode::PreviewVolumeAABox()
return mpVolumePreviewNode->AABox(); return mpVolumePreviewNode->AABox();
} }
CVector2f CScriptNode::BillboardScale() CVector2f CScriptNode::BillboardScale() const
{ {
CVector2f out = (mpInstance->Template()->ScaleType() == CScriptTemplate::eScaleEnabled ? AbsoluteScale().xz() : CVector2f(1.f)); CVector2f out = (mpInstance->Template()->ScaleType() == CScriptTemplate::eScaleEnabled ? AbsoluteScale().xz() : CVector2f(1.f));
return out * 0.5f; return out * 0.5f;
} }
// ************ PROTECTED ************
void CScriptNode::CalculateTransform(CTransform4f& rOut) const
{
CScriptTemplate *pTemp = mpInstance->Template();
if (pTemp->ScaleType() != CScriptTemplate::eScaleDisabled)
{
CVector3f Scale = (HasPreviewVolume() ? CVector3f::skOne : AbsoluteScale());
rOut.Scale(Scale * mScaleMultiplier);
}
if (UsesModel() && pTemp->RotationType() == CScriptTemplate::eRotationEnabled)
rOut.Rotate(AbsoluteRotation());
rOut.Translate(AbsolutePosition());
}

View File

@ -20,6 +20,7 @@ class CScriptNode : public CSceneNode
bool mHasValidPosition; bool mHasValidPosition;
bool mHasVolumePreview; bool mHasVolumePreview;
float mScaleMultiplier;
CModelNode *mpVolumePreviewNode; CModelNode *mpVolumePreviewNode;
CLightParameters *mpLightParameters; CLightParameters *mpLightParameters;
@ -36,12 +37,16 @@ public:
CColor TintColor(const SViewInfo &ViewInfo) const; CColor TintColor(const SViewInfo &ViewInfo) const;
CColor WireframeColor() const; CColor WireframeColor() const;
CScriptObject* Object();
CModel* ActiveModel();
void GeneratePosition(); void GeneratePosition();
bool HasPreviewVolume(); CScriptObject* Object() const;
CAABox PreviewVolumeAABox(); CModel* ActiveModel() const;
CVector2f BillboardScale(); bool UsesModel() const;
bool HasPreviewVolume() const;
CAABox PreviewVolumeAABox() const;
CVector2f BillboardScale() const;
protected:
void CalculateTransform(CTransform4f& rOut) const;
}; };
#endif // CSCRIPTNODE_H #endif // CSCRIPTNODE_H

View File

@ -64,7 +64,7 @@ void CDamageableTriggerExtra::CreateMaterial()
mpMat->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); mpMat->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
mpMat->SetLightingEnabled(true); mpMat->SetLightingEnabled(true);
mpMat->SetOptions(CMaterial::eTransparent); mpMat->SetOptions(CMaterial::eTransparent);
mpMat->SetKonst(CColor((float) 1.f, 1.f, 1.f, 51.f / 255), 0); mpMat->SetKonst(CColor((float) 1.f, 1.f, 1.f, 0.2f), 0);
mpMat->SetNumPasses(3); mpMat->SetNumPasses(3);
CMaterialPass *pPassA = mpMat->Pass(0); CMaterialPass *pPassA = mpMat->Pass(0);

View File

@ -153,7 +153,6 @@ void CModelEditorWindow::RefreshViewport()
void CModelEditorWindow::SetActiveModel(CModel *pModel) void CModelEditorWindow::SetActiveModel(CModel *pModel)
{ {
mpCurrentModelNode->SetModel(pModel); mpCurrentModelNode->SetModel(pModel);
mpCurrentModelNode->MarkTransformChanged();
mpCurrentModel = pModel; mpCurrentModel = pModel;
mModelToken = CToken(pModel); mModelToken = CToken(pModel);
ui->Viewport->Camera().SetOrbit(pModel->AABox()); ui->Viewport->Camera().SetOrbit(pModel->AABox());

View File

@ -180,7 +180,7 @@ void CWorldEditor::UpdateGizmoUI()
if (mGizmoTransforming && mGizmo.HasTransformed()) if (mGizmoTransforming && mGizmo.HasTransformed())
spinBoxValue = mGizmo.TotalScale(); spinBoxValue = mGizmo.TotalScale();
else if (!mSelection.empty()) else if (!mSelection.empty())
spinBoxValue = mSelection.front()->LocalScale(); spinBoxValue = mSelection.front()->AbsoluteScale();
break; break;
} }
} }
@ -289,7 +289,7 @@ void CWorldEditor::UpdateCameraOrbit()
if (!mSelection.isEmpty()) if (!mSelection.isEmpty())
pCamera->SetOrbit(mSelectionBounds); pCamera->SetOrbit(mSelectionBounds);
else if (mpArea) else if (mpArea)
pCamera->SetOrbit(mpArea->AABox(), 0.8f); pCamera->SetOrbit(mpArea->AABox(), 1.5f);
} }
void CWorldEditor::OnCameraSpeedChange(double speed) void CWorldEditor::OnCameraSpeedChange(double speed)
@ -325,7 +325,7 @@ void CWorldEditor::OnTransformSpinBoxModified(CVector3f value)
case CGizmo::eScale: case CGizmo::eScale:
{ {
CVector3f delta = value / mSelection.front()->LocalScale(); CVector3f delta = value / mSelection.front()->AbsoluteScale();
mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta)); mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta));
break; break;
} }