Initial commit of current work on Prime World Editor

This commit is contained in:
parax0
2015-07-26 17:39:49 -04:00
commit 66e8c2ebcb
305 changed files with 33469 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
#include "CBasicModel.h"
#include <iostream>
#include <list>
CBasicModel::CBasicModel() : CResource()
{
mVertexCount = 0;
mTriangleCount = 0;
mBuffered = false;
}
CBasicModel::~CBasicModel()
{
if (mHasOwnSurfaces)
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
delete mSurfaces[iSurf];
}
EResType CBasicModel::Type()
{
return eModel;
}
u32 CBasicModel::GetVertexCount()
{
return mVertexCount;
}
u32 CBasicModel::GetTriangleCount()
{
return mTriangleCount;
}
CAABox CBasicModel::AABox()
{
return mAABox;
}
bool CBasicModel::IsBuffered()
{
return mBuffered;
}
u32 CBasicModel::GetSurfaceCount()
{
return mSurfaces.size();
}
CAABox CBasicModel::GetSurfaceAABox(u32 Surface)
{
return mSurfaces[Surface]->AABox;
}
SSurface* CBasicModel::GetSurface(u32 Surface)
{
return mSurfaces[Surface];
}

View File

@@ -0,0 +1,37 @@
#ifndef CBASICMODEL_H
#define CBASICMODEL_H
#include "../CResource.h"
#include "SSurface.h"
#include <Common/CAABox.h>
#include <OpenGL/CVertexBuffer.h>
class CBasicModel : public CResource
{
protected:
CAABox mAABox;
u32 mVertexCount;
u32 mTriangleCount;
bool mBuffered;
bool mHasOwnMaterials;
bool mHasOwnSurfaces;
CVertexBuffer mVBO;
std::vector<SSurface*> mSurfaces;
public:
CBasicModel();
~CBasicModel();
EResType Type();
u32 GetVertexCount();
u32 GetTriangleCount();
CAABox AABox();
bool IsBuffered();
u32 GetSurfaceCount();
CAABox GetSurfaceAABox(u32 Surface);
SSurface* GetSurface(u32 Surface);
virtual void ClearGLBuffer() = 0;
};
#endif // CBASICMODEL_H

207
Resource/model/CModel.cpp Normal file
View File

