PrimeWorldEditor/src/Core/Scene/CModelNode.cpp

175 lines
5.1 KiB
C++

#include "CModelNode.h"
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CRenderer.h"
#include "Core/Render/CGraphics.h"
#include <Common/Math/MathUtil.h>
CModelNode::CModelNode(CScene *pScene, uint32 NodeID, CSceneNode *pParent, CModel *pModel)
: CSceneNode(pScene, NodeID, pParent)
, mWorldModel(false)
, mForceAlphaOn(false)
, mEnableScanOverlay(false)
, mTintColor(CColor::skWhite)
{
mScale = CVector3f::skOne;
SetModel(pModel);
}
ENodeType CModelNode::NodeType()
{
return ENodeType::Model;
}
void CModelNode::PostLoad()
{
if (mpModel)
{
mpModel->BufferGL();
mpModel->GenerateMaterialShaders();
}
}
void CModelNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo)
{
if (!mpModel) return;
if (!rkViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
if (rkViewInfo.GameMode) return;
// Transparent world models should have each surface processed separately
if (mWorldModel && mpModel->HasTransparency(mActiveMatSet))
{
pRenderer->AddMesh(this, -1, AABox(), false, ERenderCommand::DrawOpaqueParts);
for (uint32 iSurf = 0; iSurf < mpModel->GetSurfaceCount(); iSurf++)
{
if (mpModel->IsSurfaceTransparent(iSurf, mActiveMatSet))
pRenderer->AddMesh(this, iSurf, mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()), true, ERenderCommand::DrawTransparentParts);
}
}
// Other models should just draw all transparent surfaces sequentially
else
AddModelToRenderer(pRenderer, mpModel, mActiveMatSet);
if (mSelected)
pRenderer->AddMesh(this, -1, AABox(), false, ERenderCommand::DrawSelection);
}
void CModelNode::Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo)
{
if (!mpModel) return;
if (mForceAlphaOn) Options = (FRenderOptions) (Options & ~ERenderOption::NoAlpha);
if (!mWorldModel)
{
CGraphics::SetDefaultLighting();
CGraphics::UpdateLightBlock();
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor;
CGraphics::sPixelBlock.LightmapMultiplier = 1.f;
CGraphics::sPixelBlock.SetAllTevColors(CColor::skWhite);
}
else
{
bool IsLightingEnabled = CGraphics::sLightMode == CGraphics::ELightingMode::World || rkViewInfo.GameMode;
if (IsLightingEnabled)
{
CGraphics::sNumLights = 0;
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skBlack;
CGraphics::sPixelBlock.LightmapMultiplier = 1.f;
CGraphics::UpdateLightBlock();
}
else
{
LoadLights(rkViewInfo);
if (CGraphics::sLightMode == CGraphics::ELightingMode::None)
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skWhite;
}
float Mul = CGraphics::sWorldLightMultiplier;
CGraphics::sPixelBlock.SetAllTevColors(CColor(Mul,Mul,Mul));
}
CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo);
LoadModelMatrix();
if (mpModel->IsSkinned())
CGraphics::LoadIdentityBoneTransforms();
if (ComponentIndex == -1)
DrawModelParts(mpModel, Options, mActiveMatSet, Command);
else
mpModel->DrawSurface(Options, ComponentIndex, mActiveMatSet);
if (mEnableScanOverlay)
{
CDrawUtil::UseColorShader(mScanOverlayColor);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ZERO);
Options |= ERenderOption::NoMaterialSetup;
DrawModelParts(mpModel, Options, 0, Command);
}
}
void CModelNode::DrawSelection()
{
if (!mpModel) return;
LoadModelMatrix();
mpModel->DrawWireframe(ERenderOption::None, WireframeColor());
}
void CModelNode::RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& /*rkViewInfo*/)
{
if (!mpModel) return;
const CRay& rkRay = rTester.Ray();
std::pair<bool,float> BoxResult = AABox().IntersectsRay(rkRay);
if (BoxResult.first)
rTester.AddNodeModel(this, mpModel);
}
SRayIntersection CModelNode::RayNodeIntersectTest(const CRay& rkRay, uint32 AssetID, const SViewInfo& rkViewInfo)
{
SRayIntersection Out;
Out.pNode = this;
Out.ComponentIndex = AssetID;
CRay TransformedRay = rkRay.Transformed(Transform().Inverse());
FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions();
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((Options & ERenderOption::EnableBackfaceCull) == 0));
if (Result.first)
{
Out.Hit = true;
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
CVector3f WorldHitPoint = Transform() * HitPoint;
Out.Distance = Math::Distance(rkRay.Origin(), WorldHitPoint);
}
else
Out.Hit = false;
return Out;
}
CColor CModelNode::TintColor(const SViewInfo& /*rkViewInfo*/) const
{
return mTintColor;
}
void CModelNode::SetModel(CModel *pModel)
{
mpModel = pModel;
mActiveMatSet = 0;
if (pModel)
{
SetName(pModel->Source());
mLocalAABox = mpModel->AABox();
}
MarkTransformChanged();
}