diff --git a/Common/CRayCollisionTester.cpp b/Common/CRayCollisionTester.cpp index d252fd12..c1e731dc 100644 --- a/Common/CRayCollisionTester.cpp +++ b/Common/CRayCollisionTester.cpp @@ -19,7 +19,7 @@ void CRayCollisionTester::AddNode(CSceneNode *pNode, u32 AssetIndex, float Dista Intersection.Distance = Distance; } -SRayIntersection CRayCollisionTester::TestNodes() +SRayIntersection CRayCollisionTester::TestNodes(ERenderOptions options) { // Sort nodes by distance from ray mBoxIntersectList.sort( @@ -43,7 +43,7 @@ SRayIntersection CRayCollisionTester::TestNodes() // Otherwise, more intersection tests... CSceneNode *pNode = Intersection.pNode; - SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex); + SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex, options); if (MidResult.Hit) { diff --git a/Common/CRayCollisionTester.h b/Common/CRayCollisionTester.h index 573211f7..a936e2f6 100644 --- a/Common/CRayCollisionTester.h +++ b/Common/CRayCollisionTester.h @@ -6,6 +6,7 @@ #include "CVector3f.h" #include "SRayIntersection.h" #include "types.h" +#include #include @@ -21,7 +22,7 @@ public: ~CRayCollisionTester(); const CRay& Ray() const; void AddNode(CSceneNode *pNode, u32 AssetIndex, float Distance); - SRayIntersection TestNodes(); + SRayIntersection TestNodes(ERenderOptions options); }; inline const CRay& CRayCollisionTester::Ray() const diff --git a/Common/Math.cpp b/Common/Math.cpp index bf46c34c..e0737b67 100644 --- a/Common/Math.cpp +++ b/Common/Math.cpp @@ -262,12 +262,7 @@ std::pair RayTriangleIntersection(const CRay& Ray, if (!AllowBackfaces) return std::pair(false, 0); } - else if (denom < - std::numeric_limits::epsilon()) - { - if (false) - return std::pair(false, 0); - } - else + else if (denom >= - std::numeric_limits::epsilon()) { // Parallel or triangle area is close to zero when // the plane normal not normalised. diff --git a/Core/CRenderer.cpp b/Core/CRenderer.cpp index 6e5b6011..9ae72d78 100644 --- a/Core/CRenderer.cpp +++ b/Core/CRenderer.cpp @@ -20,7 +20,8 @@ u32 CRenderer::sNumRenderers = 0; // ************ INITIALIZATION ************ CRenderer::CRenderer() { - mOptions = eEnableUVScroll | eEnableBackfaceCull; + mOptions = eDrawWorld | eDrawObjects | eDrawLights | eDrawSky | + eEnableUVScroll | eEnableBackfaceCull; mBloomMode = eNoBloom; mDrawGrid = true; mInitialized = false; @@ -53,9 +54,45 @@ void CRenderer::Init() } // ************ GETTERS/SETTERS ************ -bool CRenderer::IsUVAnimationOn() +ERenderOptions CRenderer::RenderOptions() { - return ((mOptions & eUVScroll) != 0); + return mOptions; +} + +void CRenderer::ToggleWorld(bool b) +{ + if (b) mOptions |= eDrawWorld; + else mOptions &= ~eDrawWorld; +} + +void CRenderer::ToggleWorldCollision(bool b) +{ + if (b) mOptions |= eDrawWorldCollision; + else mOptions &= ~eDrawWorldCollision; +} + +void CRenderer::ToggleObjects(bool b) +{ + if (b) mOptions |= eDrawObjects; + else mOptions &= ~eDrawObjects; +} + +void CRenderer::ToggleObjectCollision(bool b) +{ + if (b) mOptions |= eDrawObjectCollision; + else mOptions &= ~eDrawObjectCollision; +} + +void CRenderer::ToggleLights(bool b) +{ + if (b) mOptions |= eDrawLights; + else mOptions &= ~eDrawLights; +} + +void CRenderer::ToggleSky(bool b) +{ + if (b) mOptions |= eDrawSky; + else mOptions &= ~eDrawSky; } void CRenderer::ToggleBackfaceCull(bool b) diff --git a/Core/CRenderer.h b/Core/CRenderer.h index 40a41470..2dc56f99 100644 --- a/Core/CRenderer.h +++ b/Core/CRenderer.h @@ -53,7 +53,13 @@ public: void Init(); // Getters/Setters - bool IsUVAnimationOn(); + ERenderOptions RenderOptions(); + void ToggleWorld(bool b); + void ToggleWorldCollision(bool b); + void ToggleObjects(bool b); + void ToggleObjectCollision(bool b); + void ToggleLights(bool b); + void ToggleSky(bool b); void ToggleBackfaceCull(bool b); void ToggleUVAnimation(bool b); void ToggleGrid(bool b); diff --git a/Core/CResCache.cpp b/Core/CResCache.cpp index 20d72c6e..cc9024af 100644 --- a/Core/CResCache.cpp +++ b/Core/CResCache.cpp @@ -150,6 +150,7 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC type) else if (type == "STRG") Res = CStringLoader::LoadSTRG(mem); else if (type == "FONT") Res = CFontLoader::LoadFONT(mem); else if (type == "SCAN") Res = CScanLoader::LoadSCAN(mem); + else if (type == "DCLN") Res = CCollisionLoader::LoadDCLN(mem); else SupportedFormat = false; // Log errors @@ -201,6 +202,7 @@ CResource* CResCache::GetResource(std::string ResPath) else if (type == "MLVL") Res = CWorldLoader::LoadMLVL(file); else if (type == "FONT") Res = CFontLoader::LoadFONT(file); else if (type == "SCAN") Res = CScanLoader::LoadSCAN(file); + else if (type == "DCLN") Res = CCollisionLoader::LoadDCLN(file); else SupportedFormat = false; if (!Res) Res = new CResource(); // Default for unsupported formats diff --git a/Core/CSceneManager.cpp b/Core/CSceneManager.cpp index 9c36f4dd..f1f18db0 100644 --- a/Core/CSceneManager.cpp +++ b/Core/CSceneManager.cpp @@ -19,10 +19,6 @@ */ CSceneManager::CSceneManager() { - mShowTerrain = true; - mShowCollision = false; - mShowObjects = true; - mShowLights = true; mSplitTerrain = true; mNodeCount = 0; mpSceneRootNode = new CRootNode(this, nullptr); @@ -56,7 +52,7 @@ CStaticNode* CSceneManager::AddStaticModel(CStaticModel *mdl) return node; } -CCollisionNode* CSceneManager::AddCollision(CCollisionMesh *mesh) +CCollisionNode* CSceneManager::AddCollision(CCollisionMeshGroup *mesh) { if (mesh == nullptr) return nullptr; @@ -143,7 +139,7 @@ void CSceneManager::SetActiveArea(CGameArea* _area) switch (pObj->ObjectTypeID()) { case 0x4E: // MP1 AreaAttributes ID - case 0x52454141: // MP2 AreaAttributes ID ("REAA") + case 0x52454141: // MP2/MP3/DKCR AreaAttributes ID ("REAA") mAreaAttributesObjects.emplace_back( CAreaAttributes(pObj) ); break; } @@ -221,7 +217,9 @@ void CSceneManager::ClearScene() void CSceneManager::AddSceneToRenderer(CRenderer *pRenderer) { - if (mShowTerrain) + ERenderOptions options = pRenderer->RenderOptions(); + + if (options & eDrawWorld) { for (u32 n = 0; n < mModelNodes.size(); n++) if (mModelNodes[n]->IsVisible()) @@ -232,29 +230,29 @@ void CSceneManager::AddSceneToRenderer(CRenderer *pRenderer) mStaticNodes[n]->AddToRenderer(pRenderer); } - if (mShowCollision) + if (options & eDrawWorldCollision) { for (u32 n = 0; n < mCollisionNodes.size(); n++) if (mCollisionNodes[n]->IsVisible()) mCollisionNodes[n]->AddToRenderer(pRenderer); } - if (mShowObjects) - { - for (u32 n = 0; n < mScriptNodes.size(); n++) - if (mScriptNodes[n]->IsVisible()) - mScriptNodes[n]->AddToRenderer(pRenderer); - } - - if (mShowLights) + if (options & eDrawLights) { for (u32 n = 0; n < mLightNodes.size(); n++) if (mLightNodes[n]->IsVisible()) mLightNodes[n]->AddToRenderer(pRenderer); } + + if ((options & eDrawObjects) || (options & eDrawObjectCollision)) + { + for (u32 n = 0; n < mScriptNodes.size(); n++) + if (mScriptNodes[n]->IsVisible()) + mScriptNodes[n]->AddToRenderer(pRenderer); + } } -SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray) +SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray, ERenderOptions renderOptions) { // Terribly hacky stuff to avoid having tons of redundant code // because I'm too lazy to rewrite CSceneManager right now and fix it @@ -267,7 +265,8 @@ SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray) reinterpret_cast*>(&mLightNodes), }; bool NodesVisible[5] = { - true, mShowTerrain, mShowCollision, mShowObjects, mShowLights + true, ((renderOptions & eDrawWorld) != 0), ((renderOptions & eDrawWorldCollision) != 0), + ((renderOptions & ((ERenderOptions) (eDrawObjects | eDrawObjectCollision))) != 0), ((renderOptions & eDrawLights) != 0) }; // Less hacky stuff @@ -284,7 +283,7 @@ SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray) vec[iNode]->RayAABoxIntersectTest(Tester); } - return Tester.TestNodes(); + return Tester.TestNodes(renderOptions); } void CSceneManager::PickEnvironmentObjects() @@ -343,43 +342,3 @@ CGameArea* CSceneManager::GetActiveArea() { return mpArea; } - -void CSceneManager::SetWorld(bool on) -{ - mShowTerrain = on; -} - -void CSceneManager::SetCollision(bool on) -{ - mShowCollision = on; -} - -void CSceneManager::SetLights(bool on) -{ - mShowLights = on; -} - -void CSceneManager::SetObjects(bool on) -{ - mShowObjects = on; -} - -bool CSceneManager::IsTerrainEnabled() -{ - return mShowTerrain; -} - -bool CSceneManager::IsCollisionEnabled() -{ - return mShowCollision; -} - -bool CSceneManager::AreLightsEnabled() -{ - return mShowLights; -} - -bool CSceneManager::AreScriptObjectsEnabled() -{ - return mShowObjects; -} diff --git a/Core/CSceneManager.h b/Core/CSceneManager.h index 2124c15b..5b018a2b 100644 --- a/Core/CSceneManager.h +++ b/Core/CSceneManager.h @@ -21,10 +21,6 @@ class CSceneManager { - bool mShowTerrain; - bool mShowCollision; - bool mShowObjects; - bool mShowLights; bool mSplitTerrain; u32 mNodeCount; @@ -55,14 +51,14 @@ public: // Scene Management CModelNode* AddModel(CModel *mdl); CStaticNode* AddStaticModel(CStaticModel *mdl); - CCollisionNode* AddCollision(CCollisionMesh *mesh); + CCollisionNode* AddCollision(CCollisionMeshGroup *mesh); CScriptNode* AddScriptObject(CScriptObject *obj); CLightNode* AddLight(CLight *Light); void SetActiveArea(CGameArea *_area); void SetActiveWorld(CWorld *_world); void ClearScene(); void AddSceneToRenderer(CRenderer *pRenderer); - SRayIntersection SceneRayCast(const CRay& Ray); + SRayIntersection SceneRayCast(const CRay& Ray, ERenderOptions renderOptions); void PickEnvironmentObjects(); CScriptNode* ScriptNodeByID(u32 InstanceID); CScriptNode* NodeForObject(CScriptObject *pObj); @@ -71,17 +67,6 @@ public: // Setters/Getters CModel* GetActiveSkybox(); CGameArea* GetActiveArea(); - - void SetBackfaceCulling(bool on); - void SetWorld(bool on); - void SetCollision(bool on); - void SetObjects(bool on); - void SetLights(bool on); - bool IsBackfaceCullEnabled(); - bool IsTerrainEnabled(); - bool IsCollisionEnabled(); - bool AreLightsEnabled(); - bool AreScriptObjectsEnabled(); }; #endif // CSCENEMANAGER_H diff --git a/Core/ERenderOptions.h b/Core/ERenderOptions.h index 9b63d73e..bf282a40 100644 --- a/Core/ERenderOptions.h +++ b/Core/ERenderOptions.h @@ -5,12 +5,18 @@ enum ERenderOptions { - eEnableUVScroll = 0x1, - eEnableBackfaceCull = 0x2, - eEnableOccluders = 0x4, - eNoMaterialSetup = 0x8, - eEnableBloom = 0x10, - eNoAlpha = 0x20 + eDrawWorld = 0x1, + eDrawWorldCollision = 0x2, + eDrawObjects = 0x4, + eDrawObjectCollision = 0x8, + eDrawLights = 0x10, + eDrawSky = 0x20, + eEnableUVScroll = 0x40, + eEnableBackfaceCull = 0x80, + eEnableOccluders = 0x100, + eNoMaterialSetup = 0x200, + eEnableBloom = 0x400, + eNoAlpha = 0x800 }; DEFINE_ENUM_FLAGS(ERenderOptions) diff --git a/Resource/CCollisionMesh.cpp b/Resource/CCollisionMesh.cpp index da631b03..74fd89c6 100644 --- a/Resource/CCollisionMesh.cpp +++ b/Resource/CCollisionMesh.cpp @@ -1,7 +1,7 @@ #include "CCollisionMesh.h" #include -CCollisionMesh::CCollisionMesh() : CResource() +CCollisionMesh::CCollisionMesh() { mVBO.SetVertexDesc(ePosition); mVertexCount = 0; @@ -21,11 +21,6 @@ CCollisionMesh::~CCollisionMesh() } } -EResType CCollisionMesh::Type() -{ - return eCollisionMesh; -} - void CCollisionMesh::BufferGL() { if (mBuffered) @@ -88,7 +83,7 @@ void CCollisionMesh::Draw() mVBO.Unbind(); } -void CCollisionMesh::DrawLines() +void CCollisionMesh::DrawWireframe() { if (!mBuffered) BufferGL(); diff --git a/Resource/CCollisionMesh.h b/Resource/CCollisionMesh.h index e3d7c797..d7257a99 100644 --- a/Resource/CCollisionMesh.h +++ b/Resource/CCollisionMesh.h @@ -6,7 +6,7 @@ #include #include "CResource.h" -class CCollisionMesh : public CResource +class CCollisionMesh { friend class CCollisionLoader; @@ -79,11 +79,10 @@ class CCollisionMesh : public CResource public: CCollisionMesh(); ~CCollisionMesh(); - EResType Type(); void BufferGL(); void Draw(); - void DrawLines(); + void DrawWireframe(); }; #endif // CCOLLISIONMESH_H diff --git a/Resource/CCollisionMeshGroup.cpp b/Resource/CCollisionMeshGroup.cpp new file mode 100644 index 00000000..a79dff9b --- /dev/null +++ b/Resource/CCollisionMeshGroup.cpp @@ -0,0 +1,43 @@ +#include "CCollisionMeshGroup.h" + +CCollisionMeshGroup::CCollisionMeshGroup() +{ +} + +CCollisionMeshGroup::~CCollisionMeshGroup() +{ + for (auto it = mMeshes.begin(); it != mMeshes.end(); it++) + delete *it; +} + +EResType CCollisionMeshGroup::Type() +{ + return eCollisionMeshGroup; +} + +u32 CCollisionMeshGroup::NumMeshes() +{ + return mMeshes.size(); +} + +CCollisionMesh* CCollisionMeshGroup::MeshByIndex(u32 index) +{ + return mMeshes[index]; +} + +void CCollisionMeshGroup::AddMesh(CCollisionMesh *pMesh) +{ + mMeshes.push_back(pMesh); +} + +void CCollisionMeshGroup::Draw() +{ + for (auto it = mMeshes.begin(); it != mMeshes.end(); it++) + (*it)->Draw(); +} + +void CCollisionMeshGroup::DrawWireframe() +{ + for (auto it = mMeshes.begin(); it != mMeshes.end(); it++) + (*it)->DrawWireframe(); +} diff --git a/Resource/CCollisionMeshGroup.h b/Resource/CCollisionMeshGroup.h new file mode 100644 index 00000000..f34687c5 --- /dev/null +++ b/Resource/CCollisionMeshGroup.h @@ -0,0 +1,25 @@ +#ifndef CCOLLISIONMESHGROUP_H +#define CCOLLISIONMESHGROUP_H + +#include "CResource.h" +#include "CCollisionMesh.h" +#include +#include + +class CCollisionMeshGroup : public CResource +{ + std::vector mMeshes; + +public: + CCollisionMeshGroup(); + ~CCollisionMeshGroup(); + EResType Type(); + + u32 NumMeshes(); + CCollisionMesh* MeshByIndex(u32 index); + void AddMesh(CCollisionMesh *pMesh); + void Draw(); + void DrawWireframe(); +}; + +#endif // CCOLLISIONMESHGROUP_H diff --git a/Resource/CGameArea.cpp b/Resource/CGameArea.cpp index f64a9a37..77837c1f 100644 --- a/Resource/CGameArea.cpp +++ b/Resource/CGameArea.cpp @@ -135,7 +135,7 @@ CStaticModel* CGameArea::GetStaticModel(u32 mdl) return mStaticTerrainModels[mdl]; } -CCollisionMesh* CGameArea::GetCollision() +CCollisionMeshGroup* CGameArea::GetCollision() { return mCollision; } diff --git a/Resource/CGameArea.h b/Resource/CGameArea.h index b810c819..0c4d06c5 100644 --- a/Resource/CGameArea.h +++ b/Resource/CGameArea.h @@ -1,7 +1,7 @@ #ifndef CGAMEAREA_H #define CGAMEAREA_H -#include "CCollisionMesh.h" +#include "CCollisionMeshGroup.h" #include "CLight.h" #include "CMaterialSet.h" #include "model/CModel.h" @@ -32,7 +32,7 @@ class CGameArea : public CResource std::unordered_map mObjectMap; // Collision - CCollisionMesh *mCollision; + CCollisionMeshGroup *mCollision; // Lights std::vector> mLightLayers; @@ -52,7 +52,7 @@ public: u32 GetStaticModelCount(); CModel* GetTerrainModel(u32 mdl); CStaticModel* GetStaticModel(u32 mdl); - CCollisionMesh* GetCollision(); + CCollisionMeshGroup* GetCollision(); u32 GetScriptLayerCount(); CScriptLayer* GetScriptLayer(u32 index); CScriptLayer* GetGeneratorLayer(); diff --git a/Resource/CResource.cpp b/Resource/CResource.cpp index 3be73c2e..e2a965d3 100644 --- a/Resource/CResource.cpp +++ b/Resource/CResource.cpp @@ -72,7 +72,7 @@ EResType CResource::ResTypeForExtension(CFourCC Extension) if (Extension == "CSMP") return eAudioSample; if (Extension == "CSNG") return eMidi; if (Extension == "CTWK") return eTweak; - if (Extension == "DCLN") return eCollisionMesh; + if (Extension == "DCLN") return eCollisionMeshGroup; if (Extension == "DGRP") return eDependencyGroup; if (Extension == "DSP ") return eMusicTrack; if (Extension == "DUMB") return eDataDump; diff --git a/Resource/EResType.h b/Resource/EResType.h index fabc1e11..90ed216d 100644 --- a/Resource/EResType.h +++ b/Resource/EResType.h @@ -13,7 +13,7 @@ enum EResType eAudioStream = 7, eAudioTable = 8, eCharacter = 9, - eCollisionMesh = 10, + eCollisionMeshGroup = 10, eCollisionResponse = 11, eDataDump = 12, eDecal = 13, diff --git a/Resource/cooker/CTemplateWriter.cpp b/Resource/cooker/CTemplateWriter.cpp index 37e1371f..4e14e02d 100644 --- a/Resource/cooker/CTemplateWriter.cpp +++ b/Resource/cooker/CTemplateWriter.cpp @@ -262,8 +262,15 @@ void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp, const std::stri for (auto it = pTemp->mAssets.begin(); it != pTemp->mAssets.end(); it++) { - std::string type = (it->AssetType == CScriptTemplate::SEditorAsset::eAnimParams ? "animparams" : "model"); std::string source = (it->AssetSource == CScriptTemplate::SEditorAsset::eFile ? "file" : "property"); + std::string type; + + switch (it->AssetType) + { + case CScriptTemplate::SEditorAsset::eModel: type = "model"; break; + case CScriptTemplate::SEditorAsset::eAnimParams: type = "animparams"; break; + case CScriptTemplate::SEditorAsset::eCollision: type = "collision"; break; + } s32 force = -1; if (it->AssetSource == CScriptTemplate::SEditorAsset::eAnimParams) force = it->ForceNodeIndex; diff --git a/Resource/factory/CCollisionLoader.cpp b/Resource/factory/CCollisionLoader.cpp index 264444cb..aaf3d1ce 100644 --- a/Resource/factory/CCollisionLoader.cpp +++ b/Resource/factory/CCollisionLoader.cpp @@ -6,131 +6,213 @@ CCollisionLoader::CCollisionLoader() { } -CCollisionMesh* CCollisionLoader::LoadAreaCollision(CInputStream& MREA) +CCollisionMesh::CCollisionOctree* CCollisionLoader::ParseOctree(CInputStream&) +{ + // Not using: Parameter 1 (CInputStream& - src) + return nullptr; +} + +CCollisionMesh::CCollisionOctree::SBranch* CCollisionLoader::ParseOctreeBranch(CInputStream&) +{ + // Not using: Parameter 1 (CInputStream& - src) + return nullptr; +} + +CCollisionMesh::CCollisionOctree::SLeaf* CCollisionLoader::ParseOctreeLeaf(CInputStream&) +{ + // Not using: Parameter 1 (CInputStream& - src) + return nullptr; +} + +void CCollisionLoader::ParseOBBNode(CInputStream& DCLN) +{ + bool b = false; + + while (b == false) + { + DCLN.Seek(0x3C, SEEK_CUR); + b = (DCLN.ReadByte() == 1); + if (!b) ParseOBBNode(DCLN); + } + + u32 numFaces = DCLN.ReadLong(); + DCLN.Seek(numFaces * 2, SEEK_CUR); +} + +void CCollisionLoader::ReadPropertyFlags(CInputStream& src) +{ + CCollisionMesh::SCollisionProperties property; + + if (mVersion == ePrime) + { + u32 flag = src.ReadLong(); + property.Invert = (flag >> 25) & 0x1; + } + + if (mVersion == eEchoes) + { + u64 flag = src.ReadLongLong(); + property.Invert = (flag >> 24) & 0x1; + } + + mProperties.push_back(property); +} + +void CCollisionLoader::LoadCollisionIndices(CInputStream &file, bool buildAABox) +{ + // Properties + u32 propSetCount = file.ReadLong(); + for (u32 iProp = 0; iProp < propSetCount; iProp++) + ReadPropertyFlags(file); + + // Property indices for vertices/lines/faces + u32 vtxIndexCount = file.ReadLong(); + std::vector vtxIndices(vtxIndexCount); + file.ReadBytes(vtxIndices.data(), vtxIndices.size()); + + u32 lineIndexCount = file.ReadLong(); + std::vector lineIndices(lineIndexCount); + file.ReadBytes(lineIndices.data(), lineIndices.size()); + + u32 faceIndexCount = file.ReadLong(); + std::vector faceIndices(faceIndexCount); + file.ReadBytes(faceIndices.data(), faceIndices.size()); + + // Lines + mpMesh->mLineCount = file.ReadLong(); + mpMesh->mCollisionLines.resize(mpMesh->mLineCount); + for (u32 iLine = 0; iLine < mpMesh->mLineCount; iLine++) + { + CCollisionMesh::CCollisionLine *pLine = &mpMesh->mCollisionLines[iLine]; + pLine->Vertices[0] = file.ReadShort(); + pLine->Vertices[1] = file.ReadShort(); + pLine->Properties = mProperties[lineIndices[iLine]]; + } + + // Faces + mpMesh->mFaceCount = file.ReadLong() / 3; // Not sure why they store it this way. It's inconsistent. + mpMesh->mCollisionFaces.resize(mpMesh->mFaceCount); + + for (u32 iFace = 0; iFace < mpMesh->mFaceCount; iFace++) + { + CCollisionMesh::CCollisionFace *pFace = &mpMesh->mCollisionFaces[iFace]; + pFace->Lines[0] = file.ReadShort(); + pFace->Lines[1] = file.ReadShort(); + pFace->Lines[2] = file.ReadShort(); + pFace->Properties = mProperties[faceIndices[iFace]]; + } + + // Echoes introduces a new data chunk; don't know what it is yet, skipping for now + if (mVersion == eEchoes) + { + u32 unknownCount = file.ReadLong(); + file.Seek(unknownCount * 2, SEEK_CUR); + } + + // Vertices + mpMesh->mVertexCount = file.ReadLong(); + mpMesh->mCollisionVertices.resize(mpMesh->mVertexCount); + CAABox bounds; + + for (u32 iVtx = 0; iVtx < mpMesh->mVertexCount; iVtx++) + { + CCollisionMesh::CCollisionVertex *pVtx = &mpMesh->mCollisionVertices[iVtx]; + pVtx->Pos = CVector3f(file); + pVtx->Properties = mProperties[vtxIndices[iVtx]]; + if (buildAABox) bounds.ExpandBounds(pVtx->Pos); + } + if (buildAABox) mpMesh->mAABox = bounds; +} + +// ************ STATIC ************ +CCollisionMeshGroup* CCollisionLoader::LoadAreaCollision(CInputStream& MREA) { if (!MREA.IsValid()) return nullptr; CCollisionLoader loader; MREA.Seek(0x8, SEEK_CUR); u32 deafbabe = MREA.ReadLong(); - if (deafbabe != 0xdeafbabe) + if (deafbabe != 0xDEAFBABE) { Log::FileError(MREA.GetSourceString(), MREA.Tell() - 4, "Invalid collision magic: " + StringUtil::ToHexString(deafbabe)); return nullptr; } u32 version = MREA.ReadLong(); - loader.version = ECollisionVersion(version); - if ((loader.version != Prime) && (loader.version != Echoes)) + loader.mVersion = GetFormatVersion(version); + if ((loader.mVersion != ePrime) && (loader.mVersion != eEchoes)) { Log::FileError(MREA.GetSourceString(), MREA.Tell() - 4, "Unsupported collision version: " + StringUtil::ToHexString(version)); return nullptr; } - loader.mesh = new CCollisionMesh; - CCollisionMesh *cmesh = loader.mesh; + loader.mpGroup = new CCollisionMeshGroup; + loader.mpMesh = new CCollisionMesh; // Octree - structure is known, but not coding this right now - cmesh->mAABox = CAABox(MREA); + loader.mpMesh->mAABox = CAABox(MREA); MREA.Seek(0x4, SEEK_CUR); u32 octreeSize = MREA.ReadLong(); MREA.Seek(octreeSize, SEEK_CUR); // Skipping the octree for now - cmesh->mOctreeLoaded = false; + loader.mpMesh->mOctreeLoaded = false; - // Properties - u32 propertySetCount = MREA.ReadLong(); - for (u32 p = 0; p < propertySetCount; p++) - loader.readPropertyFlags(MREA); - - // Property indices for vertices/lines/faces - u32 vtxIndexCount = MREA.ReadLong(); - std::vector vtxIndices(vtxIndexCount); - MREA.ReadBytes(vtxIndices.data(), vtxIndices.size()); - - u32 lineIndexCount = MREA.ReadLong(); - std::vector lineIndices(lineIndexCount); - MREA.ReadBytes(lineIndices.data(), lineIndices.size()); - - u32 faceIndexCount = MREA.ReadLong(); - std::vector faceIndices(faceIndexCount); - MREA.ReadBytes(faceIndices.data(), faceIndices.size()); - - // Lines - cmesh->mLineCount = MREA.ReadLong(); - cmesh->mCollisionLines.resize(cmesh->mLineCount); - for (u32 l = 0; l < cmesh->mLineCount; l++) - { - CCollisionMesh::CCollisionLine *Line = &cmesh->mCollisionLines[l]; - Line->Vertices[0] = MREA.ReadShort(); - Line->Vertices[1] = MREA.ReadShort(); - Line->Properties = loader.properties[lineIndices[l]]; - } - - // Faces - cmesh->mFaceCount = MREA.ReadLong() / 3; // Not sure why they store it this way. It's inconsistent. - cmesh->mCollisionFaces.resize(cmesh->mFaceCount); - for (u32 f = 0; f < cmesh->mFaceCount; f++) - { - CCollisionMesh::CCollisionFace *face = &cmesh->mCollisionFaces[f]; - face->Lines[0] = MREA.ReadShort(); - face->Lines[1] = MREA.ReadShort(); - face->Lines[2] = MREA.ReadShort(); - face->Properties = loader.properties[faceIndices[f]]; - } - - // Echoes introduces a new data chunk; don't know what it is yet, skipping for now - if (loader.version == Echoes) - { - u32 unknown_count = MREA.ReadLong(); - MREA.Seek(unknown_count * 2, SEEK_CUR); - } - - // Vertices - cmesh->mVertexCount = MREA.ReadLong(); - cmesh->mCollisionVertices.resize(cmesh->mVertexCount); - for (u32 v = 0; v < cmesh->mVertexCount; v++) - { - CCollisionMesh::CCollisionVertex *vtx = &cmesh->mCollisionVertices[v]; - vtx->Pos = CVector3f(MREA); - vtx->Properties = loader.properties[vtxIndices[v]]; - } - - return cmesh; + // Read collision indices and return + loader.LoadCollisionIndices(MREA, false); + loader.mpGroup->AddMesh(loader.mpMesh); + return loader.mpGroup; } -CCollisionMesh::CCollisionOctree* CCollisionLoader::parseOctree(CInputStream&) +CCollisionMeshGroup* CCollisionLoader::LoadDCLN(CInputStream &DCLN) { - // Not using: Parameter 1 (CInputStream& - src) - return nullptr; -} + if (!DCLN.IsValid()) return nullptr; -CCollisionMesh::CCollisionOctree::SBranch* CCollisionLoader::parseOctreeBranch(CInputStream&) -{ - // Not using: Parameter 1 (CInputStream& - src) - return nullptr; -} + CCollisionLoader loader; + loader.mpGroup = new CCollisionMeshGroup; -CCollisionMesh::CCollisionOctree::SLeaf* CCollisionLoader::parseOctreeLeaf(CInputStream&) -{ - // Not using: Parameter 1 (CInputStream& - src) - return nullptr; -} + u32 numMeshes = DCLN.ReadLong(); -void CCollisionLoader::readPropertyFlags(CInputStream& src) -{ - CCollisionMesh::SCollisionProperties property; - - if (version == Prime) + for (u32 iMesh = 0; iMesh < numMeshes; iMesh++) { - u32 flag = src.ReadLong(); - property.Invert = (flag >> 25) & 0x1; - } + u32 deafbabe = DCLN.ReadLong(); - if (version == Echoes) - { - u64 flag = src.ReadLongLong(); - property.Invert = (flag >> 24) & 0x1; - } + if (deafbabe != 0xDEAFBABE) + { + Log::FileError(DCLN.GetSourceString(), DCLN.Tell() - 4, "Invalid collision magic: " + StringUtil::ToHexString(deafbabe)); + delete loader.mpGroup; + return nullptr; + } - properties.push_back(property); + u32 version = DCLN.ReadLong(); + loader.mVersion = GetFormatVersion(version); + + if ((loader.mVersion != ePrime) && (loader.mVersion != eEchoes)) + { + Log::FileError(DCLN.GetSourceString(), DCLN.Tell() - 4, "Unsupported collision version: " + StringUtil::ToHexString(version)); + return nullptr; + } + + loader.mpMesh = new CCollisionMesh; + loader.mpMesh->mOctreeLoaded = false; + + // Read indices and return + DCLN.Seek(0x4, SEEK_CUR); + loader.LoadCollisionIndices(DCLN, true); + loader.mpGroup->AddMesh(loader.mpMesh); + + // Parse OBB tree + loader.ParseOBBNode(DCLN); + } + return loader.mpGroup; +} + +EGame CCollisionLoader::GetFormatVersion(u32 version) +{ + switch (version) + { + case 0x2: return ePrime; + case 0x3: return ePrime; + case 0x4: return eEchoes; + case 0x5: return eReturns; + default: return eUnknownVersion; + } } diff --git a/Resource/factory/CCollisionLoader.h b/Resource/factory/CCollisionLoader.h index 25c1e6c1..9225040e 100644 --- a/Resource/factory/CCollisionLoader.h +++ b/Resource/factory/CCollisionLoader.h @@ -2,30 +2,28 @@ #define CCOLLISIONLOADER_H #include "../CCollisionMesh.h" +#include "../CCollisionMeshGroup.h" +#include "../EFormatVersion.h" class CCollisionLoader { - enum ECollisionVersion; - - CCollisionMesh *mesh; - ECollisionVersion version; - std::vector properties; - - enum ECollisionVersion - { - Prime = 0x3, - Echoes = 0x4, - DonkeyKongCountryReturns = 0x5 - }; + CCollisionMeshGroup *mpGroup; + CCollisionMesh *mpMesh; + EGame mVersion; + std::vector mProperties; CCollisionLoader(); - CCollisionMesh::CCollisionOctree* parseOctree(CInputStream& src); - CCollisionMesh::CCollisionOctree::SBranch* parseOctreeBranch(CInputStream& src); - CCollisionMesh::CCollisionOctree::SLeaf* parseOctreeLeaf(CInputStream& src); - void readPropertyFlags(CInputStream& src); + CCollisionMesh::CCollisionOctree* ParseOctree(CInputStream& src); + CCollisionMesh::CCollisionOctree::SBranch* ParseOctreeBranch(CInputStream& src); + CCollisionMesh::CCollisionOctree::SLeaf* ParseOctreeLeaf(CInputStream& src); + void ParseOBBNode(CInputStream& DCLN); + void ReadPropertyFlags(CInputStream& src); + void LoadCollisionIndices(CInputStream& file, bool buildAABox); public: - static CCollisionMesh* LoadAreaCollision(CInputStream& MREA); + static CCollisionMeshGroup* LoadAreaCollision(CInputStream& MREA); + static CCollisionMeshGroup* LoadDCLN(CInputStream& DCLN); + static EGame GetFormatVersion(u32 version); }; #endif // CCOLLISIONLOADER_H diff --git a/Resource/factory/CTemplateLoader.cpp b/Resource/factory/CTemplateLoader.cpp index d10bd2d2..9f8ca911 100644 --- a/Resource/factory/CTemplateLoader.cpp +++ b/Resource/factory/CTemplateLoader.cpp @@ -221,6 +221,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(), "collision") == 0) + asset.AssetType = CScriptTemplate::SEditorAsset::eCollision; else { pAsset = pAsset->NextSiblingElement(); diff --git a/Resource/model/SSurface.cpp b/Resource/model/SSurface.cpp index cd0a9ab3..3ec4bc06 100644 --- a/Resource/model/SSurface.cpp +++ b/Resource/model/SSurface.cpp @@ -3,7 +3,7 @@ #include #include -std::pair SSurface::IntersectsRay(const CRay& Ray, float LineThreshold) +std::pair SSurface::IntersectsRay(const CRay& Ray, bool allowBackfaces, float LineThreshold) { bool Hit = false; float HitDist; @@ -61,7 +61,7 @@ std::pair SSurface::IntersectsRay(const CRay& Ray, float LineThresho } // Intersection test - std::pair TriResult = Math::RayTriangleIntersection(Ray, vtxA, vtxB, vtxC); + std::pair TriResult = Math::RayTriangleIntersection(Ray, vtxA, vtxB, vtxC, allowBackfaces); if (TriResult.first) { diff --git a/Resource/model/SSurface.h b/Resource/model/SSurface.h index d04424cf..46cb55db 100644 --- a/Resource/model/SSurface.h +++ b/Resource/model/SSurface.h @@ -33,7 +33,7 @@ struct SSurface TriangleCount = 0; } - std::pair IntersectsRay(const CRay& Ray, float LineThreshold = 0.02f); + std::pair IntersectsRay(const CRay& Ray, bool allowBackfaces = false, float LineThreshold = 0.02f); }; #endif // SSURFACE_H diff --git a/Resource/script/CScriptObject.cpp b/Resource/script/CScriptObject.cpp index 50f90f0f..d0909e92 100644 --- a/Resource/script/CScriptObject.cpp +++ b/Resource/script/CScriptObject.cpp @@ -9,6 +9,8 @@ CScriptObject::CScriptObject(CGameArea *pArea, CScriptLayer *pLayer, CScriptTemp mpLayer = pLayer; mpProperties = nullptr; mpTemplate->AddObject(this); + mpDisplayModel = nullptr; + mpCollision = nullptr; } CScriptObject::~CScriptObject() @@ -35,6 +37,7 @@ void CScriptObject::EvaluateProperties() mpLightParameters = mpTemplate->FindLightParameters(mpProperties); mVolumeShape = mpTemplate->VolumeShape(this); EvaluateDisplayModel(); + EvaluateCollisionModel(); } void CScriptObject::EvaluateDisplayModel() @@ -43,6 +46,12 @@ void CScriptObject::EvaluateDisplayModel() mModelToken = CToken(mpDisplayModel); } +void CScriptObject::EvaluateCollisionModel() +{ + mpCollision = mpTemplate->FindCollision(mpProperties); + mCollisionToken = CToken(mpCollision); +} + // ************ GETTERS ************ CPropertyBase* CScriptObject::PropertyByIndex(u32 index) const { @@ -189,6 +198,11 @@ CModel* CScriptObject::GetDisplayModel() const return mpDisplayModel; } +CCollisionMeshGroup* CScriptObject::GetCollision() const +{ + return mpCollision; +} + EVolumeShape CScriptObject::VolumeShape() const { return mVolumeShape; diff --git a/Resource/script/CScriptObject.h b/Resource/script/CScriptObject.h index d23bbd42..3baf403e 100644 --- a/Resource/script/CScriptObject.h +++ b/Resource/script/CScriptObject.h @@ -6,6 +6,7 @@ #include "CPropertyTemplate.h" #include "CScriptTemplate.h" #include "../model/CModel.h" +#include "../CCollisionMeshGroup.h" class CGameArea; class CScriptLayer; @@ -31,7 +32,9 @@ class CScriptObject CBoolProperty *mpActive; CPropertyStruct *mpLightParameters; CModel *mpDisplayModel; + CCollisionMeshGroup *mpCollision; CToken mModelToken; + CToken mCollisionToken; EVolumeShape mVolumeShape; public: @@ -41,6 +44,7 @@ public: void CopyFromTemplate(CScriptTemplate *pTemp, u32 propCount); void EvaluateProperties(); void EvaluateDisplayModel(); + void EvaluateCollisionModel(); CScriptTemplate* Template() const; CMasterTemplate* MasterTemplate() const; @@ -69,6 +73,7 @@ public: void SetActive(bool isActive); CPropertyStruct* LightParameters() const; CModel* GetDisplayModel() const; + CCollisionMeshGroup* GetCollision() const; EVolumeShape VolumeShape() const; }; diff --git a/Resource/script/CScriptTemplate.cpp b/Resource/script/CScriptTemplate.cpp index ec781914..aae7c785 100644 --- a/Resource/script/CScriptTemplate.cpp +++ b/Resource/script/CScriptTemplate.cpp @@ -242,6 +242,39 @@ CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties) return nullptr; } +CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties) +{ + for (auto it = mAssets.begin(); it != mAssets.end(); it++) + { + CResource *pRes = nullptr; + + // File + if (it->AssetSource == SEditorAsset::eFile) + { + std::string path = "../resources/" + it->AssetLocation; + pRes = gResCache.GetResource(path); + } + + // Property + else + { + CPropertyBase *pProp = pProperties->PropertyByIDString(it->AssetLocation); + + if (pProp->Type() == eFileProperty) + { + CFileProperty *pFile = static_cast(pProp); + pRes = pFile->Get(); + } + } + + // Verify resource exists + is correct type + if (pRes && (pRes->Type() == eCollisionMeshGroup)) + return static_cast(pRes); + } + + return nullptr; +} + bool CScriptTemplate::HasPosition() { return (!mPositionIDString.empty()); diff --git a/Resource/script/CScriptTemplate.h b/Resource/script/CScriptTemplate.h index 3b74823c..b4a11da8 100644 --- a/Resource/script/CScriptTemplate.h +++ b/Resource/script/CScriptTemplate.h @@ -11,6 +11,7 @@ #include #include #include +#include class CMasterTemplate; class CScriptObject; @@ -47,7 +48,7 @@ private: struct SEditorAsset { enum { - eModel, eAnimParams + eModel, eAnimParams, eCollision } AssetType; enum { @@ -114,6 +115,7 @@ public: CBoolProperty* FindActive(CPropertyStruct *pProperties); CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties); CModel* FindDisplayModel(CPropertyStruct *pProperties); + CCollisionMeshGroup* FindCollision(CPropertyStruct *pProperties); bool HasPosition(); // Object Tracking diff --git a/Scene/CCollisionNode.cpp b/Scene/CCollisionNode.cpp index 8b7dd638..9bb8fe3a 100644 --- a/Scene/CCollisionNode.cpp +++ b/Scene/CCollisionNode.cpp @@ -3,11 +3,10 @@ #include #include -CCollisionNode::CCollisionNode(CSceneManager *pScene, CSceneNode *pParent, CCollisionMesh *pMesh) +CCollisionNode::CCollisionNode(CSceneManager *pScene, CSceneNode *pParent, CCollisionMeshGroup *pCollision) : CSceneNode(pScene, pParent) { - mpMesh = pMesh; - mMeshToken = CToken(pMesh); + SetCollision(pCollision); SetName("Collision"); } @@ -18,7 +17,7 @@ ENodeType CCollisionNode::NodeType() void CCollisionNode::AddToRenderer(CRenderer *pRenderer) { - if (!mpMesh) return; + if (!mpCollision) return; pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); @@ -29,7 +28,7 @@ void CCollisionNode::AddToRenderer(CRenderer *pRenderer) void CCollisionNode::Draw(ERenderOptions) { // Not using parameter 1 (ERenderOptions - Options) - if (!mpMesh) return; + if (!mpCollision) return; LoadModelMatrix(); @@ -38,9 +37,9 @@ void CCollisionNode::Draw(ERenderOptions) glDepthMask(GL_TRUE); CDrawUtil::UseCollisionShader(); - mpMesh->Draw(); + mpCollision->Draw(); CDrawUtil::UseColorShader(CColor::skTransparentBlack); - mpMesh->DrawLines(); + mpCollision->DrawWireframe(); } void CCollisionNode::DrawAsset(ERenderOptions, u32) @@ -49,10 +48,16 @@ void CCollisionNode::DrawAsset(ERenderOptions, u32) // Not using parameter 2 (u32 - asset) } -SRayIntersection CCollisionNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID) +SRayIntersection CCollisionNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options) { // todo SRayIntersection Result; Result.Hit = false; return Result; } + +void CCollisionNode::SetCollision(CCollisionMeshGroup *pCollision) +{ + mpCollision = pCollision; + mCollisionToken = CToken(pCollision); +} diff --git a/Scene/CCollisionNode.h b/Scene/CCollisionNode.h index c0bec6fd..5c18c3ed 100644 --- a/Scene/CCollisionNode.h +++ b/Scene/CCollisionNode.h @@ -2,20 +2,21 @@ #define CCOLLISIONNODE_H #include "CSceneNode.h" -#include +#include class CCollisionNode : public CSceneNode { - CCollisionMesh *mpMesh; - CToken mMeshToken; + CCollisionMeshGroup *mpCollision; + CToken mCollisionToken; public: - CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMesh *pMesh = 0); + CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0); ENodeType NodeType(); void AddToRenderer(CRenderer *pRenderer); void Draw(ERenderOptions Options); void DrawAsset(ERenderOptions Options, u32 asset); - SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID); + SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options); + void SetCollision(CCollisionMeshGroup *pCollision); }; #endif // CCOLLISIONNODE_H diff --git a/Scene/CLightNode.cpp b/Scene/CLightNode.cpp index b5fe9bb7..8658ed7d 100644 --- a/Scene/CLightNode.cpp +++ b/Scene/CLightNode.cpp @@ -57,10 +57,12 @@ void CLightNode::DrawAsset(ERenderOptions, u32) // Not using parameter 2 (u32 - asset) } -SRayIntersection CLightNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID) +SRayIntersection CLightNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options) { // Needs redo if I ever make these look like something other than boxes - if (AABox().IsPointInBox(Ray.Origin())) + bool allowBackfaces = ((options & eEnableBackfaceCull) == 0); + + if (!allowBackfaces && (AABox().IsPointInBox(Ray.Origin()))) return SRayIntersection(false, 0.f, nullptr, 0); std::pair BoxResult = AABox().IntersectsRay(Ray); diff --git a/Scene/CLightNode.h b/Scene/CLightNode.h index 22585d25..f08576d8 100644 --- a/Scene/CLightNode.h +++ b/Scene/CLightNode.h @@ -13,7 +13,7 @@ public: void AddToRenderer(CRenderer *pRenderer); void Draw(ERenderOptions Options); void DrawAsset(ERenderOptions Options, u32 asset); - SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID); + SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options); CLight* Light(); }; diff --git a/Scene/CModelNode.cpp b/Scene/CModelNode.cpp index 15b60629..653b1d8b 100644 --- a/Scene/CModelNode.cpp +++ b/Scene/CModelNode.cpp @@ -105,14 +105,14 @@ void CModelNode::RayAABoxIntersectTest(CRayCollisionTester &Tester) } } -SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID) +SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options) { SRayIntersection out; out.pNode = this; out.AssetIndex = AssetID; CRay TransformedRay = Ray.Transformed(Transform().Inverse()); - std::pair Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay); + std::pair Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0)); if (Result.first) { diff --git a/Scene/CModelNode.h b/Scene/CModelNode.h index f0689849..a36d7fbb 100644 --- a/Scene/CModelNode.h +++ b/Scene/CModelNode.h @@ -20,7 +20,7 @@ public: virtual void Draw(ERenderOptions Options); virtual void DrawAsset(ERenderOptions Options, u32 asset); virtual void RayAABoxIntersectTest(CRayCollisionTester &Tester); - virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID); + virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options); void SetModel(CModel *pModel); void SetMatSet(u32 MatSet); diff --git a/Scene/CRootNode.h b/Scene/CRootNode.h index 49c14b7e..cddbaa84 100644 --- a/Scene/CRootNode.h +++ b/Scene/CRootNode.h @@ -20,7 +20,7 @@ public: inline void DrawAsset(ERenderOptions, u32) {} inline void RayAABoxIntersectTest(CRayCollisionTester &) {} - inline SRayIntersection RayNodeIntersectTest(const CRay &, u32) { + inline SRayIntersection RayNodeIntersectTest(const CRay &, u32, ERenderOptions) { return SRayIntersection(false, 0.f, nullptr, 0); } diff --git a/Scene/CSceneNode.h b/Scene/CSceneNode.h index 3105d0e3..aab3277e 100644 --- a/Scene/CSceneNode.h +++ b/Scene/CSceneNode.h @@ -56,7 +56,7 @@ public: virtual void DrawAsset(ERenderOptions options, u32 asset) = 0; virtual void DrawSelection(); virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester); - virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID) = 0; + virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, ERenderOptions options) = 0; virtual bool IsVisible() const; void Unparent(); diff --git a/Scene/CScriptNode.cpp b/Scene/CScriptNode.cpp index bd7d109a..7b7c1869 100644 --- a/Scene/CScriptNode.cpp +++ b/Scene/CScriptNode.cpp @@ -16,12 +16,14 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje // Evaluate instance mpInstance = pObject; mpActiveModel = nullptr; + mpCollisionNode = new CCollisionNode(pScene, this); + mpCollisionNode->SetInheritance(true, true, false); if (mpInstance) { CScriptTemplate *pTemp = mpInstance->Template(); - mpActiveModel = mpInstance->GetDisplayModel(); + // Determine transform mPosition = mpInstance->Position(); mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName()); @@ -31,10 +33,16 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje MarkTransformChanged(); + // Determine display assets + mpActiveModel = mpInstance->GetDisplayModel(); + mModelToken = CToken(mpActiveModel); + + mpCollisionNode->SetCollision(mpInstance->GetCollision()); + + // Create preview volume node mHasValidPosition = pTemp->HasPosition(); mHasVolumePreview = (pTemp->ScaleType() == CScriptTemplate::eScaleVolume); - // Create volume preview node if (mHasVolumePreview) { EVolumeShape shape = mpInstance->VolumeShape(); @@ -87,33 +95,40 @@ std::string CScriptNode::PrefixedName() const void CScriptNode::AddToRenderer(CRenderer *pRenderer) { if (!mpInstance) return; + ERenderOptions options = pRenderer->RenderOptions(); - if (!mpActiveModel) - pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); + if (options & eDrawObjectCollision) + mpCollisionNode->AddToRenderer(pRenderer); - else + if (options & eDrawObjects) { - if (!mpActiveModel->IsBuffered()) - mpActiveModel->BufferGL(); - - if (!mpActiveModel->HasTransparency(0)) + if (!mpActiveModel) pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); else { - u32 SubmeshCount = mpActiveModel->GetSurfaceCount(); + if (!mpActiveModel->IsBuffered()) + mpActiveModel->BufferGL(); - for (u32 s = 0; s < SubmeshCount; s++) + if (!mpActiveModel->HasTransparency(0)) + pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); + + else { - if (!mpActiveModel->IsSurfaceTransparent(s, 0)) - pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); - else - pRenderer->AddTransparentMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + u32 SubmeshCount = mpActiveModel->GetSurfaceCount(); + + for (u32 s = 0; s < SubmeshCount; s++) + { + if (!mpActiveModel->IsSurfaceTransparent(s, 0)) + pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + else + pRenderer->AddTransparentMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset); + } } } } - if (IsSelected()) + if (IsSelected() && (options & ((ERenderOptions) (eDrawObjects | eDrawObjectCollision))) != 0) { pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection); @@ -217,27 +232,32 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester &Tester) } } -SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID) +SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options) { + CRay TransformedRay = Ray.Transformed(Transform().Inverse()); + SRayIntersection out; out.pNode = this; out.AssetIndex = AssetID; - CRay TransformedRay = Ray.Transformed(Transform().Inverse()); - CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); - std::pair Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay); - - if (Result.first) + if (options & eDrawObjects) { - out.Hit = true; + CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel()); + std::pair Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0)); - CVector3f HitPoint = TransformedRay.PointOnRay(Result.second); - CVector3f WorldHitPoint = Transform() * HitPoint; - out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint); + if (Result.first) + { + out.Hit = true; + + CVector3f HitPoint = TransformedRay.PointOnRay(Result.second); + CVector3f WorldHitPoint = Transform() * HitPoint; + out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint); + } + + else + out.Hit = false; } - - else - out.Hit = false; + else out.Hit = false; return out; } diff --git a/Scene/CScriptNode.h b/Scene/CScriptNode.h index 9ea376c3..e51b5a72 100644 --- a/Scene/CScriptNode.h +++ b/Scene/CScriptNode.h @@ -3,12 +3,15 @@ #include "CSceneNode.h" #include "CModelNode.h" +#include "CCollisionNode.h" #include class CScriptNode : public CSceneNode { CScriptObject *mpInstance; CModel *mpActiveModel; + CToken mModelToken; + CCollisionNode *mpCollisionNode; bool mHasValidPosition; bool mHasVolumePreview; @@ -23,7 +26,7 @@ public: void DrawAsset(ERenderOptions Options, u32 Asset); void DrawSelection(); void RayAABoxIntersectTest(CRayCollisionTester &Tester); - SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID); + SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options); bool IsVisible() const; CScriptObject* Object(); CModel* ActiveModel(); diff --git a/Scene/CStaticNode.cpp b/Scene/CStaticNode.cpp index 04bb6e2a..28535b12 100644 --- a/Scene/CStaticNode.cpp +++ b/Scene/CStaticNode.cpp @@ -88,14 +88,14 @@ void CStaticNode::RayAABoxIntersectTest(CRayCollisionTester &Tester) } } -SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID) +SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options) { SRayIntersection out; out.pNode = this; out.AssetIndex = AssetID; CRay TransformedRay = Ray.Transformed(Transform().Inverse()); - std::pair Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay); + std::pair Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0)); if (Result.first) { diff --git a/Scene/CStaticNode.h b/Scene/CStaticNode.h index 057d22cc..6ca1c60a 100644 --- a/Scene/CStaticNode.h +++ b/Scene/CStaticNode.h @@ -15,7 +15,7 @@ public: void Draw(ERenderOptions Options); void DrawAsset(ERenderOptions Options, u32 asset); void RayAABoxIntersectTest(CRayCollisionTester &Tester); - SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID); + SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options); }; #endif // CSTATICNODE_H diff --git a/UI/CSceneViewport.cpp b/UI/CSceneViewport.cpp index 1d84350c..0309db66 100644 --- a/UI/CSceneViewport.cpp +++ b/UI/CSceneViewport.cpp @@ -77,7 +77,7 @@ void CSceneViewport::SceneRayCast(const CRay& ray) return; } - SRayIntersection result = mpScene->SceneRayCast(ray); + SRayIntersection result = mpScene->SceneRayCast(ray, mpRenderer->RenderOptions()); if (result.Hit) { diff --git a/UI/CWorldEditor.cpp b/UI/CWorldEditor.cpp index 4fe1be86..a28715a9 100644 --- a/UI/CWorldEditor.cpp +++ b/UI/CWorldEditor.cpp @@ -329,22 +329,22 @@ void CWorldEditor::OnTransformSpinBoxEdited(CVector3f) // These functions are from "Go to slot" in the designer void CWorldEditor::on_ActionDrawWorld_triggered() { - mScene.SetWorld(ui->ActionDrawWorld->isChecked()); + ui->MainViewport->Renderer()->ToggleWorld(ui->ActionDrawWorld->isChecked()); } void CWorldEditor::on_ActionDrawCollision_triggered() { - mScene.SetCollision(ui->ActionDrawCollision->isChecked()); + ui->MainViewport->Renderer()->ToggleWorldCollision(ui->ActionDrawCollision->isChecked()); } void CWorldEditor::on_ActionDrawObjects_triggered() { - mScene.SetObjects(ui->ActionDrawObjects->isChecked()); + ui->MainViewport->Renderer()->ToggleObjects(ui->ActionDrawObjects->isChecked()); } void CWorldEditor::on_ActionDrawLights_triggered() { - mScene.SetLights(ui->ActionDrawLights->isChecked()); + ui->MainViewport->Renderer()->ToggleLights(ui->ActionDrawLights->isChecked()); } void CWorldEditor::on_ActionDrawSky_triggered() @@ -470,3 +470,8 @@ void CWorldEditor::on_ActionDecrementGizmo_triggered() { mGizmo.DecrementSize(); } + +void CWorldEditor::on_ActionDrawObjectCollision_triggered() +{ + ui->MainViewport->Renderer()->ToggleObjectCollision(ui->ActionDrawObjectCollision->isChecked()); +} diff --git a/UI/CWorldEditor.h b/UI/CWorldEditor.h index 504845f5..b5023d59 100644 --- a/UI/CWorldEditor.h +++ b/UI/CWorldEditor.h @@ -78,6 +78,7 @@ private slots: void on_ActionEditLayers_triggered(); void on_ActionIncrementGizmo_triggered(); void on_ActionDecrementGizmo_triggered(); + void on_ActionDrawObjectCollision_triggered(); }; #endif // CWORLDEDITOR_H diff --git a/UI/CWorldEditor.ui b/UI/CWorldEditor.ui index e7ddf2cb..2e3bc942 100644 --- a/UI/CWorldEditor.ui +++ b/UI/CWorldEditor.ui @@ -270,8 +270,9 @@ - + + @@ -535,7 +536,7 @@ Collision - 2 + 3 @@ -549,7 +550,7 @@ Objects - 3 + 2 @@ -563,7 +564,7 @@ Lights - 4 + 5 @@ -577,7 +578,7 @@ Sky - 5 + 6 @@ -705,6 +706,17 @@ Qt::WindowShortcut + + + true + + + Object Collision + + + 4 + + diff --git a/UI/CWorldEditorWindow.cpp b/UI/CWorldEditorWindow.cpp index 1670c414..f24cd883 100644 --- a/UI/CWorldEditorWindow.cpp +++ b/UI/CWorldEditorWindow.cpp @@ -176,17 +176,17 @@ void CWorldEditorWindow::on_actionBackface_culling_triggered() void CWorldEditorWindow::on_actionWorld_triggered() { - mpSceneManager->SetWorld(ui->actionWorld->isChecked()); + mpRenderer->ToggleWorld(ui->actionWorld->isChecked()); } void CWorldEditorWindow::on_actionCollision_triggered() { - mpSceneManager->SetCollision(ui->actionCollision->isChecked()); + mpRenderer->ToggleWorldCollision(ui->actionCollision->isChecked()); } void CWorldEditorWindow::on_actionObjects_triggered() { - mpSceneManager->SetObjects(ui->actionObjects->isChecked()); + mpRenderer->ToggleObjects(ui->actionObjects->isChecked()); } void CWorldEditorWindow::setupInstanceViewLayers() @@ -233,7 +233,7 @@ void CWorldEditorWindow::on_actionMaterial_Animations_triggered() void CWorldEditorWindow::on_actionLights_triggered() { - mpSceneManager->SetLights(ui->actionLights->isChecked()); + mpRenderer->ToggleLights(ui->actionLights->isChecked()); } void CWorldEditorWindow::on_actionLightingNone_triggered() diff --git a/UI/WorldEditor/WInstancesTab.cpp b/UI/WorldEditor/WInstancesTab.cpp index 9b849a03..a72ad53c 100644 --- a/UI/WorldEditor/WInstancesTab.cpp +++ b/UI/WorldEditor/WInstancesTab.cpp @@ -97,15 +97,6 @@ void WInstancesTab::OnTreeClick(QModelIndex Index) } } - // Show/Hide Node Type - else if (mpTypesModel->IndexType(Index) == CTypesInstanceModel::eNodeTypeIndex) - { - CTypesInstanceModel::ENodeType type = mpTypesModel->IndexNodeType(Index); - - if (type == CTypesInstanceModel::eScriptType) - mpScene->SetObjects(!mpScene->AreScriptObjectsEnabled()); - } - if (sender() == ui->LayersTreeView) ui->LayersTreeView->update(Index); else if (sender() == ui->TypesTreeView)