@@ -0,0 +1,207 @@
#include "CModel.h"
#include <Core/CRenderer.h>
#include <OpenGL/GLCommon.h>
CModel::CModel() : CBasicModel()
{
mHasOwnMaterials = true;
mHasOwnSurfaces = true;
}
CModel::CModel(SModelData *pModelData) : CBasicModel()
{
SetData(pModelData);
mHasOwnMaterials = false;
mHasOwnSurfaces = true;
}
CModel::CModel(SModelData *data, CMaterialSet *pMatSet) : CBasicModel()
{
SetData(data);
mMaterialSets.resize(1);
mMaterialSets[0] = pMatSet;
mHasOwnMaterials = false;
mHasOwnSurfaces = true;
}
CModel::~CModel()
{
if (mHasOwnMaterials)
for (u32 m = 0; m < mMaterialSets.size(); m++)
delete mMaterialSets[m];
}
void CModel::SetData(SModelData *pModelData)
{
mAABox = pModelData->mAABox;
mSurfaces = pModelData->mSurfaces;
mVertexCount = 0;
mTriangleCount = 0;
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{
SSurface *pSurf = mSurfaces[iSurf];
mVertexCount += pSurf->VertexCount;
mTriangleCount += pSurf->TriangleCount;
}
}
void CModel::BufferGL()
{
mVBO.Clear();
mSubmeshIndexBuffers.clear();
mSubmeshIndexBuffers.resize(mSurfaces.size());
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{
SSurface *pSurf = mSurfaces[iSurf];
u16 VBOStartOffset = (u16) mVBO.Size();
mVBO.Reserve((u16) pSurf->VertexCount);
for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++)
{
SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim];
CIndexBuffer *pIBO = InternalGetIBO(iSurf, pPrim->Type);
pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
std::vector<u16> Indices(pPrim->Vertices.size());
for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++)
Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
// then add the indices to the IBO. We convert some primitives to strips to minimize draw calls.
switch (pPrim->Type) {
case eGX_Triangles:
pIBO->TrianglesToStrips(Indices.data(), Indices.size());
break;
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size());
break;
case eGX_Quads:
pIBO->QuadsToStrips(Indices.data(), Indices.size());
break;
default:
pIBO->AddIndices(Indices.data(), Indices.size());
pIBO->AddIndex(0xFFFF); // primitive restart
break;
}
}
}
mBuffered = true;
}
void CModel::ClearGLBuffer()
{
mVBO.Clear();
mSubmeshIndexBuffers.clear();
mBuffered = false;
}
void CModel::Draw(ERenderOptions Options, u32 MatSet)
{
if (!mBuffered) BufferGL();
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
DrawSurface(Options, iSurf, MatSet);
}
void CModel::DrawSurface(ERenderOptions Options, u32 Surface, u32 MatSet)
{
if (!mBuffered) BufferGL();
// Check that mat set index is valid
if (MatSet >= mMaterialSets.size())
MatSet = mMaterialSets.size() - 1;
// Bind material
SSurface *pSurf = mSurfaces[Surface];
CMaterial *pMat = mMaterialSets[MatSet]->materials[pSurf->MaterialID];
if ((Options & eNoMaterialSetup) == 0)
{
if ((!(Options & eEnableOccluders)) && (pMat->Options() & CMaterial::eOccluder))
return;
pMat->SetCurrent(Options);
}
// Draw IBOs
mVBO.Bind();
for (u32 iIBO = 0; iIBO < mSubmeshIndexBuffers[Surface].size(); iIBO++)
{
CIndexBuffer *pIBO = &mSubmeshIndexBuffers[Surface][iIBO];
pIBO->DrawElements();
}
mVBO.Unbind();
}
u32 CModel::GetMatSetCount()
{
return mMaterialSets.size();
}
u32 CModel::GetMatCount()
{
if (mMaterialSets.empty()) return 0;
else return mMaterialSets[0]->materials.size();
}
CMaterialSet* CModel::GetMatSet(u32 MatSet)
{
return mMaterialSets[MatSet];
}
CMaterial* CModel::GetMaterialByIndex(u32 MatSet, u32 Index)
{
if (MatSet >= mMaterialSets.size())
MatSet = mMaterialSets.size() - 1;
if (GetMatCount() == 0)
return nullptr;
return mMaterialSets[MatSet]->materials[Index];
}
CMaterial* CModel::GetMaterialBySurface(u32 MatSet, u32 Surface)
{
return GetMaterialByIndex(MatSet, mSurfaces[Surface]->MaterialID);
}
bool CModel::HasTransparency(u32 MatSet)
{
if (MatSet >= mMaterialSets.size())
MatSet = mMaterialSets.size() - 1;
for (u32 iMat = 0; iMat < mMaterialSets[MatSet]->materials.size(); iMat++)
if (mMaterialSets[MatSet]->materials[iMat]->Options() & CMaterial::eTransparent ) return true;
return false;
}
bool CModel::IsSurfaceTransparent(u32 Surface, u32 MatSet)
{
if (MatSet >= mMaterialSets.size())
MatSet = mMaterialSets.size() - 1;
u32 matID = mSurfaces[Surface]->MaterialID;
return (mMaterialSets[MatSet]->materials[matID]->Options() & CMaterial::eTransparent) != 0;
}
CIndexBuffer* CModel::InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive)
{
std::vector<CIndexBuffer> *pIBOs = &mSubmeshIndexBuffers[Surface];
GLenum Type = GXPrimToGLPrim(Primitive);
for (u32 iIBO = 0; iIBO < pIBOs->size(); iIBO++)
{
if ((*pIBOs)[iIBO].GetPrimitiveType() == Type)
return &(*pIBOs)[iIBO];
}
pIBOs->emplace_back(CIndexBuffer(Type));
return &pIBOs->back();
}

46
Resource/model/CModel.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef CMODEL_H
#define CMODEL_H
#include "CBasicModel.h"
#include "SModelData.h"
#include "SSurface.h"
#include "../CMaterialSet.h"
#include <Core/ERenderOptions.h>
#include <OpenGL/CIndexBuffer.h>
#include <OpenGL/GLCommon.h>
class CModel : public CBasicModel
{
friend class CModelLoader;
friend class CModelCooker;
std::vector<CMaterialSet*> mMaterialSets;
std::vector<std::vector<CIndexBuffer>> mSubmeshIndexBuffers;
bool mHasOwnMaterials;
public:
CModel();
CModel(SModelData *pModelData);
CModel(SModelData *pModelData, CMaterialSet *pMatSet);
~CModel();
void SetData(SModelData *pModelData);
void BufferGL();
void ClearGLBuffer();
void Draw(ERenderOptions Options, u32 MatSet);
void DrawSurface(ERenderOptions Options, u32 Surface, u32 MatSet);
u32 GetMatSetCount();
u32 GetMatCount();
CMaterialSet* GetMatSet(u32 MatSet);
CMaterial* GetMaterialByIndex(u32 MatSet, u32 Index);
CMaterial* GetMaterialBySurface(u32 MatSet, u32 Surface);
bool HasTransparency(u32 MatSet);
bool IsSurfaceTransparent(u32 Surface, u32 MatSet);
private:
CIndexBuffer* InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive);
};
#endif // MODEL_H

