Added support for rendering billboards for script nodes instead of a model/box

This commit is contained in:
parax0 2015-11-24 08:43:26 -07:00
parent 4cd9220763
commit 1fedc8f616
13 changed files with 235 additions and 36 deletions

View File

@ -28,6 +28,8 @@ CToken CDrawUtil::mDoubleSidedSphereToken;
CShader *CDrawUtil::mpColorShader;
CShader *CDrawUtil::mpColorShaderLighting;
CShader *CDrawUtil::mpBillboardShader;
CShader *CDrawUtil::mpLightBillboardShader;
CShader *CDrawUtil::mpTextureShader;
CShader *CDrawUtil::mpCollisionShader;
CShader *CDrawUtil::mpTextShader;
@ -35,6 +37,10 @@ CShader *CDrawUtil::mpTextShader;
CTexture *CDrawUtil::mpCheckerTexture;
CToken CDrawUtil::mCheckerTextureToken;
CTexture *CDrawUtil::mpLightTextures[4];
CTexture *CDrawUtil::mpLightMasks[4];
CToken CDrawUtil::mLightTextureTokens[8];
bool CDrawUtil::mDrawUtilInitialized = false;
// ************ PUBLIC ************
@ -193,6 +199,79 @@ void CDrawUtil::DrawSphere(const CColor &kColor)
DrawSphere(false);
}
void CDrawUtil::DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale /*= CVector2f::skOne*/, const CColor& Tint /*= CColor::skWhite*/)
{
Init();
// Create translation-only model matrix
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Position).ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Set uniforms
mpBillboardShader->SetCurrent();
GLuint ScaleLoc = mpBillboardShader->GetUniformLocation("BillboardScale");
glUniform2f(ScaleLoc, Scale.x, Scale.y);
GLuint TintLoc = mpBillboardShader->GetUniformLocation("TintColor");
CVector4f Tint4f = Tint.ToVector4f();
glUniform4f(TintLoc, Tint4f.x, Tint4f.y, Tint4f.z, Tint4f.w);
pTexture->Bind(0);
// Set other properties
CMaterial::KillCachedMaterial();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// Draw
DrawSquare();
}
void CDrawUtil::DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale /*= CVector2f::skOne*/, const CColor& Tint /*= CColor::skWhite*/)
{
Init();
// Create translation-only model matrix
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Position).ToMatrix4f();
CGraphics::UpdateMVPBlock();
// Set uniforms
mpLightBillboardShader->SetCurrent();
GLuint ScaleLoc = mpLightBillboardShader->GetUniformLocation("BillboardScale");
glUniform2f(ScaleLoc, Scale.x, Scale.y);
GLuint ColorLoc = mpLightBillboardShader->GetUniformLocation("LightColor");
CVector4f Color4f = LightColor.ToVector4f();
glUniform4f(ColorLoc, Color4f.x, Color4f.y, Color4f.z, Color4f.w);
GLuint TintLoc = mpLightBillboardShader->GetUniformLocation("TintColor");
CVector4f Tint4f = Tint.ToVector4f();
glUniform4f(TintLoc, Tint4f.x, Tint4f.y, Tint4f.z, Tint4f.w);
CTexture *pTexA = GetLightTexture(Type);
CTexture *pTexB = GetLightMask(Type);
pTexA->Bind(0);
pTexB->Bind(1);
GLuint TextureLoc = mpLightBillboardShader->GetUniformLocation("Texture");
GLuint MaskLoc = mpLightBillboardShader->GetUniformLocation("LightMask");
glUniform1i(TextureLoc, 0);
glUniform1i(MaskLoc, 1);
// Set other properties
CMaterial::KillCachedMaterial();
glBlendFunc(GL_ONE, GL_ZERO);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
// Draw
DrawSquare();
}
void CDrawUtil::UseColorShader(const CColor& kColor)
{
Init();
@ -258,6 +337,18 @@ void CDrawUtil::LoadCheckerboardTexture(u32 GLTextureUnit)
mpCheckerTexture->Bind(GLTextureUnit);
}
CTexture* CDrawUtil::GetLightTexture(ELightType Type)
{
Init();
return mpLightTextures[Type];
}
CTexture* CDrawUtil::GetLightMask(ELightType Type)
{
Init();
return mpLightMasks[Type];
}
CModel* CDrawUtil::GetCubeModel()
{
Init();
@ -422,6 +513,8 @@ void CDrawUtil::InitShaders()
Log::Write("Creating shaders");
mpColorShader = CShader::FromResourceFile("ColorShader");
mpColorShaderLighting = CShader::FromResourceFile("ColorShaderLighting");
mpBillboardShader = CShader::FromResourceFile("BillboardShader");
mpLightBillboardShader = CShader::FromResourceFile("LightBillboardShader");
mpTextureShader = CShader::FromResourceFile("TextureShader");
mpCollisionShader = CShader::FromResourceFile("CollisionShader");
mpTextShader = CShader::FromResourceFile("TextShader");
@ -429,9 +522,25 @@ void CDrawUtil::InitShaders()
void CDrawUtil::InitTextures()
{
Log::Write("Loading checkerboard texture");
Log::Write("Loading textures");
mpCheckerTexture = (CTexture*) gResCache.GetResource("../resources/Checkerboard.txtr");
mCheckerTextureToken = CToken(mpCheckerTexture);
mpLightTextures[0] = (CTexture*) gResCache.GetResource("../resources/LightAmbient.txtr");
mpLightTextures[1] = (CTexture*) gResCache.GetResource("../resources/LightDirectional.txtr");
mpLightTextures[2] = (CTexture*) gResCache.GetResource("../resources/LightCustom.txtr");
mpLightTextures[3] = (CTexture*) gResCache.GetResource("../resources/LightSpot.txtr");
mpLightMasks[0] = (CTexture*) gResCache.GetResource("../resources/LightAmbientMask.txtr");
mpLightMasks[1] = (CTexture*) gResCache.GetResource("../resources/LightDirectionalMask.txtr");
mpLightMasks[2] = (CTexture*) gResCache.GetResource("../resources/LightCustomMask.txtr");
mpLightMasks[3] = (CTexture*) gResCache.GetResource("../resources/LightSpotMask.txtr");
for (int i = 0; i < 4; i++)
{
mLightTextureTokens[i] = CToken(mpLightTextures[i]);
mLightTextureTokens[i+4] = CToken(mpLightMasks[i]);
}
}
void CDrawUtil::Shutdown()

View File

@ -5,6 +5,7 @@
#include <OpenGL/CDynamicVertexBuffer.h>
#include <OpenGL/CIndexBuffer.h>
#include <Resource/model/CModel.h>
#include <Resource/CLight.h>
class CDrawUtil
{
@ -37,6 +38,8 @@ class CDrawUtil
// Shaders
static CShader *mpColorShader;
static CShader *mpColorShaderLighting;
static CShader *mpBillboardShader;
static CShader *mpLightBillboardShader;
static CShader *mpTextureShader;
static CShader *mpCollisionShader;
static CShader *mpTextShader;
@ -45,33 +48,50 @@ class CDrawUtil
static CTexture *mpCheckerTexture;
static CToken mCheckerTextureToken;
static CTexture *mpLightTextures[4];
static CTexture *mpLightMasks[4];
static CToken mLightTextureTokens[8];
// Have all the above members been initialized?
static bool mDrawUtilInitialized;
public:
static void DrawGrid();
static void DrawSquare();
static void DrawSquare(const CVector2f& TexUL, const CVector2f& TexUR, const CVector2f& TexBR, const CVector2f& TexBL);
static void DrawSquare(const float *pTexCoords);
static void DrawLine(const CVector3f& PointA, const CVector3f& PointB);
static void DrawLine(const CVector2f& PointA, const CVector2f& PointB);
static void DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor);
static void DrawLine(const CVector2f& PointA, const CVector2f& PointB, const CColor& LineColor);
static void DrawCube();
static void DrawCube(const CColor& Color);
static void DrawCube(const CVector3f& Position, const CColor& Color);
static void DrawShadedCube(const CColor& Color);
static void DrawWireCube();
static void DrawWireCube(const CAABox& AABox, const CColor& Color);
static void DrawSphere(bool DoubleSided = false);
static void DrawSphere(const CColor& Color);
static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
static void UseColorShader(const CColor& Color);
static void UseColorShaderLighting(const CColor& Color);
static void UseTextureShader();
static void UseTextureShader(const CColor& TintColor);
static void UseCollisionShader();
static CShader* GetTextShader();
static void LoadCheckerboardTexture(u32 GLTextureUnit);
static CTexture* GetLightTexture(ELightType Type);
static CTexture* GetLightMask(ELightType Type);
static CModel* GetCubeModel();
private:

View File

@ -269,6 +269,7 @@ void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp, const TString&
{
case CScriptTemplate::SEditorAsset::eModel: type = "model"; break;
case CScriptTemplate::SEditorAsset::eAnimParams: type = "animparams"; break;
case CScriptTemplate::SEditorAsset::eBillboard: type = "billboard"; break;
case CScriptTemplate::SEditorAsset::eCollision: type = "collision"; break;
}

View File

@ -352,6 +352,8 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(tinyxml2::XMLDocument *pDoc
asset.AssetType = CScriptTemplate::SEditorAsset::eAnimParams;
else if (strcmp(pAsset->Name(), "model") == 0)
asset.AssetType = CScriptTemplate::SEditorAsset::eModel;
else if (strcmp(pAsset->Name(), "billboard") == 0)
asset.AssetType = CScriptTemplate::SEditorAsset::eBillboard;
else if (strcmp(pAsset->Name(), "collision") == 0)
asset.AssetType = CScriptTemplate::SEditorAsset::eCollision;
else

View File

@ -10,6 +10,7 @@ CScriptObject::CScriptObject(CGameArea *pArea, CScriptLayer *pLayer, CScriptTemp
mpProperties = nullptr;
mpTemplate->AddObject(this);
mpDisplayModel = nullptr;
mpBillboard = nullptr;
mpCollision = nullptr;
}
@ -37,6 +38,7 @@ void CScriptObject::EvaluateProperties()
mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
mVolumeShape = mpTemplate->VolumeShape(this);
EvaluateDisplayModel();
EvaluateBillboard();
EvaluateCollisionModel();
}
@ -46,6 +48,12 @@ void CScriptObject::EvaluateDisplayModel()
mModelToken = CToken(mpDisplayModel);
}
void CScriptObject::EvaluateBillboard()
{
mpBillboard = mpTemplate->FindBillboardTexture(mpProperties);
mBillboardToken = CToken(mpBillboard);
}
void CScriptObject::EvaluateCollisionModel()
{
mpCollision = mpTemplate->FindCollision(mpProperties);
@ -198,6 +206,11 @@ CModel* CScriptObject::GetDisplayModel() const
return mpDisplayModel;
}
CTexture* CScriptObject::GetBillboard() const
{
return mpBillboard;
}
CCollisionMeshGroup* CScriptObject::GetCollision() const
{
return mpCollision;

View File

@ -32,8 +32,10 @@ class CScriptObject
CBoolProperty *mpActive;
CPropertyStruct *mpLightParameters;
CModel *mpDisplayModel;
CTexture *mpBillboard;
CCollisionMeshGroup *mpCollision;
CToken mModelToken;
CToken mBillboardToken;
CToken mCollisionToken;
EVolumeShape mVolumeShape;
@ -44,6 +46,7 @@ public:
void CopyFromTemplate(CScriptTemplate *pTemp, u32 propCount);
void EvaluateProperties();
void EvaluateDisplayModel();
void EvaluateBillboard();
void EvaluateCollisionModel();
CScriptTemplate* Template() const;
@ -73,6 +76,7 @@ public:
void SetActive(bool isActive);
CPropertyStruct* LightParameters() const;
CModel* GetDisplayModel() const;
CTexture* GetBillboard() const;
CCollisionMeshGroup* GetCollision() const;
EVolumeShape VolumeShape() const;
};

