From 0da183b16103ac04ddb9eb83521f394dd0e244ec Mon Sep 17 00:00:00 2001 From: parax0 Date: Sun, 6 Dec 2015 21:23:52 -0700 Subject: [PATCH] Set up CCamera, CLight, and CSceneNode to use mutable members for caching; modified CSceneNode to allow subclasses to change how transform is calculated --- Core/CCamera.cpp | 224 +++++++++++++---------- Core/CCamera.h | 55 +++--- Resource/CLight.cpp | 32 ++-- Resource/CLight.h | 21 +-- Scene/CLightNode.cpp | 6 + Scene/CLightNode.h | 3 + Scene/CModelNode.cpp | 2 + Scene/CSceneNode.cpp | 52 +++--- Scene/CSceneNode.h | 25 +-- Scene/CScriptNode.cpp | 81 ++++---- Scene/CScriptNode.h | 15 +- Scene/script/CDamageableTriggerExtra.cpp | 2 +- UI/CModelEditorWindow.cpp | 1 - UI/CWorldEditor.cpp | 6 +- 14 files changed, 291 insertions(+), 234 deletions(-) diff --git a/Core/CCamera.cpp b/Core/CCamera.cpp index c91b6454..471c2b1b 100644 --- a/Core/CCamera.cpp +++ b/Core/CCamera.cpp @@ -13,36 +13,36 @@ CCamera::CCamera() mYaw = -Math::skHalfPi; mPitch = 0.0f; SetOrbit(CVector3f(0), 5.f); - Update(); mMoveSpeed = 1.f; mLookSpeed = 1.f; - mViewOutdated = true; - mProjectionOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = true; + mViewDirty = true; + mProjectionDirty = true; + mFrustumPlanesDirty = true; } CCamera::CCamera(CVector3f Position, CVector3f /*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; mMoveSpeed = 1.f; mLookSpeed = 1.f; mPosition = Position; mYaw = -Math::skHalfPi; mPitch = 0.0f; - Update(); } void CCamera::Pan(float XAmount, float YAmount) { if (mMode == eFreeCamera) { - Update(); mPosition += mRightVector * (XAmount * mMoveSpeed); mPosition += mUpVector * (YAmount * mMoveSpeed); - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } else @@ -53,24 +53,26 @@ void CCamera::Rotate(float XAmount, float YAmount) { mYaw -= (XAmount * mLookSpeed * 0.3f); mPitch -= (YAmount * mLookSpeed * 0.3f); + ValidatePitch(); - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } void CCamera::Zoom(float Amount) { if (mMode == eFreeCamera) - { - Update(); mPosition += mDirection * (Amount * mMoveSpeed); - } else + { mOrbitDistance -= Amount * mMoveSpeed; + mTransformDirty = true; + } - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } void CCamera::Snap(CVector3f Position) @@ -78,9 +80,9 @@ void CCamera::Snap(CVector3f Position) mPosition = Position; mYaw = -Math::skHalfPi; mPitch = 0.0f; - mViewOutdated = true; - mFrustumPlanesOutdated = true; - Update(); + mTransformDirty = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } 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(); @@ -134,8 +136,11 @@ CRay CCamera::CastRay(CVector2f DeviceCoords) void CCamera::SetMoveMode(ECameraMoveMode Mode) { mMode = Mode; - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mViewDirty = true; + mFrustumPlanesDirty = true; + + if (mMode == eOrbitCamera) + mTransformDirty = true; } void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance) @@ -145,24 +150,34 @@ void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance) if (mMode == eOrbitCamera) { - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = 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 Max = OrbitTarget.Max(); 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) { - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } } @@ -172,12 +187,13 @@ void CCamera::SetOrbitDistance(float Distance) if (mMode == eOrbitCamera) { - mViewOutdated = true; - mFrustumPlanesOutdated = true; + mTransformDirty = true; + mViewDirty = true; + mFrustumPlanesDirty = true; } } -void CCamera::LoadMatrices() +void CCamera::LoadMatrices() const { CGraphics::sMVPBlock.ViewMatrix = ViewMatrix(); CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix(); @@ -187,21 +203,25 @@ void CCamera::LoadMatrices() // ************ GETTERS ************ CVector3f CCamera::Position() const { + UpdateTransform(); return mPosition; } CVector3f CCamera::Direction() const { + UpdateTransform(); return mDirection; } CVector3f CCamera::UpVector() const { + UpdateTransform(); return mUpVector; } CVector3f CCamera::RightVector() const { + UpdateTransform(); return mRightVector; } @@ -225,53 +245,36 @@ ECameraMoveMode CCamera::MoveMode() const return mMode; } -const CMatrix4f& CCamera::ViewMatrix() +const CMatrix4f& CCamera::ViewMatrix() const { - if (mViewOutdated) - UpdateView(); - - return mCachedViewMatrix; + UpdateView(); + return mViewMatrix; } -const CMatrix4f& CCamera::ProjectionMatrix() +const CMatrix4f& CCamera::ProjectionMatrix() const { - if (mProjectionOutdated) - UpdateProjection(); - - return mCachedProjectionMatrix; + UpdateProjection(); + return mProjectionMatrix; } -const CFrustumPlanes& CCamera::FrustumPlanes() +const CFrustumPlanes& CCamera::FrustumPlanes() const { - if (mFrustumPlanesOutdated) - UpdateFrustum(); - - return mCachedFrustumPlanes; + UpdateFrustum(); + return mFrustumPlanes; } // ************ 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) { mYaw = Yaw; + mTransformDirty = true; } void CCamera::SetPitch(float Pitch) { mPitch = Pitch; + ValidatePitch(); + mTransformDirty = true; } void CCamera::SetMoveSpeed(float MoveSpeed) @@ -287,62 +290,81 @@ void CCamera::SetLookSpeed(float LookSpeed) void CCamera::SetAspectRatio(float AspectRatio) { mAspectRatio = AspectRatio; - mProjectionOutdated = true; - mFrustumPlanesOutdated = true; + mProjectionDirty = true; + mFrustumPlanesDirty = true; } // ************ 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; - - 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 - Update(); + UpdateTransform(); - glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z); - glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z); - glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z); - mCachedViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose(); - mViewOutdated = false; + if (mViewDirty) + { + glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z); + glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z); + 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); - mProjectionOutdated = false; + if (mProjectionDirty) + { + 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); - mFrustumPlanesOutdated = false; + UpdateTransform(); + + if (mFrustumPlanesDirty) + { + mFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f); + mFrustumPlanesDirty = false; + } } diff --git a/Core/CCamera.h b/Core/CCamera.h index e664b9d3..ea7d87c3 100644 --- a/Core/CCamera.h +++ b/Core/CCamera.h @@ -16,28 +16,38 @@ enum ECameraMoveMode 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 { ECameraMoveMode mMode; - CVector3f mPosition; - CVector3f mDirection; - CVector3f mRightVector; - CVector3f mUpVector; + mutable CVector3f mPosition; + mutable CVector3f mDirection; + mutable CVector3f mRightVector; + mutable CVector3f mUpVector; float mAspectRatio; float mYaw; float mPitch; CVector3f mOrbitTarget; - float mOrbitDistance; + mutable float mOrbitDistance; float mMoveSpeed; float mLookSpeed; - CMatrix4f mCachedViewMatrix; - CMatrix4f mCachedProjectionMatrix; - CFrustumPlanes mCachedFrustumPlanes; - bool mViewOutdated; - bool mProjectionOutdated; - bool mFrustumPlanesOutdated; + mutable CMatrix4f mViewMatrix; + mutable CMatrix4f mProjectionMatrix; + mutable CFrustumPlanes mFrustumPlanes; + + mutable bool mTransformDirty; + mutable bool mViewDirty; + mutable bool mProjectionDirty; + mutable bool mFrustumPlanesDirty; public: CCamera(); @@ -49,12 +59,12 @@ public: void Snap(CVector3f Position); void ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime); void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement); - CRay CastRay(CVector2f DeviceCoords); - void LoadMatrices(); + CRay CastRay(CVector2f DeviceCoords) const; + void LoadMatrices() const; void SetMoveMode(ECameraMoveMode Mode); 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); // Getters @@ -66,13 +76,11 @@ public: float Pitch() const; float FieldOfView() const; ECameraMoveMode MoveMode() const; - const CMatrix4f& ViewMatrix(); - const CMatrix4f& ProjectionMatrix(); - const CFrustumPlanes& FrustumPlanes(); + const CMatrix4f& ViewMatrix() const; + const CMatrix4f& ProjectionMatrix() const; + const CFrustumPlanes& FrustumPlanes() const; // Setters - void SetPosition(CVector3f Position); - void SetDirection(CVector3f Direction); void SetYaw(float Yaw); void SetPitch(float Pitch); void SetMoveSpeed(float MoveSpeed); @@ -81,10 +89,11 @@ public: // Private private: - void Update(); - void UpdateView(); - void UpdateProjection(); - void UpdateFrustum(); + void ValidatePitch(); + void UpdateTransform() const; + void UpdateView() const; + void UpdateProjection() const; + void UpdateFrustum() const; }; #endif // CCAMERA_H diff --git a/Resource/CLight.cpp b/Resource/CLight.cpp index 88d3f2b9..35a6b26e 100644 --- a/Resource/CLight.cpp +++ b/Resource/CLight.cpp @@ -12,15 +12,15 @@ CLight::CLight() mDirection = skDefaultLightDir; mDistAttenCoefficients = CVector3f(0.f, 1.f, 0.f); mAngleAttenCoefficients = CVector3f(0.f, 1.f, 0.f); - mRadius = 0.f; - mIntensity = 0.f; - mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; + mCachedRadius = 0.f; + mCachedIntensity = 0.f; + mDirtyFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; } // ************ DATA MANIPULATION ************ // This function is reverse engineered from the kiosk demo's code -float CLight::CalculateRadius() +float CLight::CalculateRadius() const { if ((mDistAttenCoefficients.y >= 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 -float CLight::CalculateIntensity() +float CLight::CalculateIntensity() const { float Multiplier = (mType == eCustom) ? mAngleAttenCoefficients.x : 1.0f; float ColorR = float(mColor.r) / 255.f; @@ -118,26 +118,26 @@ CVector3f CLight::GetAngleAttenuation() const return mAngleAttenCoefficients; } -float CLight::GetRadius() +float CLight::GetRadius() const { - if (mFlags & CLIGHT_NO_RADIUS) + if (mDirtyFlags & CLIGHT_NO_RADIUS) { - mRadius = CalculateRadius(); - mFlags &= ~CLIGHT_NO_RADIUS; + mCachedRadius = CalculateRadius(); + 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(); - mFlags &= ~CLIGHT_NO_INTENSITY; + mCachedIntensity = CalculateIntensity(); + mDirtyFlags &= ~CLIGHT_NO_INTENSITY; } - return mIntensity; + return mCachedIntensity; } // ************ SETTERS ************ @@ -159,7 +159,7 @@ void CLight::SetDirection(const CVector3f& Direction) void CLight::SetColor(const CColor& Color) { mColor = Color; - mFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; + mDirtyFlags = CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY; } void CLight::SetSpotCutoff(float Cutoff) diff --git a/Resource/CLight.h b/Resource/CLight.h index 72d439c8..7c4f7403 100644 --- a/Resource/CLight.h +++ b/Resource/CLight.h @@ -6,12 +6,9 @@ #include #include -/** - * 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 - * how much needs to be modified to properly support Prime 3 and DKCR; they - * have a new light structure. - */ + * how much needs to be modified to properly support DKCR. */ enum ELightType { eLocalAmbient = 0, @@ -31,17 +28,17 @@ class CLight CVector3f mDistAttenCoefficients; CVector3f mAngleAttenCoefficients; - float mRadius; - float mIntensity; - u8 mFlags; + mutable float mCachedRadius; + mutable float mCachedIntensity; + mutable u8 mDirtyFlags; public: CLight(); private: // Data Manipulation - float CalculateRadius(); - float CalculateIntensity(); + float CalculateRadius() const; + float CalculateIntensity() const; CVector3f CalculateSpotAngleAtten(); public: @@ -53,8 +50,8 @@ public: CColor GetColor() const; CVector3f GetDistAttenuation() const; CVector3f GetAngleAttenuation() const; - float GetRadius(); - float GetIntensity(); + float GetRadius() const; + float GetIntensity() const; // Setters void SetLayer(u32 index); diff --git a/Scene/CLightNode.cpp b/Scene/CLightNode.cpp index cff8dfc3..afbb73cf 100644 --- a/Scene/CLightNode.cpp +++ b/Scene/CLightNode.cpp @@ -134,3 +134,9 @@ CVector2f CLightNode::BillboardScale() { return AbsoluteScale().xz() * 0.75f; } + +void CLightNode::CalculateTransform(CTransform4f& rOut) const +{ + // Billboards don't rotate and their scale is applied separately + rOut.Translate(AbsolutePosition()); +} diff --git a/Scene/CLightNode.h b/Scene/CLightNode.h index bdc89780..73226967 100644 --- a/Scene/CLightNode.h +++ b/Scene/CLightNode.h @@ -17,6 +17,9 @@ public: SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo); CLight* Light(); CVector2f BillboardScale(); + +protected: + void CalculateTransform(CTransform4f& rOut) const; }; #endif // CLIGHTNODE_H diff --git a/Scene/CModelNode.cpp b/Scene/CModelNode.cpp index 8f579c08..64c2aca4 100644 --- a/Scene/CModelNode.cpp +++ b/Scene/CModelNode.cpp @@ -113,6 +113,8 @@ void CModelNode::SetModel(CModel *pModel) SetName(pModel->Source()); mLocalAABox = mpModel->AABox(); } + + MarkTransformChanged(); } void CModelNode::ForceAlphaEnabled(bool Enable) diff --git a/Scene/CSceneNode.cpp b/Scene/CSceneNode.cpp index 030bd5c9..0016db88 100644 --- a/Scene/CSceneNode.cpp +++ b/Scene/CSceneNode.cpp @@ -21,8 +21,7 @@ CSceneNode::CSceneNode(CSceneManager *pScene, CSceneNode *pParent) mPosition = CVector3f::skZero; mRotation = CQuaternion::skIdentity; mScale = CVector3f::skOne; - mScaleMultiplier = CVector3f::skOne; - _mTransformOutdated = true; + _mTransformDirty = true; _mInheritsPosition = true; _mInheritsRotation = true; @@ -208,7 +207,7 @@ void CSceneNode::LoadLights(const SViewInfo& ViewInfo) CGraphics::UpdateLightBlock(); } -void CSceneNode::DrawBoundingBox() +void CSceneNode::DrawBoundingBox() const { CDrawUtil::DrawWireCube(AABox(), CColor::skWhite); } @@ -267,52 +266,49 @@ void CSceneNode::Scale(const CVector3f& scale) MarkTransformChanged(); } -void CSceneNode::UpdateTransform() -{ - if (_mTransformOutdated) - { - ForceRecalculateTransform(); - _mTransformOutdated = false; - } -} - -void CSceneNode::ForceRecalculateTransform() +void CSceneNode::ForceRecalculateTransform() const { _mCachedTransform = CTransform4f::skIdentity; - _mCachedTransform.Scale(AbsoluteScale()); - _mCachedTransform.Rotate(AbsoluteRotation()); - _mCachedTransform.Translate(AbsolutePosition()); + CalculateTransform(_mCachedTransform); _mCachedAABox = mLocalAABox.Transformed(_mCachedTransform); // Sync with children - only needed if caller hasn't marked transform changed already // If so, the children will already be marked - if (!_mTransformOutdated) + if (!_mTransformDirty) { for (auto it = mChildren.begin(); it != mChildren.end(); it++) (*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++) (*it)->MarkTransformChanged(); } - _mTransformOutdated = true; + _mTransformDirty = true; } -const CTransform4f& CSceneNode::Transform() +const CTransform4f& CSceneNode::Transform() const { - if (_mTransformOutdated) + if (_mTransformDirty) ForceRecalculateTransform(); return _mCachedTransform; } +void CSceneNode::CalculateTransform(CTransform4f& rOut) const +{ + // Default implementation for virtual function + rOut.Scale(AbsoluteScale()); + rOut.Rotate(AbsoluteRotation()); + rOut.Translate(AbsolutePosition()); +} + // ************ GETTERS ************ TString CSceneNode::Name() const { @@ -324,7 +320,7 @@ CSceneNode* CSceneNode::Parent() const return mpParent; } -CSceneManager* CSceneNode::Scene() +CSceneManager* CSceneNode::Scene() const { return mpScene; } @@ -366,7 +362,7 @@ CVector3f CSceneNode::LocalScale() const CVector3f CSceneNode::AbsoluteScale() const { - CVector3f ret = mScale * mScaleMultiplier; + CVector3f ret = mScale; if ((mpParent) && (InheritsScale())) ret *= mpParent->AbsoluteScale(); @@ -374,15 +370,15 @@ CVector3f CSceneNode::AbsoluteScale() const return ret; } -CAABox CSceneNode::AABox() +CAABox CSceneNode::AABox() const { - if (_mTransformOutdated) + if (_mTransformDirty) ForceRecalculateTransform(); return _mCachedAABox; } -CVector3f CSceneNode::CenterPoint() +CVector3f CSceneNode::CenterPoint() const { return AABox().Center(); } diff --git a/Scene/CSceneNode.h b/Scene/CSceneNode.h index eb5c7475..19bf91c7 100644 --- a/Scene/CSceneNode.h +++ b/Scene/CSceneNode.h @@ -21,9 +21,9 @@ class CSceneManager; class CSceneNode : public IRenderable { private: - CTransform4f _mCachedTransform; - CAABox _mCachedAABox; - bool _mTransformOutdated; + mutable CTransform4f _mCachedTransform; + mutable CAABox _mCachedAABox; + mutable bool _mTransformDirty; bool _mInheritsPosition; bool _mInheritsRotation; @@ -38,7 +38,6 @@ protected: CVector3f mPosition; CQuaternion mRotation; CVector3f mScale; - CVector3f mScaleMultiplier; CAABox mLocalAABox; bool mMouseHovering; @@ -70,30 +69,32 @@ public: void LoadModelMatrix(); void BuildLightList(CGameArea *pArea); void LoadLights(const SViewInfo& ViewInfo); - void DrawBoundingBox(); + void DrawBoundingBox() const; void AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& ViewInfo); // Transform void Translate(const CVector3f& translation, ETransformSpace transformSpace); void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace); void Scale(const CVector3f& scale); - void UpdateTransform(); - void ForceRecalculateTransform(); - void MarkTransformChanged(); - const CTransform4f& Transform(); + const CTransform4f& Transform() const; +protected: + void MarkTransformChanged() const; + void ForceRecalculateTransform() const; + virtual void CalculateTransform(CTransform4f& rOut) const; +public: // Getters TString Name() const; CSceneNode* Parent() const; - CSceneManager* Scene(); + CSceneManager* Scene() const; CVector3f LocalPosition() const; CVector3f AbsolutePosition() const; CQuaternion LocalRotation() const; CQuaternion AbsoluteRotation() const; CVector3f LocalScale() const; CVector3f AbsoluteScale() const; - CAABox AABox(); - CVector3f CenterPoint(); + CAABox AABox() const; + CVector3f CenterPoint() const; u32 LightLayerIndex() const; bool MarkedVisible() const; bool IsMouseHovering() const; diff --git a/Scene/CScriptNode.cpp b/Scene/CScriptNode.cpp index 8e17ce20..addfe985 100644 --- a/Scene/CScriptNode.cpp +++ b/Scene/CScriptNode.cpp @@ -29,16 +29,12 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje // Determine transform mPosition = mpInstance->Position(); mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); - SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName()); - - if (pTemp->ScaleType() == CScriptTemplate::eScaleEnabled) - { - mScale = mpInstance->Scale(); - mScaleMultiplier = mpInstance->Template()->PreviewScale(); - } - + mScale = mpInstance->Scale(); + mScaleMultiplier = mpInstance->Template()->PreviewScale(); MarkTransformChanged(); + SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName()); + // Determine display assets mpActiveModel = mpInstance->GetDisplayModel(); mModelToken = CToken(mpActiveModel); @@ -72,8 +68,7 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje if (pVolumeModel) { mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); - mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), false); - mpVolumePreviewNode->Scale(mpInstance->Scale()); + mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), true); mpVolumePreviewNode->ForceAlphaEnabled(true); } } @@ -162,7 +157,7 @@ void CScriptNode::Draw(ERenderOptions Options, int ComponentIndex, const SViewIn if (!mpInstance) return; // Draw model - if (mpActiveModel || !mpBillboard) + if (UsesModel()) { CGraphics::SetupAmbientColor(); CGraphics::UpdateVertexBlock(); @@ -204,7 +199,7 @@ void CScriptNode::DrawSelection() glBlendFunc(GL_ONE, GL_ZERO); // Draw wireframe for models; billboards only get tinted - if (mpActiveModel || !mpBillboard) + if (UsesModel()) { LoadModelMatrix(); 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... const CRay& Ray = Tester.Ray(); - if (mpActiveModel || !mpBillboard) + if (UsesModel()) { std::pair BoxResult = AABox().IntersectsRay(Ray); @@ -294,7 +289,7 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, if (options & eDrawObjects || ViewInfo.GameMode) { // Model test - if (mpActiveModel || !mpBillboard) + if (UsesModel()) { CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); @@ -381,21 +376,6 @@ CColor CScriptNode::TintColor(const SViewInfo &ViewInfo) const 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() { 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; } -CAABox CScriptNode::PreviewVolumeAABox() +CAABox CScriptNode::PreviewVolumeAABox() const { if (!mHasVolumePreview) return CAABox::skZero; @@ -470,8 +470,25 @@ CAABox CScriptNode::PreviewVolumeAABox() return mpVolumePreviewNode->AABox(); } -CVector2f CScriptNode::BillboardScale() +CVector2f CScriptNode::BillboardScale() const { CVector2f out = (mpInstance->Template()->ScaleType() == CScriptTemplate::eScaleEnabled ? AbsoluteScale().xz() : CVector2f(1.f)); 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()); +} diff --git a/Scene/CScriptNode.h b/Scene/CScriptNode.h index 728e381e..a2769e97 100644 --- a/Scene/CScriptNode.h +++ b/Scene/CScriptNode.h @@ -20,6 +20,7 @@ class CScriptNode : public CSceneNode bool mHasValidPosition; bool mHasVolumePreview; + float mScaleMultiplier; CModelNode *mpVolumePreviewNode; CLightParameters *mpLightParameters; @@ -36,12 +37,16 @@ public: CColor TintColor(const SViewInfo &ViewInfo) const; CColor WireframeColor() const; - CScriptObject* Object(); - CModel* ActiveModel(); void GeneratePosition(); - bool HasPreviewVolume(); - CAABox PreviewVolumeAABox(); - CVector2f BillboardScale(); + CScriptObject* Object() const; + CModel* ActiveModel() const; + bool UsesModel() const; + bool HasPreviewVolume() const; + CAABox PreviewVolumeAABox() const; + CVector2f BillboardScale() const; + +protected: + void CalculateTransform(CTransform4f& rOut) const; }; #endif // CSCRIPTNODE_H diff --git a/Scene/script/CDamageableTriggerExtra.cpp b/Scene/script/CDamageableTriggerExtra.cpp index a66cb3b3..031c895a 100644 --- a/Scene/script/CDamageableTriggerExtra.cpp +++ b/Scene/script/CDamageableTriggerExtra.cpp @@ -64,7 +64,7 @@ void CDamageableTriggerExtra::CreateMaterial() mpMat->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); mpMat->SetLightingEnabled(true); 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); CMaterialPass *pPassA = mpMat->Pass(0); diff --git a/UI/CModelEditorWindow.cpp b/UI/CModelEditorWindow.cpp index 544769c3..5c3cfe39 100644 --- a/UI/CModelEditorWindow.cpp +++ b/UI/CModelEditorWindow.cpp @@ -153,7 +153,6 @@ void CModelEditorWindow::RefreshViewport() void CModelEditorWindow::SetActiveModel(CModel *pModel) { mpCurrentModelNode->SetModel(pModel); - mpCurrentModelNode->MarkTransformChanged(); mpCurrentModel = pModel; mModelToken = CToken(pModel); ui->Viewport->Camera().SetOrbit(pModel->AABox()); diff --git a/UI/CWorldEditor.cpp b/UI/CWorldEditor.cpp index b829f956..5deb1510 100644 --- a/UI/CWorldEditor.cpp +++ b/UI/CWorldEditor.cpp @@ -180,7 +180,7 @@ void CWorldEditor::UpdateGizmoUI() if (mGizmoTransforming && mGizmo.HasTransformed()) spinBoxValue = mGizmo.TotalScale(); else if (!mSelection.empty()) - spinBoxValue = mSelection.front()->LocalScale(); + spinBoxValue = mSelection.front()->AbsoluteScale(); break; } } @@ -289,7 +289,7 @@ void CWorldEditor::UpdateCameraOrbit() if (!mSelection.isEmpty()) pCamera->SetOrbit(mSelectionBounds); else if (mpArea) - pCamera->SetOrbit(mpArea->AABox(), 0.8f); + pCamera->SetOrbit(mpArea->AABox(), 1.5f); } void CWorldEditor::OnCameraSpeedChange(double speed) @@ -325,7 +325,7 @@ void CWorldEditor::OnTransformSpinBoxModified(CVector3f value) case CGizmo::eScale: { - CVector3f delta = value / mSelection.front()->LocalScale(); + CVector3f delta = value / mSelection.front()->AbsoluteScale(); mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta)); break; }