View File

@@ -0,0 +1,177 @@
#include "CStaticModel.h"
#include <Core/CRenderer.h>
#include <OpenGL/GLCommon.h>
CStaticModel::CStaticModel() : CBasicModel()
{
mpMaterial = nullptr;
mTransparent = false;
mHasOwnSurfaces = false;
mHasOwnMaterials = false;
}
CStaticModel::CStaticModel(CMaterial *pMat) : CBasicModel()
{
mpMaterial = pMat;
mTransparent = ((pMat->Options() & CMaterial::eTransparent) != 0);
mHasOwnSurfaces = false;
mHasOwnMaterials = false;
}
CStaticModel::~CStaticModel()
{
}
void CStaticModel::AddSurface(SSurface *pSurface)
{
mSurfaces.push_back(pSurface);
mAABox.ExpandBounds(pSurface->AABox);
mVertexCount += pSurface->VertexCount;
mTriangleCount += pSurface->TriangleCount;
}
void CStaticModel::BufferGL()
{
mVBO.Clear();
mIBOs.clear();
for (u32 iSurf = 0; iSurf < mSurfaces.size(); iSurf++)
{
SSurface *pSurf = mSurfaces[iSurf];
u16 VBOStartOffset = (u16) mVBO.Size();
mVBO.Reserve((u16) pSurf->VertexCount);
for (u32 iPrim = 0; iPrim < pSurf->Primitives.size(); iPrim++)
{
SSurface::SPrimitive *pPrim = &pSurf->Primitives[iPrim];
CIndexBuffer *pIBO = InternalGetIBO(pPrim->Type);
pIBO->Reserve(pPrim->Vertices.size() + 1); // Allocate enough space for this primitive, plus the restart index
// Next step: add new vertices to the VBO and create a small index buffer for the current primitive
std::vector<u16> Indices(pPrim->Vertices.size());
for (u32 iVert = 0; iVert < pPrim->Vertices.size(); iVert++)
Indices[iVert] = mVBO.AddIfUnique(pPrim->Vertices[iVert], VBOStartOffset);
// then add the indices to the IBO. We convert some primitives to strips to minimize draw calls.
switch (pPrim->Type) {
case eGX_Triangles:
pIBO->TrianglesToStrips(Indices.data(), Indices.size());
break;
case eGX_TriangleFan:
pIBO->FansToStrips(Indices.data(), Indices.size());
break;
case eGX_Quads:
pIBO->QuadsToStrips(Indices.data(), Indices.size());
break;
default:
pIBO->AddIndices(Indices.data(), Indices.size());
pIBO->AddIndex(0xFFFF); // primitive restart
break;
}
}
// Make sure the number of submesh offset vectors matches the number of IBOs, then add the offsets
while (mIBOs.size() > mSubmeshEndOffsets.size())
mSubmeshEndOffsets.emplace_back(std::vector<u32>(mSurfaces.size()));
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
mSubmeshEndOffsets[iIBO][iSurf] = mIBOs[iIBO].GetSize();
}
mVBO.Buffer();
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
mIBOs[iIBO].Buffer();
mBuffered = true;
}
void CStaticModel::ClearGLBuffer()
{
mVBO.Clear();
mIBOs.clear();
mSubmeshEndOffsets.clear();
mBuffered = false;
}
void CStaticModel::Draw(ERenderOptions Options)
{
if (!mBuffered) BufferGL();
if ((Options & eNoMaterialSetup) == 0) mpMaterial->SetCurrent(Options);
// Draw IBOs
mVBO.Bind();
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
{
CIndexBuffer *pIBO = &mIBOs[iIBO];
pIBO->Bind();
glDrawElements(pIBO->GetPrimitiveType(), pIBO->GetSize(), GL_UNSIGNED_SHORT, (void*) 0);
pIBO->Unbind();
gDrawCount++;
}
mVBO.Unbind();
}
void CStaticModel::DrawSurface(ERenderOptions Options, u32 Surface)
{
if (!mBuffered) BufferGL();
mVBO.Bind();
if ((Options & eNoMaterialSetup) == 0) mpMaterial->SetCurrent(Options);
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
{
// Since there is a shared IBO for every mesh, we need two things to draw a single one: an offset and a size
u32 Offset = 0;
if (Surface > 0) Offset = mSubmeshEndOffsets[iIBO][Surface - 1];
u32 Size = mSubmeshEndOffsets[iIBO][Surface] - Offset;
if (!Size) continue; // The chosen submesh doesn't use this IBO
// Now we have both, so we can draw
mIBOs[iIBO].DrawElements(Offset, Size);
gDrawCount++;
}
mVBO.Unbind();
}
CMaterial* CStaticModel::GetMaterial()
{
return mpMaterial;
}
void CStaticModel::SetMaterial(CMaterial *pMat)
{
mpMaterial = pMat;
mTransparent = ((pMat->Options() & CMaterial::eTransparent) != 0);
}
bool CStaticModel::IsTransparent()
{
return mTransparent;
}
bool CStaticModel::IsOccluder()
{
return ((mpMaterial->Options() & CMaterial::eOccluder) != 0);
}
CIndexBuffer* CStaticModel::InternalGetIBO(EGXPrimitiveType Primitive)
{
GLenum type = GXPrimToGLPrim(Primitive);
for (u32 iIBO = 0; iIBO < mIBOs.size(); iIBO++)
{
if (mIBOs[iIBO].GetPrimitiveType() == type)
return &mIBOs[iIBO];
}
mIBOs.emplace_back(CIndexBuffer(type));
return &mIBOs.back();
}

