mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-20 10:25:40 +00:00
Reorganized collision data classes & added basic collision editor window with an OBB tree visualization
This commit is contained in:
@@ -19,8 +19,6 @@ CGameArea::~CGameArea()
|
||||
{
|
||||
ClearTerrain();
|
||||
|
||||
delete mpCollision;
|
||||
|
||||
for (uint32 iSCLY = 0; iSCLY < mScriptLayers.size(); iSCLY++)
|
||||
delete mScriptLayers[iSCLY];
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
#define CGAMEAREA_H
|
||||
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/CLight.h"
|
||||
#include "Core/Resource/CMaterialSet.h"
|
||||
#include "Core/Resource/CPoiToWorld.h"
|
||||
#include "Core/Resource/Collision/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/Model/CStaticModel.h"
|
||||
#include <Common/BasicTypes.h>
|
||||
@@ -51,7 +51,7 @@ class CGameArea : public CResource
|
||||
std::vector<CScriptLayer*> mScriptLayers;
|
||||
std::unordered_map<uint32, CScriptObject*> mObjectMap;
|
||||
// Collision
|
||||
CCollisionMeshGroup *mpCollision;
|
||||
std::unique_ptr<CCollisionMeshGroup> mpCollision;
|
||||
// Lights
|
||||
std::vector<std::vector<CLight*>> mLightLayers;
|
||||
// Path Mesh
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
inline uint32 NumStaticModels() const { return mStaticWorldModels.size(); }
|
||||
inline CModel* TerrainModel(uint32 iMdl) const { return mWorldModels[iMdl]; }
|
||||
inline CStaticModel* StaticModel(uint32 iMdl) const { return mStaticWorldModels[iMdl]; }
|
||||
inline CCollisionMeshGroup* Collision() const { return mpCollision; }
|
||||
inline CCollisionMeshGroup* Collision() const { return mpCollision.get(); }
|
||||
inline uint32 NumScriptLayers() const { return mScriptLayers.size(); }
|
||||
inline CScriptLayer* ScriptLayer(uint32 Index) const { return mScriptLayers[Index]; }
|
||||
inline uint32 NumLightLayers() const { return mLightLayers.size(); }
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
#include "CCollisionMesh.h"
|
||||
#include "Core/Render/CRenderer.h"
|
||||
#include "Core/Render/CDrawUtil.h"
|
||||
#include <Common/Macros.h>
|
||||
|
||||
CCollisionMesh::CCollisionMesh()
|
||||
{
|
||||
mVBO.SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal);
|
||||
mVertexCount = 0;
|
||||
mLineCount = 0;
|
||||
mFaceCount = 0;
|
||||
mBuffered = false;
|
||||
mIBO.SetPrimitiveType(GL_TRIANGLES);
|
||||
}
|
||||
|
||||
CCollisionMesh::~CCollisionMesh()
|
||||
{
|
||||
if (mBuffered)
|
||||
{
|
||||
mIBO.Clear();
|
||||
mVBO.Clear();
|
||||
mBuffered = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CCollisionMesh::BufferGL()
|
||||
{
|
||||
if (mBuffered)
|
||||
{
|
||||
mIBO.Clear();
|
||||
mVBO.Clear();
|
||||
mBuffered = false;
|
||||
}
|
||||
|
||||
// Create new list of collision faces sorted by material index
|
||||
std::vector<CCollisionFace> SortedTris = mCollisionFaces;
|
||||
std::sort(SortedTris.begin(), SortedTris.end(), [](CCollisionFace& rLeft, CCollisionFace& rRight) -> bool {
|
||||
return rLeft.MaterialIdx < rRight.MaterialIdx;
|
||||
});
|
||||
|
||||
// Add all the relevant indices to the IBO
|
||||
mVBO.Reserve(SortedTris.size() * 3);
|
||||
mIBO.Reserve(SortedTris.size() * 3);
|
||||
|
||||
mMaterialOffsets.reserve(mMaterials.size());
|
||||
uint32 CurMat = 0;
|
||||
|
||||
for (uint32 iTri = 0; iTri < SortedTris.size(); iTri++)
|
||||
{
|
||||
uint16 Verts[3];
|
||||
|
||||
CCollisionFace *pFace = &SortedTris[iTri];
|
||||
CCollisionLine *pLineA = GetLine(pFace->Lines[0]);
|
||||
CCollisionLine *pLineB = GetLine(pFace->Lines[1]);
|
||||
Verts[0] = pLineA->Vertices[0];
|
||||
Verts[1] = pLineA->Vertices[1];
|
||||
|
||||
// Check if we've reached a new material
|
||||
if (pFace->MaterialIdx != CurMat)
|
||||
{
|
||||
while (CurMat != pFace->MaterialIdx)
|
||||
{
|
||||
mMaterialOffsets.push_back(mIBO.GetSize());
|
||||
CurMat++;
|
||||
}
|
||||
}
|
||||
|
||||
// We have two vertex indices; the last one is one of the ones on line B, but we're not sure which one
|
||||
if ((pLineB->Vertices[0] != Verts[0]) &&
|
||||
(pLineB->Vertices[0] != Verts[1]))
|
||||
Verts[2] = pLineB->Vertices[0];
|
||||
else
|
||||
Verts[2] = pLineB->Vertices[1];
|
||||
|
||||
// Some faces have a property that indicates they need to be inverted
|
||||
if (GetMaterial(pFace->MaterialIdx) & eCF_FlippedTri)
|
||||
{
|
||||
uint16 V0 = Verts[0];
|
||||
Verts[0] = Verts[2];
|
||||
Verts[2] = V0;
|
||||
}
|
||||
|
||||
// Generate vertices - we don't share vertices between triangles in order to get the generated normals looking correct
|
||||
CCollisionVertex& rVert0 = mCollisionVertices[Verts[0]];
|
||||
CCollisionVertex& rVert1 = mCollisionVertices[Verts[1]];
|
||||
CCollisionVertex& rVert2 = mCollisionVertices[Verts[2]];
|
||||
|
||||
CVector3f V0toV1 = (rVert1.Pos - rVert0.Pos).Normalized();
|
||||
CVector3f V0toV2 = (rVert2.Pos - rVert0.Pos).Normalized();
|
||||
CVector3f FaceNormal = V0toV1.Cross(V0toV2).Normalized();
|
||||
|
||||
for (uint32 iVtx = 0; iVtx < 3; iVtx++)
|
||||
{
|
||||
CVertex Vtx;
|
||||
Vtx.Position = mCollisionVertices[ Verts[iVtx] ].Pos;
|
||||
Vtx.Normal = FaceNormal;
|
||||
uint16 Index = mVBO.AddVertex(Vtx);
|
||||
mIBO.AddIndex(Index);
|
||||
}
|
||||
}
|
||||
|
||||
while (CurMat != mMaterials.size())
|
||||
{
|
||||
mMaterialOffsets.push_back(mIBO.GetSize());
|
||||
CurMat++;
|
||||
}
|
||||
|
||||
ASSERT(mMaterialOffsets.size() == mMaterials.size());
|
||||
|
||||
// Buffer, and done
|
||||
mVBO.Buffer();
|
||||
mIBO.Buffer();
|
||||
mBuffered = true;
|
||||
}
|
||||
|
||||
void CCollisionMesh::Draw()
|
||||
{
|
||||
if (!mBuffered) BufferGL();
|
||||
|
||||
mVBO.Bind();
|
||||
mIBO.DrawElements();
|
||||
mVBO.Unbind();
|
||||
}
|
||||
|
||||
void CCollisionMesh::DrawMaterial(uint32 MatIdx, bool Wireframe)
|
||||
{
|
||||
if (!mBuffered) BufferGL();
|
||||
ASSERT(MatIdx < mMaterials.size());
|
||||
|
||||
mVBO.Bind();
|
||||
uint32 StartIdx = (MatIdx == 0 ? 0 : mMaterialOffsets[MatIdx - 1]);
|
||||
uint32 NumElements = mMaterialOffsets[MatIdx] - StartIdx;
|
||||
|
||||
if (Wireframe)
|
||||
{
|
||||
CDrawUtil::UseColorShader(CColor::skBlack);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
mIBO.DrawElements(StartIdx, NumElements);
|
||||
|
||||
if (Wireframe)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
mVBO.Unbind();
|
||||
}
|
||||
|
||||
void CCollisionMesh::DrawWireframe()
|
||||
{
|
||||
CDrawUtil::UseColorShader(CColor::skBlack);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
Draw();
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
CCollisionMesh::CCollisionVertex* CCollisionMesh::GetVertex(uint16 Index)
|
||||
{
|
||||
return &mCollisionVertices[Index];
|
||||
}
|
||||
|
||||
CCollisionMesh::CCollisionLine* CCollisionMesh::GetLine(uint16 Index)
|
||||
{
|
||||
return &mCollisionLines[Index];
|
||||
}
|
||||
|
||||
CCollisionMesh::CCollisionFace* CCollisionMesh::GetFace(uint16 Index)
|
||||
{
|
||||
return &mCollisionFaces[Index];
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#ifndef CCOLLISIONMESH_H
|
||||
#define CCOLLISIONMESH_H
|
||||
|
||||
#include "CCollisionMaterial.h"
|
||||
#include "CResource.h"
|
||||
#include "Core/OpenGL/CVertexBuffer.h"
|
||||
#include "Core/OpenGL/CIndexBuffer.h"
|
||||
#include <Common/Math/CAABox.h>
|
||||
|
||||
class CCollisionMesh
|
||||
{
|
||||
friend class CCollisionLoader;
|
||||
|
||||
class CCollisionOctree
|
||||
{
|
||||
friend class CCollisionLoader;
|
||||
struct SOctreeNode {};
|
||||
|
||||
struct SLeaf : public SOctreeNode
|
||||
{
|
||||
CAABox AABox;
|
||||
std::vector<uint16> FaceIndices;
|
||||
};
|
||||
|
||||
struct SBranch : public SOctreeNode
|
||||
{
|
||||
uint16 Flags;
|
||||
SOctreeNode *pChildren[8];
|
||||
};
|
||||
|
||||
SOctreeNode* mpRoot;
|
||||
};
|
||||
|
||||
class CCollisionVertex
|
||||
{
|
||||
public:
|
||||
uint32 MaterialIdx;
|
||||
CVector3f Pos;
|
||||
};
|
||||
|
||||
class CCollisionLine
|
||||
{
|
||||
public:
|
||||
uint32 MaterialIdx;
|
||||
uint16 Vertices[2];
|
||||
};
|
||||
|
||||
class CCollisionFace
|
||||
{
|
||||
public:
|
||||
uint32 MaterialIdx;
|
||||
uint16 Lines[3];
|
||||
};
|
||||
|
||||
CVertexBuffer mVBO;
|
||||
CIndexBuffer mIBO;
|
||||
uint32 mVertexCount;
|
||||
uint32 mLineCount;
|
||||
uint32 mFaceCount;
|
||||
bool mBuffered;
|
||||
|
||||
CAABox mAABox;
|
||||
CCollisionOctree *mpOctree;
|
||||
std::vector<CCollisionMaterial> mMaterials;
|
||||
std::vector<CCollisionVertex> mCollisionVertices;
|
||||
std::vector<CCollisionLine> mCollisionLines;
|
||||
std::vector<CCollisionFace> mCollisionFaces;
|
||||
std::vector<uint32> mMaterialOffsets;
|
||||
bool mOctreeLoaded;
|
||||
|
||||
CCollisionVertex *GetVertex(uint16 Index);
|
||||
CCollisionLine *GetLine(uint16 Index);
|
||||
CCollisionFace *GetFace(uint16 Index);
|
||||
|
||||
public:
|
||||
CCollisionMesh();
|
||||
~CCollisionMesh();
|
||||
|
||||
void BufferGL();
|
||||
void Draw();
|
||||
void DrawMaterial(uint32 MatIdx, bool Wireframe);
|
||||
void DrawWireframe();
|
||||
|
||||
inline uint32 NumMaterials() const { return mMaterials.size(); }
|
||||
inline CCollisionMaterial& GetMaterial(uint32 Index) { return mMaterials[Index]; }
|
||||
inline const CAABox& BoundingBox() const { return mAABox; }
|
||||
};
|
||||
|
||||
#endif // CCOLLISIONMESH_H
|
||||
30
src/Core/Resource/Collision/CCollidableOBBTree.h
Normal file
30
src/Core/Resource/Collision/CCollidableOBBTree.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef CCOLLIDABLEOBBTREE_H
|
||||
#define CCOLLIDABLEOBBTREE_H
|
||||
|
||||
#include "CCollisionMesh.h"
|
||||
#include "SOBBTreeNode.h"
|
||||
|
||||
/** A collision mesh with an OBB tree for spatial queries. Represents one mesh from a DCLN file */
|
||||
class CCollidableOBBTree : public CCollisionMesh
|
||||
{
|
||||
friend class CCollisionLoader;
|
||||
std::unique_ptr<SOBBTreeNode> mpOBBTree;
|
||||
|
||||
public:
|
||||
virtual void BuildRenderData() override
|
||||
{
|
||||
if (!mRenderData.IsBuilt())
|
||||
{
|
||||
mRenderData.BuildRenderData(mIndexData);
|
||||
mRenderData.BuildBoundingHierarchyRenderData(mpOBBTree.get());
|
||||
}
|
||||
}
|
||||
|
||||
/** Accessors */
|
||||
inline SOBBTreeNode* GetOBBTree() const
|
||||
{
|
||||
return mpOBBTree.get();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CCOLLIDABLEOBBTREE_H
|
||||
9
src/Core/Resource/Collision/CCollisionMesh.cpp
Normal file
9
src/Core/Resource/Collision/CCollisionMesh.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "CCollisionMesh.h"
|
||||
|
||||
void CCollisionMesh::BuildRenderData()
|
||||
{
|
||||
if (!mRenderData.IsBuilt())
|
||||
{
|
||||
mRenderData.BuildRenderData(mIndexData);
|
||||
}
|
||||
}
|
||||
44
src/Core/Resource/Collision/CCollisionMesh.h
Normal file
44
src/Core/Resource/Collision/CCollisionMesh.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef CCOLLISIONMESH_H
|
||||
#define CCOLLISIONMESH_H
|
||||
|
||||
#include "CCollisionMaterial.h"
|
||||
#include "CCollisionRenderData.h"
|
||||
#include "SCollisionIndexData.h"
|
||||
#include <Common/Math/CAABox.h>
|
||||
|
||||
/** Base class of collision geometry */
|
||||
class CCollisionMesh
|
||||
{
|
||||
friend class CCollisionLoader;
|
||||
|
||||
protected:
|
||||
CAABox mAABox;
|
||||
SCollisionIndexData mIndexData;
|
||||
CCollisionRenderData mRenderData;
|
||||
|
||||
public:
|
||||
virtual void BuildRenderData();
|
||||
|
||||
/** Accessors */
|
||||
inline CAABox Bounds() const
|
||||
{
|
||||
return mAABox;
|
||||
}
|
||||
|
||||
inline const SCollisionIndexData& GetIndexData() const
|
||||
{
|
||||
return mIndexData;
|
||||
}
|
||||
|
||||
inline const CCollisionRenderData& GetRenderData() const
|
||||
{
|
||||
return mRenderData;
|
||||
}
|
||||
|
||||
inline CCollisionRenderData& GetRenderData()
|
||||
{
|
||||
return mRenderData;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CCOLLISIONMESH_H
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef CCOLLISIONMESHGROUP_H
|
||||
#define CCOLLISIONMESHGROUP_H
|
||||
|
||||
#include "CResource.h"
|
||||
#include "CCollisionMesh.h"
|
||||
#include "TResPtr.h"
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
#include <Common/Math/CTransform4f.h>
|
||||
#include <vector>
|
||||
|
||||
class CCollisionMeshGroup : public CResource
|
||||
@@ -24,16 +25,22 @@ public:
|
||||
inline CCollisionMesh* MeshByIndex(uint32 Index) const { return mMeshes[Index]; }
|
||||
inline void AddMesh(CCollisionMesh *pMesh) { mMeshes.push_back(pMesh); }
|
||||
|
||||
inline void BuildRenderData()
|
||||
{
|
||||
for (auto It = mMeshes.begin(); It != mMeshes.end(); It++)
|
||||
(*It)->BuildRenderData();
|
||||
}
|
||||
|
||||
inline void Draw()
|
||||
{
|
||||
for (auto it = mMeshes.begin(); it != mMeshes.end(); it++)
|
||||
(*it)->Draw();
|
||||
(*it)->GetRenderData().Render(false);
|
||||
}
|
||||
|
||||
inline void DrawWireframe()
|
||||
{
|
||||
for (auto it = mMeshes.begin(); it != mMeshes.end(); it++)
|
||||
(*it)->DrawWireframe();
|
||||
(*it)->GetRenderData().Render(true);
|
||||
}
|
||||
};
|
||||
|
||||
261
src/Core/Resource/Collision/CCollisionRenderData.cpp
Normal file
261
src/Core/Resource/Collision/CCollisionRenderData.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
#include "CCollisionRenderData.h"
|
||||
#include <Core/Render/CDrawUtil.h>
|
||||
|
||||
/** Build from collision data */
|
||||
void CCollisionRenderData::BuildRenderData(const SCollisionIndexData& kIndexData)
|
||||
{
|
||||
// Clear any existing data
|
||||
if (mBuilt)
|
||||
{
|
||||
mVertexBuffer.Clear();
|
||||
mIndexBuffer.Clear();
|
||||
mWireframeIndexBuffer.Clear();
|
||||
mMaterialIndexOffsets.clear();
|
||||
mMaterialWireIndexOffsets.clear();
|
||||
mBuilt = false;
|
||||
}
|
||||
|
||||
mIndexBuffer.SetPrimitiveType(GL_TRIANGLES);
|
||||
mWireframeIndexBuffer.SetPrimitiveType(GL_LINES);
|
||||
|
||||
// Build list of triangle indices sorted by material index
|
||||
std::vector<uint16> SortedTris(kIndexData.TriangleMaterialIndices.size(), 0);
|
||||
|
||||
for (uint16 i=0; i<SortedTris.size(); i++)
|
||||
{
|
||||
SortedTris[i] = i;
|
||||
}
|
||||
|
||||
std::sort(SortedTris.begin(), SortedTris.end(), [kIndexData](uint16 Left, uint16 Right) -> bool {
|
||||
return kIndexData.TriangleMaterialIndices[Left] < kIndexData.TriangleMaterialIndices[Right];
|
||||
});
|
||||
|
||||
mVertexBuffer.Reserve(SortedTris.size() * 3);
|
||||
mIndexBuffer.Reserve(SortedTris.size() * 3);
|
||||
mWireframeIndexBuffer.Reserve(SortedTris.size() * 6);
|
||||
mMaterialIndexOffsets.reserve(kIndexData.Materials.size());
|
||||
uint8 CurrentMatIdx = 0xFF;
|
||||
|
||||
for (uint i=0; i < SortedTris.size(); i++)
|
||||
{
|
||||
uint TriIdx = SortedTris[i];
|
||||
uint8 MaterialIdx = kIndexData.TriangleMaterialIndices[TriIdx];
|
||||
const CCollisionMaterial& kMaterial = kIndexData.Materials[MaterialIdx];
|
||||
|
||||
if (MaterialIdx != CurrentMatIdx)
|
||||
{
|
||||
// Note some collision materials have no geometry associated with them as
|
||||
// some materials are exclusively used with edges/vertices.
|
||||
ASSERT( CurrentMatIdx < MaterialIdx || CurrentMatIdx == 0xFF );
|
||||
|
||||
while (CurrentMatIdx != MaterialIdx)
|
||||
{
|
||||
mMaterialIndexOffsets.push_back( mIndexBuffer.GetSize() );
|
||||
CurrentMatIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 LineA = kIndexData.TriangleIndices[ (TriIdx*3)+0 ];
|
||||
uint16 LineB = kIndexData.TriangleIndices[ (TriIdx*3)+1 ];
|
||||
uint16 LineAVertA = kIndexData.EdgeIndices[ (LineA*2)+0 ];
|
||||
uint16 LineAVertB = kIndexData.EdgeIndices[ (LineA*2)+1 ];
|
||||
uint16 LineBVertA = kIndexData.EdgeIndices[ (LineB*2)+0 ];
|
||||
uint16 LineBVertB = kIndexData.EdgeIndices[ (LineB*2)+1 ];
|
||||
uint16 VertIdx0 = LineAVertA;
|
||||
uint16 VertIdx1 = LineAVertB;
|
||||
uint16 VertIdx2 = (LineBVertA != LineAVertA && LineBVertA != LineAVertB ? LineBVertA : LineBVertB);
|
||||
|
||||
// Reverse vertex order if material indicates tri is flipped
|
||||
if (kMaterial & eCF_FlippedTri)
|
||||
{
|
||||
uint16 Tmp = VertIdx0;
|
||||
VertIdx0 = VertIdx2;
|
||||
VertIdx2 = Tmp;
|
||||
}
|
||||
|
||||
// Generate vertex data
|
||||
const CVector3f& kVert0 = kIndexData.Vertices[VertIdx0];
|
||||
const CVector3f& kVert1 = kIndexData.Vertices[VertIdx1];
|
||||
const CVector3f& kVert2 = kIndexData.Vertices[VertIdx2];
|
||||
CVector3f V0toV1 = (kVert1 - kVert0);
|
||||
CVector3f V0toV2 = (kVert2 - kVert0);
|
||||
CVector3f TriNormal = V0toV1.Cross(V0toV2).Normalized();
|
||||
uint16 Index0 = mVertexBuffer.Size();
|
||||
uint16 Index1 = Index0 + 1;
|
||||
uint16 Index2 = Index1 + 1;
|
||||
|
||||
CVertex Vtx;
|
||||
Vtx.Normal = TriNormal;
|
||||
|
||||
Vtx.Position = kVert0;
|
||||
mVertexBuffer.AddVertex(Vtx);
|
||||
Vtx.Position = kVert1;
|
||||
mVertexBuffer.AddVertex(Vtx);
|
||||
Vtx.Position = kVert2;
|
||||
mVertexBuffer.AddVertex(Vtx);
|
||||
|
||||
mIndexBuffer.AddIndex(Index0);
|
||||
mIndexBuffer.AddIndex(Index1);
|
||||
mIndexBuffer.AddIndex(Index2);
|
||||
|
||||
mWireframeIndexBuffer.AddIndex(Index0);
|
||||
mWireframeIndexBuffer.AddIndex(Index1);
|
||||
mWireframeIndexBuffer.AddIndex(Index1);
|
||||
mWireframeIndexBuffer.AddIndex(Index2);
|
||||
mWireframeIndexBuffer.AddIndex(Index2);
|
||||
mWireframeIndexBuffer.AddIndex(Index0);
|
||||
}
|
||||
|
||||
// Fill the rest of the material offsets, adding an extra index at the end
|
||||
for (; CurrentMatIdx <= kIndexData.Materials.size(); CurrentMatIdx++)
|
||||
{
|
||||
mMaterialIndexOffsets.push_back( mIndexBuffer.GetSize() );
|
||||
}
|
||||
|
||||
// Done
|
||||
mVertexBuffer.Buffer();
|
||||
mIndexBuffer.Buffer();
|
||||
mWireframeIndexBuffer.Buffer();
|
||||
mBuilt = true;
|
||||
}
|
||||
|
||||
void CCollisionRenderData::BuildBoundingHierarchyRenderData(const SOBBTreeNode* pOBBTree)
|
||||
{
|
||||
if (mBoundingHierarchyBuilt)
|
||||
{
|
||||
mBoundingVertexBuffer.Clear();
|
||||
mBoundingIndexBuffer.Clear();
|
||||
mBoundingDepthOffsets.clear();
|
||||
mBoundingHierarchyBuilt = false;
|
||||
}
|
||||
|
||||
mBoundingIndexBuffer.SetPrimitiveType(GL_LINES);
|
||||
|
||||
// Iterate through the OBB tree, building a list of nodes as we go.
|
||||
// We iterate through this using a breadth-first search in order to group together
|
||||
// OBBs in the same depth level in the index buffer. This allows us to render a
|
||||
// subset of the bounding hierarchy based on a max depth level.
|
||||
std::vector<const SOBBTreeNode*> TreeNodes;
|
||||
TreeNodes.push_back(pOBBTree);
|
||||
uint NodeIdx = 0;
|
||||
|
||||
while (NodeIdx < TreeNodes.size())
|
||||
{
|
||||
// Keep track of the current depth level and iterate through it
|
||||
mBoundingDepthOffsets.push_back(mBoundingIndexBuffer.GetSize());
|
||||
uint DepthLevel = TreeNodes.size();
|
||||
|
||||
mBoundingVertexBuffer.Reserve(8 * (DepthLevel - NodeIdx));
|
||||
mBoundingIndexBuffer.Reserve(24 * (DepthLevel - NodeIdx));
|
||||
|
||||
for (; NodeIdx < DepthLevel; NodeIdx++)
|
||||
{
|
||||
const SOBBTreeNode* pkNode = TreeNodes[NodeIdx];
|
||||
|
||||
// Append children
|
||||
if (pkNode->NodeType == EOBBTreeNodeType::Branch)
|
||||
{
|
||||
const SOBBTreeBranch* pkBranch = static_cast<const SOBBTreeBranch*>(pkNode);
|
||||
TreeNodes.push_back(pkBranch->pLeft.get());
|
||||
TreeNodes.push_back(pkBranch->pRight.get());
|
||||
}
|
||||
|
||||
// Create a new transform with the radii combined in as a scale matrie
|
||||
CTransform4f CombinedTransform =
|
||||
pkNode->Transform * CTransform4f::ScaleMatrix(pkNode->Radii);
|
||||
|
||||
// Transform a 1x1x1 unit cube using the transform...
|
||||
static const CVector3f skUnitCubeVertices[] = {
|
||||
CVector3f(-1, -1, -1),
|
||||
CVector3f(-1, -1, 1),
|
||||
CVector3f(-1, 1, -1),
|
||||
CVector3f(-1, 1, 1),
|
||||
CVector3f( 1, -1, -1),
|
||||
CVector3f( 1, -1, 1),
|
||||
CVector3f( 1, 1, -1),
|
||||
CVector3f( 1, 1, 1)
|
||||
};
|
||||
|
||||
for (uint i=0; i<8; i++)
|
||||
{
|
||||
CVector3f Transformed = CombinedTransform * skUnitCubeVertices[i];
|
||||
mBoundingVertexBuffer.AddVertex( CVertex(Transformed) );
|
||||
}
|
||||
|
||||
// Add corresponding indices
|
||||
static const uint16 skUnitCubeWireIndices[24] = {
|
||||
0, 1,
|
||||
1, 3,
|
||||
3, 2,
|
||||
2, 0,
|
||||
4, 5,
|
||||
5, 7,
|
||||
7, 6,
|
||||
6, 4,
|
||||
0, 4,
|
||||
1, 5,
|
||||
2, 6,
|
||||
3, 7
|
||||
};
|
||||
uint FirstIndex = mBoundingIndexBuffer.GetSize();
|
||||
for (uint i=0; i<24; i++)
|
||||
{
|
||||
mBoundingIndexBuffer.AddIndex(skUnitCubeWireIndices[i] + FirstIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add an extra index at the end...
|
||||
mBoundingDepthOffsets.push_back(mBoundingIndexBuffer.GetSize());
|
||||
|
||||
// Done
|
||||
mBoundingVertexBuffer.Buffer();
|
||||
mBoundingIndexBuffer.Buffer();
|
||||
mBoundingHierarchyBuilt = true;
|
||||
}
|
||||
|
||||
/** Render */
|
||||
void CCollisionRenderData::Render(bool Wireframe, int MaterialIndex /*= -1*/)
|
||||
{
|
||||
mVertexBuffer.Bind();
|
||||
|
||||
//@todo get these ugly OpenGL calls outta here
|
||||
if (Wireframe)
|
||||
{
|
||||
CDrawUtil::UseColorShader(CColor::skBlack);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
if (MaterialIndex >= 0)
|
||||
{
|
||||
ASSERT( MaterialIndex < mMaterialIndexOffsets.size()-1 );
|
||||
uint FirstIndex = mMaterialIndexOffsets[MaterialIndex];
|
||||
uint NumIndices = mMaterialIndexOffsets[MaterialIndex+1] - FirstIndex;
|
||||
mIndexBuffer.DrawElements(FirstIndex, NumIndices);
|
||||
}
|
||||
else
|
||||
{
|
||||
mIndexBuffer.DrawElements();
|
||||
}
|
||||
|
||||
if (Wireframe)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
mVertexBuffer.Unbind();
|
||||
}
|
||||
|
||||
void CCollisionRenderData::RenderBoundingHierarchy(int MaxDepthLevel /*= -1*/)
|
||||
{
|
||||
mBoundingVertexBuffer.Bind();
|
||||
CDrawUtil::UseColorShader(CColor::skBlue);
|
||||
glLineWidth(1.f);
|
||||
uint FirstIndex = mBoundingDepthOffsets[0];
|
||||
uint LastIndex = (MaxDepthLevel > 0 ?
|
||||
mBoundingDepthOffsets[MaxDepthLevel] :
|
||||
mBoundingIndexBuffer.GetSize());
|
||||
uint NumIndices = LastIndex - FirstIndex;
|
||||
mBoundingIndexBuffer.DrawElements(FirstIndex, NumIndices);
|
||||
mBoundingVertexBuffer.Unbind();
|
||||
}
|
||||
58
src/Core/Resource/Collision/CCollisionRenderData.h
Normal file
58
src/Core/Resource/Collision/CCollisionRenderData.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef CCOLLISIONRENDERDATA_H
|
||||
#define CCOLLISIONRENDERDATA_H
|
||||
|
||||
#include "SCollisionIndexData.h"
|
||||
#include "SOBBTreeNode.h"
|
||||
#include "Core/OpenGL/CVertexBuffer.h"
|
||||
#include "Core/OpenGL/CIndexBuffer.h"
|
||||
|
||||
class CCollidableOBBTree;
|
||||
|
||||
/** Data for rendering a collision model */
|
||||
class CCollisionRenderData
|
||||
{
|
||||
/** Vertex/index buffer for the collision geometry */
|
||||
CVertexBuffer mVertexBuffer;
|
||||
CIndexBuffer mIndexBuffer;
|
||||
CIndexBuffer mWireframeIndexBuffer;
|
||||
|
||||
/** Index buffer offset for the start of each collision material.
|
||||
* This has an extra index at the end, which is the end index for the last material. */
|
||||
std::vector<uint> mMaterialIndexOffsets;
|
||||
std::vector<uint> mMaterialWireIndexOffsets;
|
||||
|
||||
/** Cached vertex/index buffer for the bounding hierarchy (octree or OBB tree) */
|
||||
CVertexBuffer mBoundingVertexBuffer;
|
||||
CIndexBuffer mBoundingIndexBuffer;
|
||||
|
||||
/** Index buffer offset for different depth levels of the bounding hierarchy.
|
||||
* This allows you to i.e. render only the first (n) levels of the hierarchy. */
|
||||
std::vector<uint> mBoundingDepthOffsets;
|
||||
|
||||
/** Whether render data has been built */
|
||||
bool mBuilt;
|
||||
|
||||
/** Whether bounding hierarchy render data has been built */
|
||||
bool mBoundingHierarchyBuilt;
|
||||
|
||||
public:
|
||||
/** Default constructor */
|
||||
CCollisionRenderData()
|
||||
: mBuilt(false)
|
||||
, mBoundingHierarchyBuilt(false)
|
||||
{}
|
||||
|
||||
/** Build from collision data */
|
||||
void BuildRenderData(const SCollisionIndexData& kIndexData);
|
||||
void BuildBoundingHierarchyRenderData(const SOBBTreeNode* pOBBTree);
|
||||
|
||||
/** Render */
|
||||
void Render(bool Wireframe, int MaterialIndex = -1);
|
||||
void RenderBoundingHierarchy(int MaxDepthLevel = -1);
|
||||
|
||||
/** Accessors */
|
||||
inline bool IsBuilt() const { return mBuilt; }
|
||||
inline int MaxBoundingHierarchyDepth() const { return mBoundingHierarchyBuilt ? mBoundingDepthOffsets.size() - 1 : 0; }
|
||||
};
|
||||
|
||||
#endif // CCOLLISIONRENDERDATA_H
|
||||
20
src/Core/Resource/Collision/SCollisionIndexData.h
Normal file
20
src/Core/Resource/Collision/SCollisionIndexData.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef SCOLLISIONINDEXDATA_H
|
||||
#define SCOLLISIONINDEXDATA_H
|
||||
|
||||
#include "CCollisionMaterial.h"
|
||||
#include <Common/Math/CVector3f.h>
|
||||
|
||||
/** Common index data found in all collision file formats */
|
||||
struct SCollisionIndexData
|
||||
{
|
||||
std::vector<CCollisionMaterial> Materials;
|
||||
std::vector<uint8> VertexMaterialIndices;
|
||||
std::vector<uint8> EdgeMaterialIndices;
|
||||
std::vector<uint8> TriangleMaterialIndices;
|
||||
std::vector<uint16> EdgeIndices;
|
||||
std::vector<uint16> TriangleIndices;
|
||||
std::vector<uint16> UnknownData;
|
||||
std::vector<CVector3f> Vertices;
|
||||
};
|
||||
|
||||
#endif // SCOLLISIONINDEXDATA_H
|
||||
43
src/Core/Resource/Collision/SOBBTreeNode.h
Normal file
43
src/Core/Resource/Collision/SOBBTreeNode.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef SOBBTREENODE_H
|
||||
#define SOBBTREENODE_H
|
||||
|
||||
#include <Common/BasicTypes.h>
|
||||
#include <Common/Math/CTransform4f.h>
|
||||
#include <Common/Math/CVector3f.h>
|
||||
#include <memory>
|
||||
|
||||
enum class EOBBTreeNodeType : uint8
|
||||
{
|
||||
Branch = 0,
|
||||
Leaf = 1
|
||||
};
|
||||
|
||||
struct SOBBTreeNode
|
||||
{
|
||||
CTransform4f Transform;
|
||||
CVector3f Radii;
|
||||
EOBBTreeNodeType NodeType;
|
||||
};
|
||||
|
||||
struct SOBBTreeBranch : public SOBBTreeNode
|
||||
{
|
||||
std::unique_ptr<SOBBTreeNode> pLeft;
|
||||
std::unique_ptr<SOBBTreeNode> pRight;
|
||||
|
||||
SOBBTreeBranch() : SOBBTreeNode()
|
||||
{
|
||||
NodeType = EOBBTreeNodeType::Branch;
|
||||
}
|
||||
};
|
||||
|
||||
struct SOBBTreeLeaf : public SOBBTreeNode
|
||||
{
|
||||
std::vector<uint16> TriangleIndices;
|
||||
|
||||
SOBBTreeLeaf() : SOBBTreeNode()
|
||||
{
|
||||
NodeType = EOBBTreeNodeType::Leaf;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SOBBTREENODE_H
|
||||
@@ -620,7 +620,8 @@ void CAreaLoader::LoadSectionDataBuffers()
|
||||
void CAreaLoader::ReadCollision()
|
||||
{
|
||||
mpSectionMgr->ToSection(mCollisionBlockNum);
|
||||
mpArea->mpCollision = CCollisionLoader::LoadAreaCollision(*mpMREA);
|
||||
CCollisionMeshGroup* pAreaCollision = CCollisionLoader::LoadAreaCollision(*mpMREA);
|
||||
mpArea->mpCollision = std::unique_ptr<CCollisionMeshGroup>(pAreaCollision);
|
||||
}
|
||||
|
||||
void CAreaLoader::ReadPATH()
|
||||
|
||||
@@ -6,6 +6,7 @@ CCollisionLoader::CCollisionLoader()
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
CCollisionMesh::CCollisionOctree* CCollisionLoader::ParseOctree(IInputStream& /*rSrc*/)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -20,172 +21,180 @@ CCollisionMesh::CCollisionOctree::SLeaf* CCollisionLoader::ParseOctreeLeaf(IInpu
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CCollisionLoader::ParseOBBNode(IInputStream& rDCLN)
|
||||
SOBBTreeNode* CCollisionLoader::ParseOBBNode(IInputStream& DCLN)
|
||||
{
|
||||
bool b = false;
|
||||
SOBBTreeNode* pOut = nullptr;
|
||||
|
||||
while (b == false)
|
||||
CTransform4f Transform(DCLN);
|
||||
CVector3f Radius(DCLN);
|
||||
bool IsLeaf = DCLN.ReadBool();
|
||||
|
||||
if (IsLeaf)
|
||||
{
|
||||
rDCLN.Seek(0x3C, SEEK_CUR);
|
||||
b = (rDCLN.ReadByte() == 1);
|
||||
if (!b) ParseOBBNode(rDCLN);
|
||||
SOBBTreeLeaf* pLeaf = new SOBBTreeLeaf;
|
||||
uint NumTris = DCLN.ReadLong();
|
||||
pLeaf->TriangleIndices.resize(NumTris);
|
||||
|
||||
for (uint i=0; i<NumTris; i++)
|
||||
pLeaf->TriangleIndices[i] = DCLN.ReadShort();
|
||||
|
||||
pOut = pLeaf;
|
||||
}
|
||||
else
|
||||
{
|
||||
SOBBTreeBranch* pBranch = new SOBBTreeBranch;
|
||||
pBranch->pLeft = std::unique_ptr<SOBBTreeNode>( ParseOBBNode(DCLN) );
|
||||
pBranch->pRight = std::unique_ptr<SOBBTreeNode>( ParseOBBNode(DCLN) );
|
||||
pOut = pBranch;
|
||||
}
|
||||
|
||||
uint32 NumFaces = rDCLN.ReadLong();
|
||||
rDCLN.Seek(NumFaces * 2, SEEK_CUR);
|
||||
pOut->Transform = Transform;
|
||||
pOut->Radii = Radius;
|
||||
return pOut;
|
||||
}
|
||||
|
||||
void CCollisionLoader::ReadPropertyFlags(IInputStream& rSrc)
|
||||
void CCollisionLoader::LoadCollisionMaterial(IInputStream& Src, CCollisionMaterial& OutMaterial)
|
||||
{
|
||||
CCollisionMaterial Material;
|
||||
uint64 RawFlags = (mVersion <= EGame::Prime ? rSrc.ReadLong() : rSrc.ReadLongLong());
|
||||
Material.mRawFlags = RawFlags;
|
||||
uint64 RawFlags = (mVersion <= EGame::Prime ? Src.ReadLong() : Src.ReadLongLong());
|
||||
OutMaterial.mRawFlags = RawFlags;
|
||||
|
||||
if (mVersion <= EGame::Prime)
|
||||
{
|
||||
if (RawFlags & 0x00000001) Material |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) Material |= eCF_Stone;
|
||||
if (RawFlags & 0x00000004) Material |= eCF_Metal;
|
||||
if (RawFlags & 0x00000008) Material |= eCF_Grass;
|
||||
if (RawFlags & 0x00000010) Material |= eCF_Ice;
|
||||
if (RawFlags & 0x00000040) Material |= eCF_MetalGrating;
|
||||
if (RawFlags & 0x00000080) Material |= eCF_Phazon;
|
||||
if (RawFlags & 0x00000100) Material |= eCF_Dirt;
|
||||
if (RawFlags & 0x00000200) Material |= eCF_Lava;
|
||||
if (RawFlags & 0x00000800) Material |= eCF_Snow;
|
||||
if (RawFlags & 0x00001000) Material |= eCF_SlowMud;
|
||||
if (RawFlags & 0x00004000) Material |= eCF_Mud;
|
||||
if (RawFlags & 0x00008000) Material |= eCF_Glass;
|
||||
if (RawFlags & 0x00010000) Material |= eCF_Shield;
|
||||
if (RawFlags & 0x00020000) Material |= eCF_Sand;
|
||||
if (RawFlags & 0x00040000) Material |= eCF_ShootThru;
|
||||
if (RawFlags & 0x00200000) Material |= eCF_CameraThru;
|
||||
if (RawFlags & 0x00400000) Material |= eCF_Wood;
|
||||
if (RawFlags & 0x00800000) Material |= eCF_Organic;
|
||||
if (RawFlags & 0x02000000) Material |= eCF_FlippedTri;
|
||||
if (RawFlags & 0x08000000) Material |= eCF_ScanThru;
|
||||
if (RawFlags & 0x10000000) Material |= eCF_AiWalkThru;
|
||||
if (RawFlags & 0x20000000) Material |= eCF_Ceiling;
|
||||
if (RawFlags & 0x40000000) Material |= eCF_Wall;
|
||||
if (RawFlags & 0x80000000) Material |= eCF_Floor;
|
||||
if (RawFlags & 0x00000001) OutMaterial |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) OutMaterial |= eCF_Stone;
|
||||
if (RawFlags & 0x00000004) OutMaterial |= eCF_Metal;
|
||||
if (RawFlags & 0x00000008) OutMaterial |= eCF_Grass;
|
||||
if (RawFlags & 0x00000010) OutMaterial |= eCF_Ice;
|
||||
if (RawFlags & 0x00000040) OutMaterial |= eCF_MetalGrating;
|
||||
if (RawFlags & 0x00000080) OutMaterial |= eCF_Phazon;
|
||||
if (RawFlags & 0x00000100) OutMaterial |= eCF_Dirt;
|
||||
if (RawFlags & 0x00000200) OutMaterial |= eCF_Lava;
|
||||
if (RawFlags & 0x00000800) OutMaterial |= eCF_Snow;
|
||||
if (RawFlags & 0x00001000) OutMaterial |= eCF_SlowMud;
|
||||
if (RawFlags & 0x00004000) OutMaterial |= eCF_Mud;
|
||||
if (RawFlags & 0x00008000) OutMaterial |= eCF_Glass;
|
||||
if (RawFlags & 0x00010000) OutMaterial |= eCF_Shield;
|
||||
if (RawFlags & 0x00020000) OutMaterial |= eCF_Sand;
|
||||
if (RawFlags & 0x00040000) OutMaterial |= eCF_ShootThru;
|
||||
if (RawFlags & 0x00200000) OutMaterial |= eCF_CameraThru;
|
||||
if (RawFlags & 0x00400000) OutMaterial |= eCF_Wood;
|
||||
if (RawFlags & 0x00800000) OutMaterial |= eCF_Organic;
|
||||
if (RawFlags & 0x02000000) OutMaterial |= eCF_FlippedTri;
|
||||
if (RawFlags & 0x08000000) OutMaterial |= eCF_ScanThru;
|
||||
if (RawFlags & 0x10000000) OutMaterial |= eCF_AiWalkThru;
|
||||
if (RawFlags & 0x20000000) OutMaterial |= eCF_Ceiling;
|
||||
if (RawFlags & 0x40000000) OutMaterial |= eCF_Wall;
|
||||
if (RawFlags & 0x80000000) OutMaterial |= eCF_Floor;
|
||||
}
|
||||
|
||||
else if (mVersion <= EGame::Corruption)
|
||||
{
|
||||
if (RawFlags & 0x00000001) Material |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) Material |= eCF_Stone;
|
||||
if (RawFlags & 0x00000004) Material |= eCF_Metal;
|
||||
if (RawFlags & 0x00000008) Material |= eCF_Grass;
|
||||
if (RawFlags & 0x00000010) Material |= eCF_Ice;
|
||||
if (RawFlags & 0x00000040) Material |= eCF_MetalGrating;
|
||||
if (RawFlags & 0x00000080) Material |= eCF_Phazon;
|
||||
if (RawFlags & 0x00000100) Material |= eCF_Dirt;
|
||||
if (RawFlags & 0x00000200) Material |= eCF_AltMetal;
|
||||
if (RawFlags & 0x00000400) Material |= eCF_Glass;
|
||||
if (RawFlags & 0x00000800) Material |= eCF_Snow;
|
||||
if (RawFlags & 0x00001000) Material |= eCF_Fabric;
|
||||
if (RawFlags & 0x00010000) Material |= eCF_Shield;
|
||||
if (RawFlags & 0x00020000) Material |= eCF_Sand;
|
||||
if (RawFlags & 0x00040000) Material |= eCF_MothSeedOrganics;
|
||||
if (RawFlags & 0x00080000) Material |= eCF_Web;
|
||||
if (RawFlags & 0x00100000) Material |= eCF_ShootThru;
|
||||
if (RawFlags & 0x00200000) Material |= eCF_CameraThru;
|
||||
if (RawFlags & 0x00400000) Material |= eCF_Wood;
|
||||
if (RawFlags & 0x00800000) Material |= eCF_Organic;
|
||||
if (RawFlags & 0x01000000) Material |= eCF_FlippedTri;
|
||||
if (RawFlags & 0x02000000) Material |= eCF_Rubber;
|
||||
if (RawFlags & 0x08000000) Material |= eCF_ScanThru;
|
||||
if (RawFlags & 0x10000000) Material |= eCF_AiWalkThru;
|
||||
if (RawFlags & 0x20000000) Material |= eCF_Ceiling;
|
||||
if (RawFlags & 0x40000000) Material |= eCF_Wall;
|
||||
if (RawFlags & 0x80000000) Material |= eCF_Floor;
|
||||
if (RawFlags & 0x00000001) OutMaterial |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) OutMaterial |= eCF_Stone;
|
||||
if (RawFlags & 0x00000004) OutMaterial |= eCF_Metal;
|
||||
if (RawFlags & 0x00000008) OutMaterial |= eCF_Grass;
|
||||
if (RawFlags & 0x00000010) OutMaterial |= eCF_Ice;
|
||||
if (RawFlags & 0x00000040) OutMaterial |= eCF_MetalGrating;
|
||||
if (RawFlags & 0x00000080) OutMaterial |= eCF_Phazon;
|
||||
if (RawFlags & 0x00000100) OutMaterial |= eCF_Dirt;
|
||||
if (RawFlags & 0x00000200) OutMaterial |= eCF_AltMetal;
|
||||
if (RawFlags & 0x00000400) OutMaterial |= eCF_Glass;
|
||||
if (RawFlags & 0x00000800) OutMaterial |= eCF_Snow;
|
||||
if (RawFlags & 0x00001000) OutMaterial |= eCF_Fabric;
|
||||
if (RawFlags & 0x00010000) OutMaterial |= eCF_Shield;
|
||||
if (RawFlags & 0x00020000) OutMaterial |= eCF_Sand;
|
||||
if (RawFlags & 0x00040000) OutMaterial |= eCF_MothSeedOrganics;
|
||||
if (RawFlags & 0x00080000) OutMaterial |= eCF_Web;
|
||||
if (RawFlags & 0x00100000) OutMaterial |= eCF_ShootThru;
|
||||
if (RawFlags & 0x00200000) OutMaterial |= eCF_CameraThru;
|
||||
if (RawFlags & 0x00400000) OutMaterial |= eCF_Wood;
|
||||
if (RawFlags & 0x00800000) OutMaterial |= eCF_Organic;
|
||||
if (RawFlags & 0x01000000) OutMaterial |= eCF_FlippedTri;
|
||||
if (RawFlags & 0x02000000) OutMaterial |= eCF_Rubber;
|
||||
if (RawFlags & 0x08000000) OutMaterial |= eCF_ScanThru;
|
||||
if (RawFlags & 0x10000000) OutMaterial |= eCF_AiWalkThru;
|
||||
if (RawFlags & 0x20000000) OutMaterial |= eCF_Ceiling;
|
||||
if (RawFlags & 0x40000000) OutMaterial |= eCF_Wall;
|
||||
if (RawFlags & 0x80000000) OutMaterial |= eCF_Floor;
|
||||
|
||||
if (RawFlags & 0x0001000000000000) Material |= eCF_AiBlock;
|
||||
if (RawFlags & 0x0400000000000000) Material |= eCF_JumpNotAllowed;
|
||||
if (RawFlags & 0x0001000000000000) OutMaterial |= eCF_AiBlock;
|
||||
if (RawFlags & 0x0400000000000000) OutMaterial |= eCF_JumpNotAllowed;
|
||||
}
|
||||
|
||||
else if (mVersion == EGame::DKCReturns)
|
||||
{
|
||||
if (RawFlags & 0x10000000) Material |= eCF_FlippedTri;
|
||||
if (RawFlags & 0x10000000) OutMaterial |= eCF_FlippedTri;
|
||||
}
|
||||
|
||||
mpMesh->mMaterials.push_back(Material);
|
||||
}
|
||||
|
||||
void CCollisionLoader::LoadCollisionIndices(IInputStream &rFile, bool BuildAABox)
|
||||
void CCollisionLoader::LoadCollisionIndices(IInputStream& File, SCollisionIndexData& OutData)
|
||||
{
|
||||
// Properties
|
||||
uint32 PropSetCount = rFile.ReadLong();
|
||||
for (uint32 iProp = 0; iProp < PropSetCount; iProp++)
|
||||
ReadPropertyFlags(rFile);
|
||||
// Materials
|
||||
uint NumMaterials = File.ReadLong();
|
||||
OutData.Materials.resize( NumMaterials );
|
||||
|
||||
// Property indices for vertices/lines/faces
|
||||
uint32 VtxIndexCount = rFile.ReadLong();
|
||||
std::vector<uint8> VtxIndices(VtxIndexCount);
|
||||
rFile.ReadBytes(VtxIndices.data(), VtxIndices.size());
|
||||
|
||||
uint32 LineIndexCount = rFile.ReadLong();
|
||||
std::vector<uint8> LineIndices(LineIndexCount);
|
||||
rFile.ReadBytes(LineIndices.data(), LineIndices.size());
|
||||
|
||||
uint32 FaceIndexCount = rFile.ReadLong();
|
||||
std::vector<uint8> FaceIndices(FaceIndexCount);
|
||||
rFile.ReadBytes(FaceIndices.data(), FaceIndices.size());
|
||||
|
||||
// Lines
|
||||
mpMesh->mLineCount = rFile.ReadLong();
|
||||
mpMesh->mCollisionLines.resize(mpMesh->mLineCount);
|
||||
for (uint32 iLine = 0; iLine < mpMesh->mLineCount; iLine++)
|
||||
for (uint i=0; i<NumMaterials; i++)
|
||||
{
|
||||
CCollisionMesh::CCollisionLine *pLine = &mpMesh->mCollisionLines[iLine];
|
||||
pLine->Vertices[0] = rFile.ReadShort();
|
||||
pLine->Vertices[1] = rFile.ReadShort();
|
||||
pLine->MaterialIdx = LineIndices[iLine];
|
||||
LoadCollisionMaterial(File, OutData.Materials[i]);
|
||||
}
|
||||
|
||||
// Faces
|
||||
mpMesh->mFaceCount = rFile.ReadLong() / 3; // Not sure why they store it this way. It's inconsistent.
|
||||
mpMesh->mCollisionFaces.resize(mpMesh->mFaceCount);
|
||||
// Property indices for vertices/edges/triangles
|
||||
uint VertexMaterialCount = File.ReadLong();
|
||||
OutData.VertexMaterialIndices.resize(VertexMaterialCount);
|
||||
File.ReadBytes(OutData.VertexMaterialIndices.data(), VertexMaterialCount);
|
||||
|
||||
for (uint32 iFace = 0; iFace < mpMesh->mFaceCount; iFace++)
|
||||
uint32 EdgeMaterialCount = File.ReadLong();
|
||||
OutData.EdgeMaterialIndices.resize(EdgeMaterialCount);
|
||||
File.ReadBytes(OutData.EdgeMaterialIndices.data(), EdgeMaterialCount);
|
||||
|
||||
uint32 TriMaterialCount = File.ReadLong();
|
||||
OutData.TriangleMaterialIndices.resize(TriMaterialCount);
|
||||
File.ReadBytes(OutData.TriangleMaterialIndices.data(), TriMaterialCount);
|
||||
|
||||
// Edges
|
||||
uint NumEdges = File.ReadLong();
|
||||
OutData.EdgeIndices.resize( NumEdges * 2 );
|
||||
|
||||
for (uint i=0; i<OutData.EdgeIndices.size(); i++)
|
||||
{
|
||||
CCollisionMesh::CCollisionFace *pFace = &mpMesh->mCollisionFaces[iFace];
|
||||
pFace->Lines[0] = rFile.ReadShort();
|
||||
pFace->Lines[1] = rFile.ReadShort();
|
||||
pFace->Lines[2] = rFile.ReadShort();
|
||||
pFace->MaterialIdx = FaceIndices[iFace];
|
||||
OutData.EdgeIndices[i] = File.ReadShort();
|
||||
}
|
||||
|
||||
// Triangles
|
||||
uint NumTris = File.ReadLong();
|
||||
OutData.TriangleIndices.resize( NumTris );
|
||||
|
||||
for (uint i=0; i<NumTris; i++)
|
||||
{
|
||||
OutData.TriangleIndices[i] = File.ReadShort();
|
||||
}
|
||||
|
||||
// Echoes introduces a new data chunk; don't know what it is yet, skipping for now
|
||||
if (mVersion >= EGame::Echoes)
|
||||
{
|
||||
uint32 UnknownCount = rFile.ReadLong();
|
||||
rFile.Seek(UnknownCount * 2, SEEK_CUR);
|
||||
uint UnknownCount = File.ReadLong();
|
||||
File.Skip(UnknownCount * 2);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
mpMesh->mVertexCount = rFile.ReadLong();
|
||||
mpMesh->mCollisionVertices.resize(mpMesh->mVertexCount);
|
||||
CAABox Bounds;
|
||||
uint NumVertices = File.ReadLong();
|
||||
OutData.Vertices.resize(NumVertices);
|
||||
|
||||
for (uint32 iVtx = 0; iVtx < mpMesh->mVertexCount; iVtx++)
|
||||
for (uint32 i=0; i<NumVertices; i++)
|
||||
{
|
||||
CCollisionMesh::CCollisionVertex *pVtx = &mpMesh->mCollisionVertices[iVtx];
|
||||
pVtx->Pos = CVector3f(rFile);
|
||||
pVtx->MaterialIdx = VtxIndices[iVtx];
|
||||
if (BuildAABox) Bounds.ExpandBounds(pVtx->Pos);
|
||||
OutData.Vertices[i].Read(File);
|
||||
}
|
||||
if (BuildAABox) mpMesh->mAABox = Bounds;
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
CCollisionMeshGroup* CCollisionLoader::LoadAreaCollision(IInputStream& rMREA)
|
||||
{
|
||||
if (!rMREA.IsValid()) return nullptr;
|
||||
CCollisionLoader loader;
|
||||
rMREA.Skip(0x8); // Skipping unknown value + collion section size
|
||||
|
||||
rMREA.Seek(0x8, SEEK_CUR);
|
||||
// Validate magic
|
||||
uint32 DeafBabe = rMREA.ReadLong();
|
||||
if (DeafBabe != 0xDEAFBABE)
|
||||
{
|
||||
@@ -193,22 +202,22 @@ CCollisionMeshGroup* CCollisionLoader::LoadAreaCollision(IInputStream& rMREA)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
loader.mVersion = GetFormatVersion(rMREA.ReadLong());
|
||||
|
||||
loader.mpGroup = new CCollisionMeshGroup;
|
||||
loader.mpMesh = new CCollisionMesh;
|
||||
CCollisionLoader Loader;
|
||||
Loader.mVersion = GetFormatVersion(rMREA.ReadLong());
|
||||
Loader.mpMesh = new CCollisionMesh;
|
||||
|
||||
// Octree - structure is known, but not coding this right now
|
||||
loader.mpMesh->mAABox = CAABox(rMREA);
|
||||
rMREA.Seek(0x4, SEEK_CUR);
|
||||
Loader.mpMesh->mAABox = CAABox(rMREA);
|
||||
rMREA.Skip(0x4);
|
||||
uint32 OctreeSize = rMREA.ReadLong();
|
||||
rMREA.Seek(OctreeSize, SEEK_CUR); // Skipping the octree for now
|
||||
loader.mpMesh->mOctreeLoaded = false;
|
||||
rMREA.Skip(OctreeSize); // Skipping the octree for now
|
||||
|
||||
// Read collision indices and return
|
||||
loader.LoadCollisionIndices(rMREA, false);
|
||||
loader.mpGroup->AddMesh(loader.mpMesh);
|
||||
return loader.mpGroup;
|
||||
Loader.LoadCollisionIndices(rMREA, Loader.mpMesh->mIndexData);
|
||||
|
||||
CCollisionMeshGroup* pOut = new CCollisionMeshGroup();
|
||||
pOut->AddMesh(Loader.mpMesh);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
CCollisionMeshGroup* CCollisionLoader::LoadDCLN(IInputStream& rDCLN, CResourceEntry *pEntry)
|
||||
@@ -220,32 +229,45 @@ CCollisionMeshGroup* CCollisionLoader::LoadDCLN(IInputStream& rDCLN, CResourceEn
|
||||
|
||||
uint32 NumMeshes = rDCLN.ReadLong();
|
||||
|
||||
for (uint32 iMesh = 0; iMesh < NumMeshes; iMesh++)
|
||||
for (uint32 MeshIdx = 0; MeshIdx < NumMeshes; MeshIdx++)
|
||||
{
|
||||
uint32 DeafBabe = rDCLN.ReadLong();
|
||||
|
||||
if (DeafBabe != 0xDEAFBABE)
|
||||
{
|
||||
errorf("%s [0x%X]: Invalid collision magic: 0x%08X", *rDCLN.GetSourceString(), rDCLN.Tell() - 4, DeafBabe);
|
||||
Loader.mpGroup.Delete();
|
||||
delete Loader.mpGroup;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Loader.mVersion = GetFormatVersion(rDCLN.ReadLong());
|
||||
|
||||
Loader.mpMesh = new CCollisionMesh;
|
||||
Loader.mpMesh->mOctreeLoaded = false;
|
||||
Loader.mpMesh = new CCollidableOBBTree;
|
||||
|
||||
if (Loader.mVersion == EGame::DKCReturns)
|
||||
Loader.mpMesh->mAABox = CAABox(rDCLN);
|
||||
|
||||
// Read indices and return
|
||||
rDCLN.Seek(0x4, SEEK_CUR);
|
||||
Loader.LoadCollisionIndices(rDCLN, Loader.mVersion != EGame::DKCReturns);
|
||||
Loader.LoadCollisionIndices(rDCLN, Loader.mpMesh->mIndexData);
|
||||
Loader.mpGroup->AddMesh(Loader.mpMesh);
|
||||
|
||||
// Build bounding box
|
||||
if (Loader.mVersion != EGame::DKCReturns)
|
||||
{
|
||||
Loader.mpMesh->mAABox = CAABox::skInfinite;
|
||||
|
||||
for (uint i=0; i<Loader.mpMesh->mIndexData.Vertices.size(); i++)
|
||||
{
|
||||
Loader.mpMesh->mAABox.ExpandBounds(
|
||||
Loader.mpMesh->mIndexData.Vertices[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse OBB tree
|
||||
Loader.ParseOBBNode(rDCLN);
|
||||
CCollidableOBBTree* pOBBTree = static_cast<CCollidableOBBTree*>(Loader.mpMesh);
|
||||
pOBBTree->mpOBBTree = std::unique_ptr<SOBBTreeNode>( Loader.ParseOBBNode(rDCLN) );
|
||||
}
|
||||
return Loader.mpGroup;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef CCOLLISIONLOADER_H
|
||||
#define CCOLLISIONLOADER_H
|
||||
|
||||
#include "Core/Resource/CCollisionMesh.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Collision/CCollisionMesh.h"
|
||||
#include "Core/Resource/Collision/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Collision/CCollidableOBBTree.h"
|
||||
#include <Common/EGame.h>
|
||||
|
||||
class CCollisionLoader
|
||||
@@ -12,17 +13,21 @@ class CCollisionLoader
|
||||
EGame mVersion;
|
||||
|
||||
CCollisionLoader();
|
||||
|
||||
#if 0
|
||||
CCollisionMesh::CCollisionOctree* ParseOctree(IInputStream& rSrc);
|
||||
CCollisionMesh::CCollisionOctree::SBranch* ParseOctreeBranch(IInputStream& rSrc);
|
||||
CCollisionMesh::CCollisionOctree::SLeaf* ParseOctreeLeaf(IInputStream& rSrc);
|
||||
void ParseOBBNode(IInputStream& rDCLN);
|
||||
void ReadPropertyFlags(IInputStream& rSrc);
|
||||
void LoadCollisionIndices(IInputStream& rFile, bool BuildAABox);
|
||||
#endif
|
||||
|
||||
SOBBTreeNode* ParseOBBNode(IInputStream& DCLN);
|
||||
void LoadCollisionMaterial(IInputStream& Src, CCollisionMaterial& OutMaterial);
|
||||
void LoadCollisionIndices(IInputStream& File, SCollisionIndexData& OutData);
|
||||
|
||||
public:
|
||||
static CCollisionMeshGroup* LoadAreaCollision(IInputStream& rMREA);
|
||||
static CCollisionMeshGroup* LoadDCLN(IInputStream& rDCLN, CResourceEntry *pEntry);
|
||||
static EGame GetFormatVersion(uint32 Version);
|
||||
static EGame GetFormatVersion(uint32 Version);
|
||||
};
|
||||
|
||||
#endif // CCOLLISIONLOADER_H
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
#include "CCollisionMeshGroup.h"
|
||||
#include "CDependencyGroup.h"
|
||||
#include "CFont.h"
|
||||
#include "CPoiToWorld.h"
|
||||
@@ -13,6 +12,7 @@
|
||||
#include "Core/Resource/Animation/CSkeleton.h"
|
||||
#include "Core/Resource/Animation/CSkin.h"
|
||||
#include "Core/Resource/Area/CGameArea.h"
|
||||
#include "Core/Resource/Collision/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/Scan/CScan.h"
|
||||
#include "Core/Resource/StringTable/CStringTable.h"
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "CScriptTemplate.h"
|
||||
#include "Core/Resource/Area/CGameArea.h"
|
||||
#include "Core/Resource/Collision/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
|
||||
class CScriptLayer;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
#include "EVolumeShape.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Collision/CCollisionMeshGroup.h"
|
||||
#include <Common/BasicTypes.h>
|
||||
#include <Common/CFourCC.h>
|
||||
#include <list>
|
||||
|
||||
Reference in New Issue
Block a user