Added support for dynamic lighting in Metroid Prime 3 + some other dynamic lighting additions and fixes
This commit is contained in:
parent
b187da3925
commit
763d4b8b0a
|
@ -156,6 +156,10 @@ void CGraphics::SetDefaultLighting()
|
|||
sDefaultDirectionalLights[0].Load();
|
||||
sDefaultDirectionalLights[1].Load();
|
||||
sDefaultDirectionalLights[2].Load();
|
||||
UpdateLightBlock();
|
||||
|
||||
sVertexBlock.COLOR0_Amb = CColor::skGray.ToVector4f();
|
||||
UpdateVertexBlock();
|
||||
}
|
||||
|
||||
void CGraphics::SetIdentityMVP()
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#include "CLightParameters.h"
|
||||
|
||||
CLightParameters::CLightParameters(CPropertyStruct *pStruct, EGame game)
|
||||
: mpStruct(pStruct), mGame(game)
|
||||
{
|
||||
}
|
||||
|
||||
CLightParameters::~CLightParameters()
|
||||
{
|
||||
}
|
||||
|
||||
int CLightParameters::LightLayerIndex()
|
||||
{
|
||||
if (!mpStruct) return 0;
|
||||
|
||||
CLongProperty *pParam;
|
||||
|
||||
if (mGame <= ePrime)
|
||||
pParam = (CLongProperty*) mpStruct->PropertyByIndex(0xD);
|
||||
else
|
||||
pParam = (CLongProperty*) mpStruct->PropertyByID(0x1F715FD3);
|
||||
|
||||
if (!pParam) return 0;
|
||||
else return pParam->Get();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef CLIGHTPARAMETERS_H
|
||||
#define CLIGHTPARAMETERS_H
|
||||
|
||||
#include <Resource/CGameArea.h>
|
||||
#include <Resource/script/CProperty.h>
|
||||
|
||||
class CLightParameters
|
||||
{
|
||||
CPropertyStruct *mpStruct;
|
||||
EGame mGame;
|
||||
|
||||
public:
|
||||
CLightParameters(CPropertyStruct *pStruct, EGame game);
|
||||
~CLightParameters();
|
||||
int LightLayerIndex();
|
||||
};
|
||||
|
||||
#endif // CLIGHTPARAMETERS_H
|
|
@ -152,7 +152,8 @@ SOURCES += \
|
|||
Resource/CAnimationParameters.cpp \
|
||||
UI/WAnimParamsEditor.cpp \
|
||||
Resource/CCollisionMeshGroup.cpp \
|
||||
Core/CFrustumPlanes.cpp
|
||||
Core/CFrustumPlanes.cpp \
|
||||
Core/CLightParameters.cpp
|
||||
|
||||
HEADERS += \
|
||||
Common/AnimUtil.h \
|
||||
|
@ -320,7 +321,8 @@ HEADERS += \
|
|||
Resource/CAnimationParameters.h \
|
||||
UI/WAnimParamsEditor.h \
|
||||
Resource/CCollisionMeshGroup.h \
|
||||
Core/CFrustumPlanes.h
|
||||
Core/CFrustumPlanes.h \
|
||||
Core/CLightParameters.h
|
||||
|
||||
FORMS += \
|
||||
UI/CWorldEditorWindow.ui \
|
||||
|
|
|
@ -88,6 +88,11 @@ ELightType CLight::GetType() const
|
|||
return mType;
|
||||
}
|
||||
|
||||
u32 CLight::GetLayerIndex() const
|
||||
{
|
||||
return mLayerIndex;
|
||||
}
|
||||
|
||||
CVector3f CLight::GetPosition() const
|
||||
{
|
||||
return mPosition;
|
||||
|
@ -136,6 +141,11 @@ float CLight::GetIntensity()
|
|||
}
|
||||
|
||||
// ************ SETTERS ************
|
||||
void CLight::SetLayer(u32 index)
|
||||
{
|
||||
mLayerIndex = index;
|
||||
}
|
||||
|
||||
void CLight::SetPosition(const CVector3f& Position)
|
||||
{
|
||||
mPosition = Position;
|
||||
|
|
|
@ -23,12 +23,14 @@ enum ELightType
|
|||
class CLight
|
||||
{
|
||||
ELightType mType;
|
||||
u32 mLayerIndex;
|
||||
CVector3f mPosition;
|
||||
CVector3f mDirection;
|
||||
CColor mColor;
|
||||
float mSpotCutoff;
|
||||
CVector3f mDistAttenCoefficients;
|
||||
CVector3f mAngleAttenCoefficients;
|
||||
|
||||
float mRadius;
|
||||
float mIntensity;
|
||||
u8 mFlags;
|
||||
|
@ -45,6 +47,7 @@ private:
|
|||
public:
|
||||
// Getters
|
||||
ELightType GetType() const;
|
||||
u32 GetLayerIndex() const;
|
||||
CVector3f GetPosition() const;
|
||||
CVector3f GetDirection() const;
|
||||
CColor GetColor() const;
|
||||
|
@ -54,6 +57,7 @@ public:
|
|||
float GetIntensity();
|
||||
|
||||
// Setters
|
||||
void SetLayer(u32 index);
|
||||
void SetPosition(const CVector3f& Position);
|
||||
void SetDirection(const CVector3f& Direction);
|
||||
void SetColor(const CColor& Color);
|
||||
|
|
|
@ -198,6 +198,7 @@ void CAreaLoader::ReadLightsPrime()
|
|||
1.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
Light->SetLayer(ly);
|
||||
mpArea->mLightLayers[ly][l] = Light;
|
||||
}
|
||||
}
|
||||
|
@ -336,7 +337,87 @@ void CAreaLoader::ReadGeometryCorruption()
|
|||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// ************ RETURNS ************
|
||||
void CAreaLoader::ReadLightsCorruption()
|
||||
{
|
||||
Log::FileWrite(mpMREA->GetSourceString(), "Reading MREA dynamic lights (MP3)");
|
||||
mBlockMgr->ToBlock(mLightsBlockNum);
|
||||
|
||||
u32 babedead = mpMREA->ReadLong();
|
||||
if (babedead != 0xbabedead) return;
|
||||
|
||||
mpArea->mLightLayers.resize(4);
|
||||
|
||||
for (u32 iLayer = 0; iLayer < 4; iLayer++)
|
||||
{
|
||||
u32 NumLights = mpMREA->ReadLong();
|
||||
mpArea->mLightLayers[iLayer].resize(NumLights);
|
||||
|
||||
for (u32 iLight = 0; iLight < NumLights; iLight++)
|
||||
{
|
||||
ELightType Type = (ELightType) mpMREA->ReadLong();
|
||||
|
||||
float r = mpMREA->ReadFloat();
|
||||
float g = mpMREA->ReadFloat();
|
||||
float b = mpMREA->ReadFloat();
|
||||
float a = mpMREA->ReadFloat();
|
||||
CColor LightColor(r, g, b, a);
|
||||
|
||||
CVector3f Position(*mpMREA);
|
||||
CVector3f Direction(*mpMREA);
|
||||
mpMREA->Seek(0xC, SEEK_CUR);
|
||||
|
||||
float Multiplier = mpMREA->ReadFloat();
|
||||
float SpotCutoff = mpMREA->ReadFloat();
|
||||
mpMREA->Seek(0x9, SEEK_CUR);
|
||||
u32 FalloffType = mpMREA->ReadLong();
|
||||
mpMREA->Seek(0x18, SEEK_CUR);
|
||||
|
||||
// Relevant data is read - now we process and form a CLight out of it
|
||||
CLight *Light;
|
||||
|
||||
if (Multiplier < FLT_EPSILON)
|
||||
Multiplier = FLT_EPSILON;
|
||||
|
||||
// Local Ambient
|
||||
if (Type == eLocalAmbient)
|
||||
{
|
||||
Light = CLight::BuildLocalAmbient(Position, LightColor * Multiplier);
|
||||
}
|
||||
|
||||
// Directional
|
||||
else if (Type == eDirectional)
|
||||
{
|
||||
Light = CLight::BuildDirectional(Position, Direction, LightColor);
|
||||
}
|
||||
|
||||
// Spot
|
||||
else if (Type == eSpot)
|
||||
{
|
||||
Light = CLight::BuildSpot(Position, Direction.Normalized(), LightColor, SpotCutoff);
|
||||
|
||||
float DistAttenA = (FalloffType == 0) ? (2.f / Multiplier) : 0.f;
|
||||
float DistAttenB = (FalloffType == 1) ? (250.f / Multiplier) : 0.f;
|
||||
float DistAttenC = (FalloffType == 2) ? (25000.f / Multiplier) : 0.f;
|
||||
Light->SetDistAtten(DistAttenA, DistAttenB, DistAttenC);
|
||||
}
|
||||
|
||||
// Custom
|
||||
else
|
||||
{
|
||||
float DistAttenA = (FalloffType == 0) ? (2.f / Multiplier) : 0.f;
|
||||
float DistAttenB = (FalloffType == 1) ? (249.9998f / Multiplier) : 0.f;
|
||||
float DistAttenC = (FalloffType == 2) ? (25000.f / Multiplier) : 0.f;
|
||||
|
||||
Light = CLight::BuildCustom(Position, Direction, LightColor,
|
||||
DistAttenA, DistAttenB, DistAttenC,
|
||||
1.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
Light->SetLayer(iLayer);
|
||||
mpArea->mLightLayers[iLayer][iLight] = Light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ************ COMMON ************
|
||||
void CAreaLoader::ReadCompressedBlocks()
|
||||
|
@ -508,6 +589,7 @@ CGameArea* CAreaLoader::LoadMREA(CInputStream& MREA)
|
|||
Loader.ReadGeometryCorruption();
|
||||
Loader.ReadSCLYEchoes();
|
||||
Loader.ReadCollision();
|
||||
if (Loader.mVersion == eCorruption) Loader.ReadLightsCorruption();
|
||||
break;
|
||||
default:
|
||||
Log::FileError(MREA.GetSourceString(), "Unsupported MREA version: " + StringUtil::ToHexString(version));
|
||||
|
|
|
@ -67,6 +67,7 @@ class CAreaLoader
|
|||
// Corruption
|
||||
void ReadHeaderCorruption();
|
||||
void ReadGeometryCorruption();
|
||||
void ReadLightsCorruption();
|
||||
|
||||
// Common
|
||||
void ReadCompressedBlocks();
|
||||
|
|
|
@ -45,7 +45,11 @@ void CLightNode::Draw(ERenderOptions)
|
|||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(1.f);
|
||||
CGraphics::sVertexBlock.COLOR0_Mat = CVector4f(1.f);
|
||||
CGraphics::UpdateVertexBlock();
|
||||
CDrawUtil::DrawShadedCube(mpLight->GetColor());
|
||||
|
||||
// Force alpha to 0 to prevent issues with bloom
|
||||
CColor cubeColor = mpLight->GetColor();
|
||||
cubeColor.a = 0;
|
||||
CDrawUtil::DrawShadedCube(cubeColor);
|
||||
|
||||
// Below commented-out code is for light radius visualization as a bounding box
|
||||
/*float r = mLight->GetRadius();
|
||||
|
|
|
@ -26,6 +26,9 @@ CSceneNode::CSceneNode(CSceneManager *pScene, CSceneNode *pParent)
|
|||
_mInheritsRotation = true;
|
||||
_mInheritsScale = true;
|
||||
|
||||
mLightLayerIndex = 0;
|
||||
mLightCount = 0;
|
||||
|
||||
mMouseHovering = false;
|
||||
mSelected = false;
|
||||
mVisible = true;
|
||||
|
@ -115,8 +118,10 @@ void CSceneNode::LoadModelMatrix()
|
|||
void CSceneNode::BuildLightList(CGameArea *pArea)
|
||||
{
|
||||
mLightCount = 0;
|
||||
mAmbientColor = CColor::skBlack;
|
||||
|
||||
u32 LayerCount = pArea->GetLightLayerCount();
|
||||
u32 index = mLightLayerIndex;
|
||||
if ((pArea->GetLightLayerCount() <= index) || (pArea->GetLightCount(index) == 0)) index = 0;
|
||||
|
||||
struct SLightEntry {
|
||||
CLight *pLight;
|
||||
|
@ -131,28 +136,27 @@ void CSceneNode::BuildLightList(CGameArea *pArea)
|
|||
};
|
||||
std::vector<SLightEntry> LightEntries;
|
||||
|
||||
for (u32 iLayer = 0; iLayer < LayerCount; iLayer++)
|
||||
// Default ambient color to white if there are no lights on the selected layer
|
||||
u32 numLights = pArea->GetLightCount(index);
|
||||
if (numLights == 0) mAmbientColor = CColor::skWhite;
|
||||
|
||||
for (u32 iLight = 0; iLight < numLights; iLight++)
|
||||
{
|
||||
u32 LightCount = pArea->GetLightCount(iLayer);
|
||||
CLight* pLight = pArea->GetLight(index, iLight);
|
||||
|
||||
for (u32 iLight = 0; iLight < LightCount; iLight++)
|
||||
// Ambient lights should only be present one per layer; need to check how the game deals with multiple ambients
|
||||
if (pLight->GetType() == eLocalAmbient)
|
||||
mAmbientColor = pLight->GetColor();
|
||||
|
||||
// Other lights will be used depending which are closest to the node
|
||||
else
|
||||
{
|
||||
CLight* pLight = pArea->GetLight(iLayer, iLight);
|
||||
bool IsInRange = AABox().IntersectsSphere(pLight->GetPosition(), pLight->GetRadius());
|
||||
|
||||
// Directional/Spot lights take priority over custom lights.
|
||||
if ((pLight->GetType() == eDirectional) || (pLight->GetType() == eSpot))
|
||||
LightEntries.push_back(SLightEntry(pLight, 0));
|
||||
|
||||
// Custom lights will be used depending which are closest to the node
|
||||
else if (pLight->GetType() == eCustom)
|
||||
if (IsInRange)
|
||||
{
|
||||
bool IsInRange = AABox().IntersectsSphere(pLight->GetPosition(), pLight->GetRadius());
|
||||
|
||||
if (IsInRange)
|
||||
{
|
||||
float Dist = mPosition.Distance(pLight->GetPosition());
|
||||
LightEntries.push_back(SLightEntry(pLight, Dist));
|
||||
}
|
||||
float Dist = mPosition.Distance(pLight->GetPosition());
|
||||
LightEntries.push_back(SLightEntry(pLight, Dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,13 +173,29 @@ void CSceneNode::LoadLights()
|
|||
{
|
||||
CGraphics::sNumLights = 0;
|
||||
|
||||
if (CGraphics::sLightMode == CGraphics::BasicLighting)
|
||||
CGraphics::SetDefaultLighting();
|
||||
switch (CGraphics::sLightMode)
|
||||
{
|
||||
case CGraphics::NoLighting:
|
||||
// No lighting: default ambient color, no dynamic lights
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
break;
|
||||
|
||||
case CGraphics::BasicLighting:
|
||||
// Basic lighting: default ambient color, default dynamic lights
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
break;
|
||||
|
||||
case CGraphics::WorldLighting:
|
||||
// World lighting: world ambient color, node dynamic lights
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = mAmbientColor.ToVector4f();
|
||||
|
||||
else if (CGraphics::sLightMode == CGraphics::WorldLighting)
|
||||
for (u32 iLight = 0; iLight < mLightCount; iLight++)
|
||||
mLights[iLight]->Load();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CGraphics::UpdateLightBlock();
|
||||
}
|
||||
|
||||
|
@ -340,6 +360,11 @@ CVector3f CSceneNode::CenterPoint()
|
|||
return AABox().Center();
|
||||
}
|
||||
|
||||
u32 CSceneNode::LightLayerIndex() const
|
||||
{
|
||||
return mLightLayerIndex;
|
||||
}
|
||||
|
||||
bool CSceneNode::MarkedVisible() const
|
||||
{
|
||||
// The reason I have this function is because the instance view needs to know whether a node is marked
|
||||
|
@ -403,6 +428,11 @@ void CSceneNode::SetScale(const CVector3f& scale)
|
|||
MarkTransformChanged();
|
||||
}
|
||||
|
||||
void CSceneNode::SetLightLayerIndex(u32 index)
|
||||
{
|
||||
mLightLayerIndex = index;
|
||||
}
|
||||
|
||||
void CSceneNode::SetMouseHovering(bool Hovering)
|
||||
{
|
||||
mMouseHovering = Hovering;
|
||||
|
|
|
@ -44,8 +44,10 @@ protected:
|
|||
bool mVisible;
|
||||
std::list<CSceneNode*> mChildren;
|
||||
|
||||
u32 mLightLayerIndex;
|
||||
u32 mLightCount;
|
||||
CLight* mLights[8];
|
||||
CColor mAmbientColor;
|
||||
|
||||
public:
|
||||
explicit CSceneNode(CSceneManager *pScene, CSceneNode *pParent = 0);
|
||||
|
@ -89,6 +91,7 @@ public:
|
|||
CVector3f AbsoluteScale() const;
|
||||
CAABox AABox();
|
||||
CVector3f CenterPoint();
|
||||
u32 LightLayerIndex() const;
|
||||
bool MarkedVisible() const;
|
||||
bool IsMouseHovering() const;
|
||||
bool IsSelected() const;
|
||||
|
@ -102,6 +105,7 @@ public:
|
|||
void SetRotation(const CQuaternion& rotation);
|
||||
void SetRotation(const CVector3f& rotEuler);
|
||||
void SetScale(const CVector3f& scale);
|
||||
void SetLightLayerIndex(u32 index);
|
||||
void SetMouseHovering(bool Hovering);
|
||||
void SetSelected(bool Selected);
|
||||
void SetVisible(bool Visible);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <Core/CRenderer.h>
|
||||
#include <Core/CResCache.h>
|
||||
#include <Core/CSceneManager.h>
|
||||
#include <Resource/script/CMasterTemplate.h>
|
||||
|
||||
CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObject *pObject)
|
||||
: CSceneNode(pScene, pParent)
|
||||
|
@ -68,6 +69,10 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
|
|||
mpVolumePreviewNode->ForceAlphaEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch LightParameters
|
||||
mpLightParameters = new CLightParameters(mpInstance->LightParameters(), mpInstance->MasterTemplate()->GetGame());
|
||||
SetLightLayerIndex(mpLightParameters->LightLayerIndex());
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -155,11 +160,6 @@ void CScriptNode::Draw(ERenderOptions Options)
|
|||
LoadModelMatrix();
|
||||
LoadLights();
|
||||
|
||||
if (CGraphics::sLightMode == CGraphics::WorldLighting)
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::sAreaAmbientColor.ToVector4f() * CGraphics::sWorldLightMultiplier;
|
||||
else
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
|
||||
// Default to drawing purple box if no model
|
||||
if (!mpActiveModel)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "CSceneNode.h"
|
||||
#include "CModelNode.h"
|
||||
#include "CCollisionNode.h"
|
||||
#include <Core/CLightParameters.h>
|
||||
#include <Resource/script/CScriptObject.h>
|
||||
|
||||
class CScriptNode : public CSceneNode
|
||||
|
@ -17,6 +18,8 @@ class CScriptNode : public CSceneNode
|
|||
bool mHasVolumePreview;
|
||||
CModelNode *mpVolumePreviewNode;
|
||||
|
||||
CLightParameters *mpLightParameters;
|
||||
|
||||
public:
|
||||
CScriptNode(CSceneManager *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0);
|
||||
ENodeType NodeType();
|
||||
|
|
|
@ -46,7 +46,7 @@ void CStaticNode::Draw(ERenderOptions Options)
|
|||
{
|
||||
if (!mpModel) return;
|
||||
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(0, 0, 0, 1);
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(0, 0, 0, 1);
|
||||
float Multiplier = CGraphics::sWorldLightMultiplier;
|
||||
CGraphics::sPixelBlock.TevColor = CVector4f(Multiplier,Multiplier,Multiplier,1);
|
||||
CGraphics::sNumLights = 0;
|
||||
|
|
Loading…
Reference in New Issue