View File

@@ -0,0 +1,39 @@
#ifndef CSTATICMODEL_H
#define CSTATICMODEL_H
#include "CBasicModel.h"
#include <Core/ERenderOptions.h>
#include <OpenGL/CIndexBuffer.h>
// A CStaticModel is meant for meshes that don't move. It's built specifically with terrain in mind.
// It only links to one material, and what it does best is combining submeshes from different models
// into shared VBOs and IBOs. This allows for a significantly reduced number of draw calls.
class CStaticModel : public CBasicModel
{
CMaterial *mpMaterial;
std::vector<CIndexBuffer> mIBOs;
std::vector<std::vector<u32>> mSubmeshEndOffsets;
bool mTransparent;
public:
CStaticModel();
CStaticModel(CMaterial *pMat);
~CStaticModel();
void AddSurface(SSurface *pSurface);
void BufferGL();
void ClearGLBuffer();
void Draw(ERenderOptions Options);
void DrawSurface(ERenderOptions Options, u32 Surface);
CMaterial* GetMaterial();
void SetMaterial(CMaterial *pMat);
bool IsTransparent();
bool IsOccluder();
private:
CIndexBuffer* InternalGetIBO(EGXPrimitiveType Primitive);
};
#endif // CSTATICMODEL_H

42
Resource/model/CVertex.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef CVERTEX_H
#define CVERTEX_H
#include <Common/CVector2f.h>
#include <Common/CVector3f.h>
#include <Common/CColor.h>
class CVertex
{
public:
u32 ArrayPosition; // Position of this vertex in the input model file.
// This is needed to resave without breaking rigging.
CVector3f Position;
CVector3f Normal;
CColor Color[2];
CVector2f Tex[8];
u8 MatrixIndices[8];
CVertex() {}
CVertex(CVector3f& Pos)
{
Position = Pos;
}
bool operator==(const CVertex& other) {
return ((Position == other.Position) &&
(Normal == other.Normal) &&
(Color[0] == other.Color[0]) &&
(Color[1] == other.Color[1]) &&
(Tex[0] == other.Tex[0]) &&
(Tex[1] == other.Tex[1]) &&
(Tex[2] == other.Tex[2]) &&
(Tex[3] == other.Tex[3]) &&
(Tex[4] == other.Tex[4]) &&
(Tex[5] == other.Tex[5]) &&
(Tex[6] == other.Tex[6]) &&
(Tex[7] == other.Tex[7]));
}
};
#endif // CVERTEX_H

View File

@@ -0,0 +1,33 @@
#ifndef EVERTEXDESCRIPTION
#define EVERTEXDESCRIPTION
#include <Common/EnumUtil.h>
enum EVertexDescription
{
eNoAttributes = 0x0,
ePosition = 0x3,
eNormal = 0xC,
eColor0 = 0x30,
eColor1 = 0xC0,
eTex0 = 0x300,
eTex1 = 0xC00,
eTex2 = 0x3000,
eTex3 = 0xC000,
eTex4 = 0x30000,
eTex5 = 0xC0000,
eTex6 = 0x300000,
eTex7 = 0xC00000,
ePosMtx = 0x1000000,
eTex0Mtx = 0x2000000,
eTex1Mtx = 0x4000000,
eTex2Mtx = 0x8000000,
eTex3Mtx = 0x10000000,
eTex4Mtx = 0x20000000,
eTex5Mtx = 0x40000000,
eTex6Mtx = 0x80000000
};
DEFINE_ENUM_FLAGS(EVertexDescription)
#endif // EVERTEXDESCRIPTION