View File

@ -210,10 +210,12 @@ CPropertyStruct* CScriptTemplate::FindLightParameters(CPropertyStruct *pProperti
return TFetchProperty<CPropertyStruct*, eStructProperty>(pProperties, mLightParametersIDString);
}
// todo: merge these three functions, they have near-identical code
CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties)
{
for (auto it = mAssets.begin(); it != mAssets.end(); it++)
{
if ((it->AssetType != SEditorAsset::eModel) && (it->AssetType != SEditorAsset::eAnimParams)) continue;
CResource *pRes = nullptr;
// File
@ -249,10 +251,45 @@ CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties)
return nullptr;
}
CTexture* CScriptTemplate::FindBillboardTexture(CPropertyStruct *pProperties)
{
for (auto it = mAssets.begin(); it != mAssets.end(); it++)
{
if (it->AssetType != SEditorAsset::eBillboard) continue;
CResource *pRes = nullptr;
// File
if (it->AssetSource == SEditorAsset::eFile)
{
TString path = "../resources/" + it->AssetLocation;
pRes = gResCache.GetResource(path);
}
// Property
else
{
CPropertyBase *pProp = pProperties->PropertyByIDString(it->AssetLocation);
if (pProp->Type() == eFileProperty)
{
CFileProperty *pFile = static_cast<CFileProperty*>(pProp);
pRes = pFile->Get();
}
}
// Verify resource exists + is correct type
if (pRes && (pRes->Type() == eTexture))
return static_cast<CTexture*>(pRes);
}
return nullptr;
}
CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties)
{
for (auto it = mAssets.begin(); it != mAssets.end(); it++)
{
if (it->AssetType != SEditorAsset::eCollision) continue;
CResource *pRes = nullptr;
// File

View File

@ -48,7 +48,7 @@ private:
struct SEditorAsset
{
enum {
eModel, eAnimParams, eCollision
eModel, eAnimParams, eBillboard, eCollision
} AssetType;
enum {
@ -115,6 +115,7 @@ public:
CBoolProperty* FindActive(CPropertyStruct *pProperties);
CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties);
CModel* FindDisplayModel(CPropertyStruct *pProperties);
CTexture* FindBillboardTexture(CPropertyStruct *pProperties);
CCollisionMeshGroup* FindCollision(CPropertyStruct *pProperties);
bool HasPosition();

View File

@ -29,27 +29,11 @@ void CLightNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frust
if (!frustum.BoxInFrustum(AABox())) return;
pRenderer->AddOpaqueMesh(this, 0, CAABox(mPosition + 0.5f, mPosition - 0.5f), eDrawMesh);
if (IsSelected())
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
}
void CLightNode::Draw(ERenderOptions)
void CLightNode::Draw(ERenderOptions /*Options*/)
{
// Not using parameter 1 (ERenderOptions - Options)
glBlendFunc(GL_ONE, GL_ZERO);
glDepthMask(GL_TRUE);
LoadModelMatrix();
CGraphics::SetDefaultLighting();
CGraphics::UpdateLightBlock();
CGraphics::sVertexBlock.COLOR0_Amb = CVector4f(1.f);
CGraphics::sVertexBlock.COLOR0_Mat = CVector4f(1.f);
CGraphics::UpdateVertexBlock();
// Force alpha to 0 to prevent issues with bloom
CColor cubeColor = mpLight->GetColor();
cubeColor.a = 0;
CDrawUtil::DrawShadedCube(cubeColor);
CDrawUtil::DrawLightBillboard(mpLight->GetType(), mpLight->GetColor(), mPosition, mScale.xy() * CVector2f(0.75f), TintColor());
// Below commented-out code is for light radius visualization as a bounding box
/*float r = mLight->GetRadius();
@ -57,10 +41,8 @@ void CLightNode::Draw(ERenderOptions)
pRenderer->DrawBoundingBox(mLight->GetColor(), AABB);*/
}
void CLightNode::DrawAsset(ERenderOptions, u32)
void CLightNode::DrawAsset(ERenderOptions /*Options*/, u32 /*asset*/)
{
// Not using parameter 1 (ERenderOptions - Options)
// Not using parameter 2 (u32 - asset)
}
SRayIntersection CLightNode::RayNodeIntersectTest(const CRay& Ray, u32 /*AssetID*/, ERenderOptions options)

View File

@ -10,6 +10,7 @@
#include <algorithm>
u32 CSceneNode::smNumNodes = 0;
CColor CSceneNode::skSelectionTint((u8) 156, 133, 155, 255);
CSceneNode::CSceneNode(CSceneManager *pScene, CSceneNode *pParent)
{
@ -302,6 +303,12 @@ CSceneManager* CSceneNode::Scene()
return mpScene;
}
CColor CSceneNode::TintColor() const
{
// convenience; this is/will be a fairly common operation
return (IsSelected() ? skSelectionTint : CColor::skWhite);
}
CVector3f CSceneNode::LocalPosition() const
{
return mPosition;

View File

@ -83,6 +83,7 @@ public:
TString Name() const;
CSceneNode* Parent() const;
CSceneManager* Scene();
CColor TintColor() const;
CVector3f LocalPosition() const;
CVector3f AbsolutePosition() const;
CQuaternion LocalRotation() const;
@ -112,6 +113,7 @@ public:
// Static
static int NumNodes();
static CColor skSelectionTint;
};
// ************ INLINE FUNCTIONS ************

View File

@ -17,6 +17,7 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
// Evaluate instance
mpInstance = pObject;
mpActiveModel = nullptr;
mpBillboard = nullptr;
mpCollisionNode = new CCollisionNode(pScene, this);
mpCollisionNode->SetInheritance(true, true, false);
@ -38,6 +39,9 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
mpActiveModel = mpInstance->GetDisplayModel();
mModelToken = CToken(mpActiveModel);
mpBillboard = mpInstance->GetBillboard();
mBillboardToken = CToken(mpBillboard);
mpCollisionNode->SetCollision(mpInstance->GetCollision());
// Create preview volume node
@ -156,24 +160,33 @@ void CScriptNode::Draw(ERenderOptions Options)
{
if (!mpInstance) return;
// Set lighting
// Draw model
if (mpActiveModel)
{
LoadModelMatrix();
LoadLights();
mpActiveModel->Draw(Options, 0);
}
// Default to drawing purple box if no model
if (!mpActiveModel)
// Draw billboard
else if (mpBillboard)
{
CDrawUtil::DrawBillboard(mpBillboard, mPosition, mScale.xy() * CVector2f(0.75f), TintColor());
}
// If no model or billboard, default to drawing a purple box
else
{
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ZERO);
glDepthMask(GL_TRUE);
LoadModelMatrix();
LoadLights();
CGraphics::UpdateVertexBlock();
CGraphics::UpdateLightBlock();
CDrawUtil::DrawShadedCube(CColor::skTransparentPurple);
return;
}
mpActiveModel->Draw(Options, 0);
}
void CScriptNode::DrawAsset(ERenderOptions Options, u32 Asset)
@ -195,7 +208,13 @@ void CScriptNode::DrawAsset(ERenderOptions Options, u32 Asset)
void CScriptNode::DrawSelection()
{
glBlendFunc(GL_ONE, GL_ZERO);
// Only draw bounding box for models; billboards get a tint color
if (mpActiveModel || !mpBillboard)
{
LoadModelMatrix();
CDrawUtil::DrawWireCube(AABox(), CColor::skTransparentWhite);
}
if (mpInstance)
{

View File

@ -11,7 +11,9 @@ class CScriptNode : public CSceneNode
{
CScriptObject *mpInstance;
CModel *mpActiveModel;
CTexture *mpBillboard;
CToken mModelToken;
CToken mBillboardToken;
CCollisionNode *mpCollisionNode;
bool mHasValidPosition;