View File

@@ -0,0 +1,13 @@
#ifndef SMODELDATA_H
#define SMODELDATA_H
#include "SSurface.h"
#include <Common/CAABox.h>
struct SModelData
{
CAABox mAABox;
std::vector<SSurface*> mSurfaces;
};
#endif // SMODELDATA_H

View File

@@ -0,0 +1,89 @@
#include "SSurface.h"
#include <Common/CRayCollisionTester.h>
#include <Common/Math.h>
#include <Core/CDrawUtil.h>
std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4f& Transform)
{
//CDrawUtil::DrawWireCube(AABox.Transformed(Transform), CColor::skRed);
bool Hit = false;
float HitDist;
for (u32 iPrim = 0; iPrim < Primitives.size(); iPrim++)
{
SPrimitive *pPrim = &Primitives[iPrim];
u32 NumVerts = pPrim->Vertices.size();
if ((pPrim->Type == eGX_Triangles) || (pPrim->Type == eGX_TriangleFan) || (pPrim->Type == eGX_TriangleStrip))
{
u32 NumTris;
if (pPrim->Type == eGX_Triangles)
NumTris = NumVerts / 3;
else
NumTris = NumVerts - 2;
CColor LineColor;
if (pPrim->Type == eGX_Triangles)
LineColor = CColor::skRed;
else if (pPrim->Type == eGX_TriangleStrip)
LineColor = CColor::skYellow;
else if (pPrim->Type == eGX_TriangleFan)
LineColor = CColor::skGreen;
for (u32 iTri = 0; iTri < NumTris; iTri++)
{
CVector3f vtxA, vtxB, vtxC;
// Get the three vertices that make up the current tri
if (pPrim->Type == eGX_Triangles)
{
u32 VertIndex = iTri * 3;
vtxA = pPrim->Vertices[VertIndex].Position;
vtxB = pPrim->Vertices[VertIndex+1].Position;
vtxC = pPrim->Vertices[VertIndex+2].Position;
}
else if (pPrim->Type == eGX_TriangleFan)
{
vtxA = pPrim->Vertices[0].Position;
vtxB = pPrim->Vertices[iTri+1].Position;
vtxC = pPrim->Vertices[iTri+2].Position;
}
else if (pPrim->Type = eGX_TriangleStrip)
{
if (iTri & 0x1)
{
vtxA = pPrim->Vertices[iTri+2].Position;
vtxB = pPrim->Vertices[iTri+1].Position;
vtxC = pPrim->Vertices[iTri].Position;
}
else
{
vtxA = pPrim->Vertices[iTri].Position;
vtxB = pPrim->Vertices[iTri+1].Position;
vtxC = pPrim->Vertices[iTri+2].Position;
}
}
// Intersection test
std::pair<bool,float> TriResult = Math::RayTriangleIntersection(Ray, vtxA, vtxB, vtxC);
if (TriResult.first)
{
if ((!Hit) || (TriResult.second < HitDist))
{
Hit = true;
HitDist = TriResult.second;
}
}
}
}
// todo: Intersection tests for line primitives
}
return std::pair<bool,float>(Hit, HitDist);
}

39
Resource/model/SSurface.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef SSURFACE_H
#define SSURFACE_H
#include "../CMaterialSet.h"
#include "CVertex.h"
#include <Common/types.h>
#include <Common/CAABox.h>
#include <Common/CRay.h>
#include <Common/CTransform4f.h>
#include <Common/CVector3f.h>
#include <Common/SRayIntersection.h>
#include <OpenGL/GLCommon.h>
#include <vector>
struct SSurface
{
u32 VertexCount;
u32 TriangleCount;
CAABox AABox;
CVector3f CenterPoint;
u32 MaterialID;
CVector3f ReflectionDirection;
struct SPrimitive
{
EGXPrimitiveType Type;
std::vector<CVertex> Vertices;
};
std::vector<SPrimitive> Primitives;
SSurface() {
VertexCount = 0;
TriangleCount = 0;
}
std::pair<bool,float> IntersectsRay(const CRay& Ray, const CTransform4f& Transform = CTransform4f::skIdentity);
};
#endif // SSURFACE_H