This commit is contained in:
Phillip Stephens 2021-02-07 17:22:00 -08:00
commit ddba742c9a
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
474 changed files with 11856 additions and 11850 deletions

View File

@ -5,10 +5,11 @@ set(MACOSX_DEPLOYMENT_TARGET 10.10)
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
endif() endif()
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
project(PrimeWorldEditor CXX) project(PrimeWorldEditor CXX)
option(PWE_PUBLIC_RELEASE "Enable end-user deployment configuration for PWE" OFF) option(PWE_PUBLIC_RELEASE "Enable end-user deployment configuration for PWE" ON)
if (PWE_PUBLIC_RELEASE) if (PWE_PUBLIC_RELEASE)
add_compile_definitions(PUBLIC_RELEASE=1) add_compile_definitions(PUBLIC_RELEASE=1)
message(STATUS "Enabled public release mode") message(STATUS "Enabled public release mode")

View File

@ -7,7 +7,7 @@
"inheritEnvironments": [ "msvc_x64_x64" ], "inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.12.6/msvc2017_64/lib/cmake/Qt5", "cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.14.1/msvc2017_64/lib/cmake/Qt5",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"variables": [] "variables": []
@ -19,7 +19,7 @@
"inheritEnvironments": [ "msvc_x64_x64" ], "inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.12.6/msvc2017_64/lib/cmake/Qt5", "cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.14.1/msvc2017_64/lib/cmake/Qt5",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"variables": [] "variables": []

View File

@ -20,7 +20,7 @@ VS_VERSION_INFO VERSIONINFO
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
BLOCK "041904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "Comments", PRODUCT_COMMENTS VALUE "Comments", PRODUCT_COMMENTS
VALUE "CompanyName", PRODUCT_COMPANY_NAME VALUE "CompanyName", PRODUCT_COMPANY_NAME
@ -35,6 +35,6 @@ BEGIN
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
BEGIN BEGIN
VALUE "Translation", 0x419, 1200 VALUE "Translation", 0x409, 1200
END END
END END

View File

@ -7,7 +7,7 @@
# It is encouraged to check this file into your project's VCS. Doing so will allow your cmake project to easily # It is encouraged to check this file into your project's VCS. Doing so will allow your cmake project to easily
# integrate with Dew. # integrate with Dew.
# #
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.12)
function(integrate_dew) function(integrate_dew)
# #
@ -17,6 +17,13 @@ function(integrate_dew)
return() return()
endif() endif()
#
# Advise the user that setting the build type is necessary for debug dependencies.
#
if (NOT CMAKE_BUILD_TYPE)
message(WARNING "CMAKE_BUILD_TYPE is not set. Dew will build release dependencies by default.")
endif()
# #
# Acquaint CMake with dew prefix # Acquaint CMake with dew prefix
# #
@ -41,7 +48,8 @@ function(integrate_dew)
message(FATAL_ERROR "Failed to install dew with pip: result: ${install_dew_result}.") message(FATAL_ERROR "Failed to install dew with pip: result: ${install_dew_result}.")
endif() endif()
message(STATUS "Building dew dependencies") message(STATUS "Building dew dependencies")
execute_process(COMMAND "${Python3_EXECUTABLE}" -m dew update --build-type ${dew_cmake_prefix_suffix} execute_process(COMMAND "${Python3_EXECUTABLE}" -m dew update --CC "${CMAKE_C_COMPILER}"
--CXX "${CMAKE_CXX_COMPILER}" --build-type ${dew_cmake_prefix_suffix}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE dew_res) RESULT_VARIABLE dew_res)
if(NOT dew_res EQUAL 0) if(NOT dew_res EQUAL 0)
@ -65,33 +73,27 @@ function(integrate_dew)
# Check if we have already added the dew directory to CMAKE_PREFIX_PATH # Check if we have already added the dew directory to CMAKE_PREFIX_PATH
# #
set(needs_new_prefix TRUE) set(needs_new_prefix TRUE)
foreach (path ${CMAKE_PREFIX_PATH}) if ("${dew_cmake_prefix_path}" IN_LIST CMAKE_PREFIX_PATH)
if (path STREQUAL "${dew_cmake_prefix_path}") set(needs_new_prefix FALSE)
set(needs_new_prefix FALSE) endif()
break()
endif()
endforeach()
# #
# Check if we have already added the dew cmake module directory to CMAKE_MODULE_PATH # Check if we have already added the dew cmake module directory to CMAKE_MODULE_PATH
# #
set(needs_new_module_path TRUE) set(needs_new_module_path TRUE)
foreach (path ${CMAKE_MODULE_PATH}) if ("${dew_cmake_module_path}" IN_LIST CMAKE_MODULE_PATH)
if (path STREQUAL "${dew_cmake_module_path}") set(needs_new_module_path FALSE)
set(needs_new_module_path FALSE) endif()
break()
endif()
endforeach()
# #
# Add dew directory to CMAKE_PREFIX_PATH if necesary # Add dew directory to CMAKE_PREFIX_PATH if necessary
# #
if ("${needs_new_prefix}") if ("${needs_new_prefix}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${dew_cmake_prefix_path}" CACHE PATH "" FORCE) set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${dew_cmake_prefix_path}" CACHE PATH "" FORCE)
endif() endif()
# #
# Add dew cmake module directory to CMAKE_MODULE_PATH if necesary # Add dew cmake module directory to CMAKE_MODULE_PATH if necessary
# #
if ("${needs_new_module_path}") if ("${needs_new_module_path}")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${dew_cmake_module_path}" CACHE PATH "" FORCE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${dew_cmake_module_path}" CACHE PATH "" FORCE)

View File

@ -28,7 +28,7 @@
"url": "https://github.com/AxioDL/nod", "url": "https://github.com/AxioDL/nod",
"type": "git", "type": "git",
"head": "master", "head": "master",
"ref": "a1284ae06586b958f36b8ecaba29390835ed2820" "ref": "f147e1235646b849f78a8574a6d554214b70792d"
}, },
{ {
"name": "lzokay", "name": "lzokay",

View File

@ -0,0 +1,88 @@
#!/bin/bash
###############################################################
# Uses LXD to create an Ubuntu Xenial container and produce #
# a reasonably portable AppImage of PrimeWorldEditor. #
###############################################################
set -e
CMAKE_VERSION=3.15.5
CONTAINER_NAME=pwe-ci
# Set up container, deleting existing if necessary
if lxc info $CONTAINER_NAME >& /dev/null
then
lxc delete $CONTAINER_NAME --force
fi
lxc init ubuntu:16.04 $CONTAINER_NAME
# Inject build script
lxc file push - $CONTAINER_NAME/root/dobuild.sh <<END
#!/bin/bash
set -e
# PWE build script for Ubuntu 16.04 LTS (Xenial)
# Install build dependencies
apt update
apt -y install build-essential software-properties-common python-software-properties
add-apt-repository -y ppa:ubuntu-toolchain-r/test
add-apt-repository -y ppa:deadsnakes/ppa
add-apt-repository -y ppa:beineri/opt-qt-5.12.3-xenial
apt update
apt -y install g++-8 curl git ninja-build libclang-6.0-dev python3.6 python3-pip zlib1g-dev qt512tools qt512svg libglu1-mesa-dev
# Expose Qt 5.12
export PATH=$PATH:/bin:/opt/qt512/bin
# Doing everything in root is fine
cd /
# Install recent CMake
curl -OL https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.sh
sh cmake-$CMAKE_VERSION-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
# Get linuxdeployqt
curl -OL https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod +x linuxdeployqt-continuous-x86_64.AppImage
/linuxdeployqt-continuous-x86_64.AppImage --appimage-extract
# Cleanup
rm -rf PrimeWorldEditor{-build,-appdir,}
# Clone repository
git clone https://github.com/AxioDL/PrimeWorldEditor
pushd PrimeWorldEditor
git submodule update --recursive --init
popd
# Build
mkdir -p PrimeWorldEditor{-build,-appdir}
pushd PrimeWorldEditor-build
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
-DPWE_PUBLIC_RELEASE=On -DCMAKE_INSTALL_PREFIX=/PrimeWorldEditor-appdir/usr \
-DCMAKE_EXECUTE_PROCESS_COMMAND_ECHO=STDERR /PrimeWorldEditor
ninja install
popd
strip -s /PrimeWorldEditor-appdir/usr/bin/PrimeWorldEditor
cp PrimeWorldEditor-appdir/usr/share/icons/hicolor/256x256/apps/PrimeWorldEditor.png PrimeWorldEditor-appdir/
cp PrimeWorldEditor-appdir/usr/share/applications/io.github.arukibree.PrimeWorldEditor.desktop PrimeWorldEditor-appdir/
/squashfs-root/usr/bin/linuxdeployqt /PrimeWorldEditor-appdir/usr/bin/PrimeWorldEditor -appimage
END
# Start container
lxc start $CONTAINER_NAME
# Wait for network
lxc exec $CONTAINER_NAME -- bash -c "while ! systemctl status network.target; do sleep 1; done"
# Run build script
lxc exec $CONTAINER_NAME -t -- bash /root/dobuild.sh
# Retrieve AppImage
lxc file pull $CONTAINER_NAME/Prime_World_Editor-x86_64.AppImage .
# Cleanup
lxc delete $CONTAINER_NAME --force

53
dist/linux-arch/PKGBUILD vendored Normal file
View File

@ -0,0 +1,53 @@
# Maintainer: Jack Andersen <jackoalan@gmail.com>
pkgbase=pwe-git
pkgname=$pkgbase
pkgver=v1.2.5.r3.56ecceb9
pkgrel=1
pkgdesc='An editor for games by Retro Studios'
arch=('x86_64')
url='https://github.com/arukibree/PrimeWorldEditor'
license=('MIT')
depends=('qt5-base' 'zlib')
makedepends=('clang' 'python' 'ninja')
source=('git+https://github.com/AxioDL/PrimeWorldEditor.git'
'git+https://github.com/AxioDL/LibCommon.git'
'git+https://github.com/AxioDL/CodeGen.git')
sha256sums=('SKIP' 'SKIP' 'SKIP')
pkgver() {
cd PrimeWorldEditor
git describe | sed 's/-/.r/; s/-g/./'
}
prepare() {
if [[ -d build ]]; then
rm -rf build
fi
mkdir build
ln -s $startdir/LibCommon $startdir/LibCommon.git
ln -s $startdir/CodeGen $startdir/CodeGen.git
cd PrimeWorldEditor
git submodule init
git config submodule.LibCommon.url $srcdir/LibCommon
git submodule update
cd externals/LibCommon
git submodule init
git config submodule.CodeGen.url $srcdir/CodeGen
git submodule update
}
build() {
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX='/usr' ../PrimeWorldEditor
ninja
}
package() {
DESTDIR="${pkgdir}" ninja -C build install
}

2
externals/LibCommon vendored

@ -1 +1 @@
Subproject commit 8524191df613b9149369ed8578a6c4ea3038552b Subproject commit 2c2e2bad43b4566e1de5452a23673f0c9d5202f7

View File

@ -7,9 +7,7 @@ CAreaAttributes::CAreaAttributes(CScriptObject *pObj)
SetObject(pObj); SetObject(pObj);
} }
CAreaAttributes::~CAreaAttributes() CAreaAttributes::~CAreaAttributes() = default;
{
}
void CAreaAttributes::SetObject(CScriptObject *pObj) void CAreaAttributes::SetObject(CScriptObject *pObj)
{ {

View File

@ -13,14 +13,14 @@ class CAreaAttributes
CAssetRef mOverrideSky; CAssetRef mOverrideSky;
public: public:
CAreaAttributes(CScriptObject *pObj); explicit CAreaAttributes(CScriptObject *pObj);
~CAreaAttributes(); ~CAreaAttributes();
void SetObject(CScriptObject *pObj); void SetObject(CScriptObject *pObj);
bool IsLayerEnabled() const; bool IsLayerEnabled() const;
bool IsSkyEnabled() const; bool IsSkyEnabled() const;
CModel* SkyModel() const; CModel* SkyModel() const;
inline CScriptObject* Instance() const { return mpObject; } CScriptObject* Instance() const { return mpObject; }
}; };
#endif // CAREAATTRIBUTES_H #endif // CAREAATTRIBUTES_H

View File

@ -19,37 +19,35 @@ void CAudioManager::LoadAssets()
// Load/sort all audio groups // Load/sort all audio groups
for (TResourceIterator<EResourceType::AudioGroup> It(mpProject->ResourceStore()); It; ++It) for (TResourceIterator<EResourceType::AudioGroup> It(mpProject->ResourceStore()); It; ++It)
{ {
CAudioGroup *pGroup = (CAudioGroup*) It->Load(); if (auto* pGroup = static_cast<CAudioGroup*>(It->Load()))
if (pGroup) mAudioGroups.push_back(pGroup); mAudioGroups.emplace_back(pGroup);
} }
std::sort(mAudioGroups.begin(), mAudioGroups.end(), [](CAudioGroup *pLeft, CAudioGroup *pRight) -> bool { std::sort(mAudioGroups.begin(), mAudioGroups.end(), [](const CAudioGroup *pLeft, const CAudioGroup *pRight) {
return pLeft->GroupID() < pRight->GroupID(); return pLeft->GroupID() < pRight->GroupID();
}); });
// Create SFX Define ID -> AGSC map // Create SFX Define ID -> AGSC map
for (uint iGrp = 0; iGrp < mAudioGroups.size(); iGrp++) for (CAudioGroup* group : mAudioGroups)
{ {
CAudioGroup *pGroup = mAudioGroups[iGrp]; for (size_t iSnd = 0; iSnd < group->NumSoundDefineIDs(); iSnd++)
for (uint iSnd = 0; iSnd < pGroup->NumSoundDefineIDs(); iSnd++)
{ {
uint16 DefineID = pGroup->SoundDefineIDByIndex(iSnd); const uint16 DefineID = group->SoundDefineIDByIndex(iSnd);
ASSERT(mSfxIdMap.find(DefineID) == mSfxIdMap.end()); ASSERT(mSfxIdMap.find(DefineID) == mSfxIdMap.cend());
mSfxIdMap[DefineID] = pGroup; mSfxIdMap.insert_or_assign(DefineID, group);
} }
} }
// Load audio lookup table + sfx name list // Load audio lookup table + sfx name list
TString AudioLookupName = (mpProject->Game() < EGame::EchoesDemo ? "sound_lookup" : "sound_lookup_ATBL"); const std::string_view AudioLookupName = mpProject->Game() < EGame::EchoesDemo ? "sound_lookup" : "sound_lookup_ATBL";
CAssetID AudioLookupID = mpProject->FindNamedResource(AudioLookupName); const CAssetID AudioLookupID = mpProject->FindNamedResource(AudioLookupName);
if (AudioLookupID.IsValid()) if (AudioLookupID.IsValid())
mpAudioLookupTable = mpProject->ResourceStore()->LoadResource<CAudioLookupTable>(AudioLookupID); mpAudioLookupTable = mpProject->ResourceStore()->LoadResource<CAudioLookupTable>(AudioLookupID);
if (mpProject->Game() >= EGame::EchoesDemo) if (mpProject->Game() >= EGame::EchoesDemo)
{ {
CAssetID SfxNameListID = mpProject->FindNamedResource("audio_name_lookup_STLC"); const CAssetID SfxNameListID = mpProject->FindNamedResource("audio_name_lookup_STLC");
if (SfxNameListID.IsValid()) if (SfxNameListID.IsValid())
mpSfxNameList = mpProject->ResourceStore()->LoadResource<CStringList>(SfxNameListID); mpSfxNameList = mpProject->ResourceStore()->LoadResource<CStringList>(SfxNameListID);
@ -64,7 +62,7 @@ void CAudioManager::ClearAssets()
mSfxIdMap.clear(); mSfxIdMap.clear();
} }
SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID) SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID) const
{ {
SSoundInfo Out; SSoundInfo Out;
Out.SoundID = SoundID; Out.SoundID = SoundID;
@ -73,8 +71,8 @@ SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID)
if (Out.DefineID != 0xFFFF) if (Out.DefineID != 0xFFFF)
{ {
auto Iter = mSfxIdMap.find(Out.DefineID); const auto Iter = mSfxIdMap.find(Out.DefineID);
if (Iter != mSfxIdMap.end()) if (Iter != mSfxIdMap.cend())
Out.pAudioGroup = Iter->second; Out.pAudioGroup = Iter->second;
if (mpProject->Game() >= EGame::EchoesDemo) if (mpProject->Game() >= EGame::EchoesDemo)
@ -84,18 +82,18 @@ SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID)
return Out; return Out;
} }
void CAudioManager::LogSoundInfo(uint32 SoundID) void CAudioManager::LogSoundInfo(uint32 SoundID) const
{ {
SSoundInfo SoundInfo = GetSoundInfo(SoundID); const SSoundInfo SoundInfo = GetSoundInfo(SoundID);
if (SoundInfo.DefineID != 0xFFFF) if (SoundInfo.DefineID == 0xFFFF)
{ return;
if (mpProject->Game() >= EGame::EchoesDemo)
debugf("Sound Name: %s", *SoundInfo.Name);
debugf("Sound ID: 0x%04x", SoundInfo.SoundID); if (mpProject->Game() >= EGame::EchoesDemo)
debugf("Define ID: 0x%04x", SoundInfo.DefineID); debugf("Sound Name: %s", *SoundInfo.Name);
debugf("Audio Group: %s", *SoundInfo.pAudioGroup->Entry()->Name());
debugf(""); debugf("Sound ID: 0x%04x", SoundInfo.SoundID);
} debugf("Define ID: 0x%04x", SoundInfo.DefineID);
debugf("Audio Group: %s", *SoundInfo.pAudioGroup->Entry()->Name());
debugf("");
} }

View File

@ -26,11 +26,11 @@ class CAudioManager
std::unordered_map<uint16, CAudioGroup*> mSfxIdMap; std::unordered_map<uint16, CAudioGroup*> mSfxIdMap;
public: public:
CAudioManager(CGameProject *pProj); explicit CAudioManager(CGameProject *pProj);
void LoadAssets(); void LoadAssets();
void ClearAssets(); void ClearAssets();
SSoundInfo GetSoundInfo(uint32 SoundID); SSoundInfo GetSoundInfo(uint32 SoundID) const;
void LogSoundInfo(uint32 SoundID); void LogSoundInfo(uint32 SoundID) const;
}; };
#endif // CAUDIOMANAGER #endif // CAUDIOMANAGER

View File

@ -4,12 +4,12 @@
#include "Core/Resource/Area/CGameArea.h" #include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Script/Property/Properties.h" #include "Core/Resource/Script/Property/Properties.h"
enum EWorldLightingOptions enum class EWorldLightingOptions
{ {
eUnknown1 = 0, Unknown1,
eNormalLighting = 1, NormalLighting,
eUnknown2 = 2, Unknown2,
eDisableWorldLighting = 3 DisableWorldLighting,
}; };
class CLightParameters class CLightParameters
@ -35,14 +35,14 @@ public:
} }
} }
inline int LightLayerIndex() const int LightLayerIndex() const
{ {
return mLightLayer.IsValid() ? mLightLayer.Get() : 0; return mLightLayer.IsValid() ? mLightLayer.Get() : 0;
} }
inline EWorldLightingOptions WorldLightingOptions() const EWorldLightingOptions WorldLightingOptions() const
{ {
return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : eNormalLighting; return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : EWorldLightingOptions::NormalLighting;
} }
}; };

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.12)
project(pwe_core CXX C) project(pwe_core CXX C)
find_package(tinyxml2 CONFIG REQUIRED) find_package(tinyxml2 CONFIG REQUIRED)
find_package(nod CONFIG REQUIRED)
find_package(logvisor CONFIG REQUIRED) find_package(logvisor CONFIG REQUIRED)
find_package(nod CONFIG REQUIRED)
find_package(lzokay CONFIG REQUIRED) find_package(lzokay CONFIG REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
find_package(assimp CONFIG REQUIRED) find_package(assimp CONFIG REQUIRED)

View File

@ -310,13 +310,13 @@ void CMayaSpline::CalculateHermiteCoefficients(const std::vector<CVector2f>& kCo
const CVector2f& kTangentB = kControlPoints[2]; const CVector2f& kTangentB = kControlPoints[2];
const CVector2f& kKnotB = kControlPoints[3]; const CVector2f& kKnotB = kControlPoints[3];
CVector2f Range = kKnotB - kKnotA; [[maybe_unused]] const CVector2f Range = kKnotB - kKnotA;
CVector2f KnotAToTangentA = kTangentA - kKnotA; const CVector2f KnotAToTangentA = kTangentA - kKnotA;
float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X); const float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X);
CVector2f KnotBToTangentB = kKnotB - kTangentB; const CVector2f KnotBToTangentB = kKnotB - kTangentB;
float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X); [[maybe_unused]] const float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X);
#if 0 #if 0
// todo: better organization and better variable names // todo: better organization and better variable names

View File

@ -22,21 +22,21 @@ public:
class CMayaSpline class CMayaSpline
{ {
uint mPreInfinity; // 0x00 uint mPreInfinity = 0; // 0x00
uint mPostInfinity; // 0x04 uint mPostInfinity = 0; // 0x04
std::vector<CMayaSplineKnot> mKnots; // 0x08, 0x0C, 0x10 std::vector<CMayaSplineKnot> mKnots; // 0x08, 0x0C, 0x10
uint mClampMode; // 0x14 - clamp mode uint mClampMode = 0; // 0x14 - clamp mode
float mMinAmplitude; // 0x18 float mMinAmplitude = 0.0f; // 0x18
float mMaxAmplitude; // 0x1C float mMaxAmplitude = 0.0f; // 0x1C
mutable int mCachedKnotIndex; // 0x20 mutable int mCachedKnotIndex = 0; // 0x20
mutable int mUnknown1; // 0x24 mutable int mUnknown1 = 0; // 0x24
mutable uint8 mDirtyFlags; // 0x28 mutable uint8 mDirtyFlags = 0; // 0x28
mutable float mCachedMinTime; // 0x2C mutable float mCachedMinTime = 0.0f; // 0x2C
mutable float mCachedHermiteCoefficients[4]; // 0x30, 0x34, 0x38, 0x3C mutable float mCachedHermiteCoefficients[4] = {}; // 0x30, 0x34, 0x38, 0x3C
public: public:
CMayaSpline() {} CMayaSpline() = default;
uint GetKnotCount() const; uint GetKnotCount() const;
const std::vector<CMayaSplineKnot>& GetKnots() const; const std::vector<CMayaSplineKnot>& GetKnots() const;
float GetMinTime() const; float GetMinTime() const;

View File

@ -6,14 +6,11 @@ CRayCollisionTester::CRayCollisionTester(const CRay& rkRay)
{ {
} }
CRayCollisionTester::~CRayCollisionTester() CRayCollisionTester::~CRayCollisionTester() = default;
{
}
void CRayCollisionTester::AddNode(CSceneNode *pNode, uint32 ComponentIndex, float Distance) void CRayCollisionTester::AddNode(CSceneNode *pNode, uint32 ComponentIndex, float Distance)
{ {
mBoxIntersectList.emplace_back(SRayIntersection()); SRayIntersection& rIntersection = mBoxIntersectList.emplace_back();
SRayIntersection& rIntersection = mBoxIntersectList.back();
rIntersection.pNode = pNode; rIntersection.pNode = pNode;
rIntersection.ComponentIndex = ComponentIndex; rIntersection.ComponentIndex = ComponentIndex;
rIntersection.Distance = Distance; rIntersection.Distance = Distance;
@ -24,46 +21,44 @@ void CRayCollisionTester::AddNodeModel(CSceneNode *pNode, CBasicModel *pModel)
// Check each of the model's surfaces and queue them for further testing if they hit // Check each of the model's surfaces and queue them for further testing if they hit
for (uint32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++) for (uint32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
{ {
std::pair<bool,float> SurfResult = pModel->GetSurfaceAABox(iSurf).Transformed(pNode->Transform()).IntersectsRay(mRay); const auto [intersects, distance] = pModel->GetSurfaceAABox(iSurf).Transformed(pNode->Transform()).IntersectsRay(mRay);
if (SurfResult.first) if (intersects)
AddNode(pNode, iSurf, SurfResult.second); AddNode(pNode, iSurf, distance);
} }
} }
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& rkViewInfo) SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& rkViewInfo)
{ {
// Sort nodes by distance from ray // Sort nodes by distance from ray
mBoxIntersectList.sort( mBoxIntersectList.sort([](const auto& rkLeft, const auto& rkRight) {
[](const SRayIntersection& rkLeft, const SRayIntersection& rkRight) -> bool return rkLeft.Distance < rkRight.Distance;
{
return (rkLeft.Distance < rkRight.Distance);
}); });
// Now do more precise intersection tests on geometry // Now do more precise intersection tests on geometry
SRayIntersection Result; SRayIntersection Result;
Result.Hit = false; Result.Hit = false;
for (auto iNode = mBoxIntersectList.begin(); iNode != mBoxIntersectList.end(); iNode++) for (const auto& rIntersection : mBoxIntersectList)
{ {
SRayIntersection& rIntersection = *iNode;
// If we have a result, and the distance for the bounding box hit is further than the current result distance // If we have a result, and the distance for the bounding box hit is further than the current result distance
// then we know that every remaining node is further away and there is no chance of finding a closer hit. // then we know that every remaining node is further away and there is no chance of finding a closer hit.
if ((Result.Hit) && (Result.Distance < rIntersection.Distance)) if (Result.Hit && Result.Distance < rIntersection.Distance)
break; break;
// Otherwise, more intersection tests... // Otherwise, more intersection tests...
CSceneNode *pNode = rIntersection.pNode; CSceneNode *pNode = rIntersection.pNode;
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, rIntersection.ComponentIndex, rkViewInfo); const SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, rIntersection.ComponentIndex, rkViewInfo);
if (MidResult.Hit) if (MidResult.Hit)
{ {
if ((!Result.Hit) || (MidResult.Distance <= Result.Distance)) if (!Result.Hit || MidResult.Distance <= Result.Distance)
Result = MidResult; Result = MidResult;
} }
} }
if (Result.Hit) Result.HitPoint = mRay.PointOnRay(Result.Distance); if (Result.Hit)
Result.HitPoint = mRay.PointOnRay(Result.Distance);
return Result; return Result;
} }

View File

@ -109,11 +109,11 @@ void GenerateAssetNames(CGameProject *pProj)
// Generate names for package named resources // Generate names for package named resources
debugf("Processing packages"); debugf("Processing packages");
for (uint32 iPkg = 0; iPkg < pProj->NumPackages(); iPkg++) for (size_t iPkg = 0; iPkg < pProj->NumPackages(); iPkg++)
{ {
CPackage *pPkg = pProj->PackageByIndex(iPkg); CPackage *pPkg = pProj->PackageByIndex(iPkg);
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
if (rkRes.Name.EndsWith("NODEPEND")) continue; if (rkRes.Name.EndsWith("NODEPEND")) continue;
@ -166,17 +166,17 @@ void GenerateAssetNames(CGameProject *pProj)
ApplyGeneratedName(pSkyEntry, WorldDir + "sky/cooked/", WorldName + "_sky"); ApplyGeneratedName(pSkyEntry, WorldDir + "sky/cooked/", WorldName + "_sky");
// Move sky textures // Move sky textures
for (uint32 iSet = 0; iSet < pSkyModel->GetMatSetCount(); iSet++) for (size_t iSet = 0; iSet < pSkyModel->GetMatSetCount(); iSet++)
{ {
CMaterialSet *pSet = pSkyModel->GetMatSet(iSet); CMaterialSet *pSet = pSkyModel->GetMatSet(iSet);
for (uint32 iMat = 0; iMat < pSet->NumMaterials(); iMat++) for (size_t mat = 0; mat < pSet->NumMaterials(); mat++)
{ {
CMaterial *pMat = pSet->MaterialByIndex(iMat, true); CMaterial *pMat = pSet->MaterialByIndex(mat, true);
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++) for (size_t pass = 0; pass < pMat->PassCount(); pass++)
{ {
CMaterialPass *pPass = pMat->Pass(iPass); CMaterialPass *pPass = pMat->Pass(pass);
if (pPass->Texture()) if (pPass->Texture())
ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + "sky/sourceimages/", pPass->Texture()->Entry()->Name()); ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + "sky/sourceimages/", pPass->Texture()->Entry()->Name());
@ -198,7 +198,7 @@ void GenerateAssetNames(CGameProject *pProj)
} }
// Areas // Areas
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++) for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
{ {
// Determine area name // Determine area name
TString AreaName = pWorld->AreaInternalName(iArea); TString AreaName = pWorld->AreaInternalName(iArea);
@ -209,7 +209,9 @@ void GenerateAssetNames(CGameProject *pProj)
// Rename area stuff // Rename area stuff
CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID); CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID);
if (!pAreaEntry) continue; // Some DKCR worlds reference areas that don't exist // Some DKCR worlds reference areas that don't exist
if (!pAreaEntry)
continue;
ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName); ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName);
CStringTable *pAreaNameTable = pWorld->AreaName(iArea); CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
@ -237,12 +239,12 @@ void GenerateAssetNames(CGameProject *pProj)
uint32 LightmapNum = 0; uint32 LightmapNum = 0;
CMaterialSet *pMaterials = pArea->Materials(); CMaterialSet *pMaterials = pArea->Materials();
for (uint32 iMat = 0; iMat < pMaterials->NumMaterials(); iMat++) for (size_t iMat = 0; iMat < pMaterials->NumMaterials(); iMat++)
{ {
CMaterial *pMat = pMaterials->MaterialByIndex(iMat, true); CMaterial *pMat = pMaterials->MaterialByIndex(iMat, true);
bool FoundLightmap = false; bool FoundLightmap = false;
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++) for (size_t iPass = 0; iPass < pMat->PassCount(); iPass++)
{ {
CMaterialPass *pPass = pMat->Pass(iPass); CMaterialPass *pPass = pMat->Pass(iPass);
@ -278,11 +280,11 @@ void GenerateAssetNames(CGameProject *pProj)
} }
// Generate names from script instance names // Generate names from script instance names
for (uint32 iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++) for (size_t iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++)
{ {
CScriptLayer *pLayer = pArea->ScriptLayer(iLyr); CScriptLayer *pLayer = pArea->ScriptLayer(iLyr);
for (uint32 iInst = 0; iInst < pLayer->NumInstances(); iInst++) for (size_t iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{ {
CScriptObject* pInst = pLayer->InstanceByIndex(iInst); CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
CStructProperty* pProperties = pInst->Template()->Properties(); CStructProperty* pProperties = pInst->Template()->Properties();
@ -407,30 +409,31 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<EResourceType::Model> It(pStore); It; ++It) for (TResourceIterator<EResourceType::Model> It(pStore); It; ++It)
{ {
CModel *pModel = (CModel*) It->Load(); CModel *pModel = (CModel*) It->Load();
uint32 LightmapNum = 0; size_t LightmapNum = 0;
for (uint32 iSet = 0; iSet < pModel->GetMatSetCount(); iSet++) for (size_t iSet = 0; iSet < pModel->GetMatSetCount(); iSet++)
{ {
CMaterialSet *pSet = pModel->GetMatSet(iSet); CMaterialSet *pSet = pModel->GetMatSet(iSet);
for (uint32 iMat = 0; iMat < pSet->NumMaterials(); iMat++) for (size_t iMat = 0; iMat < pSet->NumMaterials(); iMat++)
{ {
CMaterial *pMat = pSet->MaterialByIndex(iMat, true); CMaterial *pMat = pSet->MaterialByIndex(iMat, true);
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++) for (size_t iPass = 0; iPass < pMat->PassCount(); iPass++)
{ {
CMaterialPass *pPass = pMat->Pass(iPass); CMaterialPass *pPass = pMat->Pass(iPass);
bool IsLightmap = ( (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) || const bool IsLightmap = (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) ||
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF") ); (pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF");
if (IsLightmap) if (IsLightmap)
{ {
CTexture *pLightmapTex = pPass->Texture(); CTexture *pLightmapTex = pPass->Texture();
CResourceEntry *pTexEntry = pLightmapTex->Entry(); CResourceEntry *pTexEntry = pLightmapTex->Entry();
if (pTexEntry->IsNamed() || pTexEntry->IsCategorized()) continue; if (pTexEntry->IsNamed() || pTexEntry->IsCategorized())
continue;
TString TexName = TString::Format("%s_lightmap%d", *It->Name(), LightmapNum); TString TexName = TString::Format("%s_lightmap%zu", *It->Name(), LightmapNum);
ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName); ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName);
pTexEntry->SetHidden(true); pTexEntry->SetHidden(true);
LightmapNum++; LightmapNum++;
@ -463,23 +466,23 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<EResourceType::AudioMacro> It(pStore); It; ++It) for (TResourceIterator<EResourceType::AudioMacro> It(pStore); It; ++It)
{ {
CAudioMacro *pMacro = (CAudioMacro*) It->Load(); const auto* pMacro = static_cast<CAudioMacro*>(It->Load());
TString MacroName = pMacro->MacroName(); TString MacroName = pMacro->MacroName();
ApplyGeneratedName(*It, kSfxDir, MacroName); ApplyGeneratedName(*It, kSfxDir, MacroName);
for (uint32 iSamp = 0; iSamp < pMacro->NumSamples(); iSamp++) for (size_t iSamp = 0; iSamp < pMacro->NumSamples(); iSamp++)
{ {
CAssetID SampleID = pMacro->SampleByIndex(iSamp); const CAssetID SampleID = pMacro->SampleByIndex(iSamp);
CResourceEntry *pSample = pStore->FindEntry(SampleID); CResourceEntry* pSample = pStore->FindEntry(SampleID);
if (pSample && !pSample->IsNamed()) if (pSample != nullptr && !pSample->IsNamed())
{ {
TString SampleName; TString SampleName;
if (pMacro->NumSamples() == 1) if (pMacro->NumSamples() == 1)
SampleName = MacroName; SampleName = MacroName;
else else
SampleName = TString::Format("%s_%d", *MacroName, iSamp); SampleName = TString::Format("%s_%zu", *MacroName, iSamp);
ApplyGeneratedName(pSample, kSfxDir, SampleName); ApplyGeneratedName(pSample, kSfxDir, SampleName);
} }
@ -500,9 +503,9 @@ void GenerateAssetNames(CGameProject *pProj)
{ {
TString SetDir = It->DirectoryPath(); TString SetDir = It->DirectoryPath();
TString NewSetName; TString NewSetName;
CAnimSet *pSet = (CAnimSet*) It->Load(); auto* pSet = static_cast<CAnimSet*>(It->Load());
for (uint32 iChar = 0; iChar < pSet->NumCharacters(); iChar++) for (size_t iChar = 0; iChar < pSet->NumCharacters(); iChar++)
{ {
const SSetCharacter *pkChar = pSet->Character(iChar); const SSetCharacter *pkChar = pSet->Character(iChar);
@ -524,10 +527,8 @@ void GenerateAssetNames(CGameProject *pProj)
} }
} }
for (uint32 iOverlay = 0; iOverlay < pkChar->OverlayModels.size(); iOverlay++) for (const auto& rkOverlay : pkChar->OverlayModels)
{ {
const SOverlayModel& rkOverlay = pkChar->OverlayModels[iOverlay];
if (rkOverlay.ModelID.IsValid() || rkOverlay.SkinID.IsValid()) if (rkOverlay.ModelID.IsValid() || rkOverlay.SkinID.IsValid())
{ {
TString TypeName = ( TString TypeName = (
@ -561,17 +562,16 @@ void GenerateAssetNames(CGameProject *pProj)
std::set<CAnimPrimitive> AnimPrimitives; std::set<CAnimPrimitive> AnimPrimitives;
pSet->GetUniquePrimitives(AnimPrimitives); pSet->GetUniquePrimitives(AnimPrimitives);
for (auto It = AnimPrimitives.begin(); It != AnimPrimitives.end(); It++) for (const auto& rkPrim : AnimPrimitives)
{ {
const CAnimPrimitive& rkPrim = *It;
CAnimation *pAnim = rkPrim.Animation(); CAnimation *pAnim = rkPrim.Animation();
if (pAnim) if (pAnim != nullptr)
{ {
ApplyGeneratedName(pAnim->Entry(), SetDir, rkPrim.Name()); ApplyGeneratedName(pAnim->Entry(), SetDir, rkPrim.Name());
CAnimEventData *pEvents = pAnim->EventData(); CAnimEventData *pEvents = pAnim->EventData();
if (pEvents) if (pEvents != nullptr)
ApplyGeneratedName(pEvents->Entry(), SetDir, rkPrim.Name()); ApplyGeneratedName(pEvents->Entry(), SetDir, rkPrim.Name());
} }
} }
@ -586,12 +586,14 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<EResourceType::StringTable> It(pStore); It; ++It) for (TResourceIterator<EResourceType::StringTable> It(pStore); It; ++It)
{ {
if (It->IsNamed()) continue; if (It->IsNamed())
CStringTable *pString = (CStringTable*) It->Load(); continue;
auto *pString = static_cast<CStringTable*>(It->Load());
TString String; TString String;
for (uint32 iStr = 0; iStr < pString->NumStrings() && String.IsEmpty(); iStr++) for (size_t iStr = 0; iStr < pString->NumStrings() && String.IsEmpty(); iStr++)
String = CStringTable::StripFormatting( pString->GetString(ELanguage::English, iStr) ).Trimmed(); String = CStringTable::StripFormatting(pString->GetString(ELanguage::English, iStr)).Trimmed();
if (!String.IsEmpty()) if (!String.IsEmpty())
{ {
@ -611,31 +613,33 @@ void GenerateAssetNames(CGameProject *pProj)
debugf("Processing scans"); debugf("Processing scans");
for (TResourceIterator<EResourceType::Scan> It(pStore); It; ++It) for (TResourceIterator<EResourceType::Scan> It(pStore); It; ++It)
{ {
if (It->IsNamed()) continue; if (It->IsNamed())
CScan *pScan = (CScan*) It->Load(); continue;
auto* pScan = static_cast<CScan*>(It->Load());
TString ScanName; TString ScanName;
if (ScanName.IsEmpty()) if (ScanName.IsEmpty())
{ {
CAssetID StringID = pScan->ScanStringPropertyRef().Get(); const CAssetID StringID = pScan->ScanStringPropertyRef().Get();
CStringTable *pString = (CStringTable*) gpResourceStore->LoadResource(StringID, EResourceType::StringTable); if (const auto* pString = static_cast<CStringTable*>(gpResourceStore->LoadResource(StringID, EResourceType::StringTable)))
if (pString) ScanName = pString->Entry()->Name(); ScanName = pString->Entry()->Name();
} }
ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName); ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName);
if (!ScanName.IsEmpty() && pProj->Game() <= EGame::Prime) if (!ScanName.IsEmpty() && pProj->Game() <= EGame::Prime)
{ {
const SScanParametersMP1& kParms = *static_cast<SScanParametersMP1*>(pScan->ScanData().DataPointer()); const auto& kParms = *static_cast<SScanParametersMP1*>(pScan->ScanData().DataPointer());
CResourceEntry *pEntry = pStore->FindEntry(kParms.GuiFrame); if (CResourceEntry* pEntry = pStore->FindEntry(kParms.GuiFrame))
if (pEntry) ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), "ScanFrame"); ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), "ScanFrame");
for (uint32 iImg = 0; iImg < 4; iImg++) for (size_t iImg = 0; iImg < kParms.ScanImages.size(); iImg++)
{ {
CAssetID ImageID = kParms.ScanImages[iImg].Texture; const CAssetID ImageID = kParms.ScanImages[iImg].Texture;
CResourceEntry *pImgEntry = pStore->FindEntry(ImageID); if (CResourceEntry* pImgEntry = pStore->FindEntry(ImageID))
if (pImgEntry) ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%d", *ScanName, iImg)); ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%zu", *ScanName, iImg));
} }
} }
} }
@ -646,15 +650,12 @@ void GenerateAssetNames(CGameProject *pProj)
debugf("Processing fonts"); debugf("Processing fonts");
for (TResourceIterator<EResourceType::Font> It(pStore); It; ++It) for (TResourceIterator<EResourceType::Font> It(pStore); It; ++It)
{ {
CFont *pFont = (CFont*) It->Load(); if (auto* pFont = static_cast<CFont*>(It->Load()))
if (pFont)
{ {
ApplyGeneratedName(pFont->Entry(), pFont->Entry()->DirectoryPath(), pFont->FontName()); ApplyGeneratedName(pFont->Entry(), pFont->Entry()->DirectoryPath(), pFont->FontName());
CTexture *pFontTex = pFont->Texture();
if (pFontTex) if (CTexture* pFontTex = pFont->Texture())
ApplyGeneratedName(pFontTex->Entry(), pFont->Entry()->DirectoryPath(), pFont->Entry()->Name() + "_tex"); ApplyGeneratedName(pFontTex->Entry(), pFont->Entry()->DirectoryPath(), pFont->Entry()->Name() + "_tex");
} }
} }

View File

@ -1,5 +1,8 @@
#include "CAssetNameMap.h" #include "CAssetNameMap.h"
constexpr char gkAssetMapPath[] = "resources/gameinfo/AssetNameMap";
constexpr char gkAssetMapExt[] = "xml";
bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/) bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
{ {
if (Path.IsEmpty()) if (Path.IsEmpty())
@ -19,8 +22,8 @@ bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
else else
{ {
debugf("Failed to load asset names; expected %s IDs, got %s", debugf("Failed to load asset names; expected %s IDs, got %s",
mIDLength == k32Bit ? "32-bit" : "64-bit", mIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit",
FileIDLength == k32Bit ? "32-bit" : "64-bit" ); FileIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit" );
return false; return false;
} }
} }
@ -36,7 +39,7 @@ bool CAssetNameMap::SaveAssetNames(TString Path /*= ""*/)
if (Path.IsEmpty()) if (Path.IsEmpty())
Path = DefaultNameMapPath(mIDLength); Path = DefaultNameMapPath(mIDLength);
EGame Game = (mIDLength == k32Bit ? EGame::Prime : EGame::Corruption); EGame Game = (mIDLength == EIDLength::k32Bit ? EGame::Prime : EGame::Corruption);
CXMLWriter Writer(Path, "AssetNameMap", 0, Game); CXMLWriter Writer(Path, "AssetNameMap", 0, Game);
Serialize(Writer); Serialize(Writer);
return Writer.Save(); return Writer.Save();
@ -58,7 +61,7 @@ bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rO
else else
{ {
EGame Game = (ID.Length() == k32Bit ? EGame::Prime : EGame::Corruption); EGame Game = (ID.Length() == EIDLength::k32Bit ? EGame::Prime : EGame::Corruption);
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game); rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
rOutName = ID.ToString(); rOutName = ID.ToString();
rOutAutoGenDir = true; rOutAutoGenDir = true;
@ -146,13 +149,14 @@ void CAssetNameMap::PostLoadValidate()
mIsValid = false; mIsValid = false;
std::set<SAssetNameInfo> Dupes; std::set<SAssetNameInfo> Dupes;
for (auto Iter = mMap.begin(); Iter != mMap.end(); Iter++) for (auto Iter = mMap.begin(); Iter != mMap.end(); ++Iter)
{ {
const SAssetNameInfo& rkInfo = Iter->second; const SAssetNameInfo& rkInfo = Iter->second;
if (mUsedSet.find(rkInfo) != mUsedSet.end()) if (mUsedSet.find(rkInfo) != mUsedSet.end())
{
Dupes.insert(rkInfo); Dupes.insert(rkInfo);
}
else else
{ {
mUsedSet.insert(rkInfo); mUsedSet.insert(rkInfo);
@ -180,25 +184,32 @@ void CAssetNameMap::PostLoadValidate()
{ {
errorf("Asset name map is invalid and cannot be used! Duplicate asset entries detected:"); errorf("Asset name map is invalid and cannot be used! Duplicate asset entries detected:");
for (auto Iter = Dupes.begin(); Iter != Dupes.end(); Iter++) for (const auto& dupe : Dupes)
{ {
warnf("\t%s", *Iter->FullPath()); warnf("\t%s", *dupe.FullPath());
} }
mMap.clear(); mMap.clear();
} }
else else
{
mIsValid = !FoundErrors; mIsValid = !FoundErrors;
}
} }
TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength) TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength)
{ {
ASSERT(IDLength != kInvalidIDLength); ASSERT(IDLength != kInvalidIDLength);
TString Suffix = (IDLength == k32Bit ? "32" : "64"); const char* const Suffix = (IDLength == EIDLength::k32Bit ? "32" : "64");
return gDataDir + gkAssetMapPath + Suffix + "." + gkAssetMapExt; return gDataDir + gkAssetMapPath + Suffix + '.' + gkAssetMapExt;
} }
TString CAssetNameMap::DefaultNameMapPath(EGame Game) TString CAssetNameMap::DefaultNameMapPath(EGame Game)
{ {
return DefaultNameMapPath( CAssetID::GameIDLength(Game) ); return DefaultNameMapPath( CAssetID::GameIDLength(Game) );
} }
TString CAssetNameMap::GetExtension()
{
return gkAssetMapExt;
}

View File

@ -8,9 +8,6 @@
#include <map> #include <map>
#include <memory> #include <memory>
const TString gkAssetMapPath = "resources/gameinfo/AssetNameMap";
const TString gkAssetMapExt = "xml";
class CAssetNameMap class CAssetNameMap
{ {
struct SAssetNameInfo struct SAssetNameInfo
@ -66,8 +63,8 @@ public:
static TString DefaultNameMapPath(EIDLength IDLength); static TString DefaultNameMapPath(EIDLength IDLength);
static TString DefaultNameMapPath(EGame Game); static TString DefaultNameMapPath(EGame Game);
inline bool IsValid() const { return mIsValid; } bool IsValid() const { return mIsValid; }
inline static TString GetExtension() { return gkAssetMapExt; } static TString GetExtension();
}; };
#endif // CASSETNAMEMAP #endif // CASSETNAMEMAP

View File

@ -5,72 +5,62 @@
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h" #include "Core/Resource/Script/CScriptObject.h"
#include "Core/Resource/Script/NGameList.h" #include "Core/Resource/Script/NGameList.h"
#include <algorithm>
#include <array>
// ************ IDependencyNode ************ // ************ IDependencyNode ************
IDependencyNode::~IDependencyNode() IDependencyNode::~IDependencyNode() = default;
{
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
delete mChildren[iChild];
}
bool IDependencyNode::HasDependency(const CAssetID& rkID) const bool IDependencyNode::HasDependency(const CAssetID& id) const
{ {
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++) return std::any_of(mChildren.cbegin(), mChildren.cend(),
{ [&id](const auto& entry) { return entry->HasDependency(id); });
if (mChildren[iChild]->HasDependency(rkID))
return true;
}
return false;
} }
void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const
{ {
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++) for (const auto& child : mChildren)
mChildren[iChild]->GetAllResourceReferences(rOutSet); child->GetAllResourceReferences(rOutSet);
} }
void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData) void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData)
{ {
// Recursive function for parsing dependencies in properties // Recursive function for parsing dependencies in properties
for (uint32 PropertyIdx = 0; PropertyIdx < pProperties->NumChildren(); PropertyIdx++) for (size_t PropertyIdx = 0; PropertyIdx < pProperties->NumChildren(); PropertyIdx++)
{ {
IProperty* pProp = pProperties->ChildByIndex(PropertyIdx); IProperty* pProp = pProperties->ChildByIndex(PropertyIdx);
EPropertyType Type = pProp->Type(); const EPropertyType Type = pProp->Type();
// Technically we aren't parsing array children, but it's not really worth refactoring this function // Technically we aren't parsing array children, but it's not really worth refactoring this function
// to support it when there aren't any array properties that contain any asset references anyway... // to support it when there aren't any array properties that contain any asset references anyway...
if (Type == EPropertyType::Struct) if (Type == EPropertyType::Struct)
ParseProperties( pParentEntry, TPropCast<CStructProperty>(pProp), pData ); {
ParseProperties(pParentEntry, TPropCast<CStructProperty>(pProp), pData);
}
else if (Type == EPropertyType::Sound) else if (Type == EPropertyType::Sound)
{ {
uint32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pData); uint32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pData);
if (SoundID != -1) if (SoundID != UINT32_MAX)
{ {
CGameProject* pProj = pParentEntry->Project(); CGameProject* pProj = pParentEntry->Project();
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID); SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
if (Info.pAudioGroup) if (Info.pAudioGroup)
{ {
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), Info.pAudioGroup->ID()); mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), Info.pAudioGroup->ID()));
mChildren.push_back(pDep);
} }
} }
} }
else if (Type == EPropertyType::Asset) else if (Type == EPropertyType::Asset)
{ {
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pData); CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pData);
if (ID.IsValid()) if (ID.IsValid())
{ {
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID); mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
mChildren.push_back(pDep);
} }
} }
else if (Type == EPropertyType::AnimationSet) else if (Type == EPropertyType::AnimationSet)
{ {
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pData); CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pData);
@ -81,13 +71,11 @@ void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructPrope
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier // Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier
if (pProperties->Game() <= EGame::Echoes) if (pProperties->Game() <= EGame::Echoes)
{ {
CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex()); mChildren.push_back(std::make_unique<CCharPropertyDependency>(pProp->IDString(true), ID, Params.CharacterIndex()));
mChildren.push_back(pDep);
} }
else else
{ {
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID); mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
mChildren.push_back(pDep);
} }
} }
} }
@ -123,22 +111,25 @@ void CDependencyTree::Serialize(IArchive& rArc)
rArc << SerialParameter("Children", mChildren); rArc << SerialParameter("Children", mChildren);
} }
void CDependencyTree::AddChild(IDependencyNode *pNode) void CDependencyTree::AddChild(std::unique_ptr<IDependencyNode>&& pNode)
{ {
ASSERT(pNode); ASSERT(pNode);
mChildren.push_back(pNode); mChildren.push_back(std::move(pNode));
} }
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/) void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
{ {
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID))) return; if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID)))
CResourceDependency *pDepend = new CResourceDependency(rkID); return;
mChildren.push_back(pDepend);
mChildren.push_back(std::make_unique<CResourceDependency>(rkID));
} }
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/) void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
{ {
if (!pRes) return; if (!pRes)
return;
AddDependency(pRes->ID(), AvoidDuplicates); AddDependency(pRes->ID(), AvoidDuplicates);
} }
@ -146,9 +137,10 @@ void CDependencyTree::AddCharacterDependency(const CAnimationParameters& rkAnimP
{ {
// This is for formats other than MREA that use AnimationParameters (such as SCAN). // This is for formats other than MREA that use AnimationParameters (such as SCAN).
CAnimSet *pSet = rkAnimParams.AnimSet(); CAnimSet *pSet = rkAnimParams.AnimSet();
if (!pSet || rkAnimParams.CharacterIndex() == -1) return; if (!pSet || rkAnimParams.CharacterIndex() == UINT32_MAX)
CCharPropertyDependency *pChar = new CCharPropertyDependency("NULL", pSet->ID(), rkAnimParams.CharacterIndex()); return;
mChildren.push_back(pChar);
mChildren.push_back(std::make_unique<CCharPropertyDependency>("NULL", pSet->ID(), rkAnimParams.CharacterIndex()));
} }
// ************ CResourceDependency ************ // ************ CResourceDependency ************
@ -209,9 +201,9 @@ void CScriptInstanceDependency::Serialize(IArchive& rArc)
} }
// Static // Static
CScriptInstanceDependency* CScriptInstanceDependency::BuildTree(CScriptObject *pInstance) std::unique_ptr<CScriptInstanceDependency> CScriptInstanceDependency::BuildTree(CScriptObject *pInstance)
{ {
CScriptInstanceDependency *pInst = new CScriptInstanceDependency(); auto pInst = std::make_unique<CScriptInstanceDependency>();
pInst->mObjectType = pInstance->ObjectTypeID(); pInst->mObjectType = pInstance->ObjectTypeID();
pInst->ParseProperties(pInstance->Area()->Entry(), pInstance->Template()->Properties(), pInstance->PropertyData()); pInst->ParseProperties(pInstance->Area()->Entry(), pInstance->Template()->Properties(), pInstance->PropertyData());
return pInst; return pInst;
@ -229,36 +221,34 @@ void CSetCharacterDependency::Serialize(IArchive& rArc)
<< SerialParameter("Children", mChildren); << SerialParameter("Children", mChildren);
} }
CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar) std::unique_ptr<CSetCharacterDependency> CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar)
{ {
CSetCharacterDependency *pTree = new CSetCharacterDependency(rkChar.ID); auto pTree = std::make_unique<CSetCharacterDependency>(rkChar.ID);
pTree->AddDependency(rkChar.pModel); pTree->AddDependency(rkChar.pModel);
pTree->AddDependency(rkChar.pSkeleton); pTree->AddDependency(rkChar.pSkeleton);
pTree->AddDependency(rkChar.pSkin); pTree->AddDependency(rkChar.pSkin);
pTree->AddDependency(rkChar.AnimDataID); pTree->AddDependency(rkChar.AnimDataID);
pTree->AddDependency(rkChar.CollisionPrimitivesID); pTree->AddDependency(rkChar.CollisionPrimitivesID);
const std::vector<CAssetID> *pkParticleVectors[5] = { const std::array<const std::vector<CAssetID>*, 5> particleVectors{
&rkChar.GenericParticles, &rkChar.ElectricParticles, &rkChar.GenericParticles, &rkChar.ElectricParticles,
&rkChar.SwooshParticles, &rkChar.SpawnParticles, &rkChar.SwooshParticles, &rkChar.SpawnParticles,
&rkChar.EffectParticles &rkChar.EffectParticles
}; };
for (uint32 iVec = 0; iVec < 5; iVec++) for (const auto& vec : particleVectors)
{ {
for (uint32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++) for (const auto& dependency : *vec)
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart)); pTree->AddDependency(dependency);
} }
for (uint32 iOverlay = 0; iOverlay < rkChar.OverlayModels.size(); iOverlay++) for (const SOverlayModel& overlay : rkChar.OverlayModels)
{ {
const SOverlayModel& rkOverlay = rkChar.OverlayModels[iOverlay]; pTree->AddDependency(overlay.ModelID);
pTree->AddDependency(rkOverlay.ModelID); pTree->AddDependency(overlay.SkinID);
pTree->AddDependency(rkOverlay.SkinID);
} }
pTree->AddDependency(rkChar.SpatialPrimitives); pTree->AddDependency(rkChar.SpatialPrimitives);
return pTree; return pTree;
} }
@ -274,9 +264,9 @@ void CSetAnimationDependency::Serialize(IArchive& rArc)
<< SerialParameter("Children", mChildren); << SerialParameter("Children", mChildren);
} }
CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex) std::unique_ptr<CSetAnimationDependency> CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex)
{ {
CSetAnimationDependency *pTree = new CSetAnimationDependency; auto pTree = std::make_unique<CSetAnimationDependency>();
const SAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex); const SAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
// Find relevant character indices // Find relevant character indices
@ -284,7 +274,7 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
{ {
const SSetCharacter *pkChar = pkOwnerSet->Character(iChar); const SSetCharacter *pkChar = pkOwnerSet->Character(iChar);
if ( pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end() ) if (pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end())
pTree->mCharacterIndices.insert(iChar); pTree->mCharacterIndices.insert(iChar);
} }
@ -292,16 +282,15 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
std::set<CAnimPrimitive> UsedPrimitives; std::set<CAnimPrimitive> UsedPrimitives;
pkAnim->pMetaAnim->GetUniquePrimitives(UsedPrimitives); pkAnim->pMetaAnim->GetUniquePrimitives(UsedPrimitives);
for (auto Iter = UsedPrimitives.begin(); Iter != UsedPrimitives.end(); Iter++) for (const CAnimPrimitive& prim : UsedPrimitives)
{ {
const CAnimPrimitive& rkPrim = *Iter; pTree->AddDependency(prim.Animation());
pTree->AddDependency(rkPrim.Animation());
if (pkOwnerSet->Game() >= EGame::EchoesDemo) if (pkOwnerSet->Game() >= EGame::EchoesDemo)
{ {
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(rkPrim.ID()); CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(prim.ID());
ASSERT(pEvents && !pEvents->Entry()); ASSERT(pEvents && !pEvents->Entry());
pEvents->AddDependenciesToTree(pTree); pEvents->AddDependenciesToTree(pTree.get());
} }
} }
@ -334,27 +323,27 @@ void CAreaDependencyTree::Serialize(IArchive& rArc)
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps) void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps)
{ {
if (!pLayer) return; if (!pLayer)
return;
mLayerOffsets.push_back(mChildren.size()); mLayerOffsets.push_back(mChildren.size());
std::set<CAssetID> UsedIDs; std::set<CAssetID> UsedIDs;
for (uint32 iInst = 0; iInst < pLayer->NumInstances(); iInst++) for (size_t iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{ {
CScriptInstanceDependency *pTree = CScriptInstanceDependency::BuildTree( pLayer->InstanceByIndex(iInst) ); auto pTree = CScriptInstanceDependency::BuildTree(pLayer->InstanceByIndex(iInst));
ASSERT(pTree != nullptr); ASSERT(pTree != nullptr);
// Note: MP2+ need to track all instances (not just instances with dependencies) to be able to build the layer module list // Note: MP2+ need to track all instances (not just instances with dependencies) to be able to build the layer module list
if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= EGame::EchoesDemo) if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= EGame::EchoesDemo)
{ {
mChildren.push_back(pTree);
pTree->GetAllResourceReferences(UsedIDs); pTree->GetAllResourceReferences(UsedIDs);
mChildren.push_back(std::move(pTree));
} }
else
delete pTree;
} }
for (uint32 iDep = 0; iDep < rkExtraDeps.size(); iDep++) for (const auto& dep : rkExtraDeps)
AddDependency(rkExtraDeps[iDep]); AddDependency(dep);
} }
void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const
@ -363,34 +352,34 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
// Output module list will be split per-script layer // Output module list will be split per-script layer
// The output offset list contains two offsets per layer - start index and end index // The output offset list contains two offsets per layer - start index and end index
for (uint32 iLayer = 0; iLayer < mLayerOffsets.size(); iLayer++) for (size_t iLayer = 0; iLayer < mLayerOffsets.size(); iLayer++)
{ {
uint32 StartIdx = mLayerOffsets[iLayer]; const size_t StartIdx = mLayerOffsets[iLayer];
uint32 EndIdx = (iLayer == mLayerOffsets.size() - 1 ? mChildren.size() : mLayerOffsets[iLayer + 1]); const size_t EndIdx = (iLayer == mLayerOffsets.size() - 1 ? mChildren.size() : mLayerOffsets[iLayer + 1]);
uint32 ModuleStartIdx = rModuleDepsOut.size(); const auto ModuleStartIdx = static_cast<uint32>(rModuleDepsOut.size());
rModuleLayerOffsetsOut.push_back(ModuleStartIdx); rModuleLayerOffsetsOut.push_back(ModuleStartIdx);
// Keep track of which types we've already checked on this layer to speed things up a little... // Keep track of which types we've already checked on this layer to speed things up a little...
std::set<uint32> UsedObjectTypes; std::set<uint32> UsedObjectTypes;
for (uint32 iInst = StartIdx; iInst < EndIdx; iInst++) for (size_t iInst = StartIdx; iInst < EndIdx; iInst++)
{ {
IDependencyNode *pNode = mChildren[iInst]; const auto& pNode = mChildren[iInst];
if (pNode->Type() != EDependencyNodeType::ScriptInstance) continue; if (pNode->Type() != EDependencyNodeType::ScriptInstance)
continue;
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode); const auto *pInst = static_cast<CScriptInstanceDependency*>(pNode.get());
uint32 ObjType = pInst->ObjectType(); const uint32 ObjType = pInst->ObjectType();
if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end()) if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end())
{ {
// Get the module list for this object type and check whether any of them are new before adding them to the output list // Get the module list for this object type and check whether any of them are new before adding them to the output list
CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType); const CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
const std::vector<TString>& rkModules = pTemplate->RequiredModules(); const std::vector<TString>& rkModules = pTemplate->RequiredModules();
for (uint32 iMod = 0; iMod < rkModules.size(); iMod++) for (const auto& ModuleName : rkModules)
{ {
TString ModuleName = rkModules[iMod];
bool NewModule = true; bool NewModule = true;
for (uint32 iUsed = ModuleStartIdx; iUsed < rModuleDepsOut.size(); iUsed++) for (uint32 iUsed = ModuleStartIdx; iUsed < rModuleDepsOut.size(); iUsed++)
@ -410,6 +399,6 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
} }
} }
rModuleLayerOffsetsOut.push_back(rModuleDepsOut.size()); rModuleLayerOffsetsOut.push_back(static_cast<uint32>(rModuleDepsOut.size()));
} }
} }

View File

@ -5,6 +5,7 @@
#include <Common/CAssetID.h> #include <Common/CAssetID.h>
#include <Common/FileIO.h> #include <Common/FileIO.h>
#include <Common/Macros.h> #include <Common/Macros.h>
#include <memory>
class CScriptLayer; class CScriptLayer;
class CScriptObject; class CScriptObject;
@ -31,34 +32,34 @@ enum class EDependencyNodeType
class IDependencyNode class IDependencyNode
{ {
protected: protected:
std::vector<IDependencyNode*> mChildren; std::vector<std::unique_ptr<IDependencyNode>> mChildren;
public: public:
virtual ~IDependencyNode(); virtual ~IDependencyNode();
virtual EDependencyNodeType Type() const = 0; virtual EDependencyNodeType Type() const = 0;
virtual void Serialize(IArchive& rArc) = 0; virtual void Serialize(IArchive& rArc) = 0;
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const; virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
virtual bool HasDependency(const CAssetID& rkID) const; virtual bool HasDependency(const CAssetID& id) const;
void ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData); void ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData);
// Serialization constructor // Serialization constructor
static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type); static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type);
// Accessors // Accessors
inline uint NumChildren() const { return mChildren.size(); } size_t NumChildren() const { return mChildren.size(); }
inline IDependencyNode* ChildByIndex(uint Index) const { return mChildren[Index]; } IDependencyNode* ChildByIndex(size_t Index) const { return mChildren[Index].get(); }
}; };
// Basic dependency tree; this class is sufficient for most resource types. // Basic dependency tree; this class is sufficient for most resource types.
class CDependencyTree : public IDependencyNode class CDependencyTree : public IDependencyNode
{ {
public: public:
CDependencyTree() {} CDependencyTree() = default;
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
void AddChild(IDependencyNode *pNode); void AddChild(std::unique_ptr<IDependencyNode>&& pNode);
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true); void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
void AddDependency(CResource *pRes, bool AvoidDuplicates = true); void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
void AddCharacterDependency(const CAnimationParameters& rkAnimParams); void AddCharacterDependency(const CAnimationParameters& rkAnimParams);
@ -71,17 +72,17 @@ protected:
CAssetID mID; CAssetID mID;
public: public:
CResourceDependency() {} CResourceDependency() = default;
CResourceDependency(const CAssetID& rkID) : mID(rkID) {} explicit CResourceDependency(const CAssetID& rkID) : mID(rkID) {}
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const; void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const override;
virtual bool HasDependency(const CAssetID& rkID) const; bool HasDependency(const CAssetID& rkID) const override;
// Accessors // Accessors
inline CAssetID ID() const { return mID; } CAssetID ID() const { return mID; }
inline void SetID(const CAssetID& rkID) { mID = rkID; } void SetID(const CAssetID& rkID) { mID = rkID; }
}; };
// Node representing a single resource dependency referenced by a script property. // Node representing a single resource dependency referenced by a script property.
@ -90,81 +91,76 @@ class CPropertyDependency : public CResourceDependency
TString mIDString; TString mIDString;
public: public:
CPropertyDependency() CPropertyDependency() = default;
: CResourceDependency()
{}
CPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID) CPropertyDependency(TString rkPropID, const CAssetID& rkAssetID)
: CResourceDependency(rkAssetID) : CResourceDependency(rkAssetID)
, mIDString(rkPropID) , mIDString(std::move(rkPropID))
{} {}
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline TString PropertyID() const { return mIDString; } TString PropertyID() const { return mIDString; }
}; };
// Node representing a single animset dependency referenced by a script property. Indicates which character is being used. // Node representing a single animset dependency referenced by a script property. Indicates which character is being used.
class CCharPropertyDependency : public CPropertyDependency class CCharPropertyDependency : public CPropertyDependency
{ {
protected: protected:
int mUsedChar; int mUsedChar = -1;
public: public:
CCharPropertyDependency() CCharPropertyDependency() = default;
: CPropertyDependency()
, mUsedChar(-1)
{}
CCharPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID, int UsedChar) CCharPropertyDependency(TString rkPropID, const CAssetID& rkAssetID, int UsedChar)
: CPropertyDependency(rkPropID, rkAssetID) : CPropertyDependency(std::move(rkPropID), rkAssetID)
, mUsedChar(UsedChar) , mUsedChar(UsedChar)
{} {}
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline int UsedChar() const { return mUsedChar; } int UsedChar() const { return mUsedChar; }
}; };
// Node representing a script object. Indicates the type of object. // Node representing a script object. Indicates the type of object.
class CScriptInstanceDependency : public IDependencyNode class CScriptInstanceDependency : public IDependencyNode
{ {
protected: protected:
uint mObjectType; uint32 mObjectType = 0;
public: public:
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline uint ObjectType() const { return mObjectType; } uint32 ObjectType() const { return mObjectType; }
// Static // Static
static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance); static std::unique_ptr<CScriptInstanceDependency> BuildTree(CScriptObject *pInstance);
}; };
// Node representing an animset character. Indicates what index the character is within the animset. // Node representing an animset character. Indicates what index the character is within the animset.
class CSetCharacterDependency : public CDependencyTree class CSetCharacterDependency : public CDependencyTree
{ {
protected: protected:
uint32 mCharSetIndex; uint32 mCharSetIndex = 0;
public: public:
CSetCharacterDependency() : CDependencyTree() {} CSetCharacterDependency() = default;
CSetCharacterDependency(uint32 SetIndex) : CDependencyTree(), mCharSetIndex(SetIndex) {} explicit CSetCharacterDependency(uint32 SetIndex) : mCharSetIndex(SetIndex) {}
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline uint32 CharSetIndex() const { return mCharSetIndex; } uint32 CharSetIndex() const { return mCharSetIndex; }
// Static // Static
static CSetCharacterDependency* BuildTree(const SSetCharacter& rkChar); static std::unique_ptr<CSetCharacterDependency> BuildTree(const SSetCharacter& rkChar);
}; };
// Node representing a character animation. Indicates which character indices use this animation. // Node representing a character animation. Indicates which character indices use this animation.
@ -174,35 +170,35 @@ protected:
std::set<uint32> mCharacterIndices; std::set<uint32> mCharacterIndices;
public: public:
CSetAnimationDependency() : CDependencyTree() {} CSetAnimationDependency() = default;
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); } bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
inline bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); } bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); }
// Static // Static
static CSetAnimationDependency* BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex); static std::unique_ptr<CSetAnimationDependency> BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex);
}; };
// Node representing an animation event. Indicates which character index uses this event. // Node representing an animation event. Indicates which character index uses this event.
class CAnimEventDependency : public CResourceDependency class CAnimEventDependency : public CResourceDependency
{ {
protected: protected:
uint32 mCharIndex; uint32 mCharIndex = 0;
public: public:
CAnimEventDependency() : CResourceDependency() {} CAnimEventDependency() = default;
CAnimEventDependency(const CAssetID& rkID, uint32 CharIndex) CAnimEventDependency(const CAssetID& rkID, uint32 CharIndex)
: CResourceDependency(rkID), mCharIndex(CharIndex) {} : CResourceDependency(rkID), mCharIndex(CharIndex) {}
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
// Accessors // Accessors
inline uint32 CharIndex() const { return mCharIndex; } uint32 CharIndex() const { return mCharIndex; }
}; };
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers. // Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
@ -212,17 +208,17 @@ protected:
std::vector<uint32> mLayerOffsets; std::vector<uint32> mLayerOffsets;
public: public:
CAreaDependencyTree() : CDependencyTree() {} CAreaDependencyTree() = default;
virtual EDependencyNodeType Type() const; EDependencyNodeType Type() const override;
virtual void Serialize(IArchive& rArc); void Serialize(IArchive& rArc) override;
void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps); void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps);
void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const; void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const;
// Accessors // Accessors
inline uint32 NumScriptLayers() const { return mLayerOffsets.size(); } size_t NumScriptLayers() const { return mLayerOffsets.size(); }
inline uint32 ScriptLayerOffset(uint32 LayerIdx) const { return mLayerOffsets[LayerIdx]; } uint32 ScriptLayerOffset(size_t LayerIdx) const { return mLayerOffsets[LayerIdx]; }
}; };
#endif // CDEPENDENCYTREE #endif // CDEPENDENCYTREE

View File

@ -12,6 +12,7 @@
#include <Common/Serialization/CXMLWriter.h> #include <Common/Serialization/CXMLWriter.h>
#include <nod/nod.hpp> #include <nod/nod.hpp>
#include <nod/DiscBase.hpp>
#include <tinyxml2.h> #include <tinyxml2.h>
#define LOAD_PAKS 1 #define LOAD_PAKS 1
@ -33,7 +34,6 @@ CGameExporter::CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, EReg
, mBuildVersion(BuildVersion) , mBuildVersion(BuildVersion)
, mDiscType(DiscType) , mDiscType(DiscType)
, mFrontEnd(FrontEnd) , mFrontEnd(FrontEnd)
, mpProgress(nullptr)
{ {
ASSERT(mGame != EGame::Invalid); ASSERT(mGame != EGame::Invalid);
ASSERT(mRegion != ERegion::Unknown); ASSERT(mRegion != ERegion::Unknown);
@ -93,18 +93,20 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs
// Export finished! // Export finished!
mProjectPath = mpProject->ProjectPath(); mProjectPath = mpProject->ProjectPath();
delete mpProject; mpProject.reset();
if (pOldStore) gpResourceStore = pOldStore; if (pOldStore != nullptr)
gpResourceStore = pOldStore;
return !mpProgress->ShouldCancel(); return !mpProgress->ShouldCancel();
} }
void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer) void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer)
{ {
SResourceInstance *pInst = FindResourceInstance(rkID); SResourceInstance *pInst = FindResourceInstance(rkID);
if (pInst) LoadResource(*pInst, rBuffer); if (pInst != nullptr)
LoadResource(*pInst, rBuffer);
} }
bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot) bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot) const
{ {
if (IsInRoot && mDiscType != EDiscType::Normal) if (IsInRoot && mDiscType != EDiscType::Normal)
{ {
@ -115,49 +117,47 @@ bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
if (pkNode->getName() == "fe") if (pkNode->getName() == "fe")
return true; return true;
else if (mFrontEnd) if (mFrontEnd)
return false; return false;
switch (mGame) switch (mGame)
{ {
case EGame::Prime: case EGame::Prime:
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP1JPN") || return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP1JPN" ||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP1") ); mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP1";
case EGame::Echoes: case EGame::Echoes:
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP2JPN") || return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP2JPN" ||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP2") ); mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP2";
case EGame::Corruption: case EGame::Corruption:
return (mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP3"); return mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP3";
default: default:
return false; return false;
} }
} }
else // Files - exclude the DOLs for other games
// Files - exclude the DOLs for other games
else
{ {
// Again - always include frontend. Always include opening.bnr as well. // Again - always include frontend. Always include opening.bnr as well.
if (pkNode->getName() == "rs5fe_p.dol" || pkNode->getName() == "opening.bnr") if (pkNode->getName() == "rs5fe_p.dol" || pkNode->getName() == "opening.bnr")
return true; return true;
else if (mFrontEnd) if (mFrontEnd)
return false; return false;
switch (mGame) switch (mGame)
{ {
case EGame::Prime: case EGame::Prime:
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol") || return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol" ||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp1_p.dol") ); mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp1_p.dol";
case EGame::Echoes: case EGame::Echoes:
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol") || return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol" ||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp2_p.dol") ); mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp2_p.dol";
case EGame::Corruption: case EGame::Corruption:
return (mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp3_p.dol"); return mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp3_p.dol";
default: default:
return false; return false;
@ -233,7 +233,8 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
{ {
TString FilePath = rkDir + Iter->getName().data(); TString FilePath = rkDir + Iter->getName().data();
bool Success = Iter->extractToDirectory(TStringToNodString(rkDir), rkContext); bool Success = Iter->extractToDirectory(TStringToNodString(rkDir), rkContext);
if (!Success) return false; if (!Success)
return false;
if (FilePath.GetFileExtension().CaseInsensitiveCompare("pak")) if (FilePath.GetFileExtension().CaseInsensitiveCompare("pak"))
{ {
@ -247,10 +248,12 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
{ {
TString Subdir = rkDir + Iter->getName().data() + "/"; TString Subdir = rkDir + Iter->getName().data() + "/";
bool Success = FileUtil::MakeDirectory(Subdir); bool Success = FileUtil::MakeDirectory(Subdir);
if (!Success) return false; if (!Success)
return false;
Success = ExtractDiscNodeRecursive(&*Iter, Subdir, false, rkContext); Success = ExtractDiscNodeRecursive(&*Iter, Subdir, false, rkContext);
if (!Success) return false; if (!Success)
return false;
} }
} }
@ -279,27 +282,27 @@ void CGameExporter::LoadPaks()
} }
TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false)); TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false));
CPackage *pPackage = new CPackage(mpProject, PakPath.GetFileName(false), RelPakPath); auto pPackage = std::make_unique<CPackage>(mpProject.get(), PakPath.GetFileName(false), RelPakPath);
// MP1-MP3Proto // MP1-MP3Proto
if (mGame < EGame::Corruption) if (mGame < EGame::Corruption)
{ {
uint32 PakVersion = Pak.ReadLong(); [[maybe_unused]] const uint32 PakVersion = Pak.ReadULong();
Pak.Seek(0x4, SEEK_CUR); Pak.Seek(0x4, SEEK_CUR);
ASSERT(PakVersion == 0x00030005); ASSERT(PakVersion == 0x00030005);
// Echoes demo disc has a pak that ends right here. // Echoes demo disc has a pak that ends right here.
if (!Pak.EoF()) if (!Pak.EoF())
{ {
uint32 NumNamedResources = Pak.ReadLong(); uint32 NumNamedResources = Pak.ReadULong();
ASSERT(NumNamedResources > 0); ASSERT(NumNamedResources > 0);
for (uint32 iName = 0; iName < NumNamedResources; iName++) for (uint32 iName = 0; iName < NumNamedResources; iName++)
{ {
CFourCC ResType = Pak.ReadLong(); const CFourCC ResType = Pak.ReadULong();
CAssetID ResID(Pak, mGame); const CAssetID ResID(Pak, mGame);
uint32 NameLen = Pak.ReadLong(); const uint32 NameLen = Pak.ReadULong();
TString Name = Pak.ReadString(NameLen); const TString Name = Pak.ReadString(NameLen);
pPackage->AddResource(Name, ResID, ResType); pPackage->AddResource(Name, ResID, ResType);
} }
@ -311,14 +314,14 @@ void CGameExporter::LoadPaks()
for (uint32 iRes = 0; iRes < NumResources; iRes++) for (uint32 iRes = 0; iRes < NumResources; iRes++)
{ {
bool Compressed = (Pak.ReadLong() == 1); const bool Compressed = Pak.ReadULong() == 1;
CFourCC ResType = Pak.ReadLong(); const CFourCC ResType = Pak.ReadULong();
CAssetID ResID(Pak, mGame); const CAssetID ResID(Pak, mGame);
uint32 ResSize = Pak.ReadLong(); const uint32 ResSize = Pak.ReadULong();
uint32 ResOffset = Pak.ReadLong(); const uint32 ResOffset = Pak.ReadULong();
if (mResourceMap.find(ResID) == mResourceMap.end()) if (mResourceMap.find(ResID) == mResourceMap.cend())
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false }; mResourceMap.insert_or_assign(ResID, SResourceInstance{PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false});
// Check for duplicate resources // Check for duplicate resources
if (ResType == "MREA") if (ResType == "MREA")
@ -326,63 +329,63 @@ void CGameExporter::LoadPaks()
mAreaDuplicateMap[ResID] = AreaHasDuplicates; mAreaDuplicateMap[ResID] = AreaHasDuplicates;
AreaHasDuplicates = false; AreaHasDuplicates = false;
} }
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.cend())
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end()) {
AreaHasDuplicates = true; AreaHasDuplicates = true;
}
else else
{
PakResourceSet.insert(ResID); PakResourceSet.insert(ResID);
}
} }
} }
} }
else // MP3 + DKCR
// MP3 + DKCR
else
{ {
uint32 PakVersion = Pak.ReadLong(); [[maybe_unused]] const uint32 PakVersion = Pak.ReadULong();
uint32 PakHeaderLen = Pak.ReadLong(); const uint32 PakHeaderLen = Pak.ReadULong();
Pak.Seek(PakHeaderLen - 0x8, SEEK_CUR); Pak.Seek(PakHeaderLen - 0x8, SEEK_CUR);
ASSERT(PakVersion == 2); ASSERT(PakVersion == 2);
struct SPakSection { struct SPakSection {
CFourCC Type; uint32 Size; CFourCC Type;
uint32 Size;
}; };
std::vector<SPakSection> PakSections; std::vector<SPakSection> PakSections;
uint32 NumPakSections = Pak.ReadLong(); const uint32 NumPakSections = Pak.ReadULong();
ASSERT(NumPakSections == 3); ASSERT(NumPakSections == 3);
for (uint32 iSec = 0; iSec < NumPakSections; iSec++) for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
{ {
CFourCC Type = Pak.ReadLong(); const CFourCC Type = Pak.ReadULong();
uint32 Size = Pak.ReadLong(); const uint32 Size = Pak.ReadULong();
PakSections.push_back(SPakSection { Type, Size }); PakSections.push_back(SPakSection{Type, Size});
} }
Pak.SeekToBoundary(64); Pak.SeekToBoundary(64);
for (uint32 iSec = 0; iSec < NumPakSections; iSec++) for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
{ {
uint32 Next = Pak.Tell() + PakSections[iSec].Size; const uint32 Next = Pak.Tell() + PakSections[iSec].Size;
// Named Resources // Named Resources
if (PakSections[iSec].Type == "STRG") if (PakSections[iSec].Type == "STRG")
{ {
uint32 NumNamedResources = Pak.ReadLong(); const uint32 NumNamedResources = Pak.ReadULong();
for (uint32 iName = 0; iName < NumNamedResources; iName++) for (uint32 iName = 0; iName < NumNamedResources; iName++)
{ {
TString Name = Pak.ReadString(); const TString Name = Pak.ReadString();
CFourCC ResType = Pak.ReadLong(); const CFourCC ResType = Pak.ReadULong();
CAssetID ResID(Pak, mGame); const CAssetID ResID(Pak, mGame);
pPackage->AddResource(Name, ResID, ResType); pPackage->AddResource(Name, ResID, ResType);
} }
} }
else if (PakSections[iSec].Type == "RSHD") else if (PakSections[iSec].Type == "RSHD")
{ {
ASSERT(PakSections[iSec + 1].Type == "DATA"); ASSERT(PakSections[iSec + 1].Type == "DATA");
uint32 DataStart = Next; const uint32 DataStart = Next;
uint32 NumResources = Pak.ReadLong(); const uint32 NumResources = Pak.ReadULong();
// Keep track of which areas have duplicate resources // Keep track of which areas have duplicate resources
std::set<CAssetID> PakResourceSet; std::set<CAssetID> PakResourceSet;
@ -390,29 +393,31 @@ void CGameExporter::LoadPaks()
for (uint32 iRes = 0; iRes < NumResources; iRes++) for (uint32 iRes = 0; iRes < NumResources; iRes++)
{ {
bool Compressed = (Pak.ReadLong() == 1); const bool Compressed = Pak.ReadULong() == 1;
CFourCC Type = Pak.ReadLong(); const CFourCC Type = Pak.ReadULong();
CAssetID ResID(Pak, mGame); const CAssetID ResID(Pak, mGame);
uint32 Size = Pak.ReadLong(); const uint32 Size = Pak.ReadULong();
uint32 Offset = DataStart + Pak.ReadLong(); const uint32 Offset = DataStart + Pak.ReadULong();
if (mResourceMap.find(ResID) == mResourceMap.end()) if (mResourceMap.find(ResID) == mResourceMap.cend())
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false }; mResourceMap.insert_or_assign(ResID, SResourceInstance{PakPath, ResID, Type, Offset, Size, Compressed, false});
// Check for duplicate resources (unnecessary for DKCR) // Check for duplicate resources (unnecessary for DKCR)
if (mGame != EGame::DKCReturns) if (mGame != EGame::DKCReturns)
{ {
if (Type == "MREA") if (Type == "MREA")
{ {
mAreaDuplicateMap[ResID] = AreaHasDuplicates; mAreaDuplicateMap.insert_or_assign(ResID, AreaHasDuplicates);
AreaHasDuplicates = false; AreaHasDuplicates = false;
} }
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.cend())
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end()) {
AreaHasDuplicates = true; AreaHasDuplicates = true;
}
else else
{
PakResourceSet.insert(ResID); PakResourceSet.insert(ResID);
}
} }
} }
} }
@ -422,11 +427,12 @@ void CGameExporter::LoadPaks()
} }
// Add package to project and save // Add package to project and save
mpProject->AddPackage(pPackage);
#if SAVE_PACKAGE_DEFINITIONS #if SAVE_PACKAGE_DEFINITIONS
bool SaveSuccess = pPackage->Save(); [[maybe_unused]] const bool SaveSuccess = pPackage->Save();
ASSERT(SaveSuccess); ASSERT(SaveSuccess);
#endif #endif
mpProject->AddPackage(std::move(pPackage));
} }
#endif #endif
} }
@ -448,7 +454,7 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
{ {
std::vector<uint8> CompressedData(rkResource.PakSize); std::vector<uint8> CompressedData(rkResource.PakSize);
uint32 UncompressedSize = Pak.ReadLong(); const uint32 UncompressedSize = Pak.ReadULong();
rBuffer.resize(UncompressedSize); rBuffer.resize(UncompressedSize);
Pak.ReadBytes(CompressedData.data(), CompressedData.size()); Pak.ReadBytes(CompressedData.data(), CompressedData.size());
@ -465,24 +471,25 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
else else
{ {
CFourCC Magic = Pak.ReadLong(); [[maybe_unused]] const CFourCC Magic = Pak.ReadULong();
ASSERT(Magic == "CMPD"); ASSERT(Magic == "CMPD");
uint32 NumBlocks = Pak.ReadLong(); const uint32 NumBlocks = Pak.ReadULong();
struct SCompressedBlock { struct SCompressedBlock {
uint32 CompressedSize; uint32 UncompressedSize; uint32 CompressedSize;
uint32 UncompressedSize;
}; };
std::vector<SCompressedBlock> CompressedBlocks; std::vector<SCompressedBlock> CompressedBlocks;
uint32 TotalUncompressedSize = 0; uint32 TotalUncompressedSize = 0;
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++) for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
{ {
uint32 CompressedSize = (Pak.ReadLong() & 0x00FFFFFF); const uint32 CompressedSize = (Pak.ReadULong() & 0x00FFFFFF);
uint32 UncompressedSize = Pak.ReadLong(); const uint32 UncompressedSize = Pak.ReadULong();
TotalUncompressedSize += UncompressedSize; TotalUncompressedSize += UncompressedSize;
CompressedBlocks.push_back( SCompressedBlock { CompressedSize, UncompressedSize } ); CompressedBlocks.push_back(SCompressedBlock{CompressedSize, UncompressedSize});
} }
rBuffer.resize(TotalUncompressedSize); rBuffer.resize(TotalUncompressedSize);
@ -490,8 +497,8 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++) for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
{ {
uint32 CompressedSize = CompressedBlocks[iBlock].CompressedSize; const uint32 CompressedSize = CompressedBlocks[iBlock].CompressedSize;
uint32 UncompressedSize = CompressedBlocks[iBlock].UncompressedSize; const uint32 UncompressedSize = CompressedBlocks[iBlock].UncompressedSize;
// Block is compressed // Block is compressed
if (CompressedSize != UncompressedSize) if (CompressedSize != UncompressedSize)
@ -509,17 +516,16 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
CompressionUtil::DecompressSegmentedData(CompressedData.data(), CompressedData.size(), rBuffer.data() + Offset, UncompressedSize); CompressionUtil::DecompressSegmentedData(CompressedData.data(), CompressedData.size(), rBuffer.data() + Offset, UncompressedSize);
} }
} }
// Block is uncompressed else // Block is uncompressed
else {
Pak.ReadBytes(rBuffer.data() + Offset, UncompressedSize); Pak.ReadBytes(rBuffer.data() + Offset, UncompressedSize);
}
Offset += UncompressedSize; Offset += UncompressedSize;
} }
} }
} }
else // Handle uncompressed
// Handle uncompressed
else
{ {
rBuffer.resize(rkResource.PakSize); rBuffer.resize(rkResource.PakSize);
Pak.ReadBytes(rBuffer.data(), rBuffer.size()); Pak.ReadBytes(rBuffer.data(), rBuffer.size());
@ -535,7 +541,7 @@ void CGameExporter::ExportCookedResources()
mpProgress->SetTask(eES_ExportCooked, "Unpacking cooked assets"); mpProgress->SetTask(eES_ExportCooked, "Unpacking cooked assets");
int ResIndex = 0; int ResIndex = 0;
for (auto It = mResourceMap.begin(); It != mResourceMap.end() && !mpProgress->ShouldCancel(); It++, ResIndex++) for (auto It = mResourceMap.begin(); It != mResourceMap.end() && !mpProgress->ShouldCancel(); ++It, ResIndex++)
{ {
SResourceInstance& rRes = It->second; SResourceInstance& rRes = It->second;
@ -566,28 +572,29 @@ void CGameExporter::ExportResourceEditorData()
{ {
// Update progress // Update progress
if ((ResIndex & 0x3) == 0 || It->ResourceType() == EResourceType::Area) if ((ResIndex & 0x3) == 0 || It->ResourceType() == EResourceType::Area)
mpProgress->Report(ResIndex, mpStore->NumTotalResources(), TString::Format("Processing asset %d/%d: %s", {
ResIndex, mpStore->NumTotalResources(), *It->CookedAssetPath(true).GetFileName()) ); mpProgress->Report(ResIndex, mpStore->NumTotalResources(), TString::Format("Processing asset %u/%u: %s", ResIndex, mpStore->NumTotalResources(), *It->CookedAssetPath(true).GetFileName()));
}
// Worlds need some info we can only get from the pak at export time; namely, which areas can // Worlds need some info we can only get from the pak at export time; namely, which areas can
// have duplicates, as well as the world's internal name. // have duplicates, as well as the world's internal name.
if (It->ResourceType() == EResourceType::World) if (It->ResourceType() == EResourceType::World)
{ {
CWorld *pWorld = (CWorld*) It->Load(); auto* pWorld = static_cast<CWorld*>(It->Load());
// Set area duplicate flags // Set area duplicate flags
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++) for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
{ {
CAssetID AreaID = pWorld->AreaResourceID(iArea); const CAssetID AreaID = pWorld->AreaResourceID(iArea);
auto Find = mAreaDuplicateMap.find(AreaID); const auto Find = mAreaDuplicateMap.find(AreaID);
if (Find != mAreaDuplicateMap.end()) if (Find != mAreaDuplicateMap.cend())
pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second); pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second);
} }
// Set world name // Set world name
TString WorldName = MakeWorldName(pWorld->ID()); TString WorldName = MakeWorldName(pWorld->ID());
pWorld->SetName(WorldName); pWorld->SetName(std::move(WorldName));
} }
// Save raw resource + generate dependencies // Save raw resource + generate dependencies
@ -606,10 +613,10 @@ void CGameExporter::ExportResourceEditorData()
// All resources should have dependencies generated, so save the project files // All resources should have dependencies generated, so save the project files
SCOPED_TIMER(SaveResourceDatabase); SCOPED_TIMER(SaveResourceDatabase);
#if EXPORT_COOKED #if EXPORT_COOKED
bool ResDBSaveSuccess = mpStore->SaveDatabaseCache(); [[maybe_unused]] const bool ResDBSaveSuccess = mpStore->SaveDatabaseCache();
ASSERT(ResDBSaveSuccess); ASSERT(ResDBSaveSuccess);
#endif #endif
bool ProjectSaveSuccess = mpProject->Save(); [[maybe_unused]] const bool ProjectSaveSuccess = mpProject->Save();
ASSERT(ProjectSaveSuccess); ASSERT(ProjectSaveSuccess);
} }
} }
@ -643,7 +650,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
#if EXPORT_COOKED #if EXPORT_COOKED
// Save cooked asset // Save cooked asset
TString OutCookedPath = pEntry->CookedAssetPath(); const TString OutCookedPath = pEntry->CookedAssetPath();
FileUtil::MakeDirectory(OutCookedPath.GetFileDirectory()); FileUtil::MakeDirectory(OutCookedPath.GetFileDirectory());
CFileOutStream Out(OutCookedPath, EEndian::BigEndian); CFileOutStream Out(OutCookedPath, EEndian::BigEndian);
@ -659,17 +666,17 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
TString CGameExporter::MakeWorldName(CAssetID WorldID) TString CGameExporter::MakeWorldName(CAssetID WorldID)
{ {
CResourceEntry *pWorldEntry = mpStore->FindEntry(WorldID); [[maybe_unused]] const CResourceEntry *pWorldEntry = mpStore->FindEntry(WorldID);
ASSERT(pWorldEntry && pWorldEntry->ResourceType() == EResourceType::World); ASSERT(pWorldEntry && pWorldEntry->ResourceType() == EResourceType::World);
// Find the original world name in the package resource names // Find the original world name in the package resource names
TString WorldName; TString WorldName;
for (uint32 iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++) for (size_t iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++)
{ {
CPackage *pPkg = mpProject->PackageByIndex(iPkg); CPackage *pPkg = mpProject->PackageByIndex(iPkg);
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
@ -684,7 +691,8 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
} }
} }
if (!WorldName.IsEmpty()) break; if (!WorldName.IsEmpty())
break;
} }
// Fix up the name; remove date/time, leading exclamation points, etc // Fix up the name; remove date/time, leading exclamation points, etc
@ -697,7 +705,6 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
if (WorldName.StartsWith('!')) if (WorldName.StartsWith('!'))
WorldName = WorldName.ChopFront(1); WorldName = WorldName.ChopFront(1);
} }
// MP1 - Remove prefix characters and ending date // MP1 - Remove prefix characters and ending date
else if (mGame == EGame::Prime) else if (mGame == EGame::Prime)
{ {
@ -706,7 +713,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
while (!WorldName.IsEmpty()) while (!WorldName.IsEmpty())
{ {
char Chr = WorldName.Back(); const char Chr = WorldName.Back();
if (!StartedDate && Chr >= '0' && Chr <= '9') if (!StartedDate && Chr >= '0' && Chr <= '9')
StartedDate = true; StartedDate = true;
@ -716,54 +723,49 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
WorldName = WorldName.ChopBack(1); WorldName = WorldName.ChopBack(1);
} }
} }
// MP2 demo - Use text between the first and second underscores // MP2 demo - Use text between the first and second underscores
else if (mGame == EGame::EchoesDemo) else if (mGame == EGame::EchoesDemo)
{ {
uint32 UnderscoreA = WorldName.IndexOf('_'); const uint32 UnderscoreA = WorldName.IndexOf('_');
uint32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1); const uint32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1);
if (UnderscoreA != UnderscoreB && UnderscoreA != -1 && UnderscoreB != -1) if (UnderscoreA != UnderscoreB && UnderscoreA != UINT32_MAX && UnderscoreB != UINT32_MAX)
WorldName = WorldName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1); WorldName = WorldName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
} }
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore) // MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
else if (mGame == EGame::Echoes) else if (mGame == EGame::Echoes)
{ {
uint32 FirstUnderscore = WorldName.IndexOf('_'); const uint32 FirstUnderscore = WorldName.IndexOf('_');
uint32 LastUnderscore = WorldName.LastIndexOf('_'); const uint32 LastUnderscore = WorldName.LastIndexOf('_');
if (FirstUnderscore != LastUnderscore && FirstUnderscore != -1 && LastUnderscore != -1) if (FirstUnderscore != LastUnderscore && FirstUnderscore != UINT32_MAX && LastUnderscore != UINT32_MAX)
{ {
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore); WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
WorldName = WorldName.ChopFront(FirstUnderscore + 1); WorldName = WorldName.ChopFront(FirstUnderscore + 1);
WorldName.Remove('_'); WorldName.Remove('_');
} }
} }
// MP3 proto - Remove ! from the beginning and all text after last underscore // MP3 proto - Remove ! from the beginning and all text after last underscore
else if (mGame == EGame::CorruptionProto) else if (mGame == EGame::CorruptionProto)
{ {
if (WorldName.StartsWith('!')) if (WorldName.StartsWith('!'))
WorldName = WorldName.ChopFront(1); WorldName = WorldName.ChopFront(1);
uint32 LastUnderscore = WorldName.LastIndexOf('_'); const uint32 LastUnderscore = WorldName.LastIndexOf('_');
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore); WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
} }
// MP3 - Remove text after last underscore // MP3 - Remove text after last underscore
else if (mGame == EGame::Corruption) else if (mGame == EGame::Corruption)
{ {
uint32 LastUnderscore = WorldName.LastIndexOf('_'); const uint32 LastUnderscore = WorldName.LastIndexOf('_');
if (LastUnderscore != -1 && !WorldName.StartsWith("front_end_")) if (LastUnderscore != UINT32_MAX && !WorldName.StartsWith("front_end_"))
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore); WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
} }
// DKCR - Remove text prior to first underscore // DKCR - Remove text prior to first underscore
else if (mGame == EGame::DKCReturns) else if (mGame == EGame::DKCReturns)
{ {
uint32 Underscore = WorldName.IndexOf('_'); const uint32 Underscore = WorldName.IndexOf('_');
WorldName = WorldName.ChopFront(Underscore + 1); WorldName = WorldName.ChopFront(Underscore + 1);
} }
} }

View File

@ -9,7 +9,8 @@
#include <Common/Flags.h> #include <Common/Flags.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <map> #include <map>
#include <nod/nod.hpp> #include <memory>
#include <nod/DiscBase.hpp>
enum class EDiscType enum class EDiscType
{ {
@ -21,7 +22,7 @@ enum class EDiscType
class CGameExporter class CGameExporter
{ {
// Project Data // Project Data
CGameProject *mpProject; std::unique_ptr<CGameProject> mpProject;
TString mProjectPath; TString mProjectPath;
CResourceStore *mpStore; CResourceStore *mpStore;
EGame mGame; EGame mGame;
@ -38,15 +39,15 @@ class CGameExporter
TString mWorldsDirName; TString mWorldsDirName;
// Files // Files
nod::DiscBase *mpDisc; nod::DiscBase *mpDisc = nullptr;
EDiscType mDiscType; EDiscType mDiscType;
bool mFrontEnd; bool mFrontEnd;
// Resources // Resources
TStringList mPaks; TStringList mPaks;
std::map<CAssetID, bool> mAreaDuplicateMap; std::map<CAssetID, bool> mAreaDuplicateMap;
CAssetNameMap *mpNameMap; CAssetNameMap *mpNameMap = nullptr;
CGameInfo *mpGameInfo; CGameInfo *mpGameInfo = nullptr;
struct SResourceInstance struct SResourceInstance
{ {
@ -61,7 +62,7 @@ class CGameExporter
std::map<CAssetID, SResourceInstance> mResourceMap; std::map<CAssetID, SResourceInstance> mResourceMap;
// Progress // Progress
IProgressNotifier *mpProgress; IProgressNotifier *mpProgress = nullptr;
public: public:
enum EExportStep enum EExportStep
@ -76,9 +77,9 @@ public:
CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion); CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress); bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress);
void LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer); void LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer);
bool ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot); bool ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot) const;
inline TString ProjectPath() const { return mProjectPath; } TString ProjectPath() const { return mProjectPath; }
protected: protected:
bool ExtractDiscData(); bool ExtractDiscData();
@ -91,7 +92,7 @@ protected:
TString MakeWorldName(CAssetID WorldID); TString MakeWorldName(CAssetID WorldID);
// Convenience Functions // Convenience Functions
inline SResourceInstance* FindResourceInstance(const CAssetID& rkID) SResourceInstance* FindResourceInstance(const CAssetID& rkID)
{ {
uint64 IntegralID = rkID.ToLongLong(); uint64 IntegralID = rkID.ToLongLong();
auto Found = mResourceMap.find(IntegralID); auto Found = mResourceMap.find(IntegralID);

View File

@ -1,6 +1,10 @@
#include "CGameInfo.h" #include "CGameInfo.h"
#include "CResourceStore.h" #include "CResourceStore.h"
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <algorithm>
constexpr char gkGameInfoDir[] = "resources/gameinfo";
constexpr char gkGameInfoExt[] = "xml";
bool CGameInfo::LoadGameInfo(EGame Game) bool CGameInfo::LoadGameInfo(EGame Game)
{ {
@ -11,7 +15,7 @@ bool CGameInfo::LoadGameInfo(EGame Game)
return LoadGameInfo(Path); return LoadGameInfo(Path);
} }
bool CGameInfo::LoadGameInfo(TString Path) bool CGameInfo::LoadGameInfo(const TString& Path)
{ {
CXMLReader Reader(Path); CXMLReader Reader(Path);
@ -20,14 +24,17 @@ bool CGameInfo::LoadGameInfo(TString Path)
Serialize(Reader); Serialize(Reader);
return true; return true;
} }
else return false;
return false;
} }
bool CGameInfo::SaveGameInfo(TString Path /*= ""*/) bool CGameInfo::SaveGameInfo(TString Path)
{ {
ASSERT(mGame != EGame::Invalid); // can't save game info that was never loaded ASSERT(mGame != EGame::Invalid); // can't save game info that was never loaded
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame); if (Path.IsEmpty())
Path = GetDefaultGameInfoPath(mGame);
CXMLWriter Writer(Path, "GameInfo", 0, mGame); CXMLWriter Writer(Path, "GameInfo", 0, mGame);
Serialize(Writer); Serialize(Writer);
return Writer.Save(); return Writer.Save();
@ -50,21 +57,19 @@ void CGameInfo::Serialize(IArchive& rArc)
TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const
{ {
for (uint32 iBuild = 0; iBuild < mBuilds.size(); iBuild++) const auto it = std::find_if(mBuilds.cbegin(), mBuilds.cend(),
{ [=](const auto& entry) { return entry.Version == BuildVer && entry.Region == Region; });
const SBuildInfo& rkBuildInfo = mBuilds[iBuild];
if (rkBuildInfo.Version == BuildVer && rkBuildInfo.Region == Region) if (it == mBuilds.cend())
return rkBuildInfo.Name; return "Unknown Build";
}
return "Unknown Build"; return it->Name;
} }
TString CGameInfo::GetAreaName(const CAssetID &rkID) const TString CGameInfo::GetAreaName(const CAssetID &rkID) const
{ {
auto Iter = mAreaNameMap.find(rkID); const auto Iter = mAreaNameMap.find(rkID);
return (Iter == mAreaNameMap.end() ? "" : Iter->second); return Iter == mAreaNameMap.cend() ? "" : Iter->second;
} }
// ************ STATIC ************ // ************ STATIC ************
@ -83,6 +88,11 @@ TString CGameInfo::GetDefaultGameInfoPath(EGame Game)
if (Game == EGame::Invalid) if (Game == EGame::Invalid)
return ""; return "";
TString GameName = GetGameShortName(Game); const TString GameName = GetGameShortName(Game);
return TString::Format("%s/%s/GameInfo%s.%s", *gDataDir, *gkGameInfoDir, *GameName, *gkGameInfoExt); return TString::Format("%s/%s/GameInfo%s.%s", gDataDir.ToStdString().c_str(), gkGameInfoDir, GameName.ToStdString().c_str(), gkGameInfoExt);
}
TString CGameInfo::GetExtension()
{
return gkGameInfoExt;
} }

View File

@ -8,14 +8,11 @@
#include <Common/Serialization/XML.h> #include <Common/Serialization/XML.h>
#include <map> #include <map>
const TString gkGameInfoDir = "resources/gameinfo";
const TString gkGameInfoExt = "xml";
//@todo merge this class into CGameTemplate //@todo merge this class into CGameTemplate
// they serve similar purposes, no real reason for them to be different classes // they serve similar purposes, no real reason for them to be different classes
class CGameInfo class CGameInfo
{ {
EGame mGame; EGame mGame{EGame::Invalid};
// List of known builds of each game // List of known builds of each game
struct SBuildInfo struct SBuildInfo
@ -37,12 +34,10 @@ class CGameInfo
std::map<CAssetID, TString> mAreaNameMap; std::map<CAssetID, TString> mAreaNameMap;
public: public:
CGameInfo() CGameInfo() = default;
: mGame(EGame::Invalid)
{}
bool LoadGameInfo(EGame Game); bool LoadGameInfo(EGame Game);
bool LoadGameInfo(TString Path); bool LoadGameInfo(const TString& Path);
bool SaveGameInfo(TString Path = ""); bool SaveGameInfo(TString Path = "");
void Serialize(IArchive& rArc); void Serialize(IArchive& rArc);
@ -50,14 +45,14 @@ public:
TString GetAreaName(const CAssetID& rkID) const; TString GetAreaName(const CAssetID& rkID) const;
// Accessors // Accessors
inline EGame Game() const { return mGame; } EGame Game() const { return mGame; }
// Static // Static
static CGameInfo* GetGameInfo(EGame Game); static CGameInfo* GetGameInfo(EGame Game);
static EGame RoundGame(EGame Game); static EGame RoundGame(EGame Game);
static TString GetDefaultGameInfoPath(EGame Game); static TString GetDefaultGameInfoPath(EGame Game);
inline static TString GetExtension() { return gkGameInfoExt; } static TString GetExtension();
}; };
#endif // CGAMEINFO #endif // CGAMEINFO

View File

@ -3,7 +3,8 @@
#include "IUIRelay.h" #include "IUIRelay.h"
#include "Core/Resource/Script/CGameTemplate.h" #include "Core/Resource/Script/CGameTemplate.h"
#include <Common/Serialization/XML.h> #include <Common/Serialization/XML.h>
#include <nod/nod.hpp> #include <nod/DiscGCN.hpp>
#include <nod/DiscWii.hpp>
#if NOD_UCS2 #if NOD_UCS2
#define TStringToNodString(string) ToWChar(string) #define TStringToNodString(string) ToWChar(string)
@ -13,25 +14,22 @@
CGameProject::~CGameProject() CGameProject::~CGameProject()
{ {
if (mpResourceStore) if (!mpResourceStore)
{ return;
ASSERT(!mpResourceStore->IsCacheDirty());
if (gpResourceStore == mpResourceStore.get()) ASSERT(!mpResourceStore->IsCacheDirty());
gpResourceStore = nullptr;
}
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) if (gpResourceStore == mpResourceStore.get())
delete mPackages[iPkg]; gpResourceStore = nullptr;
} }
bool CGameProject::Save() bool CGameProject::Save()
{ {
mProjFileLock.Release(); mProjFileLock.Release();
TString ProjPath = ProjectPath(); const TString ProjPath = ProjectPath();
CXMLWriter Writer(ProjPath, "GameProject", (int) EProjectVersion::Current, mGame); CXMLWriter Writer(ProjPath, "GameProject", static_cast<int>(EProjectVersion::Current), mGame);
Serialize(Writer); Serialize(Writer);
bool SaveSuccess = Writer.Save(); const bool SaveSuccess = Writer.Save();
mProjFileLock.Lock(*ProjPath); mProjFileLock.Lock(*ProjPath);
return SaveSuccess; return SaveSuccess;
} }
@ -48,8 +46,8 @@ bool CGameProject::Serialize(IArchive& rArc)
if (!rArc.IsReader()) if (!rArc.IsReader())
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (auto& package : mPackages)
PackageList.push_back( mPackages[iPkg]->DefinitionPath(true) ); PackageList.push_back(package->DefinitionPath(true));
} }
rArc << SerialParameter("Packages", PackageList); rArc << SerialParameter("Packages", PackageList);
@ -59,15 +57,14 @@ bool CGameProject::Serialize(IArchive& rArc)
{ {
ASSERT(mPackages.empty()); ASSERT(mPackages.empty());
for (uint32 iPkg = 0; iPkg < PackageList.size(); iPkg++) for (const TString& packagePath : PackageList)
{ {
const TString& rkPackagePath = PackageList[iPkg]; TString PackageName = packagePath.GetFileName(false);
TString PackageName = rkPackagePath.GetFileName(false); TString PackageDir = packagePath.GetFileDirectory();
TString PackageDir = rkPackagePath.GetFileDirectory();
CPackage *pPackage = new CPackage(this, PackageName, PackageDir); auto pPackage = std::make_unique<CPackage>(this, std::move(PackageName), std::move(PackageDir));
bool PackageLoadSuccess = pPackage->Load(); const bool PackageLoadSuccess = pPackage->Load();
mPackages.push_back(pPackage); mPackages.push_back(std::move(pPackage));
if (!PackageLoadSuccess) if (!PackageLoadSuccess)
{ {
@ -81,16 +78,16 @@ bool CGameProject::Serialize(IArchive& rArc)
bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress) bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress)
{ {
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) ); ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
ASSERT( !IsWiiDeAsobu() && !IsTrilogy() ); ASSERT(!IsWiiDeAsobu() && !IsTrilogy());
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t) const auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
{ {
pProgress->Report((int) (ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str()); pProgress->Report(static_cast<int>(ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
}; };
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName()); pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
TString DiscRoot = DiscDir(false); const TString DiscRoot = DiscDir(false);
if (!IsWiiBuild()) if (!IsWiiBuild())
{ {
@ -106,18 +103,18 @@ bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgre
bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress) bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress)
{ {
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) ); ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
ASSERT( IsWiiDeAsobu() || IsTrilogy() ); ASSERT(IsWiiDeAsobu() || IsTrilogy());
ASSERT( pOriginalIso != nullptr ); ASSERT(pOriginalIso != nullptr);
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t) const auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
{ {
pProgress->Report((int) (ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str()); pProgress->Report(static_cast<int>(ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
}; };
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName()); pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
TString DiscRoot = DiscFilesystemRoot(false); const TString DiscRoot = DiscFilesystemRoot(false);
nod::DiscMergerWii Merger(TStringToNodString(rkIsoPath), *pOriginalIso, IsTrilogy(), ProgressCallback); nod::DiscMergerWii Merger(TStringToNodString(rkIsoPath), *pOriginalIso, IsTrilogy(), ProgressCallback);
return Merger.mergeFromDirectory(TStringToNodString(DiscRoot)) == nod::EBuildResult::Success; return Merger.mergeFromDirectory(TStringToNodString(DiscRoot)) == nod::EBuildResult::Success;
@ -125,15 +122,13 @@ bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso
void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (const auto& pPkg : mPackages)
{ {
CPackage *pPkg = mPackages[iPkg];
// Little workaround to fix some of Retro's paks having worlds listed in the wrong order... // Little workaround to fix some of Retro's paks having worlds listed in the wrong order...
// Construct a sorted list of worlds in this package // Construct a sorted list of worlds in this package
std::list<const SNamedResource*> PackageWorlds; std::list<const SNamedResource*> PackageWorlds;
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
@ -146,25 +141,22 @@ void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
}); });
// Add sorted worlds to the output world list // Add sorted worlds to the output world list
for (auto Iter = PackageWorlds.begin(); Iter != PackageWorlds.end(); Iter++) for (const auto* res : PackageWorlds)
{ {
const SNamedResource *pkRes = *Iter; rOut.push_back(res->ID);
rOut.push_back(pkRes->ID);
} }
} }
} }
CAssetID CGameProject::FindNamedResource(const TString& rkName) const CAssetID CGameProject::FindNamedResource(std::string_view name) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (const auto& pkg : mPackages)
{ {
CPackage *pPkg = mPackages[iPkg]; for (size_t iRes = 0; iRes < pkg->NumNamedResources(); iRes++)
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); const SNamedResource& rkRes = pkg->NamedResourceByIndex(iRes);
if (rkRes.Name == rkName) if (rkRes.Name == name)
return rkRes.ID; return rkRes.ID;
} }
} }
@ -172,22 +164,18 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const
return CAssetID::InvalidID(mGame); return CAssetID::InvalidID(mGame);
} }
CPackage* CGameProject::FindPackage(const TString& rkName) const CPackage* CGameProject::FindPackage(std::string_view name) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) const auto iter = std::find_if(mPackages.begin(), mPackages.end(),
{ [name](const auto& package) { return package->Name() == name; });
CPackage *pPackage = mPackages[iPkg];
if (pPackage->Name() == rkName) if (iter == mPackages.cend())
{ return nullptr;
return pPackage;
}
}
return nullptr; return iter->get();
} }
CGameProject* CGameProject::CreateProjectForExport( std::unique_ptr<CGameProject> CGameProject::CreateProjectForExport(
const TString& rkProjRootDir, const TString& rkProjRootDir,
EGame Game, EGame Game,
ERegion Region, ERegion Region,
@ -195,7 +183,7 @@ CGameProject* CGameProject::CreateProjectForExport(
float BuildVer float BuildVer
) )
{ {
CGameProject *pProj = new CGameProject; auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mGame = Game; pProj->mGame = Game;
pProj->mRegion = Region; pProj->mRegion = Region;
pProj->mGameID = rkGameID; pProj->mGameID = rkGameID;
@ -203,15 +191,15 @@ CGameProject* CGameProject::CreateProjectForExport(
pProj->mProjectRoot = rkProjRootDir; pProj->mProjectRoot = rkProjRootDir;
pProj->mProjectRoot.Replace("\\", "/"); pProj->mProjectRoot.Replace("\\", "/");
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj); pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
pProj->mpGameInfo->LoadGameInfo(Game); pProj->mpGameInfo->LoadGameInfo(Game);
return pProj; return pProj;
} }
CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress) std::unique_ptr<CGameProject> CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
{ {
// Init project // Init project
CGameProject *pProj = new CGameProject; auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mProjectRoot = rkProjPath.GetFileDirectory(); pProj->mProjectRoot = rkProjPath.GetFileDirectory();
pProj->mProjectRoot.Replace("\\", "/"); pProj->mProjectRoot.Replace("\\", "/");
@ -222,12 +210,11 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
pProgress->Report("Loading project settings"); pProgress->Report("Loading project settings");
bool LoadSuccess = false; bool LoadSuccess = false;
TString ProjPath = rkProjPath; const TString ProjPath = rkProjPath;
CXMLReader Reader(ProjPath); CXMLReader Reader(ProjPath);
if (!Reader.IsValid()) if (!Reader.IsValid())
{ {
delete pProj;
return nullptr; return nullptr;
} }
@ -237,7 +224,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
{ {
// Load resource database // Load resource database
pProgress->Report("Loading resource database"); pProgress->Report("Loading resource database");
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj); pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache(); LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
// Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long // Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long
@ -269,7 +256,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
if (!LoadSuccess) if (!LoadSuccess)
{ {
delete pProj;
return nullptr; return nullptr;
} }
@ -277,7 +263,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
pProj->mpGameInfo->LoadGameInfo(pProj->mGame); pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
// Perform update // Perform update
if (Reader.FileVersion() < (uint16) EProjectVersion::Current) if (Reader.FileVersion() < static_cast<uint16>(EProjectVersion::Current))
{ {
pProgress->Report("Updating project"); pProgress->Report("Updating project");
@ -304,7 +290,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
} }
// Create hidden files directory, if needed // Create hidden files directory, if needed
TString HiddenDir = pProj->HiddenFilesDir(); const TString HiddenDir = pProj->HiddenFilesDir();
if (!FileUtil::Exists(HiddenDir)) if (!FileUtil::Exists(HiddenDir))
{ {

View File

@ -13,6 +13,8 @@
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <Common/FileIO/CFileLock.h> #include <Common/FileIO/CFileLock.h>
#include <memory>
#include <string_view>
namespace nod { class DiscWii; } namespace nod { class DiscWii; }
@ -23,41 +25,30 @@ enum class EProjectVersion
// Add new versions before this line // Add new versions before this line
Max, Max,
Current = EProjectVersion::Max - 1 Current = Max - 1
}; };
class CGameProject class CGameProject
{ {
TString mProjectName; TString mProjectName{"Unnamed Project"};
EGame mGame; EGame mGame{EGame::Invalid};
ERegion mRegion; ERegion mRegion{ERegion::Unknown};
TString mGameID; TString mGameID{"000000"};
float mBuildVersion; float mBuildVersion = 0.f;
TString mProjectRoot; TString mProjectRoot;
std::vector<CPackage*> mPackages; std::vector<std::unique_ptr<CPackage>> mPackages;
std::unique_ptr<CResourceStore> mpResourceStore; std::unique_ptr<CResourceStore> mpResourceStore;
std::unique_ptr<CGameInfo> mpGameInfo; std::unique_ptr<CGameInfo> mpGameInfo = std::make_unique<CGameInfo>();
std::unique_ptr<CAudioManager> mpAudioManager; std::unique_ptr<CAudioManager> mpAudioManager = std::make_unique<CAudioManager>(this);
std::unique_ptr<CTweakManager> mpTweakManager; std::unique_ptr<CTweakManager> mpTweakManager = std::make_unique<CTweakManager>(this);
// Keep file handle open for the .prj file to prevent users from opening the same project // Keep file handle open for the .prj file to prevent users from opening the same project
// in multiple instances of PWE // in multiple instances of PWE
CFileLock mProjFileLock; CFileLock mProjFileLock;
// Private Constructor // Private Constructor
CGameProject() CGameProject() = default;
: mProjectName("Unnamed Project")
, mGame(EGame::Invalid)
, mRegion(ERegion::Unknown)
, mGameID("000000")
, mBuildVersion(0.f)
, mpResourceStore(nullptr)
{
mpGameInfo = std::make_unique<CGameInfo>();
mpAudioManager = std::make_unique<CAudioManager>(this);
mpTweakManager = std::make_unique<CTweakManager>(this);
}
public: public:
~CGameProject(); ~CGameProject();
@ -67,11 +58,11 @@ public:
bool BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress); bool BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress);
bool MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress); bool MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress);
void GetWorldList(std::list<CAssetID>& rOut) const; void GetWorldList(std::list<CAssetID>& rOut) const;
CAssetID FindNamedResource(const TString& rkName) const; CAssetID FindNamedResource(std::string_view name) const;
CPackage* FindPackage(const TString& rkName) const; CPackage* FindPackage(std::string_view name) const;
// Static // Static
static CGameProject* CreateProjectForExport( static std::unique_ptr<CGameProject> CreateProjectForExport(
const TString& rkProjRootDir, const TString& rkProjRootDir,
EGame Game, EGame Game,
ERegion Region, ERegion Region,
@ -79,37 +70,37 @@ public:
float BuildVer float BuildVer
); );
static CGameProject* LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress); static std::unique_ptr<CGameProject> LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress);
// Directory Handling // Directory Handling
inline TString ProjectRoot() const { return mProjectRoot; } TString ProjectRoot() const { return mProjectRoot; }
inline TString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName, false) + ".prj"; } TString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName, false) + ".prj"; }
inline TString HiddenFilesDir() const { return mProjectRoot + ".project/"; } TString HiddenFilesDir() const { return mProjectRoot + ".project/"; }
inline TString DiscDir(bool Relative) const { return Relative ? "Disc/" : mProjectRoot + "Disc/"; } TString DiscDir(bool Relative) const { return Relative ? "Disc/" : mProjectRoot + "Disc/"; }
inline TString PackagesDir(bool Relative) const { return Relative ? "Packages/" : mProjectRoot + "Packages/"; } TString PackagesDir(bool Relative) const { return Relative ? "Packages/" : mProjectRoot + "Packages/"; }
inline TString ResourcesDir(bool Relative) const { return Relative ? "Resources/" : mProjectRoot + "Resources/"; } TString ResourcesDir(bool Relative) const { return Relative ? "Resources/" : mProjectRoot + "Resources/"; }
// Disc Filesystem Management // Disc Filesystem Management
inline TString DiscFilesystemRoot(bool Relative) const { return DiscDir(Relative) + (IsWiiBuild() ? "DATA/" : "") + "files/"; } TString DiscFilesystemRoot(bool Relative) const { return DiscDir(Relative) + (IsWiiBuild() ? "DATA/" : "") + "files/"; }
// Accessors // Accessors
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; } void SetProjectName(TString name) { mProjectName = std::move(name); }
inline TString Name() const { return mProjectName; } TString Name() const { return mProjectName; }
inline uint32 NumPackages() const { return mPackages.size(); } size_t NumPackages() const { return mPackages.size(); }
inline CPackage* PackageByIndex(uint32 Index) const { return mPackages[Index]; } CPackage* PackageByIndex(size_t Index) const { return mPackages[Index].get(); }
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); } void AddPackage(std::unique_ptr<CPackage>&& package) { mPackages.push_back(std::move(package)); }
inline CResourceStore* ResourceStore() const { return mpResourceStore.get(); } CResourceStore* ResourceStore() const { return mpResourceStore.get(); }
inline CGameInfo* GameInfo() const { return mpGameInfo.get(); } CGameInfo* GameInfo() const { return mpGameInfo.get(); }
inline CAudioManager* AudioManager() const { return mpAudioManager.get(); } CAudioManager* AudioManager() const { return mpAudioManager.get(); }
inline CTweakManager* TweakManager() const { return mpTweakManager.get(); } CTweakManager* TweakManager() const { return mpTweakManager.get(); }
inline EGame Game() const { return mGame; } EGame Game() const { return mGame; }
inline ERegion Region() const { return mRegion; } ERegion Region() const { return mRegion; }
inline TString GameID() const { return mGameID; } TString GameID() const { return mGameID; }
inline float BuildVersion() const { return mBuildVersion; } float BuildVersion() const { return mBuildVersion; }
inline bool IsWiiBuild() const { return mBuildVersion >= 3.f; } bool IsWiiBuild() const { return mBuildVersion >= 3.f; }
inline bool IsTrilogy() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.593f; } bool IsTrilogy() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.593f; }
inline bool IsWiiDeAsobu() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; } bool IsWiiDeAsobu() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; }
}; };
#endif // CGAMEPROJECT_H #endif // CGAMEPROJECT_H

View File

@ -13,7 +13,7 @@ class COpeningBanner
bool mWii; bool mWii;
public: public:
COpeningBanner(CGameProject *pProj); explicit COpeningBanner(CGameProject *pProj);
TString EnglishGameName() const; TString EnglishGameName() const;
void SetEnglishGameName(const TString& rkName); void SetEnglishGameName(const TString& rkName);
void Save(); void Save();

View File

@ -12,7 +12,7 @@ using namespace tinyxml2;
bool CPackage::Load() bool CPackage::Load()
{ {
TString DefPath = DefinitionPath(false); const TString DefPath = DefinitionPath(false);
CXMLReader Reader(DefPath); CXMLReader Reader(DefPath);
if (Reader.IsValid()) if (Reader.IsValid())
@ -21,12 +21,13 @@ bool CPackage::Load()
mCacheDirty = true; mCacheDirty = true;
return true; return true;
} }
else return false;
return false;
} }
bool CPackage::Save() bool CPackage::Save()
{ {
TString DefPath = DefinitionPath(false); const TString DefPath = DefinitionPath(false);
FileUtil::MakeDirectory(DefPath.GetFileDirectory()); FileUtil::MakeDirectory(DefPath.GetFileDirectory());
CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : EGame::Invalid); CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : EGame::Invalid);
@ -53,8 +54,8 @@ void CPackage::UpdateDependencyCache() const
Builder.BuildDependencyList(false, AssetList); Builder.BuildDependencyList(false, AssetList);
mCachedDependencies.clear(); mCachedDependencies.clear();
for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++) for (const auto& asset : AssetList)
mCachedDependencies.insert(*Iter); mCachedDependencies.insert(asset);
mCacheDirty = false; mCacheDirty = false;
} }
@ -82,7 +83,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
debugf("%d assets in %s.pak", AssetList.size(), *Name()); debugf("%d assets in %s.pak", AssetList.size(), *Name());
// Write new pak // Write new pak
TString PakPath = CookedPackagePath(false); const TString PakPath = CookedPackagePath(false);
CFileOutStream Pak(PakPath, EEndian::BigEndian); CFileOutStream Pak(PakPath, EEndian::BigEndian);
if (!Pak.IsValid()) if (!Pak.IsValid())
@ -91,9 +92,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
return; return;
} }
EGame Game = mpProject->Game(); const EGame Game = mpProject->Game();
uint32 Alignment = (Game <= EGame::CorruptionProto ? 0x20 : 0x40); const uint32 Alignment = (Game <= EGame::CorruptionProto ? 0x20 : 0x40);
uint32 AlignmentMinusOne = Alignment - 1; const uint32 AlignmentMinusOne = Alignment - 1;
uint32 TocOffset = 0; uint32 TocOffset = 0;
uint32 NamesSize = 0; uint32 NamesSize = 0;
@ -110,17 +111,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// Named Resources // Named Resources
Pak.WriteLong(mResources.size()); Pak.WriteLong(mResources.size());
for (auto Iter = mResources.begin(); Iter != mResources.end(); Iter++) for (const auto& res : mResources)
{ {
const SNamedResource& rkRes = *Iter; res.Type.Write(Pak);
rkRes.Type.Write(Pak); res.ID.Write(Pak);
rkRes.ID.Write(Pak); Pak.WriteSizedString(res.Name);
Pak.WriteSizedString(rkRes.Name);
} }
} }
else // Write MP3 pak header
// Write MP3 pak header
else
{ {
// Header // Header
Pak.WriteLong(2); // Version Pak.WriteLong(2); // Version
@ -133,15 +131,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
Pak.WriteToBoundary(0x40, 0); Pak.WriteToBoundary(0x40, 0);
// Named Resources // Named Resources
uint32 NamesStart = Pak.Tell(); const uint32 NamesStart = Pak.Tell();
Pak.WriteLong(mResources.size()); Pak.WriteULong(static_cast<uint32>(mResources.size()));
for (auto Iter = mResources.begin(); Iter != mResources.end(); Iter++) for (const auto& res : mResources)
{ {
const SNamedResource& rkRes = *Iter; Pak.WriteString(res.Name);
Pak.WriteString(rkRes.Name); res.Type.Write(Pak);
rkRes.Type.Write(Pak); res.ID.Write(Pak);
rkRes.ID.Write(Pak);
} }
Pak.WriteToBoundary(0x40, 0); Pak.WriteToBoundary(0x40, 0);
@ -151,9 +148,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// Fill in resource table with junk, write later // Fill in resource table with junk, write later
ResTableOffset = Pak.Tell(); ResTableOffset = Pak.Tell();
Pak.WriteLong(AssetList.size()); Pak.WriteLong(AssetList.size());
CAssetID Dummy = CAssetID::InvalidID(Game); const CAssetID Dummy = CAssetID::InvalidID(Game);
for (uint32 iRes = 0; iRes < AssetList.size(); iRes++) for (size_t iRes = 0; iRes < AssetList.size(); iRes++)
{ {
Pak.WriteLongLong(0); Pak.WriteLongLong(0);
Dummy.Write(Pak); Dummy.Write(Pak);
@ -173,13 +170,13 @@ void CPackage::Cook(IProgressNotifier *pProgress)
}; };
std::vector<SResourceTableInfo> ResourceTableData(AssetList.size()); std::vector<SResourceTableInfo> ResourceTableData(AssetList.size());
uint32 ResIdx = 0; uint32 ResIdx = 0;
uint32 ResDataOffset = Pak.Tell(); const uint32 ResDataOffset = Pak.Tell();
for (auto Iter = AssetList.begin(); Iter != AssetList.end() && !pProgress->ShouldCancel(); Iter++, ResIdx++) for (auto Iter = AssetList.begin(); Iter != AssetList.end() && !pProgress->ShouldCancel(); Iter++, ResIdx++)
{ {
// Initialize entry, recook assets if needed // Initialize entry, recook assets if needed
uint32 AssetOffset = Pak.Tell(); const uint32 AssetOffset = Pak.Tell();
CAssetID ID = *Iter; const CAssetID ID = *Iter;
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID); CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
ASSERT(pEntry != nullptr); ASSERT(pEntry != nullptr);
@ -190,7 +187,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
} }
// Update progress bar // Update progress bar
if (ResIdx & 0x1 || ResIdx == AssetList.size() - 1) if ((ResIdx & 1) != 0 || ResIdx == AssetList.size() - 1)
{ {
pProgress->Report(ResIdx, AssetList.size(), TString::Format("Writing asset %d/%d: %s", ResIdx+1, AssetList.size(), *(pEntry->Name() + "." + pEntry->CookedExtension()))); pProgress->Report(ResIdx, AssetList.size(), TString::Format("Writing asset %d/%d: %s", ResIdx+1, AssetList.size(), *(pEntry->Name() + "." + pEntry->CookedExtension())));
} }
@ -203,15 +200,15 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// Load resource data // Load resource data
CFileInStream CookedAsset(pEntry->CookedAssetPath(), EEndian::BigEndian); CFileInStream CookedAsset(pEntry->CookedAssetPath(), EEndian::BigEndian);
ASSERT(CookedAsset.IsValid()); ASSERT(CookedAsset.IsValid());
uint32 ResourceSize = CookedAsset.Size(); const uint32 ResourceSize = CookedAsset.Size();
std::vector<uint8> ResourceData(ResourceSize); std::vector<uint8> ResourceData(ResourceSize);
CookedAsset.ReadBytes(ResourceData.data(), ResourceData.size()); CookedAsset.ReadBytes(ResourceData.data(), ResourceData.size());
// Check if this asset should be compressed; there are a few resource types that are // Check if this asset should be compressed; there are a few resource types that are
// always compressed, and some types that are compressed if they're over a certain size // always compressed, and some types that are compressed if they're over a certain size
EResourceType Type = pEntry->ResourceType(); const EResourceType Type = pEntry->ResourceType();
uint32 CompressThreshold = (Game <= EGame::CorruptionProto ? 0x400 : 0x80); const uint32 CompressThreshold = (Game <= EGame::CorruptionProto ? 0x400 : 0x80);
bool ShouldAlwaysCompress = (Type == EResourceType::Texture || Type == EResourceType::Model || bool ShouldAlwaysCompress = (Type == EResourceType::Texture || Type == EResourceType::Model ||
Type == EResourceType::Skin || Type == EResourceType::AnimSet || Type == EResourceType::Skin || Type == EResourceType::AnimSet ||
@ -226,14 +223,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
Type == EResourceType::DynamicCollision); Type == EResourceType::DynamicCollision);
} }
bool ShouldCompressConditional = !ShouldAlwaysCompress && const bool ShouldCompressConditional = !ShouldAlwaysCompress &&
(Type == EResourceType::Particle || Type == EResourceType::ParticleElectric || (Type == EResourceType::Particle || Type == EResourceType::ParticleElectric ||
Type == EResourceType::ParticleSwoosh || Type == EResourceType::ParticleWeapon || Type == EResourceType::ParticleSwoosh || Type == EResourceType::ParticleWeapon ||
Type == EResourceType::ParticleDecal || Type == EResourceType::ParticleCollisionResponse || Type == EResourceType::ParticleDecal || Type == EResourceType::ParticleCollisionResponse ||
Type == EResourceType::ParticleSpawn || Type == EResourceType::ParticleSorted || Type == EResourceType::ParticleSpawn || Type == EResourceType::ParticleSorted ||
Type == EResourceType::BurstFireData); Type == EResourceType::BurstFireData);
bool ShouldCompress = ShouldAlwaysCompress || (ShouldCompressConditional && ResourceSize >= CompressThreshold); const bool ShouldCompress = ShouldAlwaysCompress || (ShouldCompressConditional && ResourceSize >= CompressThreshold);
// Write resource data to pak // Write resource data to pak
if (!ShouldCompress) if (!ShouldCompress)
@ -241,7 +238,6 @@ void CPackage::Cook(IProgressNotifier *pProgress)
Pak.WriteBytes(ResourceData.data(), ResourceSize); Pak.WriteBytes(ResourceData.data(), ResourceSize);
rTableInfo.Compressed = false; rTableInfo.Compressed = false;
} }
else else
{ {
uint32 CompressedSize; uint32 CompressedSize;
@ -256,9 +252,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value // Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value
if (Success) if (Success)
{ {
uint32 CompressionHeaderSize = (Game <= EGame::CorruptionProto ? 4 : 0x10); const uint32 CompressionHeaderSize = (Game <= EGame::CorruptionProto ? 4 : 0x10);
uint32 PaddedUncompressedSize = (ResourceSize + AlignmentMinusOne) & ~AlignmentMinusOne; const uint32 PaddedUncompressedSize = (ResourceSize + AlignmentMinusOne) & ~AlignmentMinusOne;
uint32 PaddedCompressedSize = (CompressedSize + CompressionHeaderSize + AlignmentMinusOne) & ~AlignmentMinusOne; const uint32 PaddedCompressedSize = (CompressedSize + CompressionHeaderSize + AlignmentMinusOne) & ~AlignmentMinusOne;
Success = (PaddedCompressedSize < PaddedUncompressedSize); Success = (PaddedCompressedSize < PaddedUncompressedSize);
} }
@ -268,7 +264,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// Write MP1/2 compressed asset // Write MP1/2 compressed asset
if (Game <= EGame::CorruptionProto) if (Game <= EGame::CorruptionProto)
{ {
Pak.WriteLong(ResourceSize); Pak.WriteULong(ResourceSize);
} }
// Write MP3/DKCR compressed asset // Write MP3/DKCR compressed asset
else else
@ -279,13 +275,15 @@ void CPackage::Cook(IProgressNotifier *pProgress)
// multiple blocks or not, so for the sake of simplicity we compress everything to one block. // multiple blocks or not, so for the sake of simplicity we compress everything to one block.
Pak.WriteFourCC( FOURCC('CMPD') ); Pak.WriteFourCC( FOURCC('CMPD') );
Pak.WriteLong(1); Pak.WriteLong(1);
Pak.WriteLong(0xA0000000 | CompressedSize); Pak.WriteULong(0xA0000000 | CompressedSize);
Pak.WriteLong(ResourceSize); Pak.WriteULong(ResourceSize);
} }
Pak.WriteBytes(CompressedData.data(), CompressedSize); Pak.WriteBytes(CompressedData.data(), CompressedSize);
} }
else else
{
Pak.WriteBytes(ResourceData.data(), ResourceSize); Pak.WriteBytes(ResourceData.data(), ResourceSize);
}
rTableInfo.Compressed = Success; rTableInfo.Compressed = Success;
} }
@ -302,7 +300,6 @@ void CPackage::Cook(IProgressNotifier *pProgress)
FileUtil::DeleteFile(PakPath); FileUtil::DeleteFile(PakPath);
mNeedsRecook = true; mNeedsRecook = true;
} }
else else
{ {
// Write table of contents for real // Write table of contents for real
@ -311,26 +308,26 @@ void CPackage::Cook(IProgressNotifier *pProgress)
Pak.Seek(TocOffset, SEEK_SET); Pak.Seek(TocOffset, SEEK_SET);
Pak.WriteLong(3); // Always 3 pak sections Pak.WriteLong(3); // Always 3 pak sections
Pak.WriteFourCC( FOURCC('STRG') ); Pak.WriteFourCC( FOURCC('STRG') );
Pak.WriteLong(NamesSize); Pak.WriteULong(NamesSize);
Pak.WriteFourCC( FOURCC('RSHD') ); Pak.WriteFourCC( FOURCC('RSHD') );
Pak.WriteLong(ResTableSize); Pak.WriteULong(ResTableSize);
Pak.WriteFourCC( FOURCC('DATA') ); Pak.WriteFourCC( FOURCC('DATA') );
Pak.WriteLong(ResDataSize); Pak.WriteULong(ResDataSize);
} }
// Write resource table for real // Write resource table for real
Pak.Seek(ResTableOffset+4, SEEK_SET); Pak.Seek(ResTableOffset+4, SEEK_SET);
for (uint32 iRes = 0; iRes < AssetList.size(); iRes++) for (size_t iRes = 0; iRes < AssetList.size(); iRes++)
{ {
const SResourceTableInfo& rkInfo = ResourceTableData[iRes]; const SResourceTableInfo& rkInfo = ResourceTableData[iRes];
CResourceEntry *pEntry = rkInfo.pEntry; CResourceEntry *pEntry = rkInfo.pEntry;
Pak.WriteLong( rkInfo.Compressed ? 1 : 0 ); Pak.WriteLong(rkInfo.Compressed ? 1 : 0);
pEntry->CookedExtension().Write(Pak); pEntry->CookedExtension().Write(Pak);
pEntry->ID().Write(Pak); pEntry->ID().Write(Pak);
Pak.WriteLong(rkInfo.Size); Pak.WriteULong(rkInfo.Size);
Pak.WriteLong(rkInfo.Offset); Pak.WriteULong(rkInfo.Offset);
} }
// Clear recook flag // Clear recook flag
@ -351,11 +348,11 @@ void CPackage::CompareOriginalAssetList(const std::list<CAssetID>& rkNewList)
// Build a set out of the generated list // Build a set out of the generated list
std::set<CAssetID> NewListSet; std::set<CAssetID> NewListSet;
for (auto Iter = rkNewList.begin(); Iter != rkNewList.end(); Iter++) for (const auto& id : rkNewList)
NewListSet.insert(*Iter); NewListSet.insert(id);
// Read the original pak // Read the original pak
TString CookedPath = CookedPackagePath(false); const TString CookedPath = CookedPackagePath(false);
CFileInStream Pak(CookedPath, EEndian::BigEndian); CFileInStream Pak(CookedPath, EEndian::BigEndian);
if (!Pak.IsValid() || Pak.Size() == 0) if (!Pak.IsValid() || Pak.Size() == 0)
@ -365,79 +362,73 @@ void CPackage::CompareOriginalAssetList(const std::list<CAssetID>& rkNewList)
} }
// Determine pak version // Determine pak version
uint32 PakVersion = Pak.ReadLong(); const uint32 PakVersion = Pak.ReadULong();
std::set<CAssetID> OldListSet; std::set<CAssetID> OldListSet;
// Read MP1/2 pak // Read MP1/2 pak
if (PakVersion == 0x00030005) if (PakVersion == 0x00030005)
{ {
Pak.Seek(0x4, SEEK_CUR); Pak.Seek(0x4, SEEK_CUR);
uint32 NumNamedResources = Pak.ReadLong(); const uint32 NumNamedResources = Pak.ReadULong();
for (uint32 iName = 0; iName < NumNamedResources; iName++) for (uint32 iName = 0; iName < NumNamedResources; iName++)
{ {
Pak.Seek(0x8, SEEK_CUR); Pak.Seek(0x8, SEEK_CUR);
uint32 NameLen = Pak.ReadLong(); const uint32 NameLen = Pak.ReadULong();
Pak.Seek(NameLen, SEEK_CUR); Pak.Seek(NameLen, SEEK_CUR);
} }
// Build a set out of the original pak resource list // Build a set out of the original pak resource list
uint32 NumResources = Pak.ReadLong(); const uint32 NumResources = Pak.ReadULong();
for (uint32 iRes = 0; iRes < NumResources; iRes++) for (uint32 iRes = 0; iRes < NumResources; iRes++)
{ {
Pak.Seek(0x8, SEEK_CUR); Pak.Seek(0x8, SEEK_CUR);
OldListSet.insert( CAssetID(Pak, k32Bit) ); OldListSet.insert(CAssetID(Pak, EIDLength::k32Bit));
Pak.Seek(0x8, SEEK_CUR); Pak.Seek(0x8, SEEK_CUR);
} }
} }
else // Read MP3/DKCR pak
// Read MP3/DKCR pak
else
{ {
ASSERT(PakVersion == 0x2); ASSERT(PakVersion == 0x2);
// Skip named resources // Skip named resources
Pak.Seek(0x44, SEEK_SET); Pak.Seek(0x44, SEEK_SET);
CFourCC StringSecType = Pak.ReadLong(); [[maybe_unused]] const CFourCC StringSecType = Pak.ReadULong();
uint32 StringSecSize = Pak.ReadLong(); const uint32 StringSecSize = Pak.ReadULong();
ASSERT(StringSecType == "STRG"); ASSERT(StringSecType == "STRG");
Pak.Seek(0x80 + StringSecSize, SEEK_SET); Pak.Seek(0x80 + StringSecSize, SEEK_SET);
// Read resource table // Read resource table
uint32 NumResources = Pak.ReadLong(); const uint32 NumResources = Pak.ReadULong();
for (uint32 iRes = 0; iRes < NumResources; iRes++) for (uint32 iRes = 0; iRes < NumResources; iRes++)
{ {
Pak.Seek(0x8, SEEK_CUR); Pak.Seek(0x8, SEEK_CUR);
OldListSet.insert( CAssetID(Pak, k64Bit) ); OldListSet.insert(CAssetID(Pak, EIDLength::k64Bit));
Pak.Seek(0x8, SEEK_CUR); Pak.Seek(0x8, SEEK_CUR);
} }
} }
// Check for missing resources in the new list // Check for missing resources in the new list
for (auto Iter = OldListSet.begin(); Iter != OldListSet.end(); Iter++) for (const auto& ID : OldListSet)
{ {
CAssetID ID = *Iter;
if (NewListSet.find(ID) == NewListSet.end()) if (NewListSet.find(ID) == NewListSet.end())
{ {
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID); const CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
TString Extension = (pEntry ? "." + pEntry->CookedExtension() : ""); const TString Extension = (pEntry != nullptr ? "." + pEntry->CookedExtension() : "");
warnf("Missing resource: %s%s", *ID.ToString(), *Extension); warnf("Missing resource: %s%s", *ID.ToString(), *Extension);
} }
} }
// Check for extra resources in the new list // Check for extra resources in the new list
for (auto Iter = NewListSet.begin(); Iter != NewListSet.end(); Iter++) for (const auto& ID : NewListSet)
{ {
CAssetID ID = *Iter;
if (OldListSet.find(ID) == OldListSet.end()) if (OldListSet.find(ID) == OldListSet.end())
{ {
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID); const CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
TString Extension = (pEntry ? "." + pEntry->CookedExtension() : ""); const TString Extension = (pEntry != nullptr ? "." + pEntry->CookedExtension() : "");
warnf("Extra resource: %s%s", *ID.ToString(), *Extension); warnf("Extra resource: %s%s", *ID.ToString(), *Extension);
} }
} }

View File

@ -15,7 +15,7 @@ enum class EPackageDefinitionVersion
// Add new versions before this line // Add new versions before this line
Max, Max,
Current = EPackageDefinitionVersion::Max - 1 Current = Max - 1
}; };
struct SNamedResource struct SNamedResource
@ -34,24 +34,22 @@ struct SNamedResource
class CPackage class CPackage
{ {
CGameProject *mpProject; CGameProject *mpProject = nullptr;
TString mPakName; TString mPakName;
TString mPakPath; TString mPakPath;
std::vector<SNamedResource> mResources; std::vector<SNamedResource> mResources;
bool mNeedsRecook; bool mNeedsRecook = false;
// Cached dependency list; used to figure out if a given resource is in this package // Cached dependency list; used to figure out if a given resource is in this package
mutable bool mCacheDirty; mutable bool mCacheDirty = false;
mutable std::set<CAssetID> mCachedDependencies; mutable std::set<CAssetID> mCachedDependencies;
public: public:
CPackage() {} CPackage() = default;
CPackage(CGameProject *pProj, TString rkName, TString rkPath)
CPackage(CGameProject *pProj, const TString& rkName, const TString& rkPath)
: mpProject(pProj) : mpProject(pProj)
, mPakName(rkName) , mPakName(std::move(rkName))
, mPakPath(rkPath) , mPakPath(std::move(rkPath))
, mNeedsRecook(false)
, mCacheDirty(true) , mCacheDirty(true)
{} {}
@ -70,14 +68,14 @@ public:
TString CookedPackagePath(bool Relative) const; TString CookedPackagePath(bool Relative) const;
// Accessors // Accessors
inline TString Name() const { return mPakName; } TString Name() const { return mPakName; }
inline TString Path() const { return mPakPath; } TString Path() const { return mPakPath; }
inline CGameProject* Project() const { return mpProject; } CGameProject* Project() const { return mpProject; }
inline uint32 NumNamedResources() const { return mResources.size(); } size_t NumNamedResources() const { return mResources.size(); }
inline const SNamedResource& NamedResourceByIndex(uint32 Idx) const { return mResources[Idx]; } const SNamedResource& NamedResourceByIndex(size_t Idx) const { return mResources[Idx]; }
inline bool NeedsRecook() const { return mNeedsRecook; } bool NeedsRecook() const { return mNeedsRecook; }
inline void SetPakName(TString NewName) { mPakName = NewName; } void SetPakName(TString NewName) { mPakName = std::move(NewName); }
}; };
#endif // CPACKAGE #endif // CPACKAGE

View File

@ -11,23 +11,17 @@
#include <Common/Serialization/CXMLWriter.h> #include <Common/Serialization/CXMLWriter.h>
CResourceEntry::CResourceEntry(CResourceStore *pStore) CResourceEntry::CResourceEntry(CResourceStore *pStore)
: mpResource(nullptr) : mpStore(pStore)
, mpTypeInfo(nullptr) , mID(CAssetID::InvalidID(pStore->Game()))
, mpStore(pStore)
, mpDependencies(nullptr)
, mID( CAssetID::InvalidID(pStore->Game()) )
, mpDirectory(nullptr)
, mMetadataDirty(false)
, mCachedSize(-1)
{} {}
// Static constructors // Static constructors
CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const CAssetID& rkID, std::unique_ptr<CResourceEntry> CResourceEntry::CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
const TString& rkDir, const TString& rkName, const TString& rkDir, const TString& rkName,
EResourceType Type, bool ExistingResource /*= false*/) EResourceType Type, bool ExistingResource)
{ {
// Initialize all entry info with the input data. // Initialize all entry info with the input data.
CResourceEntry *pEntry = new CResourceEntry(pStore); auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
pEntry->mID = rkID; pEntry->mID = rkID;
pEntry->mName = rkName; pEntry->mName = rkName;
pEntry->mCachedUppercaseName = rkName.ToUpper(); pEntry->mCachedUppercaseName = rkName.ToUpper();
@ -37,7 +31,7 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDir, true); pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDir, true);
ASSERT(pEntry->mpDirectory); ASSERT(pEntry->mpDirectory);
pEntry->mpDirectory->AddChild("", pEntry); pEntry->mpDirectory->AddChild("", pEntry.get());
pEntry->mMetadataDirty = true; pEntry->mMetadataDirty = true;
@ -45,7 +39,7 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
// then instantiate the new resource data so it can be saved as soon as possible. // then instantiate the new resource data so it can be saved as soon as possible.
if (!ExistingResource) if (!ExistingResource)
{ {
pEntry->mpResource = CResourceFactory::CreateResource(pEntry); pEntry->mpResource = CResourceFactory::CreateResource(pEntry.get());
if (pEntry->mpResource) if (pEntry->mpResource)
{ {
@ -56,30 +50,30 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
return pEntry; return pEntry;
} }
CResourceEntry* CResourceEntry::BuildFromArchive(CResourceStore *pStore, IArchive& rArc) std::unique_ptr<CResourceEntry> CResourceEntry::BuildFromArchive(CResourceStore *pStore, IArchive& rArc)
{ {
// Load all entry info from the archive. // Load all entry info from the archive.
CResourceEntry *pEntry = new CResourceEntry(pStore); auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
pEntry->SerializeEntryInfo(rArc, false); pEntry->SerializeEntryInfo(rArc, false);
ASSERT(pEntry->mpTypeInfo); ASSERT(pEntry->mpTypeInfo);
ASSERT(pEntry->mpDirectory); ASSERT(pEntry->mpDirectory);
return pEntry; return pEntry;
} }
CResourceEntry* CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo, std::unique_ptr<CResourceEntry> CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
const TString& rkDirPath, const TString& rkName) const TString& rkDirPath, const TString& rkName)
{ {
// Initialize as much entry info as possible from the input data, then load the rest from the metadata file. // Initialize as much entry info as possible from the input data, then load the rest from the metadata file.
ASSERT(pTypeInfo); ASSERT(pTypeInfo);
CResourceEntry *pEntry = new CResourceEntry(pStore); auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
pEntry->mpTypeInfo = pTypeInfo; pEntry->mpTypeInfo = pTypeInfo;
pEntry->mName = rkName; pEntry->mName = rkName;
pEntry->mCachedUppercaseName = rkName.ToUpper(); pEntry->mCachedUppercaseName = rkName.ToUpper();
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDirPath, true); pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDirPath, true);
ASSERT(pEntry->mpDirectory); ASSERT(pEntry->mpDirectory);
pEntry->mpDirectory->AddChild("", pEntry); pEntry->mpDirectory->AddChild("", pEntry.get());
// Make sure we're valid, then load the remaining data from the metadata file // Make sure we're valid, then load the remaining data from the metadata file
ASSERT(pEntry->HasCookedVersion() || pEntry->HasRawVersion()); ASSERT(pEntry->HasCookedVersion() || pEntry->HasRawVersion());
@ -89,11 +83,7 @@ CResourceEntry* CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResT
return pEntry; return pEntry;
} }
CResourceEntry::~CResourceEntry() CResourceEntry::~CResourceEntry() = default;
{
if (mpResource) delete mpResource;
if (mpDependencies) delete mpDependencies;
}
bool CResourceEntry::LoadMetadata() bool CResourceEntry::LoadMetadata()
{ {
@ -171,15 +161,11 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly)
void CResourceEntry::UpdateDependencies() void CResourceEntry::UpdateDependencies()
{ {
if (mpDependencies) mpDependencies.reset();
{
delete mpDependencies;
mpDependencies = nullptr;
}
if (!mpTypeInfo->CanHaveDependencies()) if (!mpTypeInfo->CanHaveDependencies())
{ {
mpDependencies = new CDependencyTree(); mpDependencies = std::make_unique<CDependencyTree>();
return; return;
} }
@ -191,7 +177,7 @@ void CResourceEntry::UpdateDependencies()
if (!mpResource) if (!mpResource)
{ {
errorf("Unable to update cached dependencies; failed to load resource"); errorf("Unable to update cached dependencies; failed to load resource");
mpDependencies = new CDependencyTree(); mpDependencies = std::make_unique<CDependencyTree>();
return; return;
} }
@ -255,7 +241,7 @@ bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
uint64 CResourceEntry::Size() const uint64 CResourceEntry::Size() const
{ {
if (mCachedSize == -1) if (mCachedSize == UINT64_MAX)
{ {
if (HasCookedVersion()) if (HasCookedVersion())
mCachedSize = FileUtil::FileSize(CookedAssetPath()); mCachedSize = FileUtil::FileSize(CookedAssetPath());
@ -344,7 +330,7 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/, bool FlagForRecook /*=
// Flag dirty any packages that contain this resource. // Flag dirty any packages that contain this resource.
if (FlagForRecook) if (FlagForRecook)
{ {
for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++) for (size_t iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++)
{ {
CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg); CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg);
@ -391,7 +377,8 @@ bool CResourceEntry::Cook()
CResource* CResourceEntry::Load() CResource* CResourceEntry::Load()
{ {
// If the asset is already loaded then just return it immediately // If the asset is already loaded then just return it immediately
if (mpResource) return mpResource; if (mpResource)
return mpResource.get();
// Always try to load raw version as the raw version contains extra editor-only data. // Always try to load raw version as the raw version contains extra editor-only data.
// If there is no raw version (which will be the case for resource types that don't // If there is no raw version (which will be the case for resource types that don't
@ -411,8 +398,7 @@ CResource* CResourceEntry::Load()
if (!Reader.IsValid()) if (!Reader.IsValid())
{ {
errorf("Failed to load raw resource; falling back on cooked. Raw path: %s", *RawAssetPath()); errorf("Failed to load raw resource; falling back on cooked. Raw path: %s", *RawAssetPath());
delete mpResource; mpResource.reset();
mpResource = nullptr;
} }
else else
@ -424,7 +410,7 @@ CResource* CResourceEntry::Load()
} }
if (mpResource) if (mpResource)
return mpResource; return mpResource.get();
} }
ASSERT(!mpResource); ASSERT(!mpResource);
@ -451,8 +437,11 @@ CResource* CResourceEntry::Load()
CResource* CResourceEntry::LoadCooked(IInputStream& rInput) CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
{ {
// Overload to allow for load from an arbitrary input stream. // Overload to allow for load from an arbitrary input stream.
if (mpResource) return mpResource; if (mpResource)
if (!rInput.IsValid()) return nullptr; return mpResource.get();
if (!rInput.IsValid())
return nullptr;
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions // Set gpResourceStore to ensure the correct resource store is accessed by loader functions
CResourceStore *pOldStore = gpResourceStore; CResourceStore *pOldStore = gpResourceStore;
@ -463,22 +452,22 @@ CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
mpStore->TrackLoadedResource(this); mpStore->TrackLoadedResource(this);
gpResourceStore = pOldStore; gpResourceStore = pOldStore;
return mpResource; return mpResource.get();
} }
bool CResourceEntry::Unload() bool CResourceEntry::Unload()
{ {
ASSERT(mpResource != nullptr); ASSERT(mpResource != nullptr);
ASSERT(!mpResource->IsReferenced()); ASSERT(!mpResource->IsReferenced());
delete mpResource; mpResource.reset();
mpResource = nullptr;
return true; return true;
} }
bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName) bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName)
{ {
// Validate that the path/name are valid // Validate that the path/name are valid
if (!mpStore->IsValidResourcePath(rkDir, rkName)) return false; if (!CResourceStore::IsValidResourcePath(rkDir, rkName))
return false;
// We need to validate the path isn't taken already - either the directory doesn't exist, or doesn't have a resource by this name // We need to validate the path isn't taken already - either the directory doesn't exist, or doesn't have a resource by this name
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(rkDir, false); CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(rkDir, false);

View File

@ -8,10 +8,12 @@
#include <Common/CAssetID.h> #include <Common/CAssetID.h>
#include <Common/CFourCC.h> #include <Common/CFourCC.h>
#include <Common/Flags.h> #include <Common/Flags.h>
#include <memory>
class CResource;
class CGameProject;
class CDependencyTree; class CDependencyTree;
class CGameProject;
class CResource;
class IInputStream;
enum class EResEntryFlag enum class EResEntryFlag
{ {
@ -27,29 +29,29 @@ DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
class CResourceEntry class CResourceEntry
{ {
CResource *mpResource; std::unique_ptr<CResource> mpResource;
CResTypeInfo *mpTypeInfo; CResTypeInfo *mpTypeInfo = nullptr;
CResourceStore *mpStore; CResourceStore *mpStore;
CDependencyTree *mpDependencies; std::unique_ptr<CDependencyTree> mpDependencies;
CAssetID mID; CAssetID mID;
CVirtualDirectory *mpDirectory; CVirtualDirectory *mpDirectory = nullptr;
TString mName; TString mName;
FResEntryFlags mFlags; FResEntryFlags mFlags;
mutable bool mMetadataDirty; mutable bool mMetadataDirty = false;
mutable uint64 mCachedSize; mutable uint64 mCachedSize = UINT64_MAX;
mutable TString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering. mutable TString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering.
// Private constructor // Private constructor
CResourceEntry(CResourceStore *pStore); explicit CResourceEntry(CResourceStore *pStore);
public: public:
static CResourceEntry* CreateNewResource(CResourceStore *pStore, const CAssetID& rkID, static std::unique_ptr<CResourceEntry> CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
const TString& rkDir, const TString& rkName, const TString& rkDir, const TString& rkName,
EResourceType Type, bool ExistingResource = false); EResourceType Type, bool ExistingResource = false);
static CResourceEntry* BuildFromArchive(CResourceStore *pStore, IArchive& rArc); static std::unique_ptr<CResourceEntry> BuildFromArchive(CResourceStore *pStore, IArchive& rArc);
static CResourceEntry* BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo, static std::unique_ptr<CResourceEntry> BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
const TString& rkDirPath, const TString& rkName); const TString& rkDirPath, const TString& rkName);
~CResourceEntry(); ~CResourceEntry();
bool LoadMetadata(); bool LoadMetadata();
@ -86,27 +88,27 @@ public:
void ClearFlag(EResEntryFlag Flag); void ClearFlag(EResEntryFlag Flag);
// Accessors // Accessors
inline void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); } void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); }
inline void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); } void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); }
inline void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); } void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); }
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); } bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
inline bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); } bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
inline bool IsMarkedForDeletion() const { return HasFlag(EResEntryFlag::MarkedForDeletion); } bool IsMarkedForDeletion() const { return HasFlag(EResEntryFlag::MarkedForDeletion); }
inline bool IsLoaded() const { return mpResource != nullptr; } bool IsLoaded() const { return mpResource != nullptr; }
inline bool IsCategorized() const { return mpDirectory && !mpDirectory->FullPath().CaseInsensitiveCompare( mpStore->DefaultResourceDirPath() ); } bool IsCategorized() const { return mpDirectory && !mpDirectory->FullPath().CaseInsensitiveCompare( mpStore->DefaultResourceDirPath() ); }
inline bool IsNamed() const { return mName != mID.ToString(); } bool IsNamed() const { return mName != mID.ToString(); }
inline CResource* Resource() const { return mpResource; } CResource* Resource() const { return mpResource.get(); }
inline CResTypeInfo* TypeInfo() const { return mpTypeInfo; } CResTypeInfo* TypeInfo() const { return mpTypeInfo; }
inline CResourceStore* ResourceStore() const { return mpStore; } CResourceStore* ResourceStore() const { return mpStore; }
inline CDependencyTree* Dependencies() const { return mpDependencies; } CDependencyTree* Dependencies() const { return mpDependencies.get(); }
inline CAssetID ID() const { return mID; } CAssetID ID() const { return mID; }
inline CVirtualDirectory* Directory() const { return mpDirectory; } CVirtualDirectory* Directory() const { return mpDirectory; }
inline TString DirectoryPath() const { return mpDirectory->FullPath(); } TString DirectoryPath() const { return mpDirectory->FullPath(); }
inline TString Name() const { return mName; } TString Name() const { return mName; }
inline const TString& UppercaseName() const { return mCachedUppercaseName; } const TString& UppercaseName() const { return mCachedUppercaseName; }
inline EResourceType ResourceType() const { return mpTypeInfo->Type(); } EResourceType ResourceType() const { return mpTypeInfo->Type(); }
protected: protected:
CResource* InternalLoad(IInputStream& rInput); CResource* InternalLoad(IInputStream& rInput);

View File

@ -8,26 +8,27 @@ class CResourceIterator
{ {
protected: protected:
const CResourceStore *mpkStore; const CResourceStore *mpkStore;
std::map<CAssetID, CResourceEntry*>::const_iterator mIter; std::map<CAssetID, std::unique_ptr<CResourceEntry>>::const_iterator mIter;
CResourceEntry *mpCurEntry; CResourceEntry *mpCurEntry = nullptr;
public: public:
CResourceIterator(const CResourceStore *pkStore = gpResourceStore) explicit CResourceIterator(const CResourceStore *pkStore = gpResourceStore)
: mpkStore(pkStore) : mpkStore(pkStore)
, mpCurEntry(nullptr)
{ {
mIter = mpkStore->mResourceEntries.begin(); mIter = mpkStore->mResourceEntries.cbegin();
Next(); Next();
} }
virtual ~CResourceIterator() = default;
virtual CResourceEntry* Next() virtual CResourceEntry* Next()
{ {
do do
{ {
if (mIter != mpkStore->mResourceEntries.end()) if (mIter != mpkStore->mResourceEntries.cend())
{ {
mpCurEntry = mIter->second; mpCurEntry = mIter->second.get();
mIter++; ++mIter;
} }
else mpCurEntry = nullptr; else mpCurEntry = nullptr;
} }
@ -36,33 +37,33 @@ public:
return mpCurEntry; return mpCurEntry;
} }
inline bool DoneIterating() const bool DoneIterating() const
{ {
return mpCurEntry == nullptr; return mpCurEntry == nullptr;
} }
inline operator bool() const explicit operator bool() const
{ {
return !DoneIterating(); return !DoneIterating();
} }
inline CResourceEntry* operator*() const CResourceEntry* operator*() const
{ {
return mpCurEntry; return mpCurEntry;
} }
inline CResourceEntry* operator->() const CResourceEntry* operator->() const
{ {
return mpCurEntry; return mpCurEntry;
} }
inline CResourceIterator& operator++() CResourceIterator& operator++()
{ {
Next(); Next();
return *this; return *this;
} }
inline CResourceIterator operator++(int) CResourceIterator operator++(int)
{ {
CResourceIterator Copy = *this; CResourceIterator Copy = *this;
Next(); Next();
@ -74,14 +75,14 @@ template<EResourceType ResType>
class TResourceIterator : public CResourceIterator class TResourceIterator : public CResourceIterator
{ {
public: public:
TResourceIterator(CResourceStore *pStore = gpResourceStore) explicit TResourceIterator(CResourceStore *pStore = gpResourceStore)
: CResourceIterator(pStore) : CResourceIterator(pStore)
{ {
if (mpCurEntry && mpCurEntry->ResourceType() != ResType) if (mpCurEntry && mpCurEntry->ResourceType() != ResType)
Next(); Next();
} }
virtual CResourceEntry* Next() CResourceEntry* Next() override
{ {
do { do {
CResourceIterator::Next(); CResourceIterator::Next();

View File

@ -20,9 +20,6 @@ CResourceStore *gpEditorStore = nullptr;
// Constructor for editor store // Constructor for editor store
CResourceStore::CResourceStore(const TString& rkDatabasePath) CResourceStore::CResourceStore(const TString& rkDatabasePath)
: mpProj(nullptr)
, mGame(EGame::Prime)
, mDatabaseCacheDirty(false)
{ {
mpDatabaseRoot = new CVirtualDirectory(this); mpDatabaseRoot = new CVirtualDirectory(this);
mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory()); mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory());
@ -32,10 +29,7 @@ CResourceStore::CResourceStore(const TString& rkDatabasePath)
// Main constructor for game projects and game exporter // Main constructor for game projects and game exporter
CResourceStore::CResourceStore(CGameProject *pProject) CResourceStore::CResourceStore(CGameProject *pProject)
: mpProj(nullptr) : mGame(EGame::Invalid)
, mGame(EGame::Invalid)
, mpDatabaseRoot(nullptr)
, mDatabaseCacheDirty(false)
{ {
SetProject(pProject); SetProject(pProject);
} }
@ -44,9 +38,6 @@ CResourceStore::~CResourceStore()
{ {
CloseProject(); CloseProject();
DestroyUnreferencedResources(); DestroyUnreferencedResources();
for (auto It = mResourceEntries.begin(); It != mResourceEntries.end(); It++)
delete It->second;
} }
void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rOutList) void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rOutList)
@ -58,7 +49,7 @@ void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rO
} }
else else
{ {
for (uint32 SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++) for (size_t SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++)
RecursiveGetListOfEmptyDirectories(pDir->SubdirectoryByIndex(SubIdx), rOutList); RecursiveGetListOfEmptyDirectories(pDir->SubdirectoryByIndex(SubIdx), rOutList);
} }
} }
@ -75,11 +66,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
{ {
// Make sure deleted resources aren't included in the count. // Make sure deleted resources aren't included in the count.
// We can't use CResourceIterator because it skips MarkedForDeletion resources. // We can't use CResourceIterator because it skips MarkedForDeletion resources.
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++) for (const auto& entry : mResourceEntries)
{ {
CResourceEntry* pEntry = Iter->second; if (entry.second->IsMarkedForDeletion())
if (pEntry->IsMarkedForDeletion())
{ {
ResourceCount--; ResourceCount--;
} }
@ -94,9 +83,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
{ {
if (rArc.ParamBegin("Resource", 0)) if (rArc.ParamBegin("Resource", 0))
{ {
CResourceEntry *pEntry = CResourceEntry::BuildFromArchive(this, rArc); auto pEntry = CResourceEntry::BuildFromArchive(this, rArc);
ASSERT( FindEntry(pEntry->ID()) == nullptr ); ASSERT(FindEntry(pEntry->ID()) == nullptr);
mResourceEntries[pEntry->ID()] = pEntry; mResourceEntries.insert_or_assign(pEntry->ID(), std::move(pEntry));
rArc.ParamEnd(); rArc.ParamEnd();
} }
} }
@ -128,13 +117,13 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
if (rArc.IsReader()) if (rArc.IsReader())
{ {
for (auto Iter = EmptyDirectories.begin(); Iter != EmptyDirectories.end(); Iter++) for (const auto& dir : EmptyDirectories)
{ {
// Don't create empty virtual directories that don't actually exist in the filesystem // Don't create empty virtual directories that don't actually exist in the filesystem
TString AbsPath = ResourcesDir() + *Iter; const TString AbsPath = ResourcesDir() + dir;
if (FileUtil::Exists(AbsPath)) if (FileUtil::Exists(AbsPath))
CreateVirtualDirectory(*Iter); CreateVirtualDirectory(dir);
} }
} }
@ -159,7 +148,10 @@ bool CResourceStore::LoadDatabaseCache()
if (!BuildFromDirectory(true)) if (!BuildFromDirectory(true))
return false; return false;
} }
else return false; else
{
return false;
}
} }
else else
{ {
@ -192,31 +184,33 @@ bool CResourceStore::SaveDatabaseCache()
void CResourceStore::ConditionalSaveStore() void CResourceStore::ConditionalSaveStore()
{ {
if (mDatabaseCacheDirty) SaveDatabaseCache(); if (mDatabaseCacheDirty)
SaveDatabaseCache();
} }
void CResourceStore::SetProject(CGameProject *pProj) void CResourceStore::SetProject(CGameProject *pProj)
{ {
if (mpProj == pProj) return; if (mpProj == pProj)
return;
if (mpProj) if (mpProj)
CloseProject(); CloseProject();
mpProj = pProj; mpProj = pProj;
if (mpProj) if (!mpProj)
return;
mDatabasePath = mpProj->ProjectRoot();
mpDatabaseRoot = new CVirtualDirectory(this);
mGame = mpProj->Game();
// Clear deleted files from previous runs
const TString DeletedPath = DeletedResourcePath();
if (FileUtil::Exists(DeletedPath))
{ {
mDatabasePath = mpProj->ProjectRoot(); FileUtil::ClearDirectory(DeletedPath);
mpDatabaseRoot = new CVirtualDirectory(this);
mGame = mpProj->Game();
// Clear deleted files from previous runs
TString DeletedPath = DeletedResourcePath();
if (FileUtil::Exists(DeletedPath))
{
FileUtil::ClearDirectory(DeletedPath);
}
} }
} }
@ -232,9 +226,9 @@ void CResourceStore::CloseProject()
{ {
warnf("%d resources still loaded on project close:", mLoadedResources.size()); warnf("%d resources still loaded on project close:", mLoadedResources.size());
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++) for (const auto& entry : mLoadedResources)
{ {
CResourceEntry *pEntry = Iter->second; const CResourceEntry *pEntry = entry.second;
warnf("\t%s.%s", *pEntry->Name(), *pEntry->CookedExtension().ToString()); warnf("\t%s.%s", *pEntry->Name(), *pEntry->CookedExtension().ToString());
} }
@ -242,16 +236,10 @@ void CResourceStore::CloseProject()
} }
// Delete all entries from old project // Delete all entries from old project
auto It = mResourceEntries.begin(); mResourceEntries.clear();
while (It != mResourceEntries.end())
{
delete It->second;
It = mResourceEntries.erase(It);
}
// Clear deleted files from previous runs // Clear deleted files from previous runs
TString DeletedPath = DeletedResourcePath(); const TString DeletedPath = DeletedResourcePath();
if (FileUtil::Exists(DeletedPath)) if (FileUtil::Exists(DeletedPath))
{ {
@ -268,10 +256,11 @@ CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TString& rkPath, bo
{ {
if (rkPath.IsEmpty()) if (rkPath.IsEmpty())
return mpDatabaseRoot; return mpDatabaseRoot;
else if (mpDatabaseRoot)
if (mpDatabaseRoot)
return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate); return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate);
else
return nullptr; return nullptr;
} }
void CResourceStore::CreateVirtualDirectory(const TString& rkPath) void CResourceStore::CreateVirtualDirectory(const TString& rkPath)
@ -308,14 +297,14 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
{ {
if (rkID.IsValid()) if (rkID.IsValid())
{ {
auto Found = mResourceEntries.find(rkID); const auto Found = mResourceEntries.find(rkID);
if (Found != mResourceEntries.end()) if (Found != mResourceEntries.cend())
{ {
CResourceEntry* pEntry = Found->second; const auto& pEntry = Found->second;
if (!pEntry->IsMarkedForDeletion()) if (!pEntry->IsMarkedForDeletion())
return pEntry; return pEntry.get();
} }
} }
@ -324,7 +313,7 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const
{ {
return (mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr); return mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr;
} }
bool CResourceStore::AreAllEntriesValid() const bool CResourceStore::AreAllEntriesValid() const
@ -346,14 +335,12 @@ void CResourceStore::ClearDatabase()
if (!mLoadedResources.empty()) if (!mLoadedResources.empty())
{ {
debugf("ERROR: Resources still loaded:"); debugf("ERROR: Resources still loaded:");
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++) for (const auto& [asset, entry] : mLoadedResources)
debugf("\t[%s] %s", *Iter->first.ToString(), *Iter->second->CookedAssetPath(true)); debugf("\t[%s] %s", *asset.ToString(), *entry->CookedAssetPath(true));
ASSERT(false); ASSERT(false);
} }
// Clear out existing resource entries and directories // Clear out existing resource entries and directories
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
delete Iter->second;
mResourceEntries.clear(); mResourceEntries.clear();
delete mpDatabaseRoot; delete mpDatabaseRoot;
@ -371,10 +358,9 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
TStringList ResourceList; TStringList ResourceList;
FileUtil::GetDirectoryContents(ResDir, ResourceList); FileUtil::GetDirectoryContents(ResDir, ResourceList);
for (auto Iter = ResourceList.begin(); Iter != ResourceList.end(); Iter++) for (const auto& Path : ResourceList)
{ {
TString Path = *Iter; TString RelPath = Path.ChopFront(ResDir.Size());
TString RelPath = Path.ChopFront( ResDir.Size() );
if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta")) if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta"))
{ {
@ -382,11 +368,11 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
TString DirPath = RelPath.GetFileDirectory(); TString DirPath = RelPath.GetFileDirectory();
TString CookedFilename = RelPath.GetFileName(false); // This call removes the .rsmeta extension TString CookedFilename = RelPath.GetFileName(false); // This call removes the .rsmeta extension
TString ResName = CookedFilename.GetFileName(false); // This call removes the cooked extension TString ResName = CookedFilename.GetFileName(false); // This call removes the cooked extension
ASSERT( IsValidResourcePath(DirPath, ResName) ); ASSERT(IsValidResourcePath(DirPath, ResName));
// Determine resource type // Determine resource type
TString CookedExtension = CookedFilename.GetFileExtension(); TString CookedExtension = CookedFilename.GetFileExtension();
CResTypeInfo *pTypeInfo = CResTypeInfo::TypeForCookedExtension( Game(), CFourCC(CookedExtension) ); CResTypeInfo* pTypeInfo = CResTypeInfo::TypeForCookedExtension(Game(), CFourCC(CookedExtension));
if (!pTypeInfo) if (!pTypeInfo)
{ {
@ -395,18 +381,19 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
} }
// Create resource entry // Create resource entry
CResourceEntry *pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName); auto pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName);
// Validate the entry // Validate the entry
CAssetID ID = pEntry->ID(); const CAssetID ID = pEntry->ID();
ASSERT( mResourceEntries.find(ID) == mResourceEntries.end() ); ASSERT(mResourceEntries.find(ID) == mResourceEntries.cend());
ASSERT( ID.Length() == CAssetID::GameIDLength(mGame) ); ASSERT(ID.Length() == CAssetID::GameIDLength(mGame));
mResourceEntries[ID] = pEntry; mResourceEntries.insert_or_assign(ID, std::move(pEntry));
} }
else if (FileUtil::IsDirectory(Path)) else if (FileUtil::IsDirectory(Path))
{
CreateVirtualDirectory(RelPath); CreateVirtualDirectory(RelPath);
}
} }
// Generate new cache file // Generate new cache file
@ -454,30 +441,34 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
CResourceEntry *pEntry = FindEntry(rkID); CResourceEntry *pEntry = FindEntry(rkID);
if (pEntry) if (pEntry)
{
errorf("Attempted to register resource that's already tracked in the database: %s / %s / %s", *rkID.ToString(), *rkDir, *rkName); errorf("Attempted to register resource that's already tracked in the database: %s / %s / %s", *rkID.ToString(), *rkDir, *rkName);
}
else else
{ {
// Validate directory // Validate directory
if (IsValidResourcePath(rkDir, rkName)) if (IsValidResourcePath(rkDir, rkName))
{ {
pEntry = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource); auto res = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource);
mResourceEntries[rkID] = pEntry; auto* resPtr = res.get();
mResourceEntries.insert_or_assign(rkID, std::move(res));
mDatabaseCacheDirty = true; mDatabaseCacheDirty = true;
if (pEntry->IsLoaded()) if (resPtr->IsLoaded())
{ {
TrackLoadedResource(pEntry); TrackLoadedResource(resPtr);
} }
if (!ExistingResource) if (!ExistingResource)
{ {
debugf("CREATED NEW RESOURCE: [%s] %s", *rkID.ToString(), *pEntry->CookedAssetPath()); debugf("CREATED NEW RESOURCE: [%s] %s", *rkID.ToString(), *resPtr->CookedAssetPath());
} }
return resPtr;
} }
else errorf("Invalid resource path, failed to register: %s%s", *rkDir, *rkName);
errorf("Invalid resource path, failed to register: %s%s", *rkDir, *rkName);
} }
return pEntry; return pEntry;
@ -485,19 +476,18 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
CResource* CResourceStore::LoadResource(const CAssetID& rkID) CResource* CResourceStore::LoadResource(const CAssetID& rkID)
{ {
if (!rkID.IsValid()) return nullptr; if (!rkID.IsValid())
return nullptr;
CResourceEntry *pEntry = FindEntry(rkID); CResourceEntry *pEntry = FindEntry(rkID);
if (!pEntry)
if (pEntry)
return pEntry->Load();
else
{ {
// Resource doesn't seem to exist // Resource doesn't seem to exist
warnf("Can't find requested resource with ID \"%s\"", *rkID.ToString()); warnf("Can't find requested resource with ID \"%s\"", *rkID.ToString());
return nullptr; return nullptr;
} }
return pEntry->Load();
} }
CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type) CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type)
@ -521,8 +511,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type
} }
} }
else return nullptr;
return nullptr;
} }
CResource* CResourceStore::LoadResource(const TString& rkPath) CResource* CResourceStore::LoadResource(const TString& rkPath)
@ -533,7 +522,7 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
if (pEntry) if (pEntry)
{ {
// Verify extension matches the entry + load resource // Verify extension matches the entry + load resource
TString Ext = rkPath.GetFileExtension(); const TString Ext = rkPath.GetFileExtension();
if (!Ext.IsEmpty()) if (!Ext.IsEmpty())
{ {
@ -550,14 +539,14 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
return pEntry->Load(); return pEntry->Load();
} }
else return nullptr; return nullptr;
} }
void CResourceStore::TrackLoadedResource(CResourceEntry *pEntry) void CResourceStore::TrackLoadedResource(CResourceEntry *pEntry)
{ {
ASSERT(pEntry->IsLoaded()); ASSERT(pEntry->IsLoaded());
ASSERT(mLoadedResources.find(pEntry->ID()) == mLoadedResources.end()); ASSERT(mLoadedResources.find(pEntry->ID()) == mLoadedResources.end());
mLoadedResources[pEntry->ID()] = pEntry; mLoadedResources.insert_or_assign(pEntry->ID(), pEntry);
} }
void CResourceStore::DestroyUnreferencedResources() void CResourceStore::DestroyUnreferencedResources()
@ -579,22 +568,24 @@ void CResourceStore::DestroyUnreferencedResources()
It = mLoadedResources.erase(It); It = mLoadedResources.erase(It);
NumDeleted++; NumDeleted++;
} }
else
else It++; {
++It;
}
} }
} while (NumDeleted > 0); } while (NumDeleted > 0);
} }
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry) bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
{ {
CAssetID ID = pEntry->ID(); const CAssetID ID = pEntry->ID();
if (pEntry->IsLoaded()) if (pEntry->IsLoaded())
{ {
if (!pEntry->Unload()) if (!pEntry->Unload())
return false; return false;
auto It = mLoadedResources.find(ID); const auto It = mLoadedResources.find(ID);
ASSERT(It != mLoadedResources.end()); ASSERT(It != mLoadedResources.end());
mLoadedResources.erase(It); mLoadedResources.erase(It);
} }
@ -602,7 +593,7 @@ bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
if (pEntry->Directory()) if (pEntry->Directory())
pEntry->Directory()->RemoveChildResource(pEntry); pEntry->Directory()->RemoveChildResource(pEntry);
auto It = mResourceEntries.find(ID); const auto It = mResourceEntries.find(ID);
ASSERT(It != mResourceEntries.end()); ASSERT(It != mResourceEntries.end());
mResourceEntries.erase(It); mResourceEntries.erase(It);
@ -667,7 +658,7 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
// Chop name to just after "x_rep" // Chop name to just after "x_rep"
uint32 RepStart = Path.IndexOfPhrase("_rep"); uint32 RepStart = Path.IndexOfPhrase("_rep");
if (RepStart != -1) if (RepStart != UINT32_MAX)
Path = Path.ChopFront(RepStart + 5); Path = Path.ChopFront(RepStart + 5);
// If the "x_rep" folder doesn't exist in this path for some reason, but this is still a path, then just chop off the drive letter. // If the "x_rep" folder doesn't exist in this path for some reason, but this is still a path, then just chop off the drive letter.
@ -675,24 +666,24 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
else if (Path[1] == ':') else if (Path[1] == ':')
Path = Path.ChopFront(3); Path = Path.ChopFront(3);
PathMap[pEntry] = Path; PathMap.insert_or_assign(pEntry, std::move(Path));
} }
} }
fclose(pContentsFile); fclose(pContentsFile);
// Assign names // Assign names
for (auto Iter = PathMap.begin(); Iter != PathMap.end(); Iter++) for (auto& [entry, path] : PathMap)
{ {
CResourceEntry *pEntry = Iter->first; if (UnnamedOnly && entry->IsNamed())
if (UnnamedOnly && pEntry->IsNamed()) continue; continue;
TString Path = Iter->second; TString Dir = path.GetFileDirectory();
TString Dir = Path.GetFileDirectory(); TString Name = path.GetFileName(false);
TString Name = Path.GetFileName(false); if (Dir.IsEmpty())
if (Dir.IsEmpty()) Dir = pEntry->DirectoryPath(); Dir = entry->DirectoryPath();
pEntry->MoveAndRename(Dir, Name); entry->MoveAndRename(Dir, Name);
} }
// Save // Save
@ -703,13 +694,13 @@ bool CResourceStore::IsValidResourcePath(const TString& rkPath, const TString& r
{ {
// Path must not be an absolute path and must not go outside the project structure. // Path must not be an absolute path and must not go outside the project structure.
// Name must not be a path. // Name must not be a path.
return ( CVirtualDirectory::IsValidDirectoryPath(rkPath) && return CVirtualDirectory::IsValidDirectoryPath(rkPath) &&
FileUtil::IsValidName(rkName, false) && FileUtil::IsValidName(rkName, false) &&
!rkName.Contains('/') && !rkName.Contains('/') &&
!rkName.Contains('\\') ); !rkName.Contains('\\');
} }
TString CResourceStore::StaticDefaultResourceDirPath(EGame Game) TString CResourceStore::StaticDefaultResourceDirPath(EGame Game)
{ {
return (Game < EGame::CorruptionProto ? "Uncategorized/" : "uncategorized/"); return Game < EGame::CorruptionProto ? "Uncategorized/" : "uncategorized/";
} }

View File

@ -8,6 +8,7 @@
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <map> #include <map>
#include <memory>
#include <set> #include <set>
class CGameExporter; class CGameExporter;
@ -20,27 +21,27 @@ enum class EDatabaseVersion
// Add new versions before this line // Add new versions before this line
Max, Max,
Current = EDatabaseVersion::Max - 1 Current = Max - 1
}; };
class CResourceStore class CResourceStore
{ {
friend class CResourceIterator; friend class CResourceIterator;
CGameProject *mpProj; CGameProject *mpProj = nullptr;
EGame mGame; EGame mGame{EGame::Prime};
CVirtualDirectory *mpDatabaseRoot; CVirtualDirectory *mpDatabaseRoot = nullptr;
std::map<CAssetID, CResourceEntry*> mResourceEntries; std::map<CAssetID, std::unique_ptr<CResourceEntry>> mResourceEntries;
std::map<CAssetID, CResourceEntry*> mLoadedResources; std::map<CAssetID, CResourceEntry*> mLoadedResources;
bool mDatabaseCacheDirty; bool mDatabaseCacheDirty = false;
// Directory paths // Directory paths
TString mDatabasePath; TString mDatabasePath;
bool mDatabasePathExists; bool mDatabasePathExists = false;
public: public:
CResourceStore(const TString& rkDatabasePath); explicit CResourceStore(const TString& rkDatabasePath);
CResourceStore(CGameProject *pProject); explicit CResourceStore(CGameProject *pProject);
~CResourceStore(); ~CResourceStore();
bool SerializeDatabaseCache(IArchive& rArc); bool SerializeDatabaseCache(IArchive& rArc);
bool LoadDatabaseCache(); bool LoadDatabaseCache();
@ -78,19 +79,19 @@ public:
static TString StaticDefaultResourceDirPath(EGame Game); static TString StaticDefaultResourceDirPath(EGame Game);
// Accessors // Accessors
inline CGameProject* Project() const { return mpProj; } CGameProject* Project() const { return mpProj; }
inline EGame Game() const { return mGame; } EGame Game() const { return mGame; }
inline TString DatabaseRootPath() const { return mDatabasePath; } TString DatabaseRootPath() const { return mDatabasePath; }
inline bool DatabasePathExists() const { return mDatabasePathExists; } bool DatabasePathExists() const { return mDatabasePathExists; }
inline TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; } TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; }
inline TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; } TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; }
inline CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; } CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
inline uint32 NumTotalResources() const { return mResourceEntries.size(); } uint32 NumTotalResources() const { return mResourceEntries.size(); }
inline uint32 NumLoadedResources() const { return mLoadedResources.size(); } uint32 NumLoadedResources() const { return mLoadedResources.size(); }
inline bool IsCacheDirty() const { return mDatabaseCacheDirty; } bool IsCacheDirty() const { return mDatabaseCacheDirty; }
inline void SetCacheDirty() { mDatabaseCacheDirty = true; } void SetCacheDirty() { mDatabaseCacheDirty = true; }
inline bool IsEditorStore() const { return mpProj == nullptr; } bool IsEditorStore() const { return mpProj == nullptr; }
}; };
extern TString gDataDir; extern TString gDataDir;

View File

@ -5,25 +5,25 @@
#include <algorithm> #include <algorithm>
CVirtualDirectory::CVirtualDirectory(CResourceStore *pStore) CVirtualDirectory::CVirtualDirectory(CResourceStore *pStore)
: mpParent(nullptr), mpStore(pStore) : mpStore(pStore)
{} {}
CVirtualDirectory::CVirtualDirectory(const TString& rkName, CResourceStore *pStore) CVirtualDirectory::CVirtualDirectory(const TString& rkName, CResourceStore *pStore)
: mpParent(nullptr), mName(rkName), mpStore(pStore) : mpStore(pStore), mName(rkName)
{ {
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true)); ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
} }
CVirtualDirectory::CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore) CVirtualDirectory::CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore)
: mpParent(pParent), mName(rkName), mpStore(pStore) : mpParent(pParent), mpStore(pStore), mName(rkName)
{ {
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true)); ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
} }
CVirtualDirectory::~CVirtualDirectory() CVirtualDirectory::~CVirtualDirectory()
{ {
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++) for (auto* subdirectory : mSubdirectories)
delete mSubdirectories[iSub]; delete subdirectory;
} }
bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
@ -31,9 +31,11 @@ bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
if (!mResources.empty()) if (!mResources.empty())
return false; return false;
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++) for (auto* subdirectory : mSubdirectories)
if (!mSubdirectories[iSub]->IsEmpty(CheckFilesystem)) {
if (!subdirectory->IsEmpty(CheckFilesystem))
return false; return false;
}
if (CheckFilesystem && !FileUtil::IsEmpty( AbsolutePath() )) if (CheckFilesystem && !FileUtil::IsEmpty( AbsolutePath() ))
return false; return false;
@ -43,7 +45,7 @@ bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const
{ {
return (this == pDir) || (mpParent && pDir && (mpParent == pDir || mpParent->IsDescendantOf(pDir))); return (this == pDir) || (mpParent != nullptr && pDir != nullptr && (mpParent == pDir || mpParent->IsDescendantOf(pDir)));
} }
bool CVirtualDirectory::IsSafeToDelete() const bool CVirtualDirectory::IsSafeToDelete() const
@ -72,8 +74,8 @@ TString CVirtualDirectory::FullPath() const
{ {
if (IsRoot()) if (IsRoot())
return ""; return "";
else
return (mpParent ? mpParent->FullPath() + mName : static_cast<TString::BaseClass>(mName)) + '/'; return (mpParent != nullptr ? mpParent->FullPath() + mName : static_cast<TString::BaseClass>(mName)) + '/';
} }
TString CVirtualDirectory::AbsolutePath() const TString CVirtualDirectory::AbsolutePath() const
@ -83,40 +85,35 @@ TString CVirtualDirectory::AbsolutePath() const
CVirtualDirectory* CVirtualDirectory::GetRoot() CVirtualDirectory* CVirtualDirectory::GetRoot()
{ {
return (mpParent ? mpParent->GetRoot() : this); return mpParent != nullptr ? mpParent->GetRoot() : this;
} }
CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName, bool AllowCreate) CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName, bool AllowCreate)
{ {
uint32 SlashIdx = rkName.IndexOf("\\/"); const uint32 SlashIdx = rkName.IndexOf("\\/");
TString DirName = (SlashIdx == -1 ? static_cast<TString::BaseClass>(rkName) : rkName.SubString(0, SlashIdx)); const TString DirName = (SlashIdx == UINT32_MAX ? static_cast<TString::BaseClass>(rkName) : rkName.SubString(0, SlashIdx));
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++) for (auto* child : mSubdirectories)
{ {
CVirtualDirectory *pChild = mSubdirectories[iSub]; if (child->Name().CaseInsensitiveCompare(DirName))
if (pChild->Name().CaseInsensitiveCompare(DirName))
{ {
if (SlashIdx == -1) if (SlashIdx == UINT32_MAX)
return pChild; return child;
else const TString Remaining = rkName.SubString(SlashIdx + 1, rkName.Size() - SlashIdx);
{
TString Remaining = rkName.SubString(SlashIdx + 1, rkName.Size() - SlashIdx);
if (Remaining.IsEmpty()) if (Remaining.IsEmpty())
return pChild; return child;
else
return pChild->FindChildDirectory(Remaining, AllowCreate); return child->FindChildDirectory(Remaining, AllowCreate);
}
} }
} }
if (AllowCreate) if (AllowCreate)
{ {
if ( AddChild(rkName, nullptr) ) if (AddChild(rkName, nullptr))
{ {
CVirtualDirectory *pOut = FindChildDirectory(rkName, false); CVirtualDirectory* pOut = FindChildDirectory(rkName, false);
ASSERT(pOut != nullptr); ASSERT(pOut != nullptr);
return pOut; return pOut;
} }
@ -127,19 +124,19 @@ CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName,
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath) CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath)
{ {
TString Dir = rkPath.GetFileDirectory(); const TString Dir = rkPath.GetFileDirectory();
TString Name = rkPath.GetFileName(); const TString Name = rkPath.GetFileName();
if (!Dir.IsEmpty()) if (!Dir.IsEmpty())
{ {
CVirtualDirectory *pDir = FindChildDirectory(Dir, false); CVirtualDirectory* pDir = FindChildDirectory(Dir, false);
if (pDir) return pDir->FindChildResource(Name); if (pDir != nullptr)
return pDir->FindChildResource(Name);
} }
else if (!Name.IsEmpty()) else if (!Name.IsEmpty())
{ {
TString Ext = Name.GetFileExtension(); const TString Ext = Name.GetFileExtension();
EResourceType Type = CResTypeInfo::TypeForCookedExtension(mpStore->Game(), Ext)->Type(); const EResourceType Type = CResTypeInfo::TypeForCookedExtension(mpStore->Game(), Ext)->Type();
return FindChildResource(Name.GetFileName(false), Type); return FindChildResource(Name.GetFileName(false), Type);
} }
@ -148,47 +145,48 @@ CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath)
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkName, EResourceType Type) CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkName, EResourceType Type)
{ {
for (uint32 iRes = 0; iRes < mResources.size(); iRes++) const auto it = std::find_if(mResources.begin(), mResources.end(), [&](const auto* resource) {
{ return rkName.CaseInsensitiveCompare(resource->Name()) && resource->ResourceType() == Type;
if (rkName.CaseInsensitiveCompare(mResources[iRes]->Name()) && mResources[iRes]->ResourceType() == Type) });
return mResources[iRes];
}
return nullptr; if (it == mResources.cend())
return nullptr;
return *it;
} }
bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry) bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
{ {
if (rkPath.IsEmpty()) if (rkPath.IsEmpty())
{ {
if (pEntry) if (pEntry != nullptr)
{ {
mResources.push_back(pEntry); mResources.push_back(pEntry);
return true; return true;
} }
else
return false; return false;
} }
else if (IsValidDirectoryPath(rkPath)) if (IsValidDirectoryPath(rkPath))
{ {
uint32 SlashIdx = rkPath.IndexOf("\\/"); const uint32 SlashIdx = rkPath.IndexOf("\\/");
TString DirName = (SlashIdx == -1 ? static_cast<TString::BaseClass>(rkPath) : rkPath.SubString(0, SlashIdx)); const TString DirName = (SlashIdx == UINT32_MAX ? static_cast<TString::BaseClass>(rkPath) : rkPath.SubString(0, SlashIdx));
TString Remaining = (SlashIdx == -1 ? "" : rkPath.SubString(SlashIdx + 1, rkPath.Size() - SlashIdx)); const TString Remaining = (SlashIdx == UINT32_MAX ? "" : rkPath.SubString(SlashIdx + 1, rkPath.Size() - SlashIdx));
// Check if this subdirectory already exists // Check if this subdirectory already exists
CVirtualDirectory *pSubdir = nullptr; CVirtualDirectory* pSubdir = nullptr;
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++) for (auto* subdirectory : mSubdirectories)
{ {
if (mSubdirectories[iSub]->Name() == DirName) if (subdirectory->Name() == DirName)
{ {
pSubdir = mSubdirectories[iSub]; pSubdir = subdirectory;
break; break;
} }
} }
if (!pSubdir) if (pSubdir == nullptr)
{ {
// Create new subdirectory // Create new subdirectory
pSubdir = new CVirtualDirectory(this, DirName, mpStore); pSubdir = new CVirtualDirectory(this, DirName, mpStore);
@ -206,9 +204,9 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
// We also know none of the remaining directories already exist because this is a new, empty directory. // We also know none of the remaining directories already exist because this is a new, empty directory.
TStringList Components = Remaining.Split("/\\"); TStringList Components = Remaining.Split("/\\");
for (auto Iter = Components.begin(); Iter != Components.end(); Iter++) for (const auto& component : Components)
{ {
pSubdir = new CVirtualDirectory(pSubdir, *Iter, mpStore); pSubdir = new CVirtualDirectory(pSubdir, component, mpStore);
if (!pSubdir->CreateFilesystemDirectory()) if (!pSubdir->CreateFilesystemDirectory())
{ {
@ -219,29 +217,30 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
pSubdir->Parent()->mSubdirectories.push_back(pSubdir); pSubdir->Parent()->mSubdirectories.push_back(pSubdir);
} }
if (pEntry) if (pEntry != nullptr)
pSubdir->mResources.push_back(pEntry); pSubdir->mResources.push_back(pEntry);
return true; return true;
} }
// If we have another valid child to add, return whether that operation completed successfully // If we have another valid child to add, return whether that operation completed successfully
else if (!Remaining.IsEmpty() || pEntry) if (!Remaining.IsEmpty() || pEntry != nullptr)
return pSubdir->AddChild(Remaining, pEntry); return pSubdir->AddChild(Remaining, pEntry);
// Otherwise, we're done, so just return true // Otherwise, we're done, so just return true
else return true;
return true;
} }
else return false;
return false;
} }
bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir) bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir)
{ {
if (pDir->Parent() != this) return false; if (pDir->Parent() != this)
if (FindChildDirectory(pDir->Name(), false) != nullptr) return false; return false;
if (FindChildDirectory(pDir->Name(), false) != nullptr)
return false;
mSubdirectories.push_back(pDir); mSubdirectories.push_back(pDir);
SortSubdirectories(); SortSubdirectories();
@ -251,36 +250,32 @@ bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir)
bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir) bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir)
{ {
for (auto It = mSubdirectories.begin(); It != mSubdirectories.end(); It++) const auto it = std::find_if(mSubdirectories.cbegin(), mSubdirectories.cend(),
{ [pSubdir](const auto* dir) { return dir == pSubdir; });
if (*It == pSubdir)
{
mSubdirectories.erase(It);
return true;
}
}
return false; if (it == mSubdirectories.cend())
return false;
mSubdirectories.erase(it);
return true;
} }
bool CVirtualDirectory::RemoveChildResource(CResourceEntry *pEntry) bool CVirtualDirectory::RemoveChildResource(CResourceEntry *pEntry)
{ {
for (auto It = mResources.begin(); It != mResources.end(); It++) const auto it = std::find_if(mResources.cbegin(), mResources.cend(),
{ [pEntry](const auto* resource) { return resource == pEntry; });
if (*It == pEntry)
{
mResources.erase(It);
return true;
}
}
return false; if (it == mResources.cend())
return false;
mResources.erase(it);
return true;
} }
void CVirtualDirectory::SortSubdirectories() void CVirtualDirectory::SortSubdirectories()
{ {
std::sort(mSubdirectories.begin(), mSubdirectories.end(), [](CVirtualDirectory *pLeft, CVirtualDirectory *pRight) -> bool { std::sort(mSubdirectories.begin(), mSubdirectories.end(), [](const auto* pLeft, const auto* pRight) {
return (pLeft->Name().ToUpper() < pRight->Name().ToUpper()); return pLeft->Name().ToUpper() < pRight->Name().ToUpper();
}); });
} }
@ -290,10 +285,10 @@ bool CVirtualDirectory::Rename(const TString& rkNewName)
if (!IsRoot()) if (!IsRoot())
{ {
if (!mpParent->FindChildDirectory(rkNewName, false)) if (mpParent->FindChildDirectory(rkNewName, false) == nullptr)
{ {
TString AbsPath = AbsolutePath(); const TString AbsPath = AbsolutePath();
TString NewPath = mpParent->AbsolutePath() + rkNewName + "/"; const TString NewPath = mpParent->AbsolutePath() + rkNewName + "/";
if (FileUtil::MoveDirectory(AbsPath, NewPath)) if (FileUtil::MoveDirectory(AbsPath, NewPath))
{ {
@ -317,7 +312,7 @@ bool CVirtualDirectory::Delete()
{ {
if (FileUtil::DeleteDirectory(AbsolutePath(), true)) if (FileUtil::DeleteDirectory(AbsolutePath(), true))
{ {
if (!mpParent || mpParent->RemoveChildDirectory(this)) if (mpParent == nullptr || mpParent->RemoveChildDirectory(this))
{ {
mpStore->SetCacheDirty(); mpStore->SetCacheDirty();
delete this; delete this;
@ -331,7 +326,7 @@ bool CVirtualDirectory::Delete()
void CVirtualDirectory::DeleteEmptySubdirectories() void CVirtualDirectory::DeleteEmptySubdirectories()
{ {
for (uint32 SubdirIdx = 0; SubdirIdx < mSubdirectories.size(); SubdirIdx++) for (size_t SubdirIdx = 0; SubdirIdx < mSubdirectories.size(); SubdirIdx++)
{ {
CVirtualDirectory *pDir = mSubdirectories[SubdirIdx]; CVirtualDirectory *pDir = mSubdirectories[SubdirIdx];
@ -341,17 +336,19 @@ void CVirtualDirectory::DeleteEmptySubdirectories()
SubdirIdx--; SubdirIdx--;
} }
else else
{
pDir->DeleteEmptySubdirectories(); pDir->DeleteEmptySubdirectories();
}
} }
} }
bool CVirtualDirectory::CreateFilesystemDirectory() bool CVirtualDirectory::CreateFilesystemDirectory()
{ {
TString AbsPath = AbsolutePath(); const TString AbsPath = AbsolutePath();
if (!FileUtil::Exists(AbsPath)) if (!FileUtil::Exists(AbsPath))
{ {
bool CreateSuccess = FileUtil::MakeDirectory(AbsPath); const bool CreateSuccess = FileUtil::MakeDirectory(AbsPath);
if (!CreateSuccess) if (!CreateSuccess)
errorf("FAILED to create filesystem directory: %s", *AbsPath); errorf("FAILED to create filesystem directory: %s", *AbsPath);
@ -365,22 +362,23 @@ bool CVirtualDirectory::CreateFilesystemDirectory()
bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent) bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
{ {
ASSERT(!pParent->IsDescendantOf(this)); ASSERT(!pParent->IsDescendantOf(this));
if (mpParent == pParent) return true; if (mpParent == pParent)
return true;
debugf("MOVING DIRECTORY: %s -> %s", *FullPath(), *(pParent->FullPath() + mName + '/')); debugf("MOVING DIRECTORY: %s -> %s", *FullPath(), *(pParent->FullPath() + mName + '/'));
// Check for a conflict // Check for a conflict
CVirtualDirectory *pConflictDir = pParent->FindChildDirectory(mName, false); CVirtualDirectory *pConflictDir = pParent->FindChildDirectory(mName, false);
if (pConflictDir) if (pConflictDir != nullptr)
{ {
errorf("DIRECTORY MOVE FAILED: Conflicting directory exists at the destination path!"); errorf("DIRECTORY MOVE FAILED: Conflicting directory exists at the destination path!");
return false; return false;
} }
// Move filesystem contents to new path // Move filesystem contents to new path
TString AbsOldPath = mpStore->ResourcesDir() + FullPath(); const TString AbsOldPath = mpStore->ResourcesDir() + FullPath();
TString AbsNewPath = mpStore->ResourcesDir() + pParent->FullPath() + mName + '/'; const TString AbsNewPath = mpStore->ResourcesDir() + pParent->FullPath() + mName + '/';
if (mpParent->RemoveChildDirectory(this) && FileUtil::MoveDirectory(AbsOldPath, AbsNewPath)) if (mpParent->RemoveChildDirectory(this) && FileUtil::MoveDirectory(AbsOldPath, AbsNewPath))
{ {
@ -400,9 +398,9 @@ bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
// ************ STATIC ************ // ************ STATIC ************
bool CVirtualDirectory::IsValidDirectoryName(const TString& rkName) bool CVirtualDirectory::IsValidDirectoryName(const TString& rkName)
{ {
return ( rkName != "." && return rkName != "." &&
rkName != ".." && rkName != ".." &&
FileUtil::IsValidName(rkName, true) ); FileUtil::IsValidName(rkName, true);
} }
bool CVirtualDirectory::IsValidDirectoryPath(TString Path) bool CVirtualDirectory::IsValidDirectoryPath(TString Path)
@ -415,13 +413,6 @@ bool CVirtualDirectory::IsValidDirectoryPath(TString Path)
if (Path.EndsWith('/') || Path.EndsWith('\\')) if (Path.EndsWith('/') || Path.EndsWith('\\'))
Path = Path.ChopBack(1); Path = Path.ChopBack(1);
TStringList Parts = Path.Split("/\\", true); const TStringList Parts = Path.Split("/\\", true);
return std::all_of(Parts.cbegin(), Parts.cend(), IsValidDirectoryPath);
for (auto Iter = Parts.begin(); Iter != Parts.end(); Iter++)
{
if (!IsValidDirectoryName(*Iter))
return false;
}
return true;
} }

View File

@ -12,14 +12,14 @@ class CResourceStore;
class CVirtualDirectory class CVirtualDirectory
{ {
CVirtualDirectory *mpParent; CVirtualDirectory *mpParent = nullptr;
CResourceStore *mpStore; CResourceStore *mpStore;
TString mName; TString mName;
std::vector<CVirtualDirectory*> mSubdirectories; std::vector<CVirtualDirectory*> mSubdirectories;
std::vector<CResourceEntry*> mResources; std::vector<CResourceEntry*> mResources;
public: public:
CVirtualDirectory(CResourceStore *pStore); explicit CVirtualDirectory(CResourceStore *pStore);
CVirtualDirectory(const TString& rkName, CResourceStore *pStore); CVirtualDirectory(const TString& rkName, CResourceStore *pStore);
CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore); CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore);
~CVirtualDirectory(); ~CVirtualDirectory();
@ -48,14 +48,16 @@ public:
static bool IsValidDirectoryPath(TString Path); static bool IsValidDirectoryPath(TString Path);
// Accessors // Accessors
inline CVirtualDirectory* Parent() const { return mpParent; } CVirtualDirectory* Parent() const { return mpParent; }
inline bool IsRoot() const { return !mpParent; } bool IsRoot() const { return !mpParent; }
inline TString Name() const { return mName; } TString Name() const { return mName; }
inline uint32 NumSubdirectories() const { return mSubdirectories.size(); } size_t NumSubdirectories() const { return mSubdirectories.size(); }
inline CVirtualDirectory* SubdirectoryByIndex(uint32 Index) { return mSubdirectories[Index]; } CVirtualDirectory* SubdirectoryByIndex(size_t Index) { return mSubdirectories[Index]; }
inline uint32 NumResources() const { return mResources.size(); } const CVirtualDirectory* SubdirectoryByIndex(size_t Index) const { return mSubdirectories[Index]; }
inline CResourceEntry* ResourceByIndex(uint32 Index) { return mResources[Index]; } size_t NumResources() const { return mResources.size(); }
CResourceEntry* ResourceByIndex(size_t Index) { return mResources[Index]; }
const CResourceEntry* ResourceByIndex(size_t Index) const { return mResources[Index]; }
}; };
#endif // CVIRTUALDIRECTORY #endif // CVIRTUALDIRECTORY

View File

@ -1,21 +1,28 @@
#include "DependencyListBuilders.h" #include "DependencyListBuilders.h"
// ************ CCharacterUsageMap ************ // ************ CCharacterUsageMap ************
bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, uint32 CharacterIndex) const bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, size_t CharacterIndex) const
{ {
if (mpStore->Game() >= EGame::CorruptionProto) return true; if (mpStore->Game() >= EGame::CorruptionProto)
auto Find = mUsageMap.find(rkID); return true;
if (Find == mUsageMap.end()) return false;
const auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.cend())
return false;
const std::vector<bool>& rkUsageList = Find->second; const std::vector<bool>& rkUsageList = Find->second;
if (CharacterIndex >= rkUsageList.size()) return false; if (CharacterIndex >= rkUsageList.size())
else return rkUsageList[CharacterIndex]; return false;
return rkUsageList[CharacterIndex];
} }
bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const
{ {
auto Find = mUsageMap.find(rkID); const auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.end()) return false; if (Find == mUsageMap.end())
return false;
const std::vector<bool>& rkUsageList = Find->second; const std::vector<bool>& rkUsageList = Find->second;
for (uint32 iChar = 0; iChar < rkUsageList.size(); iChar++) for (uint32 iChar = 0; iChar < rkUsageList.size(); iChar++)
@ -37,7 +44,7 @@ void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntr
{ {
ASSERT(pEntry->ResourceType() == EResourceType::Area); ASSERT(pEntry->ResourceType() == EResourceType::Area);
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++) for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
{ {
if (pWorld->AreaResourceID(iArea) == pEntry->ID()) if (pWorld->AreaResourceID(iArea) == pEntry->ID())
{ {
@ -47,17 +54,19 @@ void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntr
} }
} }
void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, uint32 AreaIndex) void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, size_t AreaIndex)
{ {
// We only need to search forward from this area to other areas that both use the same character(s) + have duplicates enabled // We only need to search forward from this area to other areas that both use the same character(s) + have duplicates enabled
Clear(); Clear();
for (uint32 iArea = AreaIndex; iArea < pWorld->NumAreas(); iArea++) for (size_t iArea = AreaIndex; iArea < pWorld->NumAreas(); iArea++)
{ {
if (!mIsInitialArea && mStillLookingIDs.empty()) break; if (!mIsInitialArea && mStillLookingIDs.empty())
break;
mCurrentAreaAllowsDupes = pWorld->DoesAreaAllowPakDuplicates(iArea); mCurrentAreaAllowsDupes = pWorld->DoesAreaAllowPakDuplicates(iArea);
CAssetID AreaID = pWorld->AreaResourceID(iArea); const CAssetID AreaID = pWorld->AreaResourceID(iArea);
CResourceEntry *pEntry = mpStore->FindEntry(AreaID); CResourceEntry *pEntry = mpStore->FindEntry(AreaID);
ASSERT(pEntry && pEntry->ResourceType() == EResourceType::Area); ASSERT(pEntry && pEntry->ResourceType() == EResourceType::Area);
@ -75,11 +84,11 @@ void CCharacterUsageMap::FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 L
ASSERT(pTree->Type() == EDependencyNodeType::Area); ASSERT(pTree->Type() == EDependencyNodeType::Area);
// Only examine dependencies of the particular layer specified by the caller // Only examine dependencies of the particular layer specified by the caller
bool IsLastLayer = (mLayerIndex == pTree->NumScriptLayers() - 1); const bool IsLastLayer = mLayerIndex == pTree->NumScriptLayers() - 1;
uint32 StartIdx = pTree->ScriptLayerOffset(mLayerIndex); const size_t StartIdx = pTree->ScriptLayerOffset(mLayerIndex);
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(mLayerIndex + 1)); const size_t EndIdx = IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(mLayerIndex + 1);
for (uint32 iInst = StartIdx; iInst < EndIdx; iInst++) for (size_t iInst = StartIdx; iInst < EndIdx; iInst++)
ParseDependencyNode(pTree->ChildByIndex(iInst)); ParseDependencyNode(pTree->ChildByIndex(iInst));
} }
@ -87,7 +96,7 @@ void CCharacterUsageMap::Clear()
{ {
mUsageMap.clear(); mUsageMap.clear();
mStillLookingIDs.clear(); mStillLookingIDs.clear();
mLayerIndex = -1; mLayerIndex = UINT32_MAX;
mIsInitialArea = true; mIsInitialArea = true;
} }
@ -95,17 +104,15 @@ void CCharacterUsageMap::Clear()
void CCharacterUsageMap::DebugPrintContents() void CCharacterUsageMap::DebugPrintContents()
{ {
for (auto Iter = mUsageMap.begin(); Iter != mUsageMap.end(); Iter++) for (const auto& [ID, usedList] : mUsageMap)
{ {
CAssetID ID = Iter->first; const auto* pSet = mpStore->LoadResource<CAnimSet>(ID);
std::vector<bool>& rUsedList = Iter->second;
CAnimSet *pSet = mpStore->LoadResource<CAnimSet>(ID);
for (uint32 iChar = 0; iChar < pSet->NumCharacters(); iChar++) for (size_t iChar = 0; iChar < pSet->NumCharacters(); iChar++)
{ {
bool Used = (rUsedList.size() > iChar && rUsedList[iChar]); const bool Used = usedList.size() > iChar && usedList[iChar];
TString CharName = pSet->Character(iChar)->Name; const TString CharName = pSet->Character(iChar)->Name;
debugf("%s : Char %d : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED")); debugf("%s : Char %zu : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED"));
} }
} }
} }
@ -113,59 +120,59 @@ void CCharacterUsageMap::DebugPrintContents()
// ************ PROTECTED ************ // ************ PROTECTED ************
void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode) void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
{ {
if (!pNode) return; if (!pNode)
EDependencyNodeType Type = pNode->Type(); return;
const EDependencyNodeType Type = pNode->Type();
if (Type == EDependencyNodeType::CharacterProperty) if (Type == EDependencyNodeType::CharacterProperty)
{ {
CCharPropertyDependency *pDep = static_cast<CCharPropertyDependency*>(pNode); auto *pDep = static_cast<CCharPropertyDependency*>(pNode);
CAssetID ResID = pDep->ID(); const CAssetID ResID = pDep->ID();
auto Find = mUsageMap.find(ResID); const auto Find = mUsageMap.find(ResID);
if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.end()) if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.cend())
return; return;
if (Find != mUsageMap.end()) if (Find != mUsageMap.cend())
{ {
if (!mIsInitialArea && mCurrentAreaAllowsDupes) if (!mIsInitialArea && mCurrentAreaAllowsDupes)
{ {
mStillLookingIDs.erase( mStillLookingIDs.find(ResID) ); mStillLookingIDs.erase(mStillLookingIDs.find(ResID));
return; return;
} }
} }
else else
{ {
if (!mIsInitialArea) return; if (!mIsInitialArea)
mUsageMap[ResID] = std::vector<bool>(); return;
mUsageMap.insert_or_assign(ResID, std::vector<bool>());
mStillLookingIDs.insert(ResID); mStillLookingIDs.insert(ResID);
} }
std::vector<bool>& rUsageList = mUsageMap[ResID]; std::vector<bool>& rUsageList = mUsageMap[ResID];
uint32 UsedChar = pDep->UsedChar(); const uint32 UsedChar = pDep->UsedChar();
if (rUsageList.size() <= UsedChar) if (rUsageList.size() <= UsedChar)
rUsageList.resize(UsedChar + 1, false); rUsageList.resize(UsedChar + 1, false);
rUsageList[UsedChar] = true; rUsageList[UsedChar] = true;
} }
// Parse dependencies of the referenced resource if it's a type that can reference animsets // Parse dependencies of the referenced resource if it's a type that can reference animsets
else if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty) else if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty)
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode); auto* pDep = static_cast<CResourceDependency*>(pNode);
CResourceEntry *pEntry = mpStore->FindEntry(pDep->ID()); CResourceEntry* pEntry = mpStore->FindEntry(pDep->ID());
if (pEntry && pEntry->ResourceType() == EResourceType::Scan) if (pEntry != nullptr && pEntry->ResourceType() == EResourceType::Scan)
{ {
ParseDependencyNode(pEntry->Dependencies()); ParseDependencyNode(pEntry->Dependencies());
} }
} }
else // Look for sub-dependencies of the current node
// Look for sub-dependencies of the current node
else
{ {
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++) for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
ParseDependencyNode(pNode->ChildByIndex(iChild)); ParseDependencyNode(pNode->ChildByIndex(iChild));
} }
} }
@ -177,11 +184,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
FindUniversalAreaAssets(); FindUniversalAreaAssets();
// Iterate over all resources and parse their dependencies // Iterate over all resources and parse their dependencies
for (uint32 iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++) for (size_t iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = mpkPackage->NamedResourceByIndex(iRes); const SNamedResource& rkRes = mpkPackage->NamedResourceByIndex(iRes);
CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID); CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID);
if (!pEntry) continue; if (!pEntry)
continue;
if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG") if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG")
{ {
@ -189,16 +197,17 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
continue; continue;
} }
mIsUniversalAreaAsset = (mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.end()); mIsUniversalAreaAsset = mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.cend();
if (rkRes.Type == "MLVL") if (rkRes.Type == "MLVL")
{ {
mpWorld = (CWorld*) pEntry->Load(); mpWorld = static_cast<CWorld*>(pEntry->Load());
ASSERT(mpWorld); ASSERT(mpWorld);
} }
else else
{
mCharacterUsageMap.FindUsagesForAsset(pEntry); mCharacterUsageMap.FindUsagesForAsset(pEntry);
}
AddDependency(nullptr, rkRes.ID, rOut); AddDependency(nullptr, rkRes.ID, rOut);
mpWorld = nullptr; mpWorld = nullptr;
@ -207,9 +216,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut) void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut)
{ {
if (pCurEntry && pCurEntry->ResourceType() == EResourceType::DependencyGroup) return; if (pCurEntry && pCurEntry->ResourceType() == EResourceType::DependencyGroup)
return;
CResourceEntry *pEntry = mpStore->FindEntry(rkID); CResourceEntry *pEntry = mpStore->FindEntry(rkID);
if (!pEntry) return; if (!pEntry)
return;
EResourceType ResType = pEntry->ResourceType(); EResourceType ResType = pEntry->ResourceType();
@ -219,13 +231,16 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
(ResType != EResourceType::World || !pCurEntry) && (ResType != EResourceType::World || !pCurEntry) &&
(ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World); (ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World);
if (!IsValid) return; if (!IsValid)
if ( ( mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) ||
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ||
(!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end() ) )
return; return;
if ((mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) ||
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ||
(!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end()))
{
return;
}
// Entry is valid, parse its sub-dependencies // Entry is valid, parse its sub-dependencies
mPackageUsedAssets.insert(rkID); mPackageUsedAssets.insert(rkID);
mAreaUsedAssets.insert(rkID); mAreaUsedAssets.insert(rkID);
@ -241,7 +256,7 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
if (mEnableDuplicates) if (mEnableDuplicates)
{ {
for (uint32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++) for (size_t iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
{ {
if (mpWorld->AreaResourceID(iArea) == rkID) if (mpWorld->AreaResourceID(iArea) == rkID)
{ {
@ -251,10 +266,11 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
} }
} }
} }
// Animset - keep track of the current animset ID // Animset - keep track of the current animset ID
else if (ResType == EResourceType::AnimSet) else if (ResType == EResourceType::AnimSet)
{
mCurrentAnimSetID = rkID; mCurrentAnimSetID = rkID;
}
// Evaluate dependencies of this entry // Evaluate dependencies of this entry
CDependencyTree *pTree = pEntry->Dependencies(); CDependencyTree *pTree = pEntry->Dependencies();
@ -264,7 +280,6 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
// Revert current animset ID // Revert current animset ID
if (ResType == EResourceType::AnimSet) if (ResType == EResourceType::AnimSet)
mCurrentAnimSetID = CAssetID::InvalidID(mGame); mCurrentAnimSetID = CAssetID::InvalidID(mGame);
// Revert duplicate flag // Revert duplicate flag
else if (ResType == EResourceType::Area) else if (ResType == EResourceType::Area)
mCurrentAreaHasDuplicates = false; mCurrentAreaHasDuplicates = false;
@ -272,54 +287,54 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut) void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
{ {
if (!pNode) return; if (!pNode)
EDependencyNodeType Type = pNode->Type(); return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false; bool ParseChildren = false;
// Straight resource dependencies should just be added to the tree directly // Straight resource dependencies should just be added to the tree directly
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty) if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode); const auto *pDep = static_cast<CResourceDependency*>(pNode);
AddDependency(pCurEntry, pDep->ID(), rOut); AddDependency(pCurEntry, pDep->ID(), rOut);
} }
// Anim events should be added if either they apply to characters, or their character index is used // Anim events should be added if either they apply to characters, or their character index is used
else if (Type == EDependencyNodeType::AnimEvent) else if (Type == EDependencyNodeType::AnimEvent)
{ {
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode); const auto *pDep = static_cast<CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex(); const uint32 CharIndex = pDep->CharIndex();
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex)) if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
AddDependency(pCurEntry, pDep->ID(), rOut); AddDependency(pCurEntry, pDep->ID(), rOut);
} }
// Set characters should only be added if their character index is used // Set characters should only be added if their character index is used
else if (Type == EDependencyNodeType::SetCharacter) else if (Type == EDependencyNodeType::SetCharacter)
{ {
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode); const auto *pChar = static_cast<CSetCharacterDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || mIsPlayerActor; ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || mIsPlayerActor;
} }
// Set animations should only be added if they're being used by at least one used character // Set animations should only be added if they're being used by at least one used character
else if (Type == EDependencyNodeType::SetAnimation) else if (Type == EDependencyNodeType::SetAnimation)
{ {
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode); auto *pAnim = static_cast<CSetAnimationDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter()); ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
} }
else else
{
ParseChildren = true; ParseChildren = true;
}
// Analyze this node's children // Analyze this node's children
if (ParseChildren) if (ParseChildren)
{ {
if (Type == EDependencyNodeType::ScriptInstance) if (Type == EDependencyNodeType::ScriptInstance)
{ {
uint32 ObjType = static_cast<CScriptInstanceDependency*>(pNode)->ObjectType(); const uint32 ObjType = static_cast<CScriptInstanceDependency*>(pNode)->ObjectType();
mIsPlayerActor = (ObjType == 0x4C || ObjType == FOURCC('PLAC')); mIsPlayerActor = (ObjType == 0x4C || ObjType == FOURCC('PLAC'));
} }
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++) for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut); EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
if (Type == EDependencyNodeType::ScriptInstance) if (Type == EDependencyNodeType::ScriptInstance)
@ -335,7 +350,7 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
if (pPackage) if (pPackage)
{ {
// Iterate over all the package contents, keep track of all universal area assets // Iterate over all the package contents, keep track of all universal area assets
for (uint32 ResIdx = 0; ResIdx < pPackage->NumNamedResources(); ResIdx++) for (size_t ResIdx = 0; ResIdx < pPackage->NumNamedResources(); ResIdx++)
{ {
const SNamedResource& rkRes = pPackage->NamedResourceByIndex(ResIdx); const SNamedResource& rkRes = pPackage->NamedResourceByIndex(ResIdx);
@ -351,22 +366,22 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
if (pUniverseWorld) if (pUniverseWorld)
{ {
// Area IDs // Area IDs
for (uint32 AreaIdx = 0; AreaIdx < pUniverseWorld->NumAreas(); AreaIdx++) for (size_t AreaIdx = 0; AreaIdx < pUniverseWorld->NumAreas(); AreaIdx++)
{ {
CAssetID AreaID = pUniverseWorld->AreaResourceID(AreaIdx); const CAssetID AreaID = pUniverseWorld->AreaResourceID(AreaIdx);
if (AreaID.IsValid()) if (AreaID.IsValid())
mUniversalAreaAssets.insert(AreaID); mUniversalAreaAssets.insert(AreaID);
} }
// Map IDs // Map IDs
CDependencyGroup *pMapWorld = (CDependencyGroup*) pUniverseWorld->MapWorld(); auto *pMapWorld = static_cast<CDependencyGroup*>(pUniverseWorld->MapWorld());
if (pMapWorld) if (pMapWorld)
{ {
for (uint32 DepIdx = 0; DepIdx < pMapWorld->NumDependencies(); DepIdx++) for (size_t DepIdx = 0; DepIdx < pMapWorld->NumDependencies(); DepIdx++)
{ {
CAssetID DepID = pMapWorld->DependencyByIndex(DepIdx); const CAssetID DepID = pMapWorld->DependencyByIndex(DepIdx);
if (DepID.IsValid()) if (DepID.IsValid())
mUniversalAreaAssets.insert(DepID); mUniversalAreaAssets.insert(DepID);
@ -385,53 +400,55 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies()); CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
// Fill area base used assets set (don't actually add to list yet) // Fill area base used assets set (don't actually add to list yet)
uint32 BaseEndIndex = (pTree->NumScriptLayers() > 0 ? pTree->ScriptLayerOffset(0) : pTree->NumChildren()); const size_t BaseEndIndex = pTree->NumScriptLayers() > 0 ? pTree->ScriptLayerOffset(0) : pTree->NumChildren();
for (uint32 iDep = 0; iDep < BaseEndIndex; iDep++) for (size_t iDep = 0; iDep < BaseEndIndex; iDep++)
{ {
CResourceDependency *pRes = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep)); const auto* pRes = static_cast<const CResourceDependency*>(pTree->ChildByIndex(iDep));
ASSERT(pRes->Type() == EDependencyNodeType::Resource); ASSERT(pRes->Type() == EDependencyNodeType::Resource);
mBaseUsedAssets.insert(pRes->ID()); mBaseUsedAssets.insert(pRes->ID());
} }
// Get dependencies of each layer // Get dependencies of each layer
for (uint32 iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++) for (size_t iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
{ {
mLayerUsedAssets.clear(); mLayerUsedAssets.clear();
mCharacterUsageMap.FindUsagesForLayer(mpAreaEntry, iLyr); mCharacterUsageMap.FindUsagesForLayer(mpAreaEntry, iLyr);
rLayerOffsetsOut.push_back(rAssetsOut.size()); rLayerOffsetsOut.push_back(rAssetsOut.size());
bool IsLastLayer = (iLyr == pTree->NumScriptLayers() - 1); const bool IsLastLayer = iLyr == pTree->NumScriptLayers() - 1;
uint32 StartIdx = pTree->ScriptLayerOffset(iLyr); const size_t StartIdx = pTree->ScriptLayerOffset(iLyr);
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(iLyr + 1)); const size_t EndIdx = IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(iLyr + 1);
for (uint32 iChild = StartIdx; iChild < EndIdx; iChild++) for (size_t iChild = StartIdx; iChild < EndIdx; iChild++)
{ {
IDependencyNode *pNode = pTree->ChildByIndex(iChild); const IDependencyNode *pNode = pTree->ChildByIndex(iChild);
if (pNode->Type() == EDependencyNodeType::ScriptInstance) if (pNode->Type() == EDependencyNodeType::ScriptInstance)
{ {
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode); const auto* pInst = static_cast<const CScriptInstanceDependency*>(pNode);
mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC')); mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC'));
for (uint32 iDep = 0; iDep < pInst->NumChildren(); iDep++) for (size_t iDep = 0; iDep < pInst->NumChildren(); iDep++)
{ {
CPropertyDependency *pDep = static_cast<CPropertyDependency*>(pInst->ChildByIndex(iDep)); const auto* pDep = static_cast<const CPropertyDependency*>(pInst->ChildByIndex(iDep));
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets // For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
if (mGame == EGame::Corruption && mIsPlayerActor) if (mGame == EGame::Corruption && mIsPlayerActor)
{ {
TString PropID = pDep->PropertyID(); TString PropID = pDep->PropertyID();
if ( PropID == "0x846397A8" || PropID == "0x685A4C01" || if (PropID == "0x846397A8" || PropID == "0x685A4C01" ||
PropID == "0x9834ECC9" || PropID == "0x188B8960" || PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
PropID == "0x134A81E3" || PropID == "0x4ABF030C" || PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
PropID == "0x9BF030DC" || PropID == "0x981263D3" || PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" || PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
PropID == "0x3376814D" || PropID == "0x797CA77E" || PropID == "0x3376814D" || PropID == "0x797CA77E" ||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" || PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE" ) PropID == "0xA8778E57" || PropID == "0x1CB10DBE")
{
continue; continue;
}
} }
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut); AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
@ -439,7 +456,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
} }
else if (pNode->Type() == EDependencyNodeType::Resource) else if (pNode->Type() == EDependencyNodeType::Resource)
{ {
CResourceDependency *pResDep = static_cast<CResourceDependency*>(pNode); const auto* pResDep = static_cast<const CResourceDependency*>(pNode);
AddDependency(pResDep->ID(), rAssetsOut, pAudioGroupsOut); AddDependency(pResDep->ID(), rAssetsOut, pAudioGroupsOut);
} }
else else
@ -454,9 +471,9 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
mLayerUsedAssets.clear(); mLayerUsedAssets.clear();
rLayerOffsetsOut.push_back(rAssetsOut.size()); rLayerOffsetsOut.push_back(rAssetsOut.size());
for (uint32 iDep = 0; iDep < BaseEndIndex; iDep++) for (size_t iDep = 0; iDep < BaseEndIndex; iDep++)
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep)); const auto* pDep = static_cast<const CResourceDependency*>(pTree->ChildByIndex(iDep));
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut); AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
} }
} }
@ -464,9 +481,10 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut) void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
{ {
CResourceEntry *pEntry = mpStore->FindEntry(rkID); CResourceEntry *pEntry = mpStore->FindEntry(rkID);
if (!pEntry) return; if (!pEntry)
return;
EResourceType ResType = pEntry->ResourceType(); const EResourceType ResType = pEntry->ResourceType();
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency. // If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
if (mGame <= EGame::Prime && ResType == EResourceType::AudioGroup) if (mGame <= EGame::Prime && ResType == EResourceType::AudioGroup)
@ -515,47 +533,47 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut) void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
{ {
if (!pNode) return; if (!pNode)
EDependencyNodeType Type = pNode->Type(); return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false; bool ParseChildren = false;
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty) if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode); const auto* pDep = static_cast<const CResourceDependency*>(pNode);
AddDependency(pDep->ID(), rOut, pAudioGroupsOut); AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
} }
else if (Type == EDependencyNodeType::AnimEvent) else if (Type == EDependencyNodeType::AnimEvent)
{ {
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode); const auto* pDep = static_cast<const CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex(); const uint32 CharIndex = pDep->CharIndex();
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex)) if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
AddDependency(pDep->ID(), rOut, pAudioGroupsOut); AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
} }
else if (Type == EDependencyNodeType::SetCharacter) else if (Type == EDependencyNodeType::SetCharacter)
{ {
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one // Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
const uint32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5); const uint32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5);
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode); const auto *pChar = static_cast<const CSetCharacterDependency*>(pNode);
uint32 SetIndex = pChar->CharSetIndex(); const uint32 SetIndex = pChar->CharSetIndex();
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex); ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
} }
else if (Type == EDependencyNodeType::SetAnimation) else if (Type == EDependencyNodeType::SetAnimation)
{ {
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode); auto *pAnim = static_cast<CSetAnimationDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter()); ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
} }
else else
{
ParseChildren = true; ParseChildren = true;
}
if (ParseChildren) if (ParseChildren)
{ {
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++) for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut, pAudioGroupsOut); EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut, pAudioGroupsOut);
} }
} }
@ -570,11 +588,12 @@ void CAssetDependencyListBuilder::BuildDependencyList(std::vector<CAssetID>& Out
void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector<CAssetID>& Out) void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector<CAssetID>& Out)
{ {
CResourceEntry *pEntry = mpResourceEntry->ResourceStore()->FindEntry(kID); CResourceEntry *pEntry = mpResourceEntry->ResourceStore()->FindEntry(kID);
if (!pEntry) return; if (!pEntry)
return;
EResourceType ResType = pEntry->ResourceType(); const EResourceType ResType = pEntry->ResourceType();
if (mUsedAssets.find(kID) != mUsedAssets.end()) if (mUsedAssets.find(kID) != mUsedAssets.cend())
return; return;
// Dependency is valid! Evaluate the node tree // Dependency is valid! Evaluate the node tree
@ -598,43 +617,43 @@ void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector
void CAssetDependencyListBuilder::EvaluateDependencyNode(CResourceEntry* pCurEntry, IDependencyNode* pNode, std::vector<CAssetID>& Out) void CAssetDependencyListBuilder::EvaluateDependencyNode(CResourceEntry* pCurEntry, IDependencyNode* pNode, std::vector<CAssetID>& Out)
{ {
if (!pNode) return; if (!pNode)
EDependencyNodeType Type = pNode->Type(); return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false; bool ParseChildren = false;
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty) if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
{ {
CResourceDependency* pDep = static_cast<CResourceDependency*>(pNode); const auto* pDep = static_cast<CResourceDependency*>(pNode);
AddDependency(pDep->ID(), Out); AddDependency(pDep->ID(), Out);
} }
else if (Type == EDependencyNodeType::AnimEvent) else if (Type == EDependencyNodeType::AnimEvent)
{ {
CAnimEventDependency* pDep = static_cast<CAnimEventDependency*>(pNode); const auto* pDep = static_cast<CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex(); const uint32 CharIndex = pDep->CharIndex();
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex)) if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
AddDependency(pDep->ID(), Out); AddDependency(pDep->ID(), Out);
} }
else if (Type == EDependencyNodeType::SetCharacter) else if (Type == EDependencyNodeType::SetCharacter)
{ {
CSetCharacterDependency* pChar = static_cast<CSetCharacterDependency*>(pNode); const auto* pChar = static_cast<CSetCharacterDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()); ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex());
} }
else if (Type == EDependencyNodeType::SetAnimation) else if (Type == EDependencyNodeType::SetAnimation)
{ {
CSetAnimationDependency* pAnim = static_cast<CSetAnimationDependency*>(pNode); auto* pAnim = static_cast<CSetAnimationDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim); ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim);
} }
else else
{
ParseChildren = true; ParseChildren = true;
}
if (ParseChildren) if (ParseChildren)
{ {
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++) for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), Out); EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), Out);
} }
} }

View File

@ -12,21 +12,21 @@ class CCharacterUsageMap
{ {
std::map<CAssetID, std::vector<bool>> mUsageMap; std::map<CAssetID, std::vector<bool>> mUsageMap;
std::set<CAssetID> mStillLookingIDs; std::set<CAssetID> mStillLookingIDs;
CResourceStore *mpStore; CResourceStore *mpStore = nullptr;
uint32 mLayerIndex; uint32 mLayerIndex = UINT32_MAX;
bool mIsInitialArea; bool mIsInitialArea = true;
bool mCurrentAreaAllowsDupes; bool mCurrentAreaAllowsDupes = false;
public: public:
CCharacterUsageMap(CResourceStore *pStore) explicit CCharacterUsageMap(CResourceStore *pStore)
: mpStore(pStore), mLayerIndex(-1), mIsInitialArea(true), mCurrentAreaAllowsDupes(false) : mpStore(pStore)
{} {}
bool IsCharacterUsed(const CAssetID& rkID, uint32 CharacterIndex) const; bool IsCharacterUsed(const CAssetID& rkID, size_t CharacterIndex) const;
bool IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const; bool IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const;
void FindUsagesForAsset(CResourceEntry *pEntry); void FindUsagesForAsset(CResourceEntry *pEntry);
void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry); void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry);
void FindUsagesForArea(CWorld *pWorld, uint32 AreaIndex); void FindUsagesForArea(CWorld *pWorld, size_t AreaIndex);
void FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 LayerIndex); void FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 LayerIndex);
void Clear(); void Clear();
void DebugPrintContents(); void DebugPrintContents();
@ -47,19 +47,17 @@ class CPackageDependencyListBuilder
std::set<CAssetID> mPackageUsedAssets; std::set<CAssetID> mPackageUsedAssets;
std::set<CAssetID> mAreaUsedAssets; std::set<CAssetID> mAreaUsedAssets;
std::set<CAssetID> mUniversalAreaAssets; std::set<CAssetID> mUniversalAreaAssets;
bool mEnableDuplicates; bool mEnableDuplicates = false;
bool mCurrentAreaHasDuplicates; bool mCurrentAreaHasDuplicates = false;
bool mIsUniversalAreaAsset; bool mIsUniversalAreaAsset = false;
bool mIsPlayerActor; bool mIsPlayerActor = false;
public: public:
CPackageDependencyListBuilder(const CPackage *pkPackage) explicit CPackageDependencyListBuilder(const CPackage *pkPackage)
: mpkPackage(pkPackage) : mpkPackage(pkPackage)
, mGame(pkPackage->Project()->Game())
, mpStore(pkPackage->Project()->ResourceStore()) , mpStore(pkPackage->Project()->ResourceStore())
, mGame(pkPackage->Project()->Game())
, mCharacterUsageMap(pkPackage->Project()->ResourceStore()) , mCharacterUsageMap(pkPackage->Project()->ResourceStore())
, mCurrentAreaHasDuplicates(false)
, mIsPlayerActor(false)
{ {
} }
@ -79,10 +77,10 @@ class CAreaDependencyListBuilder
CCharacterUsageMap mCharacterUsageMap; CCharacterUsageMap mCharacterUsageMap;
std::set<CAssetID> mBaseUsedAssets; std::set<CAssetID> mBaseUsedAssets;
std::set<CAssetID> mLayerUsedAssets; std::set<CAssetID> mLayerUsedAssets;
bool mIsPlayerActor; bool mIsPlayerActor = false;
public: public:
CAreaDependencyListBuilder(CResourceEntry *pAreaEntry) explicit CAreaDependencyListBuilder(CResourceEntry *pAreaEntry)
: mpAreaEntry(pAreaEntry) : mpAreaEntry(pAreaEntry)
, mpStore(pAreaEntry->ResourceStore()) , mpStore(pAreaEntry->ResourceStore())
, mGame(pAreaEntry->Game()) , mGame(pAreaEntry->Game())
@ -106,7 +104,7 @@ class CAssetDependencyListBuilder
CAssetID mCurrentAnimSetID; CAssetID mCurrentAnimSetID;
public: public:
CAssetDependencyListBuilder(CResourceEntry* pEntry) explicit CAssetDependencyListBuilder(CResourceEntry* pEntry)
: mpResourceEntry(pEntry) : mpResourceEntry(pEntry)
, mCharacterUsageMap(pEntry->ResourceStore()) , mCharacterUsageMap(pEntry->ResourceStore())
{} {}

View File

@ -7,14 +7,12 @@
class IProgressNotifier class IProgressNotifier
{ {
TString mTaskName; TString mTaskName;
int mTaskIndex; int mTaskIndex = 0;
int mTaskCount; int mTaskCount = 1;
public: public:
IProgressNotifier() IProgressNotifier() = default;
: mTaskIndex(0) virtual ~IProgressNotifier() = default;
, mTaskCount(1)
{}
void SetNumTasks(int NumTasks) void SetNumTasks(int NumTasks)
{ {
@ -25,7 +23,7 @@ public:
void SetTask(int TaskIndex, TString TaskName) void SetTask(int TaskIndex, TString TaskName)
{ {
mTaskName = TaskName; mTaskName = std::move(TaskName);
mTaskIndex = TaskIndex; mTaskIndex = TaskIndex;
mTaskCount = Math::Max(mTaskCount, TaskIndex + 1); mTaskCount = Math::Max(mTaskCount, TaskIndex + 1);
} }
@ -67,9 +65,9 @@ protected:
class CNullProgressNotifier : public IProgressNotifier class CNullProgressNotifier : public IProgressNotifier
{ {
public: public:
bool ShouldCancel() const { return false; } bool ShouldCancel() const override{ return false; }
protected: protected:
void UpdateProgress(const TString&, const TString&, float) {} void UpdateProgress(const TString&, const TString&, float) override {}
}; };
extern CNullProgressNotifier *gpNullProgress; extern CNullProgressNotifier *gpNullProgress;

View File

@ -6,6 +6,7 @@
class IUIRelay class IUIRelay
{ {
public: public:
virtual ~IUIRelay() = default;
virtual void ShowMessageBox(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0; virtual void ShowMessageBox(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
virtual void ShowMessageBoxAsync(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0; virtual void ShowMessageBoxAsync(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
virtual bool AskYesNoQuestion(const TString& rkInfoBoxTitle, const TString& rkQuestion) = 0; virtual bool AskYesNoQuestion(const TString& rkInfoBoxTitle, const TString& rkQuestion) = 0;

View File

@ -1,16 +1,13 @@
#include "CDynamicVertexBuffer.h" #include "CDynamicVertexBuffer.h"
#include "CVertexArrayManager.h" #include "CVertexArrayManager.h"
static const uint32 gskAttribSize[] = { #include <array>
constexpr std::array<uint32, 12> gskAttribSize{
0xC, 0xC, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8 0xC, 0xC, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8
}; };
CDynamicVertexBuffer::CDynamicVertexBuffer() CDynamicVertexBuffer::CDynamicVertexBuffer() = default;
: mAttribFlags(EVertexAttribute::None)
, mBufferedFlags(EVertexAttribute::None)
, mNumVertices(0)
{
}
CDynamicVertexBuffer::~CDynamicVertexBuffer() CDynamicVertexBuffer::~CDynamicVertexBuffer()
{ {
@ -44,7 +41,7 @@ void CDynamicVertexBuffer::SetActiveAttribs(FVertexDescription AttribFlags)
void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkData) void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkData)
{ {
uint32 Index; size_t Index;
switch (Attrib) switch (Attrib)
{ {
@ -69,9 +66,9 @@ void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkD
void CDynamicVertexBuffer::ClearBuffers() void CDynamicVertexBuffer::ClearBuffers()
{ {
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++) for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{ {
int Bit = 1 << iAttrib; const int Bit = 1 << iAttrib;
if (mBufferedFlags & Bit) if (mBufferedFlags & Bit)
glDeleteBuffers(1, &mAttribBuffers[iAttrib]); glDeleteBuffers(1, &mAttribBuffers[iAttrib]);
@ -86,9 +83,9 @@ GLuint CDynamicVertexBuffer::CreateVAO()
glGenVertexArrays(1, &VertexArray); glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray); glBindVertexArray(VertexArray);
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++) for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{ {
bool HasAttrib = ((3 << (iAttrib * 2)) != 0); const bool HasAttrib = (3 << (iAttrib * 2)) != 0;
if (HasAttrib) if (HasAttrib)
{ {
@ -96,7 +93,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
GLuint NumComponents; GLuint NumComponents;
GLenum DataType; GLenum DataType;
if ((iAttrib == 2) || (iAttrib == 3)) if (iAttrib == 2 || iAttrib == 3)
{ {
NumComponents = 4; NumComponents = 4;
DataType = GL_UNSIGNED_BYTE; DataType = GL_UNSIGNED_BYTE;
@ -107,7 +104,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
DataType = GL_FLOAT; DataType = GL_FLOAT;
} }
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, (void*) 0); glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
} }
@ -119,17 +116,18 @@ GLuint CDynamicVertexBuffer::CreateVAO()
// ************ PRIVATE ************ // ************ PRIVATE ************
void CDynamicVertexBuffer::InitBuffers() void CDynamicVertexBuffer::InitBuffers()
{ {
if (mBufferedFlags) ClearBuffers(); if (mBufferedFlags)
ClearBuffers();
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++) for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{ {
bool HasAttrib = ((3 << (iAttrib * 2)) != 0); const bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
if (HasAttrib) if (HasAttrib)
{ {
glGenBuffers(1, &mAttribBuffers[iAttrib]); glGenBuffers(1, &mAttribBuffers[iAttrib]);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, gskAttribSize[iAttrib] * mNumVertices, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, gskAttribSize[iAttrib] * mNumVertices, nullptr, GL_DYNAMIC_DRAW);
} }
} }
mBufferedFlags = mAttribFlags; mBufferedFlags = mAttribFlags;

View File

@ -4,15 +4,15 @@
#include "Core/Resource/Model/EVertexAttribute.h" #include "Core/Resource/Model/EVertexAttribute.h"
#include <Common/BasicTypes.h> #include <Common/BasicTypes.h>
#include <vector> #include <array>
#include <GL/glew.h> #include <GL/glew.h>
class CDynamicVertexBuffer class CDynamicVertexBuffer
{ {
FVertexDescription mAttribFlags; FVertexDescription mAttribFlags{EVertexAttribute::None};
FVertexDescription mBufferedFlags; FVertexDescription mBufferedFlags{EVertexAttribute::None};
uint32 mNumVertices; uint32 mNumVertices = 0;
GLuint mAttribBuffers[12]; std::array<GLuint, 12> mAttribBuffers{};
public: public:
CDynamicVertexBuffer(); CDynamicVertexBuffer();

View File

@ -1,23 +1,9 @@
#include "CFramebuffer.h" #include "CFramebuffer.h"
#include <Common/Log.h> #include <Common/Log.h>
CFramebuffer::CFramebuffer() CFramebuffer::CFramebuffer() = default;
: mpRenderbuffer(nullptr)
, mpTexture(nullptr)
, mWidth(0)
, mHeight(0)
, mEnableMultisampling(false)
, mInitialized(false)
{
}
CFramebuffer::CFramebuffer(uint32 Width, uint32 Height) CFramebuffer::CFramebuffer(uint32 Width, uint32 Height)
: mpRenderbuffer(nullptr)
, mpTexture(nullptr)
, mWidth(0)
, mHeight(0)
, mEnableMultisampling(false)
, mInitialized(false)
{ {
Resize(Width, Height); Resize(Width, Height);
} }

View File

@ -7,13 +7,14 @@
class CFramebuffer class CFramebuffer
{ {
GLuint mFramebuffer; GLuint mFramebuffer = 0;
CRenderbuffer *mpRenderbuffer; CRenderbuffer *mpRenderbuffer = nullptr;
CTexture *mpTexture; CTexture *mpTexture = nullptr;
uint32 mWidth, mHeight; uint32 mWidth = 0;
bool mEnableMultisampling; uint32 mHeight = 0;
bool mInitialized; bool mEnableMultisampling = false;
GLenum mStatus; bool mInitialized = false;
GLenum mStatus{};
static GLint smDefaultFramebuffer; static GLint smDefaultFramebuffer;
static bool smStaticsInitialized; static bool smStaticsInitialized;
@ -28,7 +29,7 @@ public:
void SetMultisamplingEnabled(bool Enable); void SetMultisamplingEnabled(bool Enable);
// Accessors // Accessors
inline CTexture* Texture() const { return mpTexture; } CTexture* Texture() const { return mpTexture; }
// Static // Static
static void BindDefaultFramebuffer(GLenum Target = GL_FRAMEBUFFER); static void BindDefaultFramebuffer(GLenum Target = GL_FRAMEBUFFER);

View File

@ -1,13 +1,9 @@
#include "CIndexBuffer.h" #include "CIndexBuffer.h"
CIndexBuffer::CIndexBuffer() CIndexBuffer::CIndexBuffer() = default;
: mBuffered(false)
{
}
CIndexBuffer::CIndexBuffer(GLenum Type) CIndexBuffer::CIndexBuffer(GLenum type)
: mPrimitiveType(Type) : mPrimitiveType(type)
, mBuffered(false)
{ {
} }
@ -17,21 +13,21 @@ CIndexBuffer::~CIndexBuffer()
glDeleteBuffers(1, &mIndexBuffer); glDeleteBuffers(1, &mIndexBuffer);
} }
void CIndexBuffer::AddIndex(uint16 Index) void CIndexBuffer::AddIndex(uint16 index)
{ {
mIndices.push_back(Index); mIndices.push_back(index);
} }
void CIndexBuffer::AddIndices(uint16 *pIndices, uint Count) void CIndexBuffer::AddIndices(const uint16 *indices, size_t count)
{ {
Reserve(Count); Reserve(count);
for (uint iIdx = 0; iIdx < Count; iIdx++) for (size_t i = 0; i < count; i++)
mIndices.push_back(*pIndices++); mIndices.push_back(*indices++);
} }
void CIndexBuffer::Reserve(uint Size) void CIndexBuffer::Reserve(size_t size)
{ {
mIndices.reserve(mIndices.size() + Size); mIndices.reserve(mIndices.size() + size);
} }
void CIndexBuffer::Clear() void CIndexBuffer::Clear()
@ -57,7 +53,9 @@ void CIndexBuffer::Buffer()
void CIndexBuffer::Bind() void CIndexBuffer::Bind()
{ {
if (!mBuffered) Buffer(); if (!mBuffered)
Buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
} }
@ -68,88 +66,88 @@ void CIndexBuffer::Unbind()
void CIndexBuffer::DrawElements() void CIndexBuffer::DrawElements()
{ {
Bind(); Bind();
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, (void*) 0); glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, nullptr);
Unbind(); Unbind();
} }
void CIndexBuffer::DrawElements(uint Offset, uint Size) void CIndexBuffer::DrawElements(uint offset, uint size)
{ {
Bind(); Bind();
glDrawElements(mPrimitiveType, Size, GL_UNSIGNED_SHORT, (char*)0 + (Offset * 2)); glDrawElements(mPrimitiveType, size, GL_UNSIGNED_SHORT, (char*)0 + (offset * 2));
Unbind(); Unbind();
} }
bool CIndexBuffer::IsBuffered() bool CIndexBuffer::IsBuffered() const
{ {
return mBuffered; return mBuffered;
} }
uint CIndexBuffer::GetSize() uint CIndexBuffer::GetSize() const
{ {
return mIndices.size(); return mIndices.size();
} }
GLenum CIndexBuffer::GetPrimitiveType() GLenum CIndexBuffer::GetPrimitiveType() const
{ {
return mPrimitiveType; return mPrimitiveType;
} }
void CIndexBuffer::SetPrimitiveType(GLenum Type) void CIndexBuffer::SetPrimitiveType(GLenum type)
{ {
mPrimitiveType = Type; mPrimitiveType = type;
} }
void CIndexBuffer::TrianglesToStrips(uint16 *pIndices, uint Count) void CIndexBuffer::TrianglesToStrips(uint16 *indices, size_t count)
{ {
Reserve(Count + (Count / 3)); Reserve(count + (count / 3));
for (uint iIdx = 0; iIdx < Count; iIdx += 3) for (size_t i = 0; i < count; i += 3)
{ {
mIndices.push_back(*pIndices++); mIndices.push_back(*indices++);
mIndices.push_back(*pIndices++); mIndices.push_back(*indices++);
mIndices.push_back(*pIndices++); mIndices.push_back(*indices++);
mIndices.push_back(0xFFFF); mIndices.push_back(0xFFFF);
} }
} }
void CIndexBuffer::FansToStrips(uint16 *pIndices, uint Count) void CIndexBuffer::FansToStrips(uint16 *indices, size_t count)
{ {
Reserve(Count); Reserve(count);
uint16 FirstIndex = *pIndices; const uint16 firstIndex = *indices;
for (uint iIdx = 2; iIdx < Count; iIdx += 3) for (size_t i = 2; i < count; i += 3)
{ {
mIndices.push_back(pIndices[iIdx - 1]); mIndices.push_back(indices[i - 1]);
mIndices.push_back(pIndices[iIdx]); mIndices.push_back(indices[i]);
mIndices.push_back(FirstIndex); mIndices.push_back(firstIndex);
if (iIdx + 1 < Count) if (i + 1 < count)
mIndices.push_back(pIndices[iIdx + 1]); mIndices.push_back(indices[i + 1]);
if (iIdx + 2 < Count) if (i + 2 < count)
mIndices.push_back(pIndices[iIdx + 2]); mIndices.push_back(indices[i + 2]);
mIndices.push_back(0xFFFF); mIndices.push_back(0xFFFF);
} }
} }
void CIndexBuffer::QuadsToStrips(uint16 *pIndices, uint Count) void CIndexBuffer::QuadsToStrips(uint16 *indices, size_t count)
{ {
Reserve((uint) (Count * 1.25)); Reserve(static_cast<size_t>(count * 1.25));
uint iIdx = 3; size_t i = 3;
for (; iIdx < Count; iIdx += 4) for (; i < count; i += 4)
{ {
mIndices.push_back(pIndices[iIdx - 2]); mIndices.push_back(indices[i - 2]);
mIndices.push_back(pIndices[iIdx - 1]); mIndices.push_back(indices[i - 1]);
mIndices.push_back(pIndices[iIdx - 3]); mIndices.push_back(indices[i - 3]);
mIndices.push_back(pIndices[iIdx]); mIndices.push_back(indices[i]);
mIndices.push_back(0xFFFF); mIndices.push_back(0xFFFF);
} }
// if there's three indices present that indicates a single triangle // if there's three indices present that indicates a single triangle
if (iIdx == Count) if (i == count)
{ {
mIndices.push_back(pIndices[iIdx - 3]); mIndices.push_back(indices[i - 3]);
mIndices.push_back(pIndices[iIdx - 2]); mIndices.push_back(indices[i - 2]);
mIndices.push_back(pIndices[iIdx - 1]); mIndices.push_back(indices[i - 1]);
mIndices.push_back(0xFFFF); mIndices.push_back(0xFFFF);
} }

View File

@ -7,33 +7,33 @@
class CIndexBuffer class CIndexBuffer
{ {
GLuint mIndexBuffer; GLuint mIndexBuffer = 0;
std::vector<uint16> mIndices; std::vector<uint16> mIndices;
GLenum mPrimitiveType; GLenum mPrimitiveType{};
bool mBuffered; bool mBuffered = false;
public: public:
CIndexBuffer(); CIndexBuffer();
CIndexBuffer(GLenum Type); explicit CIndexBuffer(GLenum type);
~CIndexBuffer(); ~CIndexBuffer();
void AddIndex(uint16 Index); void AddIndex(uint16 index);
void AddIndices(uint16 *pIndices, uint Count); void AddIndices(const uint16 *indices, size_t count);
void Reserve(uint Size); void Reserve(size_t size);
void Clear(); void Clear();
void Buffer(); void Buffer();
void Bind(); void Bind();
void Unbind(); void Unbind();
void DrawElements(); void DrawElements();
void DrawElements(uint Offset, uint Size); void DrawElements(uint offset, uint size);
bool IsBuffered(); bool IsBuffered() const;
uint GetSize(); uint GetSize() const;
GLenum GetPrimitiveType(); GLenum GetPrimitiveType() const;
void SetPrimitiveType(GLenum Type); void SetPrimitiveType(GLenum type);
void TrianglesToStrips(uint16 *pIndices, uint Count); void TrianglesToStrips(uint16 *indices, size_t count);
void FansToStrips(uint16 *pIndices, uint Count); void FansToStrips(uint16 *indices, size_t count);
void QuadsToStrips(uint16 *pIndices, uint Count); void QuadsToStrips(uint16 *indices, size_t count);
}; };
#endif // CINDEXBUFFER_H #endif // CINDEXBUFFER_H

View File

@ -6,25 +6,17 @@
class CRenderbuffer class CRenderbuffer
{ {
GLuint mRenderbuffer; GLuint mRenderbuffer = 0;
uint mWidth, mHeight; uint mWidth = 0;
bool mEnableMultisampling; uint mHeight = 0;
bool mInitialized; bool mEnableMultisampling = false;
bool mInitialized = false;
public: public:
CRenderbuffer() CRenderbuffer() = default;
: mWidth(0)
, mHeight(0)
, mEnableMultisampling(false)
, mInitialized(false)
{
}
CRenderbuffer(uint Width, uint Height) CRenderbuffer(uint Width, uint Height)
: mWidth(Width) : mWidth(Width)
, mHeight(Height) , mHeight(Height)
, mEnableMultisampling(false)
, mInitialized(false)
{ {
} }
@ -41,7 +33,7 @@ public:
InitStorage(); InitStorage();
} }
inline void Resize(uint Width, uint Height) void Resize(uint Width, uint Height)
{ {
mWidth = Width; mWidth = Width;
mHeight = Height; mHeight = Height;
@ -50,23 +42,23 @@ public:
InitStorage(); InitStorage();
} }
inline void Bind() void Bind()
{ {
if (!mInitialized) Init(); if (!mInitialized) Init();
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
} }
inline void Unbind() void Unbind()
{ {
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
inline GLuint BufferID() GLuint BufferID() const
{ {
return mRenderbuffer; return mRenderbuffer;
} }
inline void SetMultisamplingEnabled(bool Enable) void SetMultisamplingEnabled(bool Enable)
{ {
if (mEnableMultisampling != Enable) if (mEnableMultisampling != Enable)
{ {

View File

@ -5,28 +5,18 @@
#include <Common/TString.h> #include <Common/TString.h>
#include <fstream> #include <fstream>
#include <sstream>
bool gDebugDumpShaders = false; static bool gDebugDumpShaders = false;
uint64 gFailedCompileCount = 0; static uint64 gFailedCompileCount = 0;
uint64 gSuccessfulCompileCount = 0; static uint64 gSuccessfulCompileCount = 0;
CShader* CShader::spCurrentShader = nullptr;
int CShader::smNumShaders = 0;
CShader::CShader() CShader::CShader()
{ {
mVertexShaderExists = false;
mPixelShaderExists = false;
mProgramExists = false;
smNumShaders++; smNumShaders++;
} }
CShader::CShader(const char *pkVertexSource, const char *pkPixelSource) CShader::CShader(const char *pkVertexSource, const char *pkPixelSource)
{ {
mVertexShaderExists = false;
mPixelShaderExists = false;
mProgramExists = false;
smNumShaders++; smNumShaders++;
CompileVertexSource(pkVertexSource); CompileVertexSource(pkVertexSource);
@ -36,18 +26,25 @@ CShader::CShader(const char *pkVertexSource, const char *pkPixelSource)
CShader::~CShader() CShader::~CShader()
{ {
if (mVertexShaderExists) glDeleteShader(mVertexShader); if (mVertexShaderExists)
if (mPixelShaderExists) glDeleteShader(mPixelShader); glDeleteShader(mVertexShader);
if (mProgramExists) glDeleteProgram(mProgram);
if (mPixelShaderExists)
glDeleteShader(mPixelShader);
if (mProgramExists)
glDeleteProgram(mProgram);
if (spCurrentShader == this)
spCurrentShader = nullptr;
if (spCurrentShader == this) spCurrentShader = 0;
smNumShaders--; smNumShaders--;
} }
bool CShader::CompileVertexSource(const char* pkSource) bool CShader::CompileVertexSource(const char* pkSource)
{ {
mVertexShader = glCreateShader(GL_VERTEX_SHADER); mVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(mVertexShader, 1, (const GLchar**) &pkSource, NULL); glShaderSource(mVertexShader, 1, (const GLchar**) &pkSource, nullptr);
glCompileShader(mVertexShader); glCompileShader(mVertexShader);
// Shader should be compiled - check for errors // Shader should be compiled - check for errors
@ -82,7 +79,7 @@ bool CShader::CompileVertexSource(const char* pkSource)
bool CShader::CompilePixelSource(const char* pkSource) bool CShader::CompilePixelSource(const char* pkSource)
{ {
mPixelShader = glCreateShader(GL_FRAGMENT_SHADER); mPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(mPixelShader, 1, (const GLchar**) &pkSource, NULL); glShaderSource(mPixelShader, 1, (const GLchar**) &pkSource, nullptr);
glCompileShader(mPixelShader); glCompileShader(mPixelShader);
// Shader should be compiled - check for errors // Shader should be compiled - check for errors
@ -116,7 +113,8 @@ bool CShader::CompilePixelSource(const char* pkSource)
bool CShader::LinkShaders() bool CShader::LinkShaders()
{ {
if ((!mVertexShaderExists) || (!mPixelShaderExists)) return false; if (!mVertexShaderExists || !mPixelShaderExists)
return false;
mProgram = glCreateProgram(); mProgram = glCreateProgram();
glAttachShader(mProgram, mVertexShader); glAttachShader(mProgram, mVertexShader);
@ -139,17 +137,12 @@ bool CShader::LinkShaders()
GLint LogLen; GLint LogLen;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &LogLen); glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &LogLen);
GLchar *pInfoLog = new GLchar[LogLen]; auto pInfoLog = std::unique_ptr<GLchar[]>(new GLchar[LogLen]);
glGetProgramInfoLog(mProgram, LogLen, NULL, pInfoLog); glGetProgramInfoLog(mProgram, LogLen, nullptr, pInfoLog.get());
std::ofstream LinkOut;
LinkOut.open(*Out);
std::ofstream LinkOut(*Out);
if (LogLen > 0) if (LogLen > 0)
LinkOut << pInfoLog; LinkOut << pInfoLog.get();
LinkOut.close();
delete[] pInfoLog;
gFailedCompileCount++; gFailedCompileCount++;
glDeleteProgram(mProgram); glDeleteProgram(mProgram);
@ -167,22 +160,22 @@ bool CShader::LinkShaders()
return true; return true;
} }
bool CShader::IsValidProgram() bool CShader::IsValidProgram() const
{ {
return mProgramExists; return mProgramExists;
} }
GLuint CShader::GetProgramID() GLuint CShader::GetProgramID() const
{ {
return mProgram; return mProgram;
} }
GLuint CShader::GetUniformLocation(const char* pkUniform) GLuint CShader::GetUniformLocation(const char* pkUniform) const
{ {
return glGetUniformLocation(mProgram, pkUniform); return glGetUniformLocation(mProgram, pkUniform);
} }
GLuint CShader::GetUniformBlockIndex(const char* pkUniformBlock) GLuint CShader::GetUniformBlockIndex(const char* pkUniformBlock) const
{ {
return glGetUniformBlockIndex(mProgram, pkUniformBlock); return glGetUniformBlockIndex(mProgram, pkUniformBlock);
} }
@ -220,7 +213,7 @@ void CShader::SetCurrent()
} }
// ************ STATIC ************ // ************ STATIC ************
CShader* CShader::FromResourceFile(const TString& rkShaderName) std::unique_ptr<CShader> CShader::FromResourceFile(const TString& rkShaderName)
{ {
TString VertexShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".vs"; TString VertexShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".vs";
TString PixelShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".ps"; TString PixelShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".ps";
@ -233,7 +226,7 @@ CShader* CShader::FromResourceFile(const TString& rkShaderName)
if (VertexShaderText.IsEmpty() || PixelShaderText.IsEmpty()) if (VertexShaderText.IsEmpty() || PixelShaderText.IsEmpty())
return nullptr; return nullptr;
CShader *pShader = new CShader(); auto pShader = std::make_unique<CShader>();
pShader->CompileVertexSource(*VertexShaderText); pShader->CompileVertexSource(*VertexShaderText);
pShader->CompilePixelSource(*PixelShaderText); pShader->CompilePixelSource(*PixelShaderText);
pShader->LinkShaders(); pShader->LinkShaders();
@ -247,15 +240,15 @@ CShader* CShader::CurrentShader()
void CShader::KillCachedShader() void CShader::KillCachedShader()
{ {
spCurrentShader = 0; spCurrentShader = nullptr;
} }
// ************ PRIVATE ************ // ************ PRIVATE ************
void CShader::CacheCommonUniforms() void CShader::CacheCommonUniforms()
{ {
for (uint32 iTex = 0; iTex < 8; iTex++) for (size_t iTex = 0; iTex < 8; iTex++)
{ {
TString TexUniform = "Texture" + TString::FromInt32(iTex); const TString TexUniform = "Texture" + std::to_string(iTex);
mTextureUniforms[iTex] = glGetUniformLocation(mProgram, *TexUniform); mTextureUniforms[iTex] = glGetUniformLocation(mProgram, *TexUniform);
} }
@ -264,26 +257,20 @@ void CShader::CacheCommonUniforms()
void CShader::DumpShaderSource(GLuint Shader, const TString& rkOut) void CShader::DumpShaderSource(GLuint Shader, const TString& rkOut)
{ {
GLint SourceLen; GLint SourceLen = 0;
glGetShaderiv(Shader, GL_SHADER_SOURCE_LENGTH, &SourceLen); glGetShaderiv(Shader, GL_SHADER_SOURCE_LENGTH, &SourceLen);
GLchar *Source = new GLchar[SourceLen]; auto Source = std::unique_ptr<GLchar[]>(new GLchar[SourceLen]);
glGetShaderSource(Shader, SourceLen, NULL, Source); glGetShaderSource(Shader, SourceLen, nullptr, Source.get());
GLint LogLen; GLint LogLen = 0;
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLen); glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLen);
GLchar *pInfoLog = new GLchar[LogLen]; auto pInfoLog = std::unique_ptr<GLchar[]>(new GLchar[LogLen]);
glGetShaderInfoLog(Shader, LogLen, NULL, pInfoLog); glGetShaderInfoLog(Shader, LogLen, nullptr, pInfoLog.get());
std::ofstream ShaderOut; std::ofstream ShaderOut(*rkOut);
ShaderOut.open(*rkOut);
if (SourceLen > 0) if (SourceLen > 0)
ShaderOut << Source; ShaderOut << Source.get();
if (LogLen > 0) if (LogLen > 0)
ShaderOut << pInfoLog; ShaderOut << pInfoLog.get();
ShaderOut.close();
delete[] Source;
delete[] pInfoLog;
} }

View File

@ -3,28 +3,30 @@
#include <Common/TString.h> #include <Common/TString.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <array>
#include <memory>
class CShader class CShader
{ {
bool mVertexShaderExists; bool mVertexShaderExists = false;
bool mPixelShaderExists; bool mPixelShaderExists = false;
bool mProgramExists; bool mProgramExists = false;
GLuint mVertexShader; GLuint mVertexShader = 0;
GLuint mPixelShader; GLuint mPixelShader = 0;
GLuint mProgram; GLuint mProgram = 0;
GLuint mMVPBlockIndex; GLuint mMVPBlockIndex = 0;
GLuint mVertexBlockIndex; GLuint mVertexBlockIndex = 0;
GLuint mPixelBlockIndex; GLuint mPixelBlockIndex = 0;
GLuint mLightBlockIndex; GLuint mLightBlockIndex = 0;
GLuint mBoneTransformBlockIndex; GLuint mBoneTransformBlockIndex = 0;
// Cached uniform locations // Cached uniform locations
GLint mTextureUniforms[8]; std::array<GLint, 8> mTextureUniforms{};
GLint mNumLightsUniform; GLint mNumLightsUniform = 0;
static int smNumShaders; static inline int smNumShaders = 0;
static CShader* spCurrentShader; static inline CShader* spCurrentShader = nullptr;
public: public:
CShader(); CShader();
@ -33,21 +35,21 @@ public:
bool CompileVertexSource(const char* pkSource); bool CompileVertexSource(const char* pkSource);
bool CompilePixelSource(const char* pkSource); bool CompilePixelSource(const char* pkSource);
bool LinkShaders(); bool LinkShaders();
bool IsValidProgram(); bool IsValidProgram() const;
GLuint GetProgramID(); GLuint GetProgramID() const;
GLuint GetUniformLocation(const char* pkUniform); GLuint GetUniformLocation(const char* pkUniform) const;
GLuint GetUniformBlockIndex(const char* pkUniformBlock); GLuint GetUniformBlockIndex(const char* pkUniformBlock) const;
void UniformBlockBinding(GLuint BlockIndex, GLuint BlockBinding); void UniformBlockBinding(GLuint BlockIndex, GLuint BlockBinding);
void SetTextureUniforms(uint32 NumTextures); void SetTextureUniforms(uint32 NumTextures);
void SetNumLights(uint32 NumLights); void SetNumLights(uint32 NumLights);
void SetCurrent(); void SetCurrent();
// Static // Static
static CShader* FromResourceFile(const TString& rkShaderName); static std::unique_ptr<CShader> FromResourceFile(const TString& rkShaderName);
static CShader* CurrentShader(); static CShader* CurrentShader();
static void KillCachedShader(); static void KillCachedShader();
inline static int NumShaders() { return smNumShaders; } static int NumShaders() { return smNumShaders; }
private: private:
void CacheCommonUniforms(); void CacheCommonUniforms();

View File

@ -1,149 +1,148 @@
#include "CShaderGenerator.h" #include "CShaderGenerator.h"
#include <Common/Macros.h> #include <Common/Macros.h>
#include <iostream> #include <array>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <string_view>
#include <GL/glew.h> #include <GL/glew.h>
const TString gkCoordSrc[] = { using namespace std::string_view_literals;
"ModelSpacePos.xyz",
"ModelSpaceNormal.xyz", constexpr std::array gkCoordSrc{
"0.0, 0.0, 0.0", "ModelSpacePos.xyz"sv,
"0.0, 0.0, 0.0", "ModelSpaceNormal.xyz"sv,
"RawTex0.xy, 1.0", "0.0, 0.0, 0.0"sv,
"RawTex1.xy, 1.0", "0.0, 0.0, 0.0"sv,
"RawTex2.xy, 1.0", "RawTex0.xy, 1.0"sv,
"RawTex3.xy, 1.0", "RawTex1.xy, 1.0"sv,
"RawTex4.xy, 1.0", "RawTex2.xy, 1.0"sv,
"RawTex5.xy, 1.0", "RawTex3.xy, 1.0"sv,
"RawTex6.xy, 1.0", "RawTex4.xy, 1.0"sv,
"RawTex7.xy, 1.0" "RawTex5.xy, 1.0"sv,
"RawTex6.xy, 1.0"sv,
"RawTex7.xy, 1.0"sv,
}; };
const TString gkRasSel[] = { constexpr std::array gkRasSel{
"vec4(COLOR0A0.rgb, 1.0)", "vec4(COLOR0A0.rgb, 1.0)"sv,
"vec4(COLOR1A1.rgb, 1.0)", "vec4(COLOR1A1.rgb, 1.0)"sv,
"vec4(0.0, 0.0, 0.0, COLOR0A0.a)", "vec4(0.0, 0.0, 0.0, COLOR0A0.a)"sv,
"vec4(0.0, 0.0, 0.0, COLOR1A1.a)", "vec4(0.0, 0.0, 0.0, COLOR1A1.a)"sv,
"COLOR0A0", "COLOR0A0"sv,
"COLOR1A1", "COLOR1A1"sv,
"vec4(0.0, 0.0, 0.0, 0.0)" "vec4(0.0, 0.0, 0.0, 0.0)"sv,
}; };
const TString gkKonstColor[] = { constexpr std::array gkKonstColor{
"1.0, 1.0, 1.0", "1.0, 1.0, 1.0"sv,
"0.875, 0.875, 0.875", "0.875, 0.875, 0.875"sv,
"0.75, 0.75, 0.75", "0.75, 0.75, 0.75"sv,
"0.625, 0.625, 0.625", "0.625, 0.625, 0.625"sv,
"0.5, 0.5, 0.5", "0.5, 0.5, 0.5"sv,
"0.375, 0.375, 0.375", "0.375, 0.375, 0.375"sv,
"0.25, 0.25, 0.25", "0.25, 0.25, 0.25"sv,
"0.125, 0.125, 0.125", "0.125, 0.125, 0.125"sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"KonstColors[0].rgb", "KonstColors[0].rgb"sv,
"KonstColors[1].rgb", "KonstColors[1].rgb"sv,
"KonstColors[2].rgb", "KonstColors[2].rgb"sv,
"KonstColors[3].rgb", "KonstColors[3].rgb"sv,
"KonstColors[0].rrr", "KonstColors[0].rrr"sv,
"KonstColors[1].rrr", "KonstColors[1].rrr"sv,
"KonstColors[2].rrr", "KonstColors[2].rrr"sv,
"KonstColors[3].rrr", "KonstColors[3].rrr"sv,
"KonstColors[0].ggg", "KonstColors[0].ggg"sv,
"KonstColors[1].ggg", "KonstColors[1].ggg"sv,
"KonstColors[2].ggg", "KonstColors[2].ggg"sv,
"KonstColors[3].ggg", "KonstColors[3].ggg"sv,
"KonstColors[0].bbb", "KonstColors[0].bbb"sv,
"KonstColors[1].bbb", "KonstColors[1].bbb"sv,
"KonstColors[2].bbb", "KonstColors[2].bbb"sv,
"KonstColors[3].bbb", "KonstColors[3].bbb"sv,
"KonstColors[0].aaa", "KonstColors[0].aaa"sv,
"KonstColors[1].aaa", "KonstColors[1].aaa"sv,
"KonstColors[2].aaa", "KonstColors[2].aaa"sv,
"KonstColors[3].aaa" "KonstColors[3].aaa"sv,
}; };
const TString gkKonstAlpha[] = { constexpr std::array gkKonstAlpha{
"1.0", "1.0"sv,
"0.875", "0.875"sv,
"0.75", "0.75"sv,
"0.625", "0.625"sv,
"0.5", "0.5"sv,
"0.375", "0.375"sv,
"0.25", "0.25"sv,
"0.125", "0.125"sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"", ""sv,
"KonstColors[0].r", "KonstColors[0].r"sv,
"KonstColors[1].r", "KonstColors[1].r"sv,
"KonstColors[2].r", "KonstColors[2].r"sv,
"KonstColors[3].r", "KonstColors[3].r"sv,
"KonstColors[0].g", "KonstColors[0].g"sv,
"KonstColors[1].g", "KonstColors[1].g"sv,
"KonstColors[2].g", "KonstColors[2].g"sv,
"KonstColors[3].g", "KonstColors[3].g"sv,
"KonstColors[0].b", "KonstColors[0].b"sv,
"KonstColors[1].b", "KonstColors[1].b"sv,
"KonstColors[2].b", "KonstColors[2].b"sv,
"KonstColors[3].b", "KonstColors[3].b"sv,
"KonstColors[0].a", "KonstColors[0].a"sv,
"KonstColors[1].a", "KonstColors[1].a"sv,
"KonstColors[2].a", "KonstColors[2].a"sv,
"KonstColors[3].a" "KonstColors[3].a"sv,
}; };
const TString gkTevColor[] = { constexpr std::array gkTevColor{
"Prev.rgb", "Prev.rgb"sv,
"Prev.aaa", "Prev.aaa"sv,
"C0.rgb", "C0.rgb"sv,
"C0.aaa", "C0.aaa"sv,
"C1.rgb", "C1.rgb"sv,
"C1.aaa", "C1.aaa"sv,
"C2.rgb", "C2.rgb"sv,
"C2.aaa", "C2.aaa"sv,
"Tex.rgb", "Tex.rgb"sv,
"Tex.aaa", "Tex.aaa"sv,
"Ras.rgb", "Ras.rgb"sv,
"Ras.aaa", "Ras.aaa"sv,
"1.0, 1.0, 1.0", "1.0, 1.0, 1.0"sv,
"0.5, 0.5, 0.5", "0.5, 0.5, 0.5"sv,
"Konst.rgb", "Konst.rgb"sv,
"0.0, 0.0, 0.0" "0.0, 0.0, 0.0"sv,
}; };
const TString gkTevAlpha[] = { constexpr std::array gkTevAlpha{
"Prev.a", "Prev.a"sv,
"C0.a", "C0.a"sv,
"C1.a", "C1.a"sv,
"C2.a", "C2.a"sv,
"Tex.a", "Tex.a"sv,
"Ras.a", "Ras.a"sv,
"Konst.a", "Konst.a"sv,
"0.0" "0.0"sv,
}; };
const TString gkTevRigid[] = { constexpr std::array gkTevRigid{
"Prev", "Prev"sv,
"C0", "C0"sv,
"C1", "C1"sv,
"C2" "C2"sv,
}; };
CShaderGenerator::CShaderGenerator() CShaderGenerator::CShaderGenerator() = default;
{
}
CShaderGenerator::~CShaderGenerator() CShaderGenerator::~CShaderGenerator() = default;
{
}
bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat) bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
{ {
@ -366,34 +365,34 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
return mpShader->CompileVertexSource(ShaderCode.str().c_str()); return mpShader->CompileVertexSource(ShaderCode.str().c_str());
} }
static TString GetColorInputExpression(const CMaterialPass* pPass, ETevColorInput iInput) static std::string GetColorInputExpression(const CMaterialPass* pPass, ETevColorInput iInput)
{ {
if (iInput == ETevColorInput::kTextureRGB) if (iInput == ETevColorInput::kTextureRGB)
{ {
TString Ret("Tex."); std::string Ret("Tex.");
for (uint32 i = 0; i < 3; ++i) for (uint32 i = 0; i < 3; ++i)
Ret += pPass->TexSwapComp(i); Ret += pPass->TexSwapComp(i);
return Ret; return Ret;
} }
else if (iInput == ETevColorInput::kTextureAAA) else if (iInput == ETevColorInput::kTextureAAA)
{ {
TString Ret("Tex."); std::string Ret("Tex.");
for (uint32 i = 0; i < 3; ++i) for (uint32 i = 0; i < 3; ++i)
Ret += pPass->TexSwapComp(3); Ret += pPass->TexSwapComp(3);
return Ret; return Ret;
} }
return gkTevColor[iInput]; return std::string(gkTevColor[iInput]);
} }
static TString GetAlphaInputExpression(const CMaterialPass* pPass, ETevAlphaInput iInput) static std::string GetAlphaInputExpression(const CMaterialPass* pPass, ETevAlphaInput iInput)
{ {
if (iInput == ETevAlphaInput::kTextureAlpha) if (iInput == ETevAlphaInput::kTextureAlpha)
{ {
TString Ret("Tex."); std::string Ret("Tex.");
Ret += pPass->TexSwapComp(3); Ret += pPass->TexSwapComp(3);
return Ret; return Ret;
} }
return gkTevAlpha[iInput]; return std::string(gkTevAlpha[iInput]);
} }
bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat) bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)

View File

@ -22,7 +22,7 @@
*/ */
class CShaderGenerator class CShaderGenerator
{ {
CShader *mpShader; CShader *mpShader = nullptr;
CShaderGenerator(); CShaderGenerator();
~CShaderGenerator(); ~CShaderGenerator();

View File

@ -7,7 +7,7 @@
class CUniformBuffer class CUniformBuffer
{ {
GLuint mUniformBuffer; GLuint mUniformBuffer;
uint mBufferSize; uint32 mBufferSize;
public: public:
@ -17,7 +17,7 @@ public:
SetBufferSize(0); SetBufferSize(0);
} }
CUniformBuffer(uint Size) explicit CUniformBuffer(uint32 Size)
{ {
glGenBuffers(1, &mUniformBuffer); glGenBuffers(1, &mUniformBuffer);
SetBufferSize(Size); SetBufferSize(Size);
@ -52,20 +52,20 @@ public:
Unbind(); Unbind();
} }
void BufferRange(const void *pkData, uint Offset, uint Size) void BufferRange(const void *pkData, uint32 Offset, uint32 Size)
{ {
Bind(); Bind();
glBufferSubData(GL_UNIFORM_BUFFER, Offset, Size, pkData); glBufferSubData(GL_UNIFORM_BUFFER, Offset, Size, pkData);
Unbind(); Unbind();
} }
void SetBufferSize(uint Size) void SetBufferSize(uint32 Size)
{ {
mBufferSize = Size; mBufferSize = Size;
InitializeBuffer(); InitializeBuffer();
} }
uint GetBufferSize() uint32 GetBufferSize() const
{ {
return mBufferSize; return mBufferSize;
} }
@ -74,7 +74,7 @@ private:
void InitializeBuffer() void InitializeBuffer()
{ {
Bind(); Bind();
glBufferData(GL_UNIFORM_BUFFER, mBufferSize, 0, GL_DYNAMIC_DRAW); glBufferData(GL_UNIFORM_BUFFER, mBufferSize, nullptr, GL_DYNAMIC_DRAW);
Unbind(); Unbind();
} }
}; };

View File

@ -22,8 +22,10 @@ CVertexArrayManager::~CVertexArrayManager()
sVAManagers.erase(sVAManagers.begin() + mVectorIndex); sVAManagers.erase(sVAManagers.begin() + mVectorIndex);
if (sVAManagers.size() > mVectorIndex) if (sVAManagers.size() > mVectorIndex)
{
for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++) for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++)
(*it)->mVectorIndex--; (*it)->mVectorIndex--;
}
} }
// ************ PUBLIC ************ // ************ PUBLIC ************
@ -34,15 +36,16 @@ void CVertexArrayManager::SetCurrent()
void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO) void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
{ {
auto it = mVBOMap.find(pVBO); const auto it = mVBOMap.find(pVBO);
if (it != mVBOMap.end()) if (it != mVBOMap.cend())
{
glBindVertexArray(it->second); glBindVertexArray(it->second);
}
else else
{ {
GLuint VAO = pVBO->CreateVAO(); const GLuint VAO = pVBO->CreateVAO();
mVBOMap[pVBO] = VAO; mVBOMap.insert_or_assign(pVBO, VAO);
glBindVertexArray(VAO); glBindVertexArray(VAO);
} }
} }
@ -50,40 +53,41 @@ void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
void CVertexArrayManager::BindVAO(CDynamicVertexBuffer *pVBO) void CVertexArrayManager::BindVAO(CDynamicVertexBuffer *pVBO)
{ {
// Overload for CDynamicVertexBuffer // Overload for CDynamicVertexBuffer
auto it = mDynamicVBOMap.find(pVBO); const auto it = mDynamicVBOMap.find(pVBO);
if (it != mDynamicVBOMap.end()) if (it != mDynamicVBOMap.cend())
{
glBindVertexArray(it->second); glBindVertexArray(it->second);
}
else else
{ {
GLuint VAO = pVBO->CreateVAO(); const GLuint VAO = pVBO->CreateVAO();
mDynamicVBOMap[pVBO] = VAO; mDynamicVBOMap.insert_or_assign(pVBO, VAO);
glBindVertexArray(VAO); glBindVertexArray(VAO);
} }
} }
void CVertexArrayManager::DeleteVAO(CVertexBuffer *pVBO) void CVertexArrayManager::DeleteVAO(CVertexBuffer *pVBO)
{ {
auto it = mVBOMap.find(pVBO); const auto it = mVBOMap.find(pVBO);
if (it != mVBOMap.end()) if (it == mVBOMap.cend())
{ return;
glDeleteVertexArrays(1, &it->second);
mVBOMap.erase(it); glDeleteVertexArrays(1, &it->second);
} mVBOMap.erase(it);
} }
void CVertexArrayManager::DeleteVAO(CDynamicVertexBuffer *pVBO) void CVertexArrayManager::DeleteVAO(CDynamicVertexBuffer *pVBO)
{ {
// Overload for CDynamicVertexBuffer // Overload for CDynamicVertexBuffer
auto it = mDynamicVBOMap.find(pVBO); const auto it = mDynamicVBOMap.find(pVBO);
if (it != mDynamicVBOMap.end()) if (it == mDynamicVBOMap.cend())
{ return;
glDeleteVertexArrays(1, &it->second);
mDynamicVBOMap.erase(it); glDeleteVertexArrays(1, &it->second);
} mDynamicVBOMap.erase(it);
} }
// ************ STATIC ************ // ************ STATIC ************
@ -94,12 +98,12 @@ CVertexArrayManager* CVertexArrayManager::Current()
void CVertexArrayManager::DeleteAllArraysForVBO(CVertexBuffer *pVBO) void CVertexArrayManager::DeleteAllArraysForVBO(CVertexBuffer *pVBO)
{ {
for (uint32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++) for (auto* vam : sVAManagers)
sVAManagers[iVAM]->DeleteVAO(pVBO); vam->DeleteVAO(pVBO);
} }
void CVertexArrayManager::DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO) void CVertexArrayManager::DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO)
{ {
for (uint32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++) for (auto* vam : sVAManagers)
sVAManagers[iVAM]->DeleteVAO(pVBO); vam->DeleteVAO(pVBO);
} }

View File

@ -12,7 +12,7 @@ class CVertexArrayManager
{ {
std::unordered_map<CVertexBuffer*, GLuint> mVBOMap; std::unordered_map<CVertexBuffer*, GLuint> mVBOMap;
std::unordered_map<CDynamicVertexBuffer*, GLuint> mDynamicVBOMap; std::unordered_map<CDynamicVertexBuffer*, GLuint> mDynamicVBOMap;
uint32 mVectorIndex; uint32 mVectorIndex = 0;
static std::vector<CVertexArrayManager*> sVAManagers; static std::vector<CVertexArrayManager*> sVAManagers;
static CVertexArrayManager *spCurrentManager; static CVertexArrayManager *spCurrentManager;

View File

@ -3,7 +3,6 @@
CVertexBuffer::CVertexBuffer() CVertexBuffer::CVertexBuffer()
{ {
mBuffered = false;
SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal | SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal |
EVertexAttribute::Tex0 | EVertexAttribute::Tex1 | EVertexAttribute::Tex0 | EVertexAttribute::Tex1 |
EVertexAttribute::Tex2 | EVertexAttribute::Tex3 | EVertexAttribute::Tex2 | EVertexAttribute::Tex3 |
@ -22,72 +21,103 @@ CVertexBuffer::~CVertexBuffer()
CVertexArrayManager::DeleteAllArraysForVBO(this); CVertexArrayManager::DeleteAllArraysForVBO(this);
if (mBuffered) if (mBuffered)
glDeleteBuffers(14, mAttribBuffers); glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
} }
uint16 CVertexBuffer::AddVertex(const CVertex& rkVtx) uint16 CVertexBuffer::AddVertex(const CVertex& rkVtx)
{ {
if (mPositions.size() == 0xFFFF) throw std::overflow_error("VBO contains too many vertices"); if (mPositions.size() == 0xFFFF)
throw std::overflow_error("VBO contains too many vertices");
if (mVtxDesc & EVertexAttribute::Position) mPositions.push_back(rkVtx.Position); if ((mVtxDesc & EVertexAttribute::Position) != 0)
if (mVtxDesc & EVertexAttribute::Normal) mNormals.push_back(rkVtx.Normal); mPositions.emplace_back(rkVtx.Position);
if (mVtxDesc & EVertexAttribute::Color0) mColors[0].push_back(rkVtx.Color[0]); if ((mVtxDesc & EVertexAttribute::Normal) != 0)
if (mVtxDesc & EVertexAttribute::Color1) mColors[1].push_back(rkVtx.Color[1]); mNormals.emplace_back(rkVtx.Normal);
if ((mVtxDesc & EVertexAttribute::Color0) != 0)
mColors[0].emplace_back(rkVtx.Color[0]);
if ((mVtxDesc & EVertexAttribute::Color1) != 0)
mColors[1].emplace_back(rkVtx.Color[1]);
for (uint32 iTex = 0; iTex < 8; iTex++) for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
if (mVtxDesc & (EVertexAttribute::Tex0 << iTex)) mTexCoords[iTex].push_back(rkVtx.Tex[iTex]);
for (uint32 iMtx = 0; iMtx < 8; iMtx++)
if (mVtxDesc & (EVertexAttribute::PosMtx << iMtx)) mTexCoords[iMtx].push_back(rkVtx.MatrixIndices[iMtx]);
if (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights) && mpSkin)
{ {
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition); if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
if (mVtxDesc & EVertexAttribute::BoneIndices) mBoneIndices.push_back(rkWeights.Indices); mTexCoords[iTex].emplace_back(rkVtx.Tex[iTex]);
if (mVtxDesc & EVertexAttribute::BoneWeights) mBoneWeights.push_back(rkWeights.Weights);
} }
return (mPositions.size() - 1); for (size_t iMtx = 0; iMtx < mTexCoords.size(); iMtx++)
{
if ((mVtxDesc & (EVertexAttribute::PosMtx << iMtx)) != 0)
mTexCoords[iMtx].emplace_back(rkVtx.MatrixIndices[iMtx]);
}
if (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights) && mpSkin != nullptr)
{
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
if ((mVtxDesc & EVertexAttribute::BoneIndices) != 0)
mBoneIndices.emplace_back(rkWeights.Indices);
if ((mVtxDesc & EVertexAttribute::BoneWeights) != 0)
mBoneWeights.emplace_back(rkWeights.Weights);
}
return mPositions.size() - 1;
} }
uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start) uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start)
{ {
if (Start < mPositions.size()) if (Start < mPositions.size())
{ {
for (uint16 iVert = Start; iVert < mPositions.size(); iVert++) for (size_t iVert = Start; iVert < mPositions.size(); iVert++)
{ {
// I use a bool because "continue" doesn't work properly within the iTex loop // I use a bool because "continue" doesn't work properly within the iTex loop
bool Unique = false; bool Unique = false;
if (mVtxDesc & EVertexAttribute::Position) if ((mVtxDesc & EVertexAttribute::Position) != 0)
if (rkVtx.Position != mPositions[iVert]) Unique = true; {
if (rkVtx.Position != mPositions[iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Normal)) if (!Unique && (mVtxDesc & EVertexAttribute::Normal) != 0)
if (rkVtx.Normal != mNormals[iVert]) Unique = true; {
if (rkVtx.Normal != mNormals[iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Color0)) if (!Unique && (mVtxDesc & EVertexAttribute::Color0) != 0)
if (rkVtx.Color[0] != mColors[0][iVert]) Unique = true; {
if (rkVtx.Color[0] != mColors[0][iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Color1)) if (!Unique && (mVtxDesc & EVertexAttribute::Color1) != 0)
if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true; {
if (rkVtx.Color[1] != mColors[1][iVert])
Unique = true;
}
if (!Unique) if (!Unique)
for (uint32 iTex = 0; iTex < 8; iTex++) {
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex))) for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
{
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
{
if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert]) if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert])
{ {
Unique = true; Unique = true;
break; break;
} }
}
}
}
if (!Unique && mpSkin && (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights))) if (!Unique && mpSkin != nullptr && (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights)))
{ {
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition); const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
for (uint32 iWgt = 0; iWgt < 4; iWgt++) for (uint32 iWgt = 0; iWgt < 4; iWgt++)
{ {
if ( ((mVtxDesc & EVertexAttribute::BoneIndices) && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) || if (((mVtxDesc & EVertexAttribute::BoneIndices) != 0 && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
((mVtxDesc & EVertexAttribute::BoneWeights) && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])) ) ((mVtxDesc & EVertexAttribute::BoneWeights) != 0 && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])))
{ {
Unique = true; Unique = true;
break; break;
@ -95,44 +125,47 @@ uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start)
} }
} }
if (!Unique) return iVert; if (!Unique)
return static_cast<uint16>(iVert);
} }
} }
return AddVertex(rkVtx); return AddVertex(rkVtx);
} }
void CVertexBuffer::Reserve(uint16 Size) void CVertexBuffer::Reserve(size_t Size)
{ {
uint32 ReserveSize = mPositions.size() + Size; const size_t ReserveSize = mPositions.size() + Size;
if (mVtxDesc & EVertexAttribute::Position) if ((mVtxDesc & EVertexAttribute::Position) != 0)
mPositions.reserve(ReserveSize); mPositions.reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::Normal) if ((mVtxDesc & EVertexAttribute::Normal) != 0)
mNormals.reserve(ReserveSize); mNormals.reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::Color0) if ((mVtxDesc & EVertexAttribute::Color0) != 0)
mColors[0].reserve(ReserveSize); mColors[0].reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::Color1) if ((mVtxDesc & EVertexAttribute::Color1) != 0)
mColors[1].reserve(ReserveSize); mColors[1].reserve(ReserveSize);
for (uint32 iTex = 0; iTex < 8; iTex++) for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
if (mVtxDesc & (EVertexAttribute::Tex0 << iTex)) {
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
mTexCoords[iTex].reserve(ReserveSize); mTexCoords[iTex].reserve(ReserveSize);
}
if (mVtxDesc & EVertexAttribute::BoneIndices) if ((mVtxDesc & EVertexAttribute::BoneIndices) != 0)
mBoneIndices.reserve(ReserveSize); mBoneIndices.reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::BoneWeights) if ((mVtxDesc & EVertexAttribute::BoneWeights) != 0)
mBoneWeights.reserve(ReserveSize); mBoneWeights.reserve(ReserveSize);
} }
void CVertexBuffer::Clear() void CVertexBuffer::Clear()
{ {
if (mBuffered) if (mBuffered)
glDeleteBuffers(14, mAttribBuffers); glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
mBuffered = false; mBuffered = false;
mPositions.clear(); mPositions.clear();
@ -140,8 +173,8 @@ void CVertexBuffer::Clear()
mColors[0].clear(); mColors[0].clear();
mColors[1].clear(); mColors[1].clear();
for (uint32 iTex = 0; iTex < 8; iTex++) for (auto& coord : mTexCoords)
mTexCoords[iTex].clear(); coord.clear();
mBoneIndices.clear(); mBoneIndices.clear();
mBoneWeights.clear(); mBoneWeights.clear();
@ -152,49 +185,46 @@ void CVertexBuffer::Buffer()
// Make sure we don't end up with two buffers for the same data... // Make sure we don't end up with two buffers for the same data...
if (mBuffered) if (mBuffered)
{ {
glDeleteBuffers(14, mAttribBuffers); glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
mBuffered = false; mBuffered = false;
} }
// Generate buffers // Generate buffers
glGenBuffers(14, mAttribBuffers); glGenBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
for (uint32 iAttrib = 0; iAttrib < 14; iAttrib++) for (size_t iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{ {
int Attrib = (EVertexAttribute::Position << iAttrib); const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
bool HasAttrib = ((mVtxDesc & Attrib) != 0); const bool HasAttrib = (mVtxDesc & Attrib) != 0;
if (!HasAttrib) continue; if (!HasAttrib)
continue;
if (iAttrib < 2) if (iAttrib < 2)
{ {
std::vector<CVector3f> *pBuffer = (iAttrib == 0) ? &mPositions : &mNormals; const std::vector<CVector3f>& pBuffer = iAttrib == 0 ? mPositions : mNormals;
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, pBuffer->size() * sizeof(CVector3f), pBuffer->data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, pBuffer.size() * sizeof(CVector3f), pBuffer.data(), GL_STATIC_DRAW);
} }
else if (iAttrib < 4) else if (iAttrib < 4)
{ {
uint8 Index = (uint8) (iAttrib - 2); const auto Index = static_cast<uint8>(iAttrib - 2);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW);
} }
else if (iAttrib < 12) else if (iAttrib < 12)
{ {
uint8 Index = (uint8) (iAttrib - 4); const auto Index = static_cast<uint8>(iAttrib - 4);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW);
} }
else if (iAttrib == 12) else if (iAttrib == 12)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW);
} }
else if (iAttrib == 13) else if (iAttrib == 13)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
@ -207,7 +237,9 @@ void CVertexBuffer::Buffer()
void CVertexBuffer::Bind() void CVertexBuffer::Bind()
{ {
if (!mBuffered) Buffer(); if (!mBuffered)
Buffer();
CVertexArrayManager::Current()->BindVAO(this); CVertexArrayManager::Current()->BindVAO(this);
} }
@ -216,12 +248,12 @@ void CVertexBuffer::Unbind()
glBindVertexArray(0); glBindVertexArray(0);
} }
bool CVertexBuffer::IsBuffered() bool CVertexBuffer::IsBuffered() const
{ {
return mBuffered; return mBuffered;
} }
FVertexDescription CVertexBuffer::VertexDesc() FVertexDescription CVertexBuffer::VertexDesc() const
{ {
return mVtxDesc; return mVtxDesc;
} }
@ -238,7 +270,7 @@ void CVertexBuffer::SetSkin(CSkin *pSkin)
mpSkin = pSkin; mpSkin = pSkin;
} }
uint32 CVertexBuffer::Size() size_t CVertexBuffer::Size() const
{ {
return mPositions.size(); return mPositions.size();
} }
@ -249,44 +281,40 @@ GLuint CVertexBuffer::CreateVAO()
glGenVertexArrays(1, &VertexArray); glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray); glBindVertexArray(VertexArray);
for (uint32 iAttrib = 0; iAttrib < 14; iAttrib++) for (size_t iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{ {
int Attrib = (EVertexAttribute::Position << iAttrib); const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
bool HasAttrib = ((mVtxDesc & Attrib) != 0); const bool HasAttrib = (mVtxDesc & Attrib) != 0;
if (!HasAttrib) continue; if (!HasAttrib) continue;
if (iAttrib < 2) if (iAttrib < 2)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), (void*) 0); glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else if (iAttrib < 4) else if (iAttrib < 4)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), (void*) 0); glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else if (iAttrib < 12) else if (iAttrib < 12)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0); glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else if (iAttrib == 12) else if (iAttrib == 12)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribIPointer(iAttrib, 1, GL_UNSIGNED_INT, sizeof(TBoneIndices), (void*) 0); glVertexAttribIPointer(iAttrib, 1, GL_UNSIGNED_INT, sizeof(TBoneIndices), nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else if (iAttrib == 13) else if (iAttrib == 13)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(TBoneWeights), (void*) 0); glVertexAttribPointer(iAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(TBoneWeights), nullptr);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
} }

View File

@ -5,38 +5,39 @@
#include "Core/Resource/Animation/CSkin.h" #include "Core/Resource/Animation/CSkin.h"
#include "Core/Resource/Model/CVertex.h" #include "Core/Resource/Model/CVertex.h"
#include "Core/Resource/Model/EVertexAttribute.h" #include "Core/Resource/Model/EVertexAttribute.h"
#include <array>
#include <vector> #include <vector>
#include <GL/glew.h> #include <GL/glew.h>
class CVertexBuffer class CVertexBuffer
{ {
FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
GLuint mAttribBuffers[14]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently. std::array<GLuint, 14> mAttribBuffers{}; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models; TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models;
std::vector<CVector3f> mPositions; // Vector of vertex positions std::vector<CVector3f> mPositions; // Vector of vertex positions
std::vector<CVector3f> mNormals; // Vector of vertex normals std::vector<CVector3f> mNormals; // Vector of vertex normals
std::vector<CColor> mColors[2]; // Vectors of vertex colors std::array<std::vector<CColor>, 2> mColors; // Vectors of vertex colors
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates std::array<std::vector<CVector2f>, 8> mTexCoords; // Vectors of texture coordinates
std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices
std::vector<TBoneWeights> mBoneWeights; // Vectors of bone weights std::vector<TBoneWeights> mBoneWeights; // Vectors of bone weights
bool mBuffered; // Bool value that indicates whether the attributes have been buffered. bool mBuffered = false; // Bool value that indicates whether the attributes have been buffered.
public: public:
CVertexBuffer(); CVertexBuffer();
CVertexBuffer(FVertexDescription Desc); explicit CVertexBuffer(FVertexDescription Desc);
~CVertexBuffer(); ~CVertexBuffer();
uint16 AddVertex(const CVertex& rkVtx); uint16 AddVertex(const CVertex& rkVtx);
uint16 AddIfUnique(const CVertex& rkVtx, uint16 Start); uint16 AddIfUnique(const CVertex& rkVtx, uint16 Start);
void Reserve(uint16 Size); void Reserve(size_t Size);
void Clear(); void Clear();
void Buffer(); void Buffer();
void Bind(); void Bind();
void Unbind(); void Unbind();
bool IsBuffered(); bool IsBuffered() const;
FVertexDescription VertexDesc(); FVertexDescription VertexDesc() const;
void SetVertexDesc(FVertexDescription Desc); void SetVertexDesc(FVertexDescription Desc);
void SetSkin(CSkin *pSkin); void SetSkin(CSkin *pSkin);
uint32 Size(); size_t Size() const;
GLuint CreateVAO(); GLuint CreateVAO();
}; };

View File

@ -1,7 +1,7 @@
#include "GLCommon.h" #include "GLCommon.h"
#include <Common/Macros.h> #include <Common/Macros.h>
GLenum gBlendFactor[] = const std::array<GLenum, 8> gBlendFactor
{ {
GL_ZERO, // GX_BL_ZERO GL_ZERO, // GX_BL_ZERO
GL_ONE, // GX_BL_ONE GL_ONE, // GX_BL_ONE
@ -14,7 +14,7 @@ GLenum gBlendFactor[] =
}; };
GLenum gZMode[] = const std::array<GLenum, 7> gZMode
{ {
GL_NEVER, // GX_NEVER GL_NEVER, // GX_NEVER
GL_LESS, // GX_LESS GL_LESS, // GX_LESS

View File

@ -3,6 +3,7 @@
#include <Common/BasicTypes.h> #include <Common/BasicTypes.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <array>
enum class EBlendFactor enum class EBlendFactor
{ {
@ -29,8 +30,8 @@ enum class EPrimitiveType
Points = 0xB8 Points = 0xB8
}; };
extern GLenum gBlendFactor[]; extern const std::array<GLenum, 8> gBlendFactor;
extern GLenum gZMode[]; extern const std::array<GLenum, 7> gZMode;
GLenum GXPrimToGLPrim(EPrimitiveType Type); GLenum GXPrimToGLPrim(EPrimitiveType Type);
#endif // GLCOMMON_H #endif // GLCOMMON_H

View File

@ -11,16 +11,16 @@ class CBoneTransformData
std::vector<CTransform4f> mBoneMatrices; std::vector<CTransform4f> mBoneMatrices;
public: public:
CBoneTransformData() { } CBoneTransformData() = default;
CBoneTransformData(CSkeleton *pSkel) { ResizeToSkeleton(pSkel); } explicit CBoneTransformData(CSkeleton *pSkel) { ResizeToSkeleton(pSkel); }
inline void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); } void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); }
inline CTransform4f& BoneMatrix(uint32 BoneID) { return mBoneMatrices[BoneID]; } CTransform4f& BoneMatrix(size_t BoneID) { return mBoneMatrices[BoneID]; }
inline const CTransform4f& BoneMatrix(uint32 BoneID) const { return mBoneMatrices[BoneID]; } const CTransform4f& BoneMatrix(size_t BoneID) const { return mBoneMatrices[BoneID]; }
inline const void* Data() const { return mBoneMatrices.data(); } const void* Data() const { return mBoneMatrices.data(); }
inline uint32 DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); } size_t DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); }
inline uint32 NumTrackedBones() const { return mBoneMatrices.size(); } size_t NumTrackedBones() const { return mBoneMatrices.size(); }
inline CTransform4f& operator[](uint32 BoneIndex) { return BoneMatrix(BoneIndex); } CTransform4f& operator[](size_t BoneIndex) { return BoneMatrix(BoneIndex); }
inline const CTransform4f& operator[](uint32 BoneIndex) const { return BoneMatrix(BoneIndex); } const CTransform4f& operator[](size_t BoneIndex) const { return BoneMatrix(BoneIndex); }
}; };
#endif // CBONETRANSFORMDATA #endif // CBONETRANSFORMDATA

View File

@ -4,17 +4,7 @@
#include <Common/Math/MathUtil.h> #include <Common/Math/MathUtil.h>
CCamera::CCamera() CCamera::CCamera()
: mMode(ECameraMoveMode::Free) : mYaw(-Math::skHalfPi)
, mPosition(0)
, mAspectRatio(1.7777777f)
, mYaw(-Math::skHalfPi)
, mPitch(0.f)
, mMoveSpeed(1.f)
, mLookSpeed(1.f)
, mTransformDirty(true)
, mViewDirty(true)
, mProjectionDirty(true)
, mFrustumPlanesDirty(true)
{ {
ResetOrbit(); ResetOrbit();
} }
@ -22,12 +12,8 @@ CCamera::CCamera()
// todo: make it actually look at the target! // todo: make it actually look at the target!
// don't actually use this constructor, it's unfinished and won't work properly // don't actually use this constructor, it's unfinished and won't work properly
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/) CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
: mMode(ECameraMoveMode::Free) : mPosition(Position)
, mMoveSpeed(1.f)
, mLookSpeed(1.f)
, mPosition(Position)
, mYaw(-Math::skHalfPi) , mYaw(-Math::skHalfPi)
, mPitch(0.f)
{ {
} }

View File

@ -26,28 +26,28 @@ enum class ECameraMoveMode
* const function). */ * const function). */
class CCamera class CCamera
{ {
ECameraMoveMode mMode; ECameraMoveMode mMode{ECameraMoveMode::Free};
mutable CVector3f mPosition; mutable CVector3f mPosition;
mutable CVector3f mDirection; mutable CVector3f mDirection;
mutable CVector3f mRightVector; mutable CVector3f mRightVector;
mutable CVector3f mUpVector; mutable CVector3f mUpVector;
float mAspectRatio; float mAspectRatio = 1.7777777f;
float mYaw; float mYaw;
float mPitch; float mPitch = 0.0f;
CVector3f mOrbitTarget; CVector3f mOrbitTarget;
mutable float mOrbitDistance; mutable float mOrbitDistance = 0.0f;
float mMoveSpeed; float mMoveSpeed = 1.0f;
float mLookSpeed; float mLookSpeed = 1.0f;
mutable CMatrix4f mViewMatrix; mutable CMatrix4f mViewMatrix;
mutable CMatrix4f mProjectionMatrix; mutable CMatrix4f mProjectionMatrix;
mutable CFrustumPlanes mFrustumPlanes; mutable CFrustumPlanes mFrustumPlanes;
mutable bool mTransformDirty; mutable bool mTransformDirty = true;
mutable bool mViewDirty; mutable bool mViewDirty = true;
mutable bool mProjectionDirty; mutable bool mProjectionDirty = true;
mutable bool mFrustumPlanesDirty; mutable bool mFrustumPlanesDirty = true;
public: public:
CCamera(); CCamera();
@ -70,25 +70,25 @@ public:
void SetOrbitDistance(float Distance); void SetOrbitDistance(float Distance);
// Inline Accessors // Inline Accessors
inline CVector3f Position() const { UpdateTransform(); return mPosition; } CVector3f Position() const { UpdateTransform(); return mPosition; }
inline CVector3f Direction() const { UpdateTransform(); return mDirection; } CVector3f Direction() const { UpdateTransform(); return mDirection; }
inline CVector3f UpVector() const { UpdateTransform(); return mUpVector; } CVector3f UpVector() const { UpdateTransform(); return mUpVector; }
inline CVector3f RightVector() const { UpdateTransform(); return mRightVector; } CVector3f RightVector() const { UpdateTransform(); return mRightVector; }
inline float Yaw() const { return mYaw; } float Yaw() const { return mYaw; }
inline float Pitch() const { return mPitch; } float Pitch() const { return mPitch; }
inline float FieldOfView() const { return 55.f; } float FieldOfView() const { return 55.f; }
inline ECameraMoveMode MoveMode() const { return mMode; } ECameraMoveMode MoveMode() const { return mMode; }
inline const CMatrix4f& ViewMatrix() const { UpdateView(); return mViewMatrix; } const CMatrix4f& ViewMatrix() const { UpdateView(); return mViewMatrix; }
inline const CMatrix4f& ProjectionMatrix() const { UpdateProjection(); return mProjectionMatrix; } const CMatrix4f& ProjectionMatrix() const { UpdateProjection(); return mProjectionMatrix; }
inline const CFrustumPlanes& FrustumPlanes() const { UpdateFrustum(); return mFrustumPlanes; } const CFrustumPlanes& FrustumPlanes() const { UpdateFrustum(); return mFrustumPlanes; }
inline void SetYaw(float Yaw) { mYaw = Yaw; mTransformDirty = true; } void SetYaw(float Yaw) { mYaw = Yaw; mTransformDirty = true; }
inline void SetPitch(float Pitch) { mPitch = Pitch; ValidatePitch(); mTransformDirty = true; } void SetPitch(float Pitch) { mPitch = Pitch; ValidatePitch(); mTransformDirty = true; }
inline void SetMoveSpeed(float MoveSpeed) { mMoveSpeed = MoveSpeed; } void SetMoveSpeed(float MoveSpeed) { mMoveSpeed = MoveSpeed; }
inline void SetLookSpeed(float LookSpeed) { mLookSpeed = LookSpeed; } void SetLookSpeed(float LookSpeed) { mLookSpeed = LookSpeed; }
inline void SetAspectRatio(float AspectRatio) { mAspectRatio = AspectRatio; mProjectionDirty = true; mFrustumPlanesDirty = true; } void SetAspectRatio(float AspectRatio) { mAspectRatio = AspectRatio; mProjectionDirty = true; mFrustumPlanesDirty = true; }
inline void ResetOrbit() { SetOrbit(CVector3f::skZero, 5.f); } void ResetOrbit() { SetOrbit(CVector3f::Zero(), 5.f); }
// Private // Private
private: private:

View File

@ -3,42 +3,6 @@
#include "Core/GameProject/CResourceStore.h" #include "Core/GameProject/CResourceStore.h"
#include <Common/Log.h> #include <Common/Log.h>
#include <Common/Math/CTransform4f.h> #include <Common/Math/CTransform4f.h>
#include <iostream>
// ************ MEMBER INITIALIZATION ************
std::optional<CVertexBuffer> CDrawUtil::mGridVertices;
CIndexBuffer CDrawUtil::mGridIndices;
std::optional<CDynamicVertexBuffer> CDrawUtil::mSquareVertices;
CIndexBuffer CDrawUtil::mSquareIndices;
std::optional<CDynamicVertexBuffer> CDrawUtil::mLineVertices;
CIndexBuffer CDrawUtil::mLineIndices;
TResPtr<CModel> CDrawUtil::mpCubeModel;
std::optional<CVertexBuffer> CDrawUtil::mWireCubeVertices;
CIndexBuffer CDrawUtil::mWireCubeIndices;
TResPtr<CModel> CDrawUtil::mpSphereModel;
TResPtr<CModel> CDrawUtil::mpDoubleSidedSphereModel;
TResPtr<CModel> CDrawUtil::mpWireSphereModel;
CShader *CDrawUtil::mpColorShader;
CShader *CDrawUtil::mpColorShaderLighting;
CShader *CDrawUtil::mpBillboardShader;
CShader *CDrawUtil::mpLightBillboardShader;
CShader *CDrawUtil::mpTextureShader;
CShader *CDrawUtil::mpCollisionShader;
CShader *CDrawUtil::mpTextShader;
TResPtr<CTexture> CDrawUtil::mpCheckerTexture;
TResPtr<CTexture> CDrawUtil::mpLightTextures[4];
TResPtr<CTexture> CDrawUtil::mpLightMasks[4];
bool CDrawUtil::mDrawUtilInitialized = false;
// ************ PUBLIC ************ // ************ PUBLIC ************
void CDrawUtil::DrawGrid(CColor LineColor, CColor BoldLineColor) void CDrawUtil::DrawGrid(CColor LineColor, CColor BoldLineColor)
@ -99,13 +63,13 @@ void CDrawUtil::DrawSquare(const float *pTexCoords)
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB) void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB)
{ {
DrawLine(PointA, PointB, CColor::skWhite); DrawLine(PointA, PointB, CColor::White());
} }
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB) void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB)
{ {
// Overload for 2D lines // Overload for 2D lines
DrawLine(CVector3f(PointA.X, PointA.Y, 0.f), CVector3f(PointB.X, PointB.Y, 0.f), CColor::skWhite); DrawLine(CVector3f(PointA.X, PointA.Y, 0.f), CVector3f(PointB.X, PointB.Y, 0.f), CColor::White());
} }
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor) void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor)
@ -317,7 +281,7 @@ void CDrawUtil::UseColorShaderLighting(const CColor& kColor)
void CDrawUtil::UseTextureShader() void CDrawUtil::UseTextureShader()
{ {
UseTextureShader(CColor::skWhite); UseTextureShader(CColor::White());
} }
void CDrawUtil::UseTextureShader(const CColor& TintColor) void CDrawUtil::UseTextureShader(const CColor& TintColor)
@ -354,7 +318,7 @@ void CDrawUtil::UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColo
CShader* CDrawUtil::GetTextShader() CShader* CDrawUtil::GetTextShader()
{ {
Init(); Init();
return mpTextShader; return mpTextShader.get();
} }
void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit) void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
@ -366,13 +330,13 @@ void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
CTexture* CDrawUtil::GetLightTexture(ELightType Type) CTexture* CDrawUtil::GetLightTexture(ELightType Type)
{ {
Init(); Init();
return mpLightTextures[(int) Type]; return mpLightTextures[static_cast<size_t>(Type)];
} }
CTexture* CDrawUtil::GetLightMask(ELightType Type) CTexture* CDrawUtil::GetLightMask(ELightType Type)
{ {
Init(); Init();
return mpLightMasks[(int) Type]; return mpLightMasks[static_cast<size_t>(Type)];
} }
CModel* CDrawUtil::GetCubeModel() CModel* CDrawUtil::GetCubeModel()
@ -410,16 +374,18 @@ void CDrawUtil::InitGrid()
const int kGridSize = 501; // must be odd const int kGridSize = 501; // must be odd
const float kGridSpacing = 1.f; const float kGridSpacing = 1.f;
int MinIdx = (kGridSize - 1) / -2; const int MinIdx = (kGridSize - 1) / -2;
int MaxIdx = (kGridSize - 1) / 2; const int MaxIdx = (kGridSize - 1) / 2;
mGridVertices.emplace(); mGridVertices.emplace();
mGridVertices->SetVertexDesc(EVertexAttribute::Position); mGridVertices->SetVertexDesc(EVertexAttribute::Position);
mGridVertices->Reserve(kGridSize * 4); mGridVertices->Reserve(static_cast<size_t>(kGridSize * 4));
for (int32 i = MinIdx; i <= MaxIdx; i++) for (int32 i = MinIdx; i <= MaxIdx; i++)
{ {
if (i == 0) continue; if (i == 0)
continue;
mGridVertices->AddVertex(CVector3f(MinIdx * kGridSpacing, i * kGridSpacing, 0.0f)); mGridVertices->AddVertex(CVector3f(MinIdx * kGridSpacing, i * kGridSpacing, 0.0f));
mGridVertices->AddVertex(CVector3f(MaxIdx * kGridSpacing, i * kGridSpacing, 0.0f)); mGridVertices->AddVertex(CVector3f(MaxIdx * kGridSpacing, i * kGridSpacing, 0.0f));
mGridVertices->AddVertex(CVector3f(i * kGridSpacing, MinIdx * kGridSpacing, 0.0f)); mGridVertices->AddVertex(CVector3f(i * kGridSpacing, MinIdx * kGridSpacing, 0.0f));
@ -431,9 +397,10 @@ void CDrawUtil::InitGrid()
mGridVertices->AddVertex(CVector3f(0, MinIdx * kGridSpacing, 0.0f)); mGridVertices->AddVertex(CVector3f(0, MinIdx * kGridSpacing, 0.0f));
mGridVertices->AddVertex(CVector3f(0, MaxIdx * kGridSpacing, 0.0f)); mGridVertices->AddVertex(CVector3f(0, MaxIdx * kGridSpacing, 0.0f));
int NumIndices = kGridSize * 4; const auto NumIndices = static_cast<size_t>(kGridSize * 4);
mGridIndices.Reserve(NumIndices); mGridIndices.Reserve(NumIndices);
for (uint16 i = 0; i < NumIndices; i++) mGridIndices.AddIndex(i); for (uint16 i = 0; i < NumIndices; i++)
mGridIndices.AddIndex(i);
mGridIndices.SetPrimitiveType(GL_LINES); mGridIndices.SetPrimitiveType(GL_LINES);
} }
@ -450,37 +417,37 @@ void CDrawUtil::InitSquare()
EVertexAttribute::Tex4 | EVertexAttribute::Tex4 |
EVertexAttribute::Tex5 | EVertexAttribute::Tex5 |
EVertexAttribute::Tex6 | EVertexAttribute::Tex6 |
EVertexAttribute::Tex7 ); EVertexAttribute::Tex7);
mSquareVertices->SetVertexCount(4); mSquareVertices->SetVertexCount(4);
CVector3f SquareVertices[] = { static constexpr std::array SquareVertices{
CVector3f(-1.f, 1.f, 0.f), CVector3f(-1.f, 1.f, 0.f),
CVector3f( 1.f, 1.f, 0.f), CVector3f( 1.f, 1.f, 0.f),
CVector3f( 1.f, -1.f, 0.f), CVector3f( 1.f, -1.f, 0.f),
CVector3f(-1.f, -1.f, 0.f) CVector3f(-1.f, -1.f, 0.f)
}; };
CVector3f SquareNormals[] = { static constexpr std::array SquareNormals{
CVector3f(0.f, 0.f, 1.f), CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f), CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f), CVector3f(0.f, 0.f, 1.f),
CVector3f(0.f, 0.f, 1.f) CVector3f(0.f, 0.f, 1.f)
}; };
CVector2f SquareTexCoords[] = { static constexpr std::array SquareTexCoords{
CVector2f(0.f, 1.f), CVector2f(0.f, 1.f),
CVector2f(1.f, 1.f), CVector2f(1.f, 1.f),
CVector2f(1.f, 0.f), CVector2f(1.f, 0.f),
CVector2f(0.f, 0.f) CVector2f(0.f, 0.f)
}; };
mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices); mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices.data());
mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals); mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals.data());
for (uint32 iTex = 0; iTex < 8; iTex++) for (uint32 iTex = 0; iTex < 8; iTex++)
{ {
EVertexAttribute Attrib = (EVertexAttribute) (EVertexAttribute::Tex0 << iTex); const auto Attrib = static_cast<EVertexAttribute>(EVertexAttribute::Tex0 << iTex);
mSquareVertices->BufferAttrib(Attrib, SquareTexCoords); mSquareVertices->BufferAttrib(Attrib, SquareTexCoords.data());
} }
mSquareIndices.Reserve(4); mSquareIndices.Reserve(4);
@ -525,7 +492,7 @@ void CDrawUtil::InitWireCube()
mWireCubeVertices->AddVertex(CVector3f( 0.5f, 0.5f, 0.5f)); mWireCubeVertices->AddVertex(CVector3f( 0.5f, 0.5f, 0.5f));
mWireCubeVertices->AddVertex(CVector3f(-0.5f, 0.5f, 0.5f)); mWireCubeVertices->AddVertex(CVector3f(-0.5f, 0.5f, 0.5f));
uint16 Indices[] = { static constexpr std::array<uint16, 24> Indices{
0, 1, 0, 1,
1, 2, 1, 2,
2, 3, 2, 3,
@ -539,7 +506,7 @@ void CDrawUtil::InitWireCube()
2, 6, 2, 6,
3, 5 3, 5
}; };
mWireCubeIndices.AddIndices(Indices, sizeof(Indices) / sizeof(uint16)); mWireCubeIndices.AddIndices(Indices.data(), Indices.size());
mWireCubeIndices.SetPrimitiveType(GL_LINES); mWireCubeIndices.SetPrimitiveType(GL_LINES);
} }
@ -586,18 +553,18 @@ void CDrawUtil::InitTextures()
void CDrawUtil::Shutdown() void CDrawUtil::Shutdown()
{ {
if (mDrawUtilInitialized) if (!mDrawUtilInitialized)
{ return;
debugf("Shutting down");
mGridVertices = std::nullopt; debugf("Shutting down");
mSquareVertices = std::nullopt; mGridVertices.reset();
mLineVertices = std::nullopt; mSquareVertices.reset();
mWireCubeVertices = std::nullopt; mLineVertices.reset();
delete mpColorShader; mWireCubeVertices.reset();
delete mpColorShaderLighting; mpColorShader.reset();
delete mpTextureShader; mpColorShaderLighting.reset();
delete mpCollisionShader; mpTextureShader.reset();
delete mpTextShader; mpCollisionShader.reset();
mDrawUtilInitialized = false; mpTextShader.reset();
} mDrawUtilInitialized = false;
} }

View File

@ -7,6 +7,7 @@
#include "Core/Resource/Model/CModel.h" #include "Core/Resource/Model/CModel.h"
#include "Core/Resource/CLight.h" #include "Core/Resource/CLight.h"
#include <array>
#include <optional> #include <optional>
/** /**
@ -19,48 +20,48 @@
class CDrawUtil class CDrawUtil
{ {
// 7x7 Grid // 7x7 Grid
static std::optional<CVertexBuffer> mGridVertices; static inline std::optional<CVertexBuffer> mGridVertices;
static CIndexBuffer mGridIndices; static inline CIndexBuffer mGridIndices;
// Square // Square
static std::optional<CDynamicVertexBuffer> mSquareVertices; static inline std::optional<CDynamicVertexBuffer> mSquareVertices;
static CIndexBuffer mSquareIndices; static inline CIndexBuffer mSquareIndices;
// Line // Line
static std::optional<CDynamicVertexBuffer> mLineVertices; static inline std::optional<CDynamicVertexBuffer> mLineVertices;
static CIndexBuffer mLineIndices; static inline CIndexBuffer mLineIndices;
// Cube // Cube
static TResPtr<CModel> mpCubeModel; static inline TResPtr<CModel> mpCubeModel;
// Wire Cube // Wire Cube
static std::optional<CVertexBuffer> mWireCubeVertices; static inline std::optional<CVertexBuffer> mWireCubeVertices;
static CIndexBuffer mWireCubeIndices; static inline CIndexBuffer mWireCubeIndices;
// Sphere // Sphere
static TResPtr<CModel> mpSphereModel; static inline TResPtr<CModel> mpSphereModel;
static TResPtr<CModel> mpDoubleSidedSphereModel; static inline TResPtr<CModel> mpDoubleSidedSphereModel;
// Wire Sphere // Wire Sphere
static TResPtr<CModel> mpWireSphereModel; static inline TResPtr<CModel> mpWireSphereModel;
// Shaders // Shaders
static CShader *mpColorShader; static inline std::unique_ptr<CShader> mpColorShader;
static CShader *mpColorShaderLighting; static inline std::unique_ptr<CShader> mpColorShaderLighting;
static CShader *mpBillboardShader; static inline std::unique_ptr<CShader> mpBillboardShader;
static CShader *mpLightBillboardShader; static inline std::unique_ptr<CShader> mpLightBillboardShader;
static CShader *mpTextureShader; static inline std::unique_ptr<CShader> mpTextureShader;
static CShader *mpCollisionShader; static inline std::unique_ptr<CShader> mpCollisionShader;
static CShader *mpTextShader; static inline std::unique_ptr<CShader> mpTextShader;
// Textures // Textures
static TResPtr<CTexture> mpCheckerTexture; static inline TResPtr<CTexture> mpCheckerTexture;
static TResPtr<CTexture> mpLightTextures[4]; static inline std::array<TResPtr<CTexture>, 4> mpLightTextures;
static TResPtr<CTexture> mpLightMasks[4]; static inline std::array<TResPtr<CTexture>, 4> mpLightMasks;
// Have all the above members been initialized? // Have all the above members been initialized?
static bool mDrawUtilInitialized; static inline bool mDrawUtilInitialized = false;
public: public:
static void DrawGrid(CColor LineColor, CColor BoldLineColor); static void DrawGrid(CColor LineColor, CColor BoldLineColor);
@ -85,17 +86,17 @@ public:
static void DrawSphere(bool DoubleSided = false); static void DrawSphere(bool DoubleSided = false);
static void DrawSphere(const CColor& Color); static void DrawSphere(const CColor& Color);
static void DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color = CColor::skWhite); static void DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color = CColor::White());
static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite); static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::One(), const CColor& Tint = CColor::White());
static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite); static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::One(), const CColor& Tint = CColor::White());
static void UseColorShader(const CColor& Color); static void UseColorShader(const CColor& Color);
static void UseColorShaderLighting(const CColor& Color); static void UseColorShaderLighting(const CColor& Color);
static void UseTextureShader(); static void UseTextureShader();
static void UseTextureShader(const CColor& TintColor); static void UseTextureShader(const CColor& TintColor);
static void UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColor& TintColor = CColor::skWhite); static void UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColor& TintColor = CColor::White());
static CShader* GetTextShader(); static CShader* GetTextShader();
static void LoadCheckerboardTexture(uint32 GLTextureUnit); static void LoadCheckerboardTexture(uint32 GLTextureUnit);

View File

@ -22,14 +22,13 @@ CGraphics::SLightBlock CGraphics::sLightBlock;
CGraphics::ELightingMode CGraphics::sLightMode; CGraphics::ELightingMode CGraphics::sLightMode;
uint32 CGraphics::sNumLights; uint32 CGraphics::sNumLights;
const CColor CGraphics::skDefaultAmbientColor = CColor(0.5f, 0.5f, 0.5f, 0.0f); CColor CGraphics::sAreaAmbientColor = CColor::TransparentBlack();
CColor CGraphics::sAreaAmbientColor = CColor::skTransparentBlack;
float CGraphics::sWorldLightMultiplier; float CGraphics::sWorldLightMultiplier;
CLight CGraphics::sDefaultDirectionalLights[3] = { std::array<CLight, 3> CGraphics::sDefaultDirectionalLights{{
CLight::BuildDirectional(CVector3f(0), CVector3f (0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)), CLight::BuildDirectional(CVector3f(0), CVector3f(0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
CLight::BuildDirectional(CVector3f(0), CVector3f(-0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)), CLight::BuildDirectional(CVector3f(0), CVector3f(-0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
CLight::BuildDirectional(CVector3f(0), CVector3f( 0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)) CLight::BuildDirectional(CVector3f(0), CVector3f(0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
}; }};
// ************ FUNCTIONS ************ // ************ FUNCTIONS ************
void CGraphics::Initialize() void CGraphics::Initialize()
@ -170,8 +169,8 @@ void CGraphics::SetDefaultLighting()
sNumLights = 0; sNumLights = 0;
UpdateLightBlock(); UpdateLightBlock();
sVertexBlock.COLOR0_Amb = CColor::skGray; sVertexBlock.COLOR0_Amb = CColor::Gray();
sVertexBlock.COLOR0_Mat = CColor::skWhite; sVertexBlock.COLOR0_Mat = CColor::White();
UpdateVertexBlock(); UpdateVertexBlock();
} }
@ -182,7 +181,7 @@ void CGraphics::SetupAmbientColor()
else if (sLightMode == ELightingMode::Basic) else if (sLightMode == ELightingMode::Basic)
sVertexBlock.COLOR0_Amb = skDefaultAmbientColor; sVertexBlock.COLOR0_Amb = skDefaultAmbientColor;
else else
sVertexBlock.COLOR0_Amb = CColor::skTransparentWhite; sVertexBlock.COLOR0_Amb = CColor::TransparentWhite();
} }
void CGraphics::SetIdentityMVP() void CGraphics::SetIdentityMVP()

View File

@ -9,6 +9,7 @@
#include <Common/Math/CMatrix4f.h> #include <Common/Math/CMatrix4f.h>
#include <Common/Math/CVector3f.h> #include <Common/Math/CVector3f.h>
#include <Common/Math/CVector4f.h> #include <Common/Math/CVector4f.h>
#include <array>
/** /**
* todo: this entire thing needs to be further abstracted, other classes shouldn't * todo: this entire thing needs to be further abstracted, other classes shouldn't
@ -43,8 +44,8 @@ public:
// SVertexBlock // SVertexBlock
struct SVertexBlock struct SVertexBlock
{ {
CMatrix4f TexMatrices[10]; std::array<CMatrix4f, 10> TexMatrices;
CMatrix4f PostMatrices[20]; std::array<CMatrix4f, 20> PostMatrices;
CColor COLOR0_Amb; CColor COLOR0_Amb;
CColor COLOR0_Mat; CColor COLOR0_Mat;
CColor COLOR1_Amb; CColor COLOR1_Amb;
@ -55,15 +56,15 @@ public:
// SPixelBlock // SPixelBlock
struct SPixelBlock struct SPixelBlock
{ {
CColor Konst[4]; std::array<CColor, 4> Konst;
CColor TevColor[4]; std::array<CColor, 4> TevColor;
CColor TintColor; CColor TintColor;
float LightmapMultiplier; float LightmapMultiplier;
float Padding[3]; std::array<float, 3> Padding;
void SetAllTevColors(const CColor& color) void SetAllTevColors(const CColor& color)
{ {
std::fill(std::begin(TevColor), std::end(TevColor), color); TevColor.fill(color);
} }
}; };
static SPixelBlock sPixelBlock; static SPixelBlock sPixelBlock;
@ -79,7 +80,7 @@ public:
CVector4f DistAtten; CVector4f DistAtten;
CVector4f AngleAtten; CVector4f AngleAtten;
}; };
SGXLight Lights[8]; std::array<SGXLight, 8> Lights;
}; };
static SLightBlock sLightBlock; static SLightBlock sLightBlock;
@ -87,10 +88,10 @@ public:
enum class ELightingMode { None, Basic, World }; enum class ELightingMode { None, Basic, World };
static ELightingMode sLightMode; static ELightingMode sLightMode;
static uint32 sNumLights; static uint32 sNumLights;
static const CColor skDefaultAmbientColor; static constexpr CColor skDefaultAmbientColor{0.5f, 0.5f, 0.5f, 0.0f};
static CColor sAreaAmbientColor; static CColor sAreaAmbientColor;
static float sWorldLightMultiplier; static float sWorldLightMultiplier;
static CLight sDefaultDirectionalLights[3]; static std::array<CLight, 3> sDefaultDirectionalLights;
// Functions // Functions
static void Initialize(); static void Initialize();

View File

@ -18,52 +18,55 @@ void CRenderBucket::CSubBucket::Add(const SRenderablePtr& rkPtr)
void CRenderBucket::CSubBucket::Sort(const CCamera* pkCamera, bool DebugVisualization) void CRenderBucket::CSubBucket::Sort(const CCamera* pkCamera, bool DebugVisualization)
{ {
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize, std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize,
[&, pkCamera](const SRenderablePtr& rkLeft, const SRenderablePtr& rkRight) -> bool [&, pkCamera](const auto& rkLeft, const auto& rkRight) {
const CVector3f CamPos = pkCamera->Position();
const CVector3f CamDir = pkCamera->Direction();
const CVector3f DistL = rkLeft.AABox.ClosestPointAlongVector(CamDir) - CamPos;
const CVector3f DistR = rkRight.AABox.ClosestPointAlongVector(CamDir) - CamPos;
const float DotL = DistL.Dot(CamDir);
const float DotR = DistR.Dot(CamDir);
return DotL > DotR;
});
if (!DebugVisualization)
return;
for (size_t iPtr = 0; iPtr < mSize; iPtr++)
{ {
CVector3f CamPos = pkCamera->Position(); const SRenderablePtr *pPtr = &mRenderables[iPtr];
CVector3f CamDir = pkCamera->Direction(); const CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::White());
CVector3f DistL = rkLeft.AABox.ClosestPointAlongVector(CamDir) - CamPos; const CVector3f Dist = Point - pkCamera->Position();
CVector3f DistR = rkRight.AABox.ClosestPointAlongVector(CamDir) - CamPos; float Dot = Dist.Dot(pkCamera->Direction());
float DotL = DistL.Dot(CamDir); if (Dot < 0.f)
float DotR = DistR.Dot(CamDir); Dot = -Dot;
return (DotL > DotR); Dot = std::min(Dot, 50.f);
}); const float Intensity = 1.f - (Dot / 50.f);
const CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
if (DebugVisualization) CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Point);
{ CGraphics::UpdateMVPBlock();
for (uint32 iPtr = 0; iPtr < mSize; iPtr++) CDrawUtil::DrawCube(CubeColor);
{
SRenderablePtr *pPtr = &mRenderables[iPtr];
CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::skWhite);
CVector3f Dist = Point - pkCamera->Position();
float Dot = Dist.Dot(pkCamera->Direction());
if (Dot < 0.f) Dot = -Dot;
if (Dot > 50.f) Dot = 50.f;
float Intensity = 1.f - (Dot / 50.f);
CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Point);
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawCube(CubeColor);
}
} }
} }
void CRenderBucket::CSubBucket::Clear() void CRenderBucket::CSubBucket::Clear()
{ {
mEstSize = mSize; mEstSize = mSize;
if (mRenderables.size() > mSize) mRenderables.resize(mSize);
if (mRenderables.size() > mSize)
mRenderables.resize(mSize);
mSize = 0; mSize = 0;
} }
void CRenderBucket::CSubBucket::Draw(const SViewInfo& rkViewInfo) void CRenderBucket::CSubBucket::Draw(const SViewInfo& rkViewInfo)
{ {
FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions(); const FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions();
for (uint32 iPtr = 0; iPtr < mSize; iPtr++) for (size_t iPtr = 0; iPtr < mSize; iPtr++)
{ {
const SRenderablePtr& rkPtr = mRenderables[iPtr]; const SRenderablePtr& rkPtr = mRenderables[iPtr];

View File

@ -12,19 +12,16 @@
class CRenderBucket class CRenderBucket
{ {
bool mEnableDepthSortDebugVisualization; bool mEnableDepthSortDebugVisualization = false;
class CSubBucket class CSubBucket
{ {
std::vector<SRenderablePtr> mRenderables; std::vector<SRenderablePtr> mRenderables;
uint32 mEstSize; uint32 mEstSize = 0;
uint32 mSize; uint32 mSize = 0;
public: public:
CSubBucket() CSubBucket() = default;
: mEstSize(0)
, mSize(0)
{}
void Add(const SRenderablePtr &rkPtr); void Add(const SRenderablePtr &rkPtr);
void Sort(const CCamera *pkCamera, bool DebugVisualization); void Sort(const CCamera *pkCamera, bool DebugVisualization);
@ -36,9 +33,7 @@ class CRenderBucket
CSubBucket mTransparentSubBucket; CSubBucket mTransparentSubBucket;
public: public:
CRenderBucket() CRenderBucket() = default;
: mEnableDepthSortDebugVisualization(false)
{}
void Add(const SRenderablePtr& rkPtr, bool Transparent); void Add(const SRenderablePtr& rkPtr, bool Transparent);
void Clear(); void Clear();

View File

@ -6,22 +6,11 @@
#include "Core/Resource/Factory/CTextureDecoder.h" #include "Core/Resource/Factory/CTextureDecoder.h"
#include <Common/Math/CTransform4f.h> #include <Common/Math/CTransform4f.h>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
// ************ STATIC MEMBER INITIALIZATION ************ // ************ STATIC MEMBER INITIALIZATION ************
uint32 CRenderer::sNumRenderers = 0; uint32 CRenderer::sNumRenderers = 0;
// ************ INITIALIZATION ************ // ************ INITIALIZATION ************
CRenderer::CRenderer() CRenderer::CRenderer()
: mOptions(ERenderOption::EnableUVScroll | ERenderOption::EnableBackfaceCull)
, mBloomMode(EBloomMode::NoBloom)
, mDrawGrid(true)
, mInitialized(false)
, mContextIndex(-1)
{ {
sNumRenderers++; sNumRenderers++;
} }
@ -104,10 +93,10 @@ void CRenderer::SetViewportSize(uint32 Width, uint32 Height)
{ {
mViewportWidth = Width; mViewportWidth = Width;
mViewportHeight = Height; mViewportHeight = Height;
mBloomHScale = ((float) Width / 640); mBloomHScale = static_cast<float>(Width) / 640.0f;
mBloomVScale = ((float) Height / 528); mBloomVScale = static_cast<float>(Height) / 528.0f;
mBloomWidth = (uint32) (320 * mBloomHScale); mBloomWidth = static_cast<uint32>(320.0f * mBloomHScale);
mBloomHeight = (uint32) (224 * mBloomVScale); mBloomHeight = static_cast<uint32>(224.0f * mBloomVScale);
mBloomHScale = 1.f / mBloomHScale; mBloomHScale = 1.f / mBloomHScale;
mBloomVScale = 1.f / mBloomVScale; mBloomVScale = 1.f / mBloomVScale;
} }
@ -115,12 +104,16 @@ void CRenderer::SetViewportSize(uint32 Width, uint32 Height)
// ************ RENDER ************ // ************ RENDER ************
void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo) void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
{ {
if (!mInitialized) Init(); if (!mInitialized)
Init();
mSceneFramebuffer.Bind(); mSceneFramebuffer.Bind();
// Set backface culling // Set backface culling
if (mOptions & ERenderOption::EnableBackfaceCull) glEnable(GL_CULL_FACE); if ((mOptions & ERenderOption::EnableBackfaceCull) != 0)
else glDisable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
// Render scene to texture // Render scene to texture
glDepthRange(0.f, 1.f); glDepthRange(0.f, 1.f);
@ -146,26 +139,41 @@ void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
void CRenderer::RenderBloom() void CRenderer::RenderBloom()
{ {
// Check to ensure bloom is enabled. Also don't render bloom in unlit mode. // Check to ensure bloom is enabled. Also don't render bloom in unlit mode.
if (mBloomMode == EBloomMode::NoBloom || CGraphics::sLightMode != CGraphics::ELightingMode::World) return; if (mBloomMode == EBloomMode::NoBloom || CGraphics::sLightMode != CGraphics::ELightingMode::World)
return;
// Setup // Setup
static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f, static constexpr std::array skHOffset{
0.002345f, 0.005470f, 0.008595f }; -0.008595f,
-0.005470f,
-0.002345f,
0.002345f,
0.005470f,
0.008595f,
};
static const float skVOffset[6] = { -0.012275f, -0.007815f, -0.003350f, static constexpr std::array skVOffset{
0.003350f, 0.007815f, 0.012275f }; -0.012275f,
-0.007815f,
-0.003350f,
0.003350f,
0.007815f,
0.012275f,
};
static const CColor skTintColors[6] = { CColor::Integral(17, 17, 17), static constexpr std::array skTintColors{
CColor::Integral(53, 53, 53), CColor::Integral(17, 17, 17),
CColor::Integral(89, 89, 89), CColor::Integral(53, 53, 53),
CColor::Integral(89, 89, 89), CColor::Integral(89, 89, 89),
CColor::Integral(53, 53, 53), CColor::Integral(89, 89, 89),
CColor::Integral(17, 17, 17) }; CColor::Integral(53, 53, 53),
CColor::Integral(17, 17, 17),
};
uint32 BloomWidth = (mBloomMode == EBloomMode::Bloom ? mBloomWidth : mViewportWidth); const uint32 BloomWidth = (mBloomMode == EBloomMode::Bloom ? mBloomWidth : mViewportWidth);
uint32 BloomHeight = (mBloomMode == EBloomMode::Bloom ? mBloomHeight : mViewportHeight); const uint32 BloomHeight = (mBloomMode == EBloomMode::Bloom ? mBloomHeight : mViewportHeight);
float BloomHScale = (mBloomMode == EBloomMode::Bloom ? mBloomHScale : 0); const float BloomHScale = (mBloomMode == EBloomMode::Bloom ? mBloomHScale : 0);
float BloomVScale = (mBloomMode == EBloomMode::Bloom ? mBloomVScale : 0); const float BloomVScale = (mBloomMode == EBloomMode::Bloom ? mBloomVScale : 0);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glViewport(0, 0, BloomWidth, BloomHeight); glViewport(0, 0, BloomWidth, BloomHeight);
@ -195,15 +203,15 @@ void CRenderer::RenderBloom()
mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight); mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight);
mBloomFramebuffers[1].Bind(); mBloomFramebuffers[1].Bind();
CDrawUtil::UseTextureShader(CColor::skGray); CDrawUtil::UseTextureShader(CColor::Gray());
glBlendFunc(GL_ONE, GL_ZERO); glBlendFunc(GL_ONE, GL_ZERO);
mBloomFramebuffers[0].Texture()->Bind(0); mBloomFramebuffers[0].Texture()->Bind(0);
CDrawUtil::DrawSquare(); CDrawUtil::DrawSquare();
for (uint32 iPass = 0; iPass < 6; iPass++) for (size_t iPass = 0; iPass < skTintColors.size(); iPass++)
{ {
CDrawUtil::UseTextureShader(skTintColors[iPass]); CDrawUtil::UseTextureShader(skTintColors[iPass]);
CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f); const CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate); CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
glBlendFunc(GL_ONE, GL_ONE); glBlendFunc(GL_ONE, GL_ONE);
@ -215,15 +223,15 @@ void CRenderer::RenderBloom()
mBloomFramebuffers[2].Bind(); mBloomFramebuffers[2].Bind();
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
CDrawUtil::UseTextureShader(CColor::skGray); CDrawUtil::UseTextureShader(CColor::Gray());
glBlendFunc(GL_ONE, GL_ZERO); glBlendFunc(GL_ONE, GL_ZERO);
mBloomFramebuffers[1].Texture()->Bind(0); mBloomFramebuffers[1].Texture()->Bind(0);
CDrawUtil::DrawSquare(); CDrawUtil::DrawSquare();
for (uint32 iPass = 0; iPass < 6; iPass++) for (size_t iPass = 0; iPass < skTintColors.size(); iPass++)
{ {
CDrawUtil::UseTextureShader(skTintColors[iPass]); CDrawUtil::UseTextureShader(skTintColors[iPass]);
CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f); const CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate); CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
glBlendFunc(GL_ONE, GL_ONE); glBlendFunc(GL_ONE, GL_ONE);
@ -247,7 +255,7 @@ void CRenderer::RenderBloom()
{ {
// Bloom maps are in the framebuffer alpha channel. // Bloom maps are in the framebuffer alpha channel.
// White * dst alpha = bloom map colors // White * dst alpha = bloom map colors
CDrawUtil::UseColorShader(CColor::skWhite); CDrawUtil::UseColorShader(CColor::White());
glBlendFunc(GL_DST_ALPHA, GL_ZERO); glBlendFunc(GL_DST_ALPHA, GL_ZERO);
CDrawUtil::DrawSquare(); CDrawUtil::DrawSquare();
} }
@ -263,16 +271,19 @@ void CRenderer::RenderBloom()
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& rkViewInfo) void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& rkViewInfo)
{ {
if (!mInitialized) Init(); if (!mInitialized)
if (!pSkyboxModel) return; Init();
if (pSkyboxModel == nullptr)
return;
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity; CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skTransparentWhite; CGraphics::sVertexBlock.COLOR0_Amb = CColor::TransparentWhite();
CGraphics::sVertexBlock.COLOR0_Mat = CColor::skTransparentWhite; CGraphics::sVertexBlock.COLOR0_Mat = CColor::TransparentWhite();
CGraphics::sPixelBlock.SetAllTevColors(CColor::skWhite); CGraphics::sPixelBlock.SetAllTevColors(CColor::White());
CGraphics::sPixelBlock.TintColor = CColor::skWhite; CGraphics::sPixelBlock.TintColor = CColor::White();
CGraphics::sNumLights = 0; CGraphics::sNumLights = 0;
CGraphics::UpdateVertexBlock(); CGraphics::UpdateVertexBlock();
CGraphics::UpdatePixelBlock(); CGraphics::UpdatePixelBlock();
@ -316,7 +327,8 @@ void CRenderer::AddMesh(IRenderable *pRenderable, int ComponentIndex, const CAAB
void CRenderer::BeginFrame() void CRenderer::BeginFrame()
{ {
if (!mInitialized) Init(); if (!mInitialized)
Init();
CGraphics::SetActiveContext(mContextIndex); CGraphics::SetActiveContext(mContextIndex);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer);

View File

@ -19,6 +19,8 @@
#include <Common/Math/CAABox.h> #include <Common/Math/CAABox.h>
#include <Common/Math/CMatrix4f.h> #include <Common/Math/CMatrix4f.h>
#include <array>
enum class EBloomMode enum class EBloomMode
{ {
NoBloom, NoBloom,
@ -48,20 +50,23 @@ enum class EBloomMode
*/ */
class CRenderer class CRenderer
{ {
FRenderOptions mOptions; FRenderOptions mOptions{ERenderOption::EnableUVScroll | ERenderOption::EnableBackfaceCull};
EBloomMode mBloomMode; EBloomMode mBloomMode{EBloomMode::NoBloom};
bool mDrawGrid; bool mDrawGrid = true;
CColor mClearColor; CColor mClearColor;
uint32 mContextIndex; uint32 mContextIndex = UINT32_MAX;
bool mInitialized; bool mInitialized = false;
uint32 mViewportWidth, mViewportHeight; uint32 mViewportWidth = 0;
uint32 mBloomWidth, mBloomHeight; uint32 mViewportHeight = 0;
float mBloomHScale, mBloomVScale; uint32 mBloomWidth = 0;
uint32 mBloomHeight = 0;
float mBloomHScale = 0.0f;
float mBloomVScale = 0.0f;
CFramebuffer mSceneFramebuffer; CFramebuffer mSceneFramebuffer;
CFramebuffer mPostProcessFramebuffer; CFramebuffer mPostProcessFramebuffer;
CFramebuffer mBloomFramebuffers[3]; std::array<CFramebuffer, 3> mBloomFramebuffers;
GLint mDefaultFramebuffer; GLint mDefaultFramebuffer = 0;
CRenderBucket mBackgroundBucket; CRenderBucket mBackgroundBucket;
CRenderBucket mMidgroundBucket; CRenderBucket mMidgroundBucket;

View File

@ -11,8 +11,8 @@ class CRenderer;
class IRenderable class IRenderable
{ {
public: public:
IRenderable() {} IRenderable() = default;
virtual ~IRenderable() {} virtual ~IRenderable() = default;
virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo) = 0; virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo) = 0;
virtual void Draw(FRenderOptions /*Options*/, int /*ComponentIndex*/, ERenderCommand /*Command*/, const SViewInfo& /*rkViewInfo*/) {} virtual void Draw(FRenderOptions /*Options*/, int /*ComponentIndex*/, ERenderCommand /*Command*/, const SViewInfo& /*rkViewInfo*/) {}
virtual void DrawSelection() {} virtual void DrawSelection() {}

View File

@ -9,28 +9,19 @@
struct SCollisionRenderSettings struct SCollisionRenderSettings
{ {
uint64 HighlightMask; uint64 HighlightMask = 0;
uint64 HideMask; uint64 HideMask = 0;
int BoundingHierarchyRenderDepth; int BoundingHierarchyRenderDepth = 0;
CCollisionMaterial HideMaterial; CCollisionMaterial HideMaterial;
bool DrawWireframe; bool DrawWireframe = true;
bool DrawBackfaces; bool DrawBackfaces = false;
bool DrawAreaCollisionBounds; bool DrawAreaCollisionBounds = true;
bool DrawBoundingHierarchy; bool DrawBoundingHierarchy = false;
bool TintWithSurfaceColor; bool TintWithSurfaceColor = true;
bool TintUnwalkableTris; bool TintUnwalkableTris = true;
SCollisionRenderSettings() SCollisionRenderSettings() = default;
: HighlightMask(0)
, HideMask(0)
, BoundingHierarchyRenderDepth(0)
, DrawWireframe(true)
, DrawBackfaces(false)
, DrawAreaCollisionBounds(true)
, DrawBoundingHierarchy(false)
, TintWithSurfaceColor(true)
, TintUnwalkableTris(true) {}
}; };
struct SViewInfo struct SViewInfo

View File

@ -2,6 +2,8 @@
#define CANIMEVENTDATA #define CANIMEVENTDATA
#include "Core/Resource/CResource.h" #include "Core/Resource/CResource.h"
#include <memory>
#include <vector>
class CAnimEventData : public CResource class CAnimEventData : public CResource
{ {
@ -16,38 +18,36 @@ class CAnimEventData : public CResource
std::vector<SEvent> mEvents; std::vector<SEvent> mEvents;
public: public:
CAnimEventData(CResourceEntry *pEntry = 0) explicit CAnimEventData(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
{ {
} }
CDependencyTree* BuildDependencyTree() const std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
AddDependenciesToTree(pTree); AddDependenciesToTree(pTree.get());
return pTree; return pTree;
} }
void AddDependenciesToTree(CDependencyTree *pTree) const void AddDependenciesToTree(CDependencyTree *pTree) const
{ {
for (uint32 iEvt = 0; iEvt < mEvents.size(); iEvt++) for (const SEvent& event : mEvents)
{ {
const SEvent& rkEvent = mEvents[iEvt]; CAssetID ID = event.mAssetRef;
CAssetID ID = rkEvent.mAssetRef;
if (ID.IsValid() && !pTree->HasDependency(ID)) if (ID.IsValid() && !pTree->HasDependency(ID))
{ {
CAnimEventDependency *pDep = new CAnimEventDependency(ID, rkEvent.mCharacterIndex); pTree->AddChild(std::make_unique<CAnimEventDependency>(ID, event.mCharacterIndex));
pTree->AddChild(pDep);
} }
} }
} }
inline uint32 NumEvents() const { return mEvents.size(); } size_t NumEvents() const { return mEvents.size(); }
inline uint32 EventCharacterIndex(uint32 EventIdx) const { return mEvents[EventIdx].mCharacterIndex; } uint32 EventCharacterIndex(size_t EventIdx) const { return mEvents[EventIdx].mCharacterIndex; }
inline CAssetID EventAssetRef(uint32 EventIdx) const { return mEvents[EventIdx].mAssetRef; } CAssetID EventAssetRef(size_t EventIdx) const { return mEvents[EventIdx].mAssetRef; }
inline void AddEvent(uint32 CharIdx, CAssetID AssetID) { mEvents.push_back( SEvent { CharIdx, AssetID } ); } void AddEvent(uint32 CharIdx, CAssetID AssetID) { mEvents.push_back(SEvent{CharIdx, AssetID}); }
}; };
#endif // CANIMEVENTDATA #endif // CANIMEVENTDATA

View File

@ -14,6 +14,8 @@
#include "Core/Resource/Model/CModel.h" #include "Core/Resource/Model/CModel.h"
#include <Common/BasicTypes.h> #include <Common/BasicTypes.h>
#include <memory>
#include <set>
#include <vector> #include <vector>
// Animation structures // Animation structures
@ -27,7 +29,7 @@ struct SAdditiveAnim
struct SAnimation struct SAnimation
{ {
TString Name; TString Name;
IMetaAnimation *pMetaAnim; std::unique_ptr<IMetaAnimation> pMetaAnim;
}; };
struct STransition struct STransition
@ -35,13 +37,13 @@ struct STransition
uint32 Unknown; uint32 Unknown;
uint32 AnimIdA; uint32 AnimIdA;
uint32 AnimIdB; uint32 AnimIdB;
IMetaTransition *pMetaTrans; std::unique_ptr<IMetaTransition> pMetaTrans;
}; };
struct SHalfTransition struct SHalfTransition
{ {
uint32 AnimID; uint32 AnimID;
IMetaTransition *pMetaTrans; std::unique_ptr<IMetaTransition> pMetaTrans;
}; };
// Character structures // Character structures
@ -94,50 +96,37 @@ class CAnimSet : public CResource
std::vector<CAnimPrimitive> mAnimPrimitives; std::vector<CAnimPrimitive> mAnimPrimitives;
std::vector<SAnimation> mAnimations; std::vector<SAnimation> mAnimations;
std::vector<STransition> mTransitions; std::vector<STransition> mTransitions;
IMetaTransition *mpDefaultTransition; std::unique_ptr<IMetaTransition> mpDefaultTransition;
std::vector<SAdditiveAnim> mAdditiveAnims; std::vector<SAdditiveAnim> mAdditiveAnims;
float mDefaultAdditiveFadeIn; float mDefaultAdditiveFadeIn = 0.0f;
float mDefaultAdditiveFadeOut; float mDefaultAdditiveFadeOut = 0.0f;
std::vector<SHalfTransition> mHalfTransitions; std::vector<SHalfTransition> mHalfTransitions;
std::vector<CAnimEventData*> mAnimEvents; // note: these are for MP2, where event data isn't a standalone resource; these are owned by the animset std::vector<std::unique_ptr<CAnimEventData>> mAnimEvents; // note: these are for MP2, where event data isn't a standalone resource; these are owned by the animset
public: public:
CAnimSet(CResourceEntry *pEntry = 0) explicit CAnimSet(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
, mpDefaultTransition(nullptr)
{} {}
~CAnimSet() ~CAnimSet() override
{ {
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
delete mAnimations[iAnim].pMetaAnim;
for (uint32 iTrans = 0; iTrans < mTransitions.size(); iTrans++)
delete mTransitions[iTrans].pMetaTrans;
for (uint32 iHalf = 0; iHalf < mHalfTransitions.size(); iHalf++)
delete mHalfTransitions[iHalf].pMetaTrans;
delete mpDefaultTransition;
// For MP2, anim events need to be cleaned up manually // For MP2, anim events need to be cleaned up manually
for (uint32 iEvent = 0; iEvent < mAnimEvents.size(); iEvent++) for ([[maybe_unused]] const auto& event : mAnimEvents)
{ {
ASSERT(mAnimEvents[iEvent] && !mAnimEvents[iEvent]->Entry()); ASSERT(event != nullptr && !event->Entry());
delete mAnimEvents[iEvent];
} }
} }
CDependencyTree* BuildDependencyTree() const std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
// Character dependencies // Character dependencies
for (uint32 iChar = 0; iChar < mCharacters.size(); iChar++) for (const auto& character : mCharacters)
{ {
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree( mCharacters[iChar] ); auto pCharTree = CSetCharacterDependency::BuildTree(character);
ASSERT(pCharTree); ASSERT(pCharTree);
pTree->AddChild(pCharTree); pTree->AddChild(std::move(pCharTree));
} }
// Animation dependencies // Animation dependencies
@ -145,58 +134,52 @@ public:
{ {
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++) for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{ {
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim); auto pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
ASSERT(pAnimTree); ASSERT(pAnimTree);
pTree->AddChild(pAnimTree); pTree->AddChild(std::move(pAnimTree));
} }
} }
else if (Game() <= EGame::Corruption) else if (Game() <= EGame::Corruption)
{ {
const SSetCharacter& rkChar = mCharacters[0]; const SSetCharacter& rkChar = mCharacters[0];
std::set<CAnimPrimitive> PrimitiveSet; std::set<CAnimPrimitive> PrimitiveSet;
// Animations // Animations
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++) for (const auto& anim : mAnimations)
{ {
const SAnimation& rkAnim = mAnimations[iAnim]; anim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
rkAnim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
} }
CSourceAnimData *pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID); if (auto* pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID))
if (pAnimData) pAnimData->AddTransitionDependencies(pTree.get());
pAnimData->AddTransitionDependencies(pTree);
for (auto Iter = PrimitiveSet.begin(); Iter != PrimitiveSet.end(); Iter++) for (const auto& prim : PrimitiveSet)
{ {
const CAnimPrimitive& rkPrim = *Iter; pTree->AddDependency(prim.Animation());
pTree->AddDependency(rkPrim.Animation());
} }
// Event sounds // Event sounds
for (uint32 iSound = 0; iSound < rkChar.SoundEffects.size(); iSound++) for (const auto& effect : rkChar.SoundEffects)
{ {
pTree->AddDependency(rkChar.SoundEffects[iSound]); pTree->AddDependency(effect);
} }
} }
else else
{ {
const SSetCharacter& rkChar = mCharacters[0]; const SSetCharacter& rkChar = mCharacters[0];
for (uint32 iDep = 0; iDep < rkChar.DKDependencies.size(); iDep++) for (const auto& dep : rkChar.DKDependencies)
pTree->AddDependency(rkChar.DKDependencies[iDep]); pTree->AddDependency(dep);
} }
return pTree; return pTree;
} }
CAnimation* FindAnimationAsset(uint32 AnimID) const CAnimation* FindAnimationAsset(size_t AnimID) const
{ {
if (AnimID >= 0 && AnimID < mAnimPrimitives.size()) if (AnimID < mAnimPrimitives.size())
{ {
CAnimPrimitive Prim = mAnimPrimitives[AnimID]; return mAnimPrimitives[AnimID].Animation();
return Prim.Animation();
} }
return nullptr; return nullptr;
@ -204,39 +187,37 @@ public:
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
{ {
for (uint32 iAnim = 0; iAnim < mAnimPrimitives.size(); iAnim++) rPrimSet.insert(mAnimPrimitives.cbegin(), mAnimPrimitives.cend());
rPrimSet.insert(mAnimPrimitives[iAnim]);
} }
// Accessors // Accessors
inline uint32 NumCharacters() const { return mCharacters.size(); } size_t NumCharacters() const { return mCharacters.size(); }
inline uint32 NumAnimations() const { return mAnimations.size(); } size_t NumAnimations() const { return mAnimations.size(); }
inline const SSetCharacter* Character(uint32 Index) const const SSetCharacter* Character(size_t Index) const
{ {
ASSERT(Index >= 0 && Index < NumCharacters()); ASSERT(Index < NumCharacters());
return &mCharacters[Index]; return &mCharacters[Index];
} }
inline const SAnimation* Animation(uint32 Index) const const SAnimation* Animation(size_t Index) const
{ {
ASSERT(Index >= 0 && Index < NumAnimations()); ASSERT(Index < NumAnimations());
return &mAnimations[Index]; return &mAnimations[Index];
} }
CAnimEventData* AnimationEventData(uint32 Index) const CAnimEventData* AnimationEventData(size_t Index) const
{ {
ASSERT(Index >= 0 && Index < NumAnimations()); ASSERT(Index < NumAnimations());
if (Game() <= EGame::Prime) if (Game() <= EGame::Prime)
{ {
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index]; const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
return rkPrim.Animation() ? rkPrim.Animation()->EventData() : nullptr; return rkPrim.Animation() != nullptr ? rkPrim.Animation()->EventData() : nullptr;
} }
else else
{ {
return (Index < mAnimEvents.size() ? mAnimEvents[Index] : nullptr); return (Index < mAnimEvents.size() ? mAnimEvents[Index].get() : nullptr);
} }
} }
}; };

View File

@ -6,21 +6,12 @@
CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/) CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/)
: CResource(pEntry) : CResource(pEntry)
, mDuration(0.f)
, mTickInterval(0.0333333f)
, mNumKeys(0)
{ {
for (uint32 iBone = 0; iBone < 100; iBone++)
{
mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
mBoneInfo[iBone].ScaleChannelIdx = 0xFF;
}
} }
CDependencyTree* CAnimation::BuildDependencyTree() const std::unique_ptr<CDependencyTree> CAnimation::BuildDependencyTree() const
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
pTree->AddDependency(mpEventData); pTree->AddDependency(mpEventData);
return pTree; return pTree;
} }

View File

@ -6,6 +6,7 @@
#include "Core/Resource/Animation/CAnimEventData.h" #include "Core/Resource/Animation/CAnimEventData.h"
#include <Common/Math/CQuaternion.h> #include <Common/Math/CQuaternion.h>
#include <Common/Math/CVector3f.h> #include <Common/Math/CVector3f.h>
#include <array>
#include <vector> #include <vector>
class CAnimation : public CResource class CAnimation : public CResource
@ -13,13 +14,13 @@ class CAnimation : public CResource
DECLARE_RESOURCE_TYPE(Animation) DECLARE_RESOURCE_TYPE(Animation)
friend class CAnimationLoader; friend class CAnimationLoader;
typedef std::vector<CVector3f> TScaleChannel; using TScaleChannel = std::vector<CVector3f>;
typedef std::vector<CQuaternion> TRotationChannel; using TRotationChannel = std::vector<CQuaternion>;
typedef std::vector<CVector3f> TTranslationChannel; using TTranslationChannel = std::vector<CVector3f>;
float mDuration; float mDuration = 0.0f;
float mTickInterval; float mTickInterval = 0.0333333f;
uint32 mNumKeys; uint32 mNumKeys = 0;
std::vector<TScaleChannel> mScaleChannels; std::vector<TScaleChannel> mScaleChannels;
std::vector<TRotationChannel> mRotationChannels; std::vector<TRotationChannel> mRotationChannels;
@ -27,24 +28,24 @@ class CAnimation : public CResource
struct SBoneChannelInfo struct SBoneChannelInfo
{ {
uint8 ScaleChannelIdx; uint8 ScaleChannelIdx = 0xFF;
uint8 RotationChannelIdx; uint8 RotationChannelIdx = 0xFF;
uint8 TranslationChannelIdx; uint8 TranslationChannelIdx = 0xFF;
}; };
SBoneChannelInfo mBoneInfo[100]; std::array<SBoneChannelInfo, 100> mBoneInfo;
TResPtr<CAnimEventData> mpEventData; TResPtr<CAnimEventData> mpEventData;
public: public:
CAnimation(CResourceEntry *pEntry = 0); explicit CAnimation(CResourceEntry *pEntry = nullptr);
CDependencyTree* BuildDependencyTree() const; std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
void EvaluateTransform(float Time, uint32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const; void EvaluateTransform(float Time, uint32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const;
bool HasTranslation(uint32 BoneID) const; bool HasTranslation(uint32 BoneID) const;
inline float Duration() const { return mDuration; } float Duration() const { return mDuration; }
inline uint32 NumKeys() const { return mNumKeys; } uint32 NumKeys() const { return mNumKeys; }
inline float TickInterval() const { return mTickInterval; } float TickInterval() const { return mTickInterval; }
inline CAnimEventData* EventData() const { return mpEventData; } CAnimEventData* EventData() const { return mpEventData; }
}; };
#endif // CANIMATION_H #endif // CANIMATION_H

View File

@ -2,33 +2,16 @@
#include "CAnimSet.h" #include "CAnimSet.h"
#include "Core/GameProject/CResourceStore.h" #include "Core/GameProject/CResourceStore.h"
#include <Common/Log.h> #include <Common/Log.h>
#include <iostream>
CAnimationParameters::CAnimationParameters() CAnimationParameters::CAnimationParameters() = default;
: mGame(EGame::Prime)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
}
CAnimationParameters::CAnimationParameters(EGame Game) CAnimationParameters::CAnimationParameters(EGame Game)
: mGame(Game) : mGame(Game), mCharacterID(CAssetID::InvalidID(Game))
, mCharacterID( CAssetID::InvalidID(Game) )
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{ {
} }
CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game) CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
: mGame(Game) : mGame(Game)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{ {
if (Game <= EGame::Echoes) if (Game <= EGame::Echoes)
{ {
@ -156,36 +139,36 @@ void CAnimationParameters::Serialize(IArchive& rArc)
} }
} }
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(int32 NodeIndex /*= -1*/) const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(int32 NodeIndex) const
{ {
CAnimSet *pSet = AnimSet(); const CAnimSet *pSet = AnimSet();
if (pSet && (pSet->Type() == EResourceType::AnimSet || pSet->Type() == EResourceType::Character)) if (pSet != nullptr && (pSet->Type() == EResourceType::AnimSet || pSet->Type() == EResourceType::Character))
{ {
if (NodeIndex == -1) if (NodeIndex == -1)
NodeIndex = mCharIndex; NodeIndex = mCharIndex;
if (mCharIndex != -1 && pSet->NumCharacters() > (uint32) NodeIndex) if (mCharIndex != UINT32_MAX && pSet->NumCharacters() > static_cast<uint32>(NodeIndex))
return pSet->Character(NodeIndex); return pSet->Character(NodeIndex);
} }
return nullptr; return nullptr;
} }
CModel* CAnimationParameters::GetCurrentModel(int32 NodeIndex /*= -1*/) CModel* CAnimationParameters::GetCurrentModel(int32 NodeIndex)
{ {
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex); const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->pModel : nullptr; return pkChar != nullptr ? pkChar->pModel : nullptr;
} }
TString CAnimationParameters::GetCurrentCharacterName(int32 NodeIndex /*= -1*/) TString CAnimationParameters::GetCurrentCharacterName(int32 NodeIndex) const
{ {
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex); const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
return pkChar ? pkChar->Name : ""; return pkChar != nullptr ? pkChar->Name : "";
} }
// ************ ACCESSORS ************ // ************ ACCESSORS ************
uint32 CAnimationParameters::Unknown(uint32 Index) uint32 CAnimationParameters::Unknown(uint32 Index) const
{ {
// mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot // mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot
// of UI stuff that depends on these functions atm for accessing and editing parameters. // of UI stuff that depends on these functions atm for accessing and editing parameters.
@ -225,8 +208,14 @@ void CAnimationParameters::SetUnknown(uint32 Index, uint32 Value)
{ {
switch (Index) switch (Index)
{ {
case 0: mAnimIndex = Value; case 0:
case 1: mUnknown2 = Value; mAnimIndex = Value;
case 2: mUnknown3 = Value; break;
case 1:
mUnknown2 = Value;
break;
case 2:
mUnknown3 = Value;
break;
} }
} }

View File

@ -8,35 +8,39 @@ class CModel;
class CAnimationParameters class CAnimationParameters
{ {
EGame mGame; EGame mGame = EGame::Prime;
CAssetID mCharacterID; CAssetID mCharacterID;
uint32 mCharIndex; uint32 mCharIndex = 0;
uint32 mAnimIndex; uint32 mAnimIndex = 0;
uint32 mUnknown2; uint32 mUnknown2 = 0;
uint32 mUnknown3; uint32 mUnknown3 = 0;
public: public:
CAnimationParameters(); CAnimationParameters();
CAnimationParameters(EGame Game); explicit CAnimationParameters(EGame Game);
CAnimationParameters(IInputStream& rSCLY, EGame Game); explicit CAnimationParameters(IInputStream& rSCLY, EGame Game);
CAnimationParameters(const CAnimationParameters&) = default;
CAnimationParameters& operator=(const CAnimationParameters&) = default;
void Write(IOutputStream& rSCLY); void Write(IOutputStream& rSCLY);
void Serialize(IArchive& rArc); void Serialize(IArchive& rArc);
const SSetCharacter* GetCurrentSetCharacter(int32 NodeIndex = -1); const SSetCharacter* GetCurrentSetCharacter(int32 NodeIndex = -1) const;
CModel* GetCurrentModel(int32 NodeIndex = -1); CModel* GetCurrentModel(int32 NodeIndex = -1);
TString GetCurrentCharacterName(int32 NodeIndex = -1); TString GetCurrentCharacterName(int32 NodeIndex = -1) const;
// Accessors // Accessors
inline EGame Version() const { return mGame; } EGame Version() const { return mGame; }
inline CAssetID ID() const { return mCharacterID; } CAssetID ID() const { return mCharacterID; }
inline CAnimSet* AnimSet() const { return (CAnimSet*) gpResourceStore->LoadResource(mCharacterID); } CAnimSet* AnimSet() const { return (CAnimSet*) gpResourceStore->LoadResource(mCharacterID); }
inline uint32 CharacterIndex() const { return mCharIndex; } uint32 CharacterIndex() const { return mCharIndex; }
inline uint32 AnimIndex() const { return mAnimIndex; } uint32 AnimIndex() const { return mAnimIndex; }
inline void SetCharIndex(uint32 Index) { mCharIndex = Index; } void SetCharIndex(uint32 Index) { mCharIndex = Index; }
inline void SetAnimIndex(uint32 Index) { mAnimIndex = Index; } void SetAnimIndex(uint32 Index) { mAnimIndex = Index; }
inline void SetGame(EGame Game) void SetGame(EGame Game)
{ {
mGame = Game; mGame = Game;
@ -50,30 +54,22 @@ public:
} }
} }
uint32 Unknown(uint32 Index); uint32 Unknown(uint32 Index) const;
void SetResource(const CAssetID& rkID); void SetResource(const CAssetID& rkID);
void SetUnknown(uint32 Index, uint32 Value); void SetUnknown(uint32 Index, uint32 Value);
// Operators bool operator==(const CAnimationParameters& other) const
inline CAnimationParameters& operator=(const CAnimationParameters& rkOther)
{ {
mGame = rkOther.mGame; return mGame == other.mGame &&
mCharacterID = rkOther.mCharacterID; mCharacterID == other.mCharacterID &&
mCharIndex = rkOther.mCharIndex; mCharIndex == other.mCharIndex &&
mAnimIndex = rkOther.mAnimIndex; mAnimIndex == other.mAnimIndex &&
mUnknown2 = rkOther.mUnknown2; mUnknown2 == other.mUnknown2 &&
mUnknown3 = rkOther.mUnknown3; mUnknown3 == other.mUnknown3;
return *this;
} }
bool operator!=(const CAnimationParameters& other) const
inline bool operator==(const CAnimationParameters& rkOther) const
{ {
return ( (mGame == rkOther.mGame) && return !operator==(other);
(mCharacterID == rkOther.mCharacterID) &&
(mCharIndex == rkOther.mCharIndex) &&
(mAnimIndex == rkOther.mAnimIndex) &&
(mUnknown2 == rkOther.mUnknown2) &&
(mUnknown3 == rkOther.mUnknown3) );
} }
}; };

View File

@ -5,12 +5,12 @@
#include <Common/Macros.h> #include <Common/Macros.h>
#include <Common/Math/MathUtil.h> #include <Common/Math/MathUtil.h>
#include <algorithm>
#include <cfloat> #include <cfloat>
// ************ CBone ************ // ************ CBone ************
CBone::CBone(CSkeleton *pSkel) CBone::CBone(CSkeleton *pSkel)
: mpSkeleton(pSkel) : mpSkeleton(pSkel)
, mSelected(false)
{ {
} }
@ -24,7 +24,7 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo&
pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale); pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
if (AnchorRoot && IsRoot()) if (AnchorRoot && IsRoot())
TransformInfo.Position = CVector3f::skZero; TransformInfo.Position = CVector3f::Zero();
// Apply parent transform // Apply parent transform
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position)); TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position));
@ -39,8 +39,8 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo&
rTransform *= mInvBind; rTransform *= mInvBind;
// Calculate children // Calculate children
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++) for (auto* child : mChildren)
mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot); child->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
} }
CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
@ -58,57 +58,51 @@ bool CBone::IsRoot() const
// In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the // In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the
// actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton), // actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton),
// so we need to account for both // so we need to account for both
return (mpParent == nullptr || mpParent->Parent() == nullptr); return mpParent == nullptr || mpParent->Parent() == nullptr;
} }
// ************ CSkeleton ************ // ************ CSkeleton ************
const float CSkeleton::skSphereRadius = 0.025f;
CSkeleton::CSkeleton(CResourceEntry *pEntry /*= 0*/) CSkeleton::CSkeleton(CResourceEntry *pEntry)
: CResource(pEntry) : CResource(pEntry)
, mpRootBone(nullptr)
{ {
} }
CSkeleton::~CSkeleton() CSkeleton::~CSkeleton() = default;
{
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
delete mBones[iBone];
}
CBone* CSkeleton::BoneByID(uint32 BoneID) const CBone* CSkeleton::BoneByID(uint32 BoneID) const
{ {
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) const auto iter = std::find_if(mBones.begin(), mBones.end(),
{ [BoneID](const auto& bone) { return bone->ID() == BoneID; });
if (mBones[iBone]->ID() == BoneID)
return mBones[iBone];
}
return nullptr; if (iter == mBones.cend())
return nullptr;
return iter->get();
} }
CBone* CSkeleton::BoneByName(const TString& rkBoneName) const CBone* CSkeleton::BoneByName(std::string_view name) const
{ {
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) const auto iter = std::find_if(mBones.begin(), mBones.end(),
{ [&name](const auto& bone) { return bone->Name() == name; });
if (mBones[iBone]->Name() == rkBoneName)
return mBones[iBone];
}
return nullptr; if (iter == mBones.cend())
return nullptr;
return iter->get();
} }
uint32 CSkeleton::MaxBoneID() const uint32 CSkeleton::MaxBoneID() const
{ {
uint32 ID = 0; const auto iter = std::max_element(mBones.cbegin(), mBones.cend(),
[](const auto& a, const auto& b) { return a->ID() < b->ID(); });
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) if (iter == mBones.cend())
{ {
if (mBones[iBone]->ID() > ID) return 0;
ID = mBones[iBone]->ID();
} }
return ID; return (*iter)->ID();
} }
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot) void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
@ -123,55 +117,52 @@ void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkDat
glLineWidth(1.f); glLineWidth(1.f);
// Draw all child links first to minimize model matrix swaps. // Draw all child links first to minimize model matrix swaps.
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) for (const auto& pBone : mBones)
{ {
CBone *pBone = mBones[iBone]; const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw the bone's local XYZ axes for selected bones // Draw the bone's local XYZ axes for selected bones
if (pBone->IsSelected()) if (pBone->IsSelected())
{ {
CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation(); const CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::skRed); CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::Red());
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::skGreen); CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::Green());
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::skBlue); CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::Blue());
} }
// Draw child links // Draw child links
for (uint32 iChild = 0; iChild < pBone->NumChildren(); iChild++) for (size_t iChild = 0; iChild < pBone->NumChildren(); iChild++)
{ {
CBone *pChild = pBone->ChildByIndex(iChild); const CBone *pChild = pBone->ChildByIndex(iChild);
CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position(); const CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
CDrawUtil::DrawLine(BonePos, ChildPos); CDrawUtil::DrawLine(BonePos, ChildPos);
} }
} }
// Draw bone spheres // Draw bone spheres
CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix; const CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix;
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) for (const auto& pBone : mBones)
{ {
CBone *pBone = mBones[iBone]; const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
CTransform4f Transform; CTransform4f Transform;
Transform.Scale(skSphereRadius); Transform.Scale(skSphereRadius);
Transform.Translate(BonePos); Transform.Translate(BonePos);
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform; CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
CGraphics::UpdateMVPBlock(); CGraphics::UpdateMVPBlock();
CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::skRed : CColor::skWhite); CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::Red() : CColor::White());
} }
} }
std::pair<int32,float> CSkeleton::RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData) std::pair<int32,float> CSkeleton::RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData) const
{ {
std::pair<int32,float> Out(-1, FLT_MAX); std::pair<int32,float> Out(-1, FLT_MAX);
for (uint32 iBone = 0; iBone < mBones.size(); iBone++) for (const auto& pBone : mBones)
{ {
CBone *pBone = mBones[iBone]; const CVector3f BonePos = pBone->TransformedPosition(rkData);
CVector3f BonePos = pBone->TransformedPosition(rkData); const std::pair<bool, float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
std::pair<bool,float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
if (Intersect.first && Intersect.second < Out.second) if (Intersect.first && Intersect.second < Out.second)
{ {

View File

@ -8,18 +8,17 @@
#include <Common/TString.h> #include <Common/TString.h>
#include <Common/Math/CRay.h> #include <Common/Math/CRay.h>
#include <Common/Math/CVector3f.h> #include <Common/Math/CVector3f.h>
#include <memory>
#include <string_view>
class CBoneTransformData; class CBoneTransformData;
class CBone; class CBone;
struct SBoneTransformInfo struct SBoneTransformInfo
{ {
CVector3f Position; CVector3f Position{CVector3f::Zero()};
CQuaternion Rotation; CQuaternion Rotation{CQuaternion::Identity()};
CVector3f Scale; CVector3f Scale{CVector3f::One()};
SBoneTransformInfo()
: Position(CVector3f::skZero), Rotation(CQuaternion::skIdentity), Scale(CVector3f::skOne) {}
}; };
class CSkeleton : public CResource class CSkeleton : public CResource
@ -27,24 +26,24 @@ class CSkeleton : public CResource
DECLARE_RESOURCE_TYPE(Skeleton) DECLARE_RESOURCE_TYPE(Skeleton)
friend class CSkeletonLoader; friend class CSkeletonLoader;
CBone *mpRootBone; CBone *mpRootBone = nullptr;
std::vector<CBone*> mBones; std::vector<std::unique_ptr<CBone>> mBones;
static const float skSphereRadius; static constexpr float skSphereRadius = 0.025f;
public: public:
CSkeleton(CResourceEntry *pEntry = 0); explicit CSkeleton(CResourceEntry *pEntry = nullptr);
~CSkeleton(); ~CSkeleton() override;
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot); void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
CBone* BoneByID(uint32 BoneID) const; CBone* BoneByID(uint32 BoneID) const;
CBone* BoneByName(const TString& rkBoneName) const; CBone* BoneByName(std::string_view name) const;
uint32 MaxBoneID() const; uint32 MaxBoneID() const;
void Draw(FRenderOptions Options, const CBoneTransformData *pkData); void Draw(FRenderOptions Options, const CBoneTransformData *pkData);
std::pair<int32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData); std::pair<int32, float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData) const;
inline uint32 NumBones() const { return mBones.size(); } size_t NumBones() const { return mBones.size(); }
inline CBone* RootBone() const { return mpRootBone; } CBone* RootBone() const { return mpRootBone; }
}; };
class CBone class CBone
@ -52,38 +51,38 @@ class CBone
friend class CSkeletonLoader; friend class CSkeletonLoader;
CSkeleton *mpSkeleton; CSkeleton *mpSkeleton;
CBone *mpParent; CBone *mpParent = nullptr;
std::vector<CBone*> mChildren; std::vector<CBone*> mChildren;
uint32 mID; uint32 mID = 0;
CVector3f mPosition; CVector3f mPosition;
CVector3f mLocalPosition; CVector3f mLocalPosition;
CQuaternion mRotation; CQuaternion mRotation;
CQuaternion mLocalRotation; CQuaternion mLocalRotation;
TString mName; TString mName;
CTransform4f mInvBind; CTransform4f mInvBind;
bool mSelected; bool mSelected = false;
public: public:
CBone(CSkeleton *pSkel); explicit CBone(CSkeleton *pSkel);
void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot); void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
CVector3f TransformedPosition(const CBoneTransformData& rkData) const; CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
CQuaternion TransformedRotation(const CBoneTransformData& rkData) const; CQuaternion TransformedRotation(const CBoneTransformData& rkData) const;
bool IsRoot() const; bool IsRoot() const;
// Accessors // Accessors
inline CSkeleton* Skeleton() const { return mpSkeleton; } CSkeleton* Skeleton() const { return mpSkeleton; }
inline CBone* Parent() const { return mpParent; } CBone* Parent() const { return mpParent; }
inline uint32 NumChildren() const { return mChildren.size(); } size_t NumChildren() const { return mChildren.size(); }
inline CBone* ChildByIndex(uint32 Index) const { return mChildren[Index]; } CBone* ChildByIndex(size_t Index) const { return mChildren[Index]; }
inline uint32 ID() const { return mID; } uint32 ID() const { return mID; }
inline CVector3f Position() const { return mPosition; } CVector3f Position() const { return mPosition; }
inline CVector3f LocalPosition() const { return mLocalPosition; } CVector3f LocalPosition() const { return mLocalPosition; }
inline CQuaternion Rotation() const { return mRotation; } CQuaternion Rotation() const { return mRotation; }
inline CQuaternion LocalRotation() const { return mLocalRotation; } CQuaternion LocalRotation() const { return mLocalRotation; }
inline TString Name() const { return mName; } TString Name() const { return mName; }
inline bool IsSelected() const { return mSelected; } bool IsSelected() const { return mSelected; }
inline void SetSelected(bool Selected) { mSelected = Selected; } void SetSelected(bool Selected) { mSelected = Selected; }
}; };
#endif // CSKELETON_H #endif // CSKELETON_H

View File

@ -23,24 +23,24 @@ class CSkin : public CResource
std::vector<SVertGroup> mVertGroups; std::vector<SVertGroup> mVertGroups;
public: public:
CSkin(CResourceEntry *pEntry = 0) : CResource(pEntry) {} explicit CSkin(CResourceEntry *pEntry = nullptr) : CResource(pEntry) {}
const SVertexWeights& WeightsForVertex(uint32 VertIdx) const SVertexWeights& WeightsForVertex(uint32 VertIdx)
{ {
// Null weights bind everything to the root bone in case there is no matching vertex group // Null weights bind everything to the root bone in case there is no matching vertex group
static const SVertexWeights skNullWeights = { static constexpr SVertexWeights skNullWeights{
{ 3, 0, 0, 0 }, {3, 0, 0, 0},
{ 1.f, 0.f, 0.f, 0.f } {1.f, 0.f, 0.f, 0.f},
}; };
uint32 Index = 0; uint32 Index = 0;
for (uint32 iGrp = 0; iGrp < mVertGroups.size(); iGrp++) for (const auto& group : mVertGroups)
{ {
if (VertIdx < Index + mVertGroups[iGrp].NumVertices) if (VertIdx < Index + group.NumVertices)
return mVertGroups[iGrp].Weights; return group.Weights;
Index += mVertGroups[iGrp].NumVertices; Index += group.NumVertices;
} }
return skNullWeights; return skNullWeights;

View File

@ -4,6 +4,8 @@
#include "Core/Resource/CResource.h" #include "Core/Resource/CResource.h"
#include "IMetaTransition.h" #include "IMetaTransition.h"
#include <memory>
class CSourceAnimData : public CResource class CSourceAnimData : public CResource
{ {
DECLARE_RESOURCE_TYPE(SourceAnimData) DECLARE_RESOURCE_TYPE(SourceAnimData)
@ -13,52 +15,42 @@ class CSourceAnimData : public CResource
{ {
CAssetID AnimA; CAssetID AnimA;
CAssetID AnimB; CAssetID AnimB;
IMetaTransition *pTransition; std::unique_ptr<IMetaTransition> pTransition;
}; };
struct SHalfTransition struct SHalfTransition
{ {
CAssetID Anim; CAssetID Anim;
IMetaTransition *pTransition; std::unique_ptr<IMetaTransition> pTransition;
}; };
std::vector<STransition> mTransitions; std::vector<STransition> mTransitions;
std::vector<SHalfTransition> mHalfTransitions; std::vector<SHalfTransition> mHalfTransitions;
IMetaTransition *mpDefaultTransition; std::unique_ptr<IMetaTransition> mpDefaultTransition;
public: public:
CSourceAnimData(CResourceEntry *pEntry = 0) explicit CSourceAnimData(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
, mpDefaultTransition(nullptr)
{} {}
~CSourceAnimData() ~CSourceAnimData() override = default;
{
for (uint32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++)
delete mTransitions[TransIdx].pTransition;
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++) std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
delete mHalfTransitions[HalfIdx].pTransition;
delete mpDefaultTransition;
}
CDependencyTree* BuildDependencyTree() const
{ {
// SAND normally has dependencies from meta-transitions and events // SAND normally has dependencies from meta-transitions and events
// However, all of these can be character-specific. To simplify things, all SAND // However, all of these can be character-specific. To simplify things, all SAND
// dependencies are being added to the CHAR dependency tree instead. Therefore the // dependencies are being added to the CHAR dependency tree instead. Therefore the
// SAND dependency tree is left empty. // SAND dependency tree is left empty.
return new CDependencyTree(); return std::make_unique<CDependencyTree>();
} }
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
{ {
for (uint32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++) for (const auto& transition : mTransitions)
mTransitions[TransIdx].pTransition->GetUniquePrimitives(rPrimSet); transition.pTransition->GetUniquePrimitives(rPrimSet);
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++) for (const auto& halfTrans : mHalfTransitions)
mHalfTransitions[HalfIdx].pTransition->GetUniquePrimitives(rPrimSet); halfTrans.pTransition->GetUniquePrimitives(rPrimSet);
if (mpDefaultTransition) if (mpDefaultTransition)
mpDefaultTransition->GetUniquePrimitives(rPrimSet); mpDefaultTransition->GetUniquePrimitives(rPrimSet);
@ -74,33 +66,31 @@ public:
// Find all relevant primitives // Find all relevant primitives
std::set<CAnimPrimitive> PrimSet; std::set<CAnimPrimitive> PrimSet;
if (UsedTransitions.find(mpDefaultTransition) == UsedTransitions.end()) if (UsedTransitions.find(mpDefaultTransition.get()) == UsedTransitions.cend())
{ {
mpDefaultTransition->GetUniquePrimitives(PrimSet); mpDefaultTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(mpDefaultTransition); UsedTransitions.insert(mpDefaultTransition.get());
} }
for (uint32 TransitionIdx = 0; TransitionIdx < mTransitions.size(); TransitionIdx++) for (const STransition& transition : mTransitions)
{ {
const STransition& rkTransition = mTransitions[TransitionIdx]; IMetaTransition *pTransition = transition.pTransition.get();
IMetaTransition *pTransition = rkTransition.pTransition;
if ( pTree->HasDependency(rkTransition.AnimA) && if (pTree->HasDependency(transition.AnimA) &&
pTree->HasDependency(rkTransition.AnimB) && pTree->HasDependency(transition.AnimB) &&
UsedTransitions.find(pTransition) == UsedTransitions.end() ) UsedTransitions.find(pTransition) == UsedTransitions.cend())
{ {
pTransition->GetUniquePrimitives(PrimSet); pTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(pTransition); UsedTransitions.insert(pTransition);
} }
} }
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++) for (const SHalfTransition& halfTrans : mHalfTransitions)
{ {
const SHalfTransition& rkHalfTrans = mHalfTransitions[HalfIdx]; IMetaTransition *pTransition = halfTrans.pTransition.get();
IMetaTransition *pTransition = rkHalfTrans.pTransition;
if ( pTree->HasDependency(rkHalfTrans.Anim) && if (pTree->HasDependency(halfTrans.Anim) &&
UsedTransitions.find(pTransition) == UsedTransitions.end() ) UsedTransitions.find(pTransition) == UsedTransitions.cend())
{ {
pTransition->GetUniquePrimitives(PrimSet); pTransition->GetUniquePrimitives(PrimSet);
UsedTransitions.insert(pTransition); UsedTransitions.insert(pTransition);
@ -112,8 +102,8 @@ public:
break; break;
// Add all transition primitives to the tree // Add all transition primitives to the tree
for (auto Iter = PrimSet.begin(); Iter != PrimSet.end(); Iter++) for (const auto& primitive : PrimSet)
pTree->AddDependency(Iter->Animation()); pTree->AddDependency(primitive.Animation());
} }
} }
}; };

View File

@ -3,27 +3,27 @@
// ************ CMetaAnimFactory ************ // ************ CMetaAnimFactory ************
CMetaAnimFactory gMetaAnimFactory; CMetaAnimFactory gMetaAnimFactory;
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game) std::unique_ptr<IMetaAnimation> CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
{ {
EMetaAnimType Type = (EMetaAnimType) rInput.ReadLong(); const auto Type = static_cast<EMetaAnimType>(rInput.ReadLong());
switch (Type) switch (Type)
{ {
case EMetaAnimType::Play: case EMetaAnimType::Play:
return new CMetaAnimPlay(rInput, Game); return std::make_unique<CMetaAnimPlay>(rInput, Game);
case EMetaAnimType::Blend: case EMetaAnimType::Blend:
case EMetaAnimType::PhaseBlend: case EMetaAnimType::PhaseBlend:
return new CMetaAnimBlend(Type, rInput, Game); return std::make_unique<CMetaAnimBlend>(Type, rInput, Game);
case EMetaAnimType::Random: case EMetaAnimType::Random:
return new CMetaAnimRandom(rInput, Game); return std::make_unique<CMetaAnimRandom>(rInput, Game);
case EMetaAnimType::Sequence: case EMetaAnimType::Sequence:
return new CMetaAnimSequence(rInput, Game); return std::make_unique<CMetaAnimSequence>(rInput, Game);
default: default:
errorf("Unrecognized meta-animation type: %d", Type); errorf("Unrecognized meta-animation type: %d", static_cast<int>(Type));
return nullptr; return nullptr;
} }
} }
@ -64,11 +64,7 @@ CMetaAnimBlend::CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame G
mUnknownB = rInput.ReadBool(); mUnknownB = rInput.ReadBool();
} }
CMetaAnimBlend::~CMetaAnimBlend() CMetaAnimBlend::~CMetaAnimBlend() = default;
{
delete mpMetaAnimA;
delete mpMetaAnimB;
}
EMetaAnimType CMetaAnimBlend::Type() const EMetaAnimType CMetaAnimBlend::Type() const
{ {
@ -84,7 +80,7 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) con
// ************ CMetaAnimRandom ************ // ************ CMetaAnimRandom ************
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game) CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
{ {
uint32 NumPairs = rInput.ReadLong(); const uint32 NumPairs = rInput.ReadLong();
mProbabilityPairs.reserve(NumPairs); mProbabilityPairs.reserve(NumPairs);
for (uint32 iAnim = 0; iAnim < NumPairs; iAnim++) for (uint32 iAnim = 0; iAnim < NumPairs; iAnim++)
@ -92,15 +88,11 @@ CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
SAnimProbabilityPair Pair; SAnimProbabilityPair Pair;
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game); Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
Pair.Probability = rInput.ReadLong(); Pair.Probability = rInput.ReadLong();
mProbabilityPairs.push_back(Pair); mProbabilityPairs.push_back(std::move(Pair));
} }
} }
CMetaAnimRandom::~CMetaAnimRandom() CMetaAnimRandom::~CMetaAnimRandom() = default;
{
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
delete mProbabilityPairs[iPair].pAnim;
}
EMetaAnimType CMetaAnimRandom::Type() const EMetaAnimType CMetaAnimRandom::Type() const
{ {
@ -109,28 +101,23 @@ EMetaAnimType CMetaAnimRandom::Type() const
void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
{ {
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++) for (const auto& pair : mProbabilityPairs)
mProbabilityPairs[iPair].pAnim->GetUniquePrimitives(rPrimSet); pair.pAnim->GetUniquePrimitives(rPrimSet);
} }
// ************ CMetaAnimSequence ************ // ************ CMetaAnimSequence ************
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game) CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
{ {
uint32 NumAnims = rInput.ReadLong(); const uint32 NumAnims = rInput.ReadLong();
mAnimations.reserve(NumAnims); mAnimations.reserve(NumAnims);
for (uint32 iAnim = 0; iAnim < NumAnims; iAnim++) for (uint32 iAnim = 0; iAnim < NumAnims; iAnim++)
{ {
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game); mAnimations.push_back(gMetaAnimFactory.LoadFromStream(rInput, Game));
mAnimations.push_back(pAnim);
} }
} }
CMetaAnimSequence::~CMetaAnimSequence() CMetaAnimSequence::~CMetaAnimSequence() = default;
{
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
delete mAnimations[iAnim];
}
EMetaAnimType CMetaAnimSequence::Type() const EMetaAnimType CMetaAnimSequence::Type() const
{ {
@ -139,6 +126,6 @@ EMetaAnimType CMetaAnimSequence::Type() const
void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
{ {
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++) for (const auto& anim : mAnimations)
mAnimations[iAnim]->GetUniquePrimitives(rPrimSet); anim->GetUniquePrimitives(rPrimSet);
} }

View File

@ -18,7 +18,7 @@ enum class EMetaAnimType
class CMetaAnimFactory class CMetaAnimFactory
{ {
public: public:
class IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game); std::unique_ptr<class IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game) const;
}; };
extern CMetaAnimFactory gMetaAnimFactory; extern CMetaAnimFactory gMetaAnimFactory;
@ -26,11 +26,11 @@ extern CMetaAnimFactory gMetaAnimFactory;
class CAnimPrimitive class CAnimPrimitive
{ {
TResPtr<CAnimation> mpAnim; TResPtr<CAnimation> mpAnim;
uint32 mID; uint32 mID = 0;
TString mName; TString mName;
public: public:
CAnimPrimitive() : mID(0) {} CAnimPrimitive() = default;
CAnimPrimitive(const CAssetID& rkAnimAssetID, uint32 CharAnimID, const TString& rkAnimName) CAnimPrimitive(const CAssetID& rkAnimAssetID, uint32 CharAnimID, const TString& rkAnimName)
: mID(CharAnimID), mName(rkAnimName) : mID(CharAnimID), mName(rkAnimName)
@ -45,8 +45,9 @@ public:
mName = rInput.ReadString(); mName = rInput.ReadString();
} }
inline bool operator==(const CAnimPrimitive& rkRight) const { return mID == rkRight.mID; } bool operator==(const CAnimPrimitive& other) const { return mID == other.mID; }
inline bool operator< (const CAnimPrimitive& rkRight) const { return mID < rkRight.mID; } bool operator!=(const CAnimPrimitive& other) const { return !operator==(other); }
bool operator< (const CAnimPrimitive& other) const { return mID < other.mID; }
// Accessors // Accessors
CAnimation* Animation() const { return mpAnim; } CAnimation* Animation() const { return mpAnim; }
@ -58,13 +59,13 @@ public:
class IMetaAnimation class IMetaAnimation
{ {
public: public:
IMetaAnimation() {} IMetaAnimation() = default;
virtual ~IMetaAnimation() {} virtual ~IMetaAnimation() = default;
virtual EMetaAnimType Type() const = 0; virtual EMetaAnimType Type() const = 0;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
// Static // Static
static IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game); static std::unique_ptr<IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game);
}; };
// CMetaAnimPlay - plays an animation // CMetaAnimPlay - plays an animation
@ -78,13 +79,13 @@ protected:
public: public:
CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, uint32 UnkB); CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, uint32 UnkB);
CMetaAnimPlay(IInputStream& rInput, EGame Game); CMetaAnimPlay(IInputStream& rInput, EGame Game);
virtual EMetaAnimType Type() const; EMetaAnimType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
// Accessors // Accessors
inline CAnimPrimitive Primitive() const { return mPrimitive; } CAnimPrimitive Primitive() const { return mPrimitive; }
inline float UnknownA() const { return mUnknownA; } float UnknownA() const { return mUnknownA; }
inline uint32 UnknownB() const { return mUnknownB; } uint32 UnknownB() const { return mUnknownB; }
}; };
// CMetaAnimBlend - blend between two animations // CMetaAnimBlend - blend between two animations
@ -92,28 +93,28 @@ class CMetaAnimBlend : public IMetaAnimation
{ {
protected: protected:
EMetaAnimType mType; EMetaAnimType mType;
IMetaAnimation *mpMetaAnimA; std::unique_ptr<IMetaAnimation> mpMetaAnimA;
IMetaAnimation *mpMetaAnimB; std::unique_ptr<IMetaAnimation> mpMetaAnimB;
float mUnknownA; float mUnknownA;
bool mUnknownB; bool mUnknownB;
public: public:
CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame Game); CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame Game);
~CMetaAnimBlend(); ~CMetaAnimBlend() override;
virtual EMetaAnimType Type() const; EMetaAnimType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
// Accessors // Accessors
inline IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA; } IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA.get(); }
inline IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB; } IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB.get(); }
inline float UnknownA() const { return mUnknownA; } float UnknownA() const { return mUnknownA; }
inline bool UnknownB() const { return mUnknownB; } bool UnknownB() const { return mUnknownB; }
}; };
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value // SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
struct SAnimProbabilityPair struct SAnimProbabilityPair
{ {
IMetaAnimation *pAnim; std::unique_ptr<IMetaAnimation> pAnim;
uint32 Probability; uint32 Probability;
}; };
@ -125,22 +126,22 @@ protected:
public: public:
CMetaAnimRandom(IInputStream& rInput, EGame Game); CMetaAnimRandom(IInputStream& rInput, EGame Game);
~CMetaAnimRandom(); ~CMetaAnimRandom() override;
virtual EMetaAnimType Type() const; EMetaAnimType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
// CMetaAnim - play a series of animations in sequence // CMetaAnim - play a series of animations in sequence
class CMetaAnimSequence : public IMetaAnimation class CMetaAnimSequence : public IMetaAnimation
{ {
protected: protected:
std::vector<IMetaAnimation*> mAnimations; std::vector<std::unique_ptr<IMetaAnimation>> mAnimations;
public: public:
CMetaAnimSequence(IInputStream& rInput, EGame Game); CMetaAnimSequence(IInputStream& rInput, EGame Game);
~CMetaAnimSequence(); ~CMetaAnimSequence() override;
virtual EMetaAnimType Type() const; EMetaAnimType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
#endif // IMETAANIMATION #endif // IMETAANIMATION

View File

@ -4,41 +4,38 @@
// ************ CMetaTransFactory ************ // ************ CMetaTransFactory ************
CMetaTransFactory gMetaTransFactory; CMetaTransFactory gMetaTransFactory;
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game) std::unique_ptr<IMetaTransition> CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
{ {
EMetaTransType Type = (EMetaTransType) rInput.ReadLong(); const auto Type = static_cast<EMetaTransType>(rInput.ReadLong());
switch (Type) switch (Type)
{ {
case EMetaTransType::MetaAnim: case EMetaTransType::MetaAnim:
return new CMetaTransMetaAnim(rInput, Game); return std::make_unique<CMetaTransMetaAnim>(rInput, Game);
case EMetaTransType::Trans: case EMetaTransType::Trans:
case EMetaTransType::PhaseTrans: case EMetaTransType::PhaseTrans:
return new CMetaTransTrans(Type, rInput, Game); return std::make_unique<CMetaTransTrans>(Type, rInput, Game);
case EMetaTransType::Snap: case EMetaTransType::Snap:
return new CMetaTransSnap(rInput, Game); return std::make_unique<CMetaTransSnap>(rInput, Game);
case EMetaTransType::Type4: case EMetaTransType::Type4:
return new CMetaTransType4(rInput, Game); return std::make_unique<CMetaTransType4>(rInput, Game);
default: default:
errorf("Unrecognized meta-transition type: %d", Type); errorf("Unrecognized meta-transition type: %d", static_cast<int>(Type));
return nullptr; return nullptr;
} }
} }
// ************ CMetaTransMetaAnim ************ // ************ CMetaTransMetaAnim ************
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game) CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
: mpAnim{gMetaAnimFactory.LoadFromStream(rInput, Game)}
{ {
mpAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
} }
CMetaTransMetaAnim::~CMetaTransMetaAnim() CMetaTransMetaAnim::~CMetaTransMetaAnim() = default;
{
delete mpAnim;
}
EMetaTransType CMetaTransMetaAnim::Type() const EMetaTransType CMetaTransMetaAnim::Type() const
{ {

View File

@ -2,9 +2,13 @@
#define IMETATRANSITION_H #define IMETATRANSITION_H
#include "IMetaAnimation.h" #include "IMetaAnimation.h"
#include <memory>
#include <set>
class IInputStream;
class IMetaAnimation; class IMetaAnimation;
class IMetaTransition; class IMetaTransition;
enum class EGame;
enum class EMetaTransType enum class EMetaTransType
{ {
@ -19,7 +23,7 @@ enum class EMetaTransType
class CMetaTransFactory class CMetaTransFactory
{ {
public: public:
class IMetaTransition* LoadFromStream(IInputStream& rInput, EGame Game); std::unique_ptr<IMetaTransition> LoadFromStream(IInputStream& rInput, EGame Game) const;
}; };
extern CMetaTransFactory gMetaTransFactory; extern CMetaTransFactory gMetaTransFactory;
@ -27,8 +31,8 @@ extern CMetaTransFactory gMetaTransFactory;
class IMetaTransition class IMetaTransition
{ {
public: public:
IMetaTransition() {} IMetaTransition() = default;
virtual ~IMetaTransition() {} virtual ~IMetaTransition() = default;
virtual EMetaTransType Type() const = 0; virtual EMetaTransType Type() const = 0;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0; virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
}; };
@ -36,29 +40,29 @@ public:
// CMetaTransMetaAnim // CMetaTransMetaAnim
class CMetaTransMetaAnim : public IMetaTransition class CMetaTransMetaAnim : public IMetaTransition
{ {
IMetaAnimation *mpAnim; std::unique_ptr<IMetaAnimation> mpAnim;
public: public:
CMetaTransMetaAnim(IInputStream& rInput, EGame Game); CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
~CMetaTransMetaAnim(); ~CMetaTransMetaAnim() override;
virtual EMetaTransType Type() const; EMetaTransType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
// CMetaTransTrans // CMetaTransTrans
class CMetaTransTrans : public IMetaTransition class CMetaTransTrans : public IMetaTransition
{ {
EMetaTransType mType; EMetaTransType mType;
float mUnknownA; float mUnknownA = 0.0f;
uint32 mUnknownB; uint32 mUnknownB = 0;
bool mUnknownC; bool mUnknownC = false;
bool mUnknownD; bool mUnknownD = false;
uint32 mUnknownE; uint32 mUnknownE = 0;
public: public:
CMetaTransTrans(EMetaTransType Type, IInputStream& rInput, EGame Game); CMetaTransTrans(EMetaTransType Type, IInputStream& rInput, EGame Game);
virtual EMetaTransType Type() const; EMetaTransType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
// CMetaTransSnap // CMetaTransSnap
@ -66,8 +70,8 @@ class CMetaTransSnap : public IMetaTransition
{ {
public: public:
CMetaTransSnap(IInputStream& rInput, EGame Game); CMetaTransSnap(IInputStream& rInput, EGame Game);
virtual EMetaTransType Type() const; EMetaTransType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
// CMetaTransType4 // CMetaTransType4
@ -75,8 +79,8 @@ class CMetaTransType4 : public IMetaTransition
{ {
public: public:
CMetaTransType4(IInputStream& rInput, EGame Game); CMetaTransType4(IInputStream& rInput, EGame Game);
virtual EMetaTransType Type() const; EMetaTransType Type() const override;
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const; void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
}; };
#endif // IMETATRANSITION_H #endif // IMETATRANSITION_H

View File

@ -2,37 +2,26 @@
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
CGameArea::CGameArea(CResourceEntry *pEntry /*= 0*/) CGameArea::CGameArea(CResourceEntry *pEntry)
: CResource(pEntry) : CResource(pEntry)
, mWorldIndex(-1)
, mVertexCount(0)
, mTriangleCount(0)
, mTerrainMerged(false)
, mOriginalWorldMeshCount(0)
, mUsesCompression(false)
, mpMaterialSet(nullptr)
, mpCollision(nullptr)
{ {
} }
CGameArea::~CGameArea() CGameArea::~CGameArea()
{ {
ClearTerrain(); ClearTerrain();
for (uint32 iSCLY = 0; iSCLY < mScriptLayers.size(); iSCLY++)
delete mScriptLayers[iSCLY];
} }
CDependencyTree* CGameArea::BuildDependencyTree() const std::unique_ptr<CDependencyTree> CGameArea::BuildDependencyTree() const
{ {
// Base dependencies // Base dependencies
CAreaDependencyTree *pTree = new CAreaDependencyTree(); auto pTree = std::make_unique<CAreaDependencyTree>();
std::set<CAssetID> MatTextures; std::set<CAssetID> MatTextures;
mpMaterialSet->GetUsedTextureIDs(MatTextures); mpMaterialSet->GetUsedTextureIDs(MatTextures);
for (auto Iter = MatTextures.begin(); Iter != MatTextures.end(); Iter++) for (const auto& id : MatTextures)
pTree->AddDependency(*Iter); pTree->AddDependency(id);
pTree->AddDependency(mPathID); pTree->AddDependency(mPathID);
@ -43,8 +32,8 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
} }
// Extra deps // Extra deps
for (uint32 iDep = 0; iDep < mExtraAreaDeps.size(); iDep++) for (const auto& dep : mExtraAreaDeps)
pTree->AddDependency(mExtraAreaDeps[iDep]); pTree->AddDependency(dep);
// Layer dependencies // Layer dependencies
std::vector<CAssetID> DummyDeps; std::vector<CAssetID> DummyDeps;
@ -52,18 +41,19 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
for (uint32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++) for (uint32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
{ {
const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps); const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps);
pTree->AddScriptLayer(mScriptLayers[iLayer], rkExtras); pTree->AddScriptLayer(mScriptLayers[iLayer].get(), rkExtras);
} }
return pTree; return pTree;
} }
void CGameArea::AddWorldModel(CModel *pModel) void CGameArea::AddWorldModel(std::unique_ptr<CModel>&& pModel)
{ {
mWorldModels.push_back(pModel);
mVertexCount += pModel->GetVertexCount(); mVertexCount += pModel->GetVertexCount();
mTriangleCount += pModel->GetTriangleCount(); mTriangleCount += pModel->GetTriangleCount();
mAABox.ExpandBounds(pModel->AABox()); mAABox.ExpandBounds(pModel->AABox());
mWorldModels.push_back(std::move(pModel));
} }
void CGameArea::MergeTerrain() void CGameArea::MergeTerrain()
@ -71,18 +61,17 @@ void CGameArea::MergeTerrain()
if (mTerrainMerged) return; if (mTerrainMerged) return;
// Nothing really complicated here - iterate through every terrain submesh, add each to a static model // Nothing really complicated here - iterate through every terrain submesh, add each to a static model
for (uint32 iMdl = 0; iMdl < mWorldModels.size(); iMdl++) for (auto& pMdl : mWorldModels)
{ {
CModel *pMdl = mWorldModels[iMdl]; const size_t SubmeshCount = pMdl->GetSurfaceCount();
uint32 SubmeshCount = pMdl->GetSurfaceCount();
for (uint32 iSurf = 0; iSurf < SubmeshCount; iSurf++) for (size_t iSurf = 0; iSurf < SubmeshCount; iSurf++)
{ {
SSurface *pSurf = pMdl->GetSurface(iSurf); SSurface *pSurf = pMdl->GetSurface(iSurf);
CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID, false); CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID, false);
bool NewMat = true; bool NewMat = true;
for (std::vector<CStaticModel*>::iterator it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); it++) for (auto it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); ++it)
{ {
if ((*it)->GetMaterial() == pMat) if ((*it)->GetMaterial() == pMat)
{ {
@ -91,10 +80,10 @@ void CGameArea::MergeTerrain()
// (particularly with multi-layered transparent meshes) // (particularly with multi-layered transparent meshes)
// so we need to at least try to maintain it. // so we need to at least try to maintain it.
// This is maybe not the most efficient way to do this, but it works. // This is maybe not the most efficient way to do this, but it works.
CStaticModel *pStatic = *it; auto pStatic = std::move(*it);
pStatic->AddSurface(pSurf); pStatic->AddSurface(pSurf);
mStaticWorldModels.erase(it); mStaticWorldModels.erase(it);
mStaticWorldModels.push_back(pStatic); mStaticWorldModels.push_back(std::move(pStatic));
NewMat = false; NewMat = false;
break; break;
} }
@ -102,9 +91,9 @@ void CGameArea::MergeTerrain()
if (NewMat) if (NewMat)
{ {
CStaticModel *pStatic = new CStaticModel(pMat); auto pStatic = std::make_unique<CStaticModel>(pMat);
pStatic->AddSurface(pSurf); pStatic->AddSurface(pSurf);
mStaticWorldModels.push_back(pStatic); mStaticWorldModels.push_back(std::move(pStatic));
} }
} }
} }
@ -112,44 +101,41 @@ void CGameArea::MergeTerrain()
void CGameArea::ClearTerrain() void CGameArea::ClearTerrain()
{ {
for (uint32 iModel = 0; iModel < mWorldModels.size(); iModel++)
delete mWorldModels[iModel];
mWorldModels.clear(); mWorldModels.clear();
for (uint32 iStatic = 0; iStatic < mStaticWorldModels.size(); iStatic++)
delete mStaticWorldModels[iStatic];
mStaticWorldModels.clear(); mStaticWorldModels.clear();
if (mpMaterialSet) delete mpMaterialSet; if (mpMaterialSet)
delete mpMaterialSet;
mVertexCount = 0; mVertexCount = 0;
mTriangleCount = 0; mTriangleCount = 0;
mTerrainMerged = false; mTerrainMerged = false;
mAABox = CAABox::skInfinite; mAABox = CAABox::Infinite();
} }
void CGameArea::ClearScriptLayers() void CGameArea::ClearScriptLayers()
{ {
for (auto it = mScriptLayers.begin(); it != mScriptLayers.end(); it++)
delete *it;
mScriptLayers.clear(); mScriptLayers.clear();
} }
uint32 CGameArea::TotalInstanceCount() const size_t CGameArea::TotalInstanceCount() const
{ {
uint32 Num = 0; size_t Num = 0;
for (uint32 iLyr = 0; iLyr < mScriptLayers.size(); iLyr++) for (const auto& layer : mScriptLayers)
Num += mScriptLayers[iLyr]->NumInstances(); Num += layer->NumInstances();
return Num; return Num;
} }
CScriptObject* CGameArea::InstanceByID(uint32 InstanceID) CScriptObject* CGameArea::InstanceByID(uint32 InstanceID)
{ {
auto it = mObjectMap.find(InstanceID); const auto it = mObjectMap.find(InstanceID);
if (it != mObjectMap.end()) return it->second;
else return nullptr; if (it != mObjectMap.cend())
return it->second;
return nullptr;
} }
uint32 CGameArea::FindUnusedInstanceID() const uint32 CGameArea::FindUnusedInstanceID() const
@ -178,30 +164,30 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
uint32 SuggestedLayerIndex /*= -1*/ ) uint32 SuggestedLayerIndex /*= -1*/ )
{ {
// Verify we can fit another instance in this area. // Verify we can fit another instance in this area.
uint32 NumInstances = TotalInstanceCount(); const size_t NumInstances = TotalInstanceCount();
if (NumInstances >= 0xFFFF) if (NumInstances >= 0xFFFF)
{ {
errorf("Unable to spawn a new script instance; too many instances in area (%d)", NumInstances); errorf("Unable to spawn a new script instance; too many instances in area (%zu)", NumInstances);
return nullptr; return nullptr;
} }
// Check whether the suggested instance ID is valid // Check whether the suggested instance ID is valid
uint32 InstanceID = SuggestedID; uint32 InstanceID = SuggestedID;
if (InstanceID != -1) if (InstanceID != UINT32_MAX)
{ {
if (mObjectMap.find(InstanceID) == mObjectMap.end()) if (mObjectMap.find(InstanceID) == mObjectMap.cend())
InstanceID = -1; InstanceID = UINT32_MAX;
} }
// If not valid (or if there's no suggested ID) then determine a new instance ID // If not valid (or if there's no suggested ID) then determine a new instance ID
if (InstanceID == -1) if (InstanceID == UINT32_MAX)
{ {
// Determine layer index // Determine layer index
uint32 LayerIndex = pLayer->AreaIndex(); const uint32 LayerIndex = pLayer->AreaIndex();
if (LayerIndex == -1) if (LayerIndex == UINT32_MAX)
{ {
errorf("Unable to spawn a new script instance; invalid script layer passed in"); errorf("Unable to spawn a new script instance; invalid script layer passed in");
return nullptr; return nullptr;
@ -212,13 +198,14 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
} }
// Spawn instance // Spawn instance
CScriptObject *pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate); auto* pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate);
pInstance->EvaluateProperties(); pInstance->EvaluateProperties();
pInstance->SetPosition(rkPosition); pInstance->SetPosition(rkPosition);
pInstance->SetRotation(rkRotation.ToEuler()); pInstance->SetRotation(rkRotation.ToEuler());
pInstance->SetScale(rkScale); pInstance->SetScale(rkScale);
pInstance->SetName(pTemplate->Name()); pInstance->SetName(pTemplate->Name());
if (pTemplate->Game() < EGame::EchoesDemo) pInstance->SetActive(true); if (pTemplate->Game() < EGame::EchoesDemo)
pInstance->SetActive(true);
pLayer->AddInstance(pInstance, SuggestedLayerIndex); pLayer->AddInstance(pInstance, SuggestedLayerIndex);
mObjectMap[InstanceID] = pInstance; mObjectMap[InstanceID] = pInstance;
return pInstance; return pInstance;

View File

@ -12,7 +12,9 @@
#include <Common/Math/CQuaternion.h> #include <Common/Math/CQuaternion.h>
#include <Common/Math/CTransform4f.h> #include <Common/Math/CTransform4f.h>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector>
class CScriptLayer; class CScriptLayer;
class CScriptObject; class CScriptObject;
@ -24,17 +26,17 @@ class CGameArea : public CResource
friend class CAreaLoader; friend class CAreaLoader;
friend class CAreaCooker; friend class CAreaCooker;
uint32 mWorldIndex; uint32 mWorldIndex = UINT32_MAX;
uint32 mVertexCount; uint32 mVertexCount = 0;
uint32 mTriangleCount; uint32 mTriangleCount = 0;
bool mTerrainMerged; bool mTerrainMerged = false;
CTransform4f mTransform; CTransform4f mTransform;
CAABox mAABox; CAABox mAABox;
// Data saved from the original file to help on recook // Data saved from the original file to help on recook
std::vector<std::vector<uint8>> mSectionDataBuffers; std::vector<std::vector<uint8>> mSectionDataBuffers;
uint32 mOriginalWorldMeshCount; uint32 mOriginalWorldMeshCount = 0;
bool mUsesCompression; bool mUsesCompression = false;
struct SSectionNumber struct SSectionNumber
{ {
@ -44,11 +46,11 @@ class CGameArea : public CResource
std::vector<SSectionNumber> mSectionNumbers; std::vector<SSectionNumber> mSectionNumbers;
// Geometry // Geometry
CMaterialSet *mpMaterialSet; CMaterialSet *mpMaterialSet = nullptr;
std::vector<CModel*> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor std::vector<std::unique_ptr<CModel>> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
std::vector<CStaticModel*> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor std::vector<std::unique_ptr<CStaticModel>> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor
// Script // Script
std::vector<CScriptLayer*> mScriptLayers; std::vector<std::unique_ptr<CScriptLayer>> mScriptLayers;
std::unordered_map<uint32, CScriptObject*> mObjectMap; std::unordered_map<uint32, CScriptObject*> mObjectMap;
// Collision // Collision
std::unique_ptr<CCollisionMeshGroup> mpCollision; std::unique_ptr<CCollisionMeshGroup> mpCollision;
@ -65,46 +67,47 @@ class CGameArea : public CResource
std::vector< std::vector<CAssetID> > mExtraLayerDeps; std::vector< std::vector<CAssetID> > mExtraLayerDeps;
public: public:
CGameArea(CResourceEntry *pEntry = 0); explicit CGameArea(CResourceEntry *pEntry = nullptr);
~CGameArea(); ~CGameArea() override;
CDependencyTree* BuildDependencyTree() const; std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
void AddWorldModel(CModel *pModel); void AddWorldModel(std::unique_ptr<CModel>&& pModel);
void MergeTerrain(); void MergeTerrain();
void ClearTerrain(); void ClearTerrain();
void ClearScriptLayers(); void ClearScriptLayers();
uint32 TotalInstanceCount() const; size_t TotalInstanceCount() const;
CScriptObject* InstanceByID(uint32 InstanceID); CScriptObject* InstanceByID(uint32 InstanceID);
uint32 FindUnusedInstanceID() const; uint32 FindUnusedInstanceID() const;
CScriptObject* SpawnInstance(CScriptTemplate *pTemplate, CScriptLayer *pLayer, CScriptObject* SpawnInstance(CScriptTemplate* pTemplate, CScriptLayer* pLayer,
const CVector3f& rkPosition = CVector3f::skZero, const CVector3f& rkPosition = CVector3f::Zero(),
const CQuaternion& rkRotation = CQuaternion::skIdentity, const CQuaternion& rkRotation = CQuaternion::Identity(),
const CVector3f& rkScale = CVector3f::skOne, const CVector3f& rkScale = CVector3f::One(),
uint32 SuggestedID = -1, uint32 SuggestedLayerIndex = -1); uint32 SuggestedID = UINT32_MAX,
uint32 SuggestedLayerIndex = UINT32_MAX);
void AddInstanceToArea(CScriptObject *pInstance); void AddInstanceToArea(CScriptObject *pInstance);
void DeleteInstance(CScriptObject *pInstance); void DeleteInstance(CScriptObject *pInstance);
void ClearExtraDependencies(); void ClearExtraDependencies();
// Inline Accessors // Accessors
inline uint32 WorldIndex() const { return mWorldIndex; } uint32 WorldIndex() const { return mWorldIndex; }
inline CTransform4f Transform() const { return mTransform; } CTransform4f Transform() const { return mTransform; }
inline CMaterialSet* Materials() const { return mpMaterialSet; } CMaterialSet* Materials() const { return mpMaterialSet; }
inline uint32 NumWorldModels() const { return mWorldModels.size(); } size_t NumWorldModels() const { return mWorldModels.size(); }
inline uint32 NumStaticModels() const { return mStaticWorldModels.size(); } size_t NumStaticModels() const { return mStaticWorldModels.size(); }
inline CModel* TerrainModel(uint32 iMdl) const { return mWorldModels[iMdl]; } CModel* TerrainModel(size_t iMdl) const { return mWorldModels[iMdl].get(); }
inline CStaticModel* StaticModel(uint32 iMdl) const { return mStaticWorldModels[iMdl]; } CStaticModel* StaticModel(size_t iMdl) const { return mStaticWorldModels[iMdl].get(); }
inline CCollisionMeshGroup* Collision() const { return mpCollision.get(); } CCollisionMeshGroup* Collision() const { return mpCollision.get(); }
inline uint32 NumScriptLayers() const { return mScriptLayers.size(); } size_t NumScriptLayers() const { return mScriptLayers.size(); }
inline CScriptLayer* ScriptLayer(uint32 Index) const { return mScriptLayers[Index]; } CScriptLayer* ScriptLayer(size_t Index) const { return mScriptLayers[Index].get(); }
inline uint32 NumLightLayers() const { return mLightLayers.size(); } size_t NumLightLayers() const { return mLightLayers.size(); }
inline uint32 NumLights(uint32 LayerIndex) const { return (LayerIndex < mLightLayers.size() ? mLightLayers[LayerIndex].size() : 0); } size_t NumLights(size_t LayerIndex) const { return (LayerIndex < mLightLayers.size() ? mLightLayers[LayerIndex].size() : 0); }
inline CLight* Light(uint32 LayerIndex, uint32 LightIndex) { return &mLightLayers[LayerIndex][LightIndex]; } CLight* Light(size_t LayerIndex, size_t LightIndex) { return &mLightLayers[LayerIndex][LightIndex]; }
inline CAssetID PathID() const { return mPathID; } CAssetID PathID() const { return mPathID; }
inline CPoiToWorld* PoiToWorldMap() const { return mpPoiToWorldMap; } CPoiToWorld* PoiToWorldMap() const { return mpPoiToWorldMap; }
inline CAssetID PortalAreaID() const { return mPortalAreaID; } CAssetID PortalAreaID() const { return mPortalAreaID; }
inline CAABox AABox() const { return mAABox; } CAABox AABox() const { return mAABox; }
inline void SetWorldIndex(uint32 NewWorldIndex) { mWorldIndex = NewWorldIndex; } void SetWorldIndex(uint32 NewWorldIndex) { mWorldIndex = NewWorldIndex; }
}; };
#endif // CGAMEAREA_H #endif // CGAMEAREA_H

View File

@ -10,20 +10,19 @@ class CAudioGroup : public CResource
friend class CAudioGroupLoader; friend class CAudioGroupLoader;
TString mGroupName; TString mGroupName;
uint32 mGroupID; uint32 mGroupID = UINT32_MAX;
std::vector<uint16> mDefineIDs; std::vector<uint16> mDefineIDs;
public: public:
CAudioGroup(CResourceEntry *pEntry = 0) explicit CAudioGroup(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
, mGroupID(-1)
{} {}
// Accessors // Accessors
inline TString GroupName() const { return mGroupName; } TString GroupName() const { return mGroupName; }
inline uint32 GroupID() const { return mGroupID; } uint32 GroupID() const { return mGroupID; }
inline uint32 NumSoundDefineIDs() const { return mDefineIDs.size(); } size_t NumSoundDefineIDs() const { return mDefineIDs.size(); }
inline uint16 SoundDefineIDByIndex(uint32 Index) const { return mDefineIDs[Index]; } uint16 SoundDefineIDByIndex(size_t Index) const { return mDefineIDs[Index]; }
}; };
#endif // CAUDIOGROUP #endif // CAUDIOGROUP

View File

@ -2,6 +2,7 @@
#define CAUDIOLOOKUPTABLE #define CAUDIOLOOKUPTABLE
#include "CResource.h" #include "CResource.h"
#include <vector>
class CAudioLookupTable : public CResource class CAudioLookupTable : public CResource
{ {
@ -10,13 +11,15 @@ class CAudioLookupTable : public CResource
std::vector<uint16> mDefineIDs; std::vector<uint16> mDefineIDs;
public: public:
CAudioLookupTable(CResourceEntry *pEntry = 0) explicit CAudioLookupTable(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
{} {}
inline uint16 FindSoundDefineID(uint32 SoundID) uint16 FindSoundDefineID(size_t SoundID) const
{ {
if (SoundID >= mDefineIDs.size()) return -1; if (SoundID >= mDefineIDs.size())
return UINT16_MAX;
return mDefineIDs[SoundID]; return mDefineIDs[SoundID];
} }
}; };

View File

@ -12,24 +12,24 @@ class CAudioMacro : public CResource
std::vector<CAssetID> mSamples; std::vector<CAssetID> mSamples;
public: public:
CAudioMacro(CResourceEntry *pEntry = 0) explicit CAudioMacro(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
{} {}
virtual CDependencyTree* BuildDependencyTree() const std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
for (uint32 iSamp = 0; iSamp < mSamples.size(); iSamp++) for (const auto& sample : mSamples)
pTree->AddDependency(mSamples[iSamp]); pTree->AddDependency(sample);
return pTree; return pTree;
} }
// Accessors // Accessors
inline TString MacroName() const { return mMacroName; } TString MacroName() const { return mMacroName; }
inline uint32 NumSamples() const { return mSamples.size(); } size_t NumSamples() const { return mSamples.size(); }
inline CAssetID SampleByIndex(uint32 Index) const { return mSamples[Index]; } CAssetID SampleByIndex(size_t Index) const { return mSamples[Index]; }
}; };
#endif // CAUDIOMACRO_H #endif // CAUDIOMACRO_H

View File

@ -2,6 +2,7 @@
#define CDEPENDENCYGROUP #define CDEPENDENCYGROUP
#include "CResource.h" #include "CResource.h"
#include <algorithm>
class CDependencyGroup : public CResource class CDependencyGroup : public CResource
{ {
@ -9,53 +10,47 @@ class CDependencyGroup : public CResource
std::vector<CAssetID> mDependencies; std::vector<CAssetID> mDependencies;
public: public:
CDependencyGroup(CResourceEntry *pEntry = 0) : CResource(pEntry) {} explicit CDependencyGroup(CResourceEntry *pEntry = nullptr) : CResource(pEntry) {}
inline void Clear() { mDependencies.clear(); } void Clear() { mDependencies.clear(); }
inline uint32 NumDependencies() const { return mDependencies.size(); } uint32 NumDependencies() const { return mDependencies.size(); }
inline CAssetID DependencyByIndex(uint32 Index) const { return mDependencies[Index]; } CAssetID DependencyByIndex(size_t Index) const { return mDependencies[Index]; }
inline void AddDependency(const CAssetID& rkID) void AddDependency(const CAssetID& rkID)
{ {
if (!HasDependency(rkID)) if (!HasDependency(rkID))
mDependencies.push_back(rkID); mDependencies.push_back(rkID);
} }
inline void AddDependency(CResource *pRes) void AddDependency(const CResource* pRes)
{ {
if ( pRes && !HasDependency(pRes->ID()) ) if (pRes != nullptr && !HasDependency(pRes->ID()))
mDependencies.push_back(pRes->ID()); mDependencies.push_back(pRes->ID());
} }
void RemoveDependency(const CAssetID& rkID) void RemoveDependency(const CAssetID& rkID)
{ {
for (auto Iter = mDependencies.begin(); Iter != mDependencies.end(); Iter++) const auto it = std::find_if(mDependencies.cbegin(), mDependencies.cend(),
{ [&rkID](const auto& entry) { return entry == rkID; });
if (*Iter == rkID)
{ if (it == mDependencies.cend())
mDependencies.erase(Iter); return;
return;
} mDependencies.erase(it);
}
} }
bool HasDependency(const CAssetID &rkID) const bool HasDependency(const CAssetID& rkID) const
{ {
for (uint32 iDep = 0; iDep < mDependencies.size(); iDep++) return std::any_of(mDependencies.cbegin(), mDependencies.cend(),
{ [&rkID](const auto& entry) { return entry == rkID; });
if (mDependencies[iDep] == rkID)
return true;
}
return false;
} }
CDependencyTree* BuildDependencyTree() const std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
for (auto DepIt = mDependencies.begin(); DepIt != mDependencies.end(); DepIt++) for (const auto& dep : mDependencies)
pTree->AddDependency(*DepIt); pTree->AddDependency(dep);
return pTree; return pTree;
} }

View File

@ -4,27 +4,25 @@
#include "Core/Render/CRenderer.h" #include "Core/Render/CRenderer.h"
std::optional<CDynamicVertexBuffer> CFont::smGlyphVertices; std::optional<CDynamicVertexBuffer> CFont::smGlyphVertices;
CIndexBuffer CFont::smGlyphIndices; CIndexBuffer CFont::smGlyphIndices;
bool CFont::smBuffersInitialized = false; bool CFont::smBuffersInitialized = false;
CFont::CFont(CResourceEntry *pEntry /*= 0*/) : CResource(pEntry) CFont::CFont(CResourceEntry *pEntry) : CResource(pEntry)
{ {
} }
CFont::~CFont() CFont::~CFont() = default;
{
}
inline float PtsToFloat(int32 Pt) static constexpr float PtsToFloat(int32 Pt)
{ {
// This is a bit of an arbitrary number but it works // This is a bit of an arbitrary number but it works
// 1 / (1280 / 1.333333f / 2) // 1 / (1280 / 1.333333f / 2)
return 0.00208333f * Pt; return 0.00208333f * Pt;
} }
CDependencyTree* CFont::BuildDependencyTree() const std::unique_ptr<CDependencyTree> CFont::BuildDependencyTree() const
{ {
CDependencyTree *pOut = new CDependencyTree(); auto pOut = std::make_unique<CDependencyTree>();
pOut->AddDependency(mpFontTexture); pOut->AddDependency(mpFontTexture);
return pOut; return pOut;
} }
@ -33,32 +31,35 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, uint32 FontSize) CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, uint32 FontSize)
{ {
// WIP // WIP
if (!smBuffersInitialized) InitBuffers(); if (!smBuffersInitialized)
InitBuffers();
// Shader setup // Shader setup
CShader *pTextShader = CDrawUtil::GetTextShader(); CShader *pTextShader = CDrawUtil::GetTextShader();
pTextShader->SetCurrent(); pTextShader->SetCurrent();
GLuint ModelMtxLoc = pTextShader->GetUniformLocation("ModelMtx"); const GLuint ModelMtxLoc = pTextShader->GetUniformLocation("ModelMtx");
GLuint ColorLoc = pTextShader->GetUniformLocation("FontColor"); const GLuint ColorLoc = pTextShader->GetUniformLocation("FontColor");
GLuint LayerLoc = pTextShader->GetUniformLocation("RGBALayer"); const GLuint LayerLoc = pTextShader->GetUniformLocation("RGBALayer");
mpFontTexture->Bind(0); mpFontTexture->Bind(0);
smGlyphVertices->Bind(); smGlyphVertices->Bind();
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
// Initialize some more stuff before we start the character loop // Initialize some more stuff before we start the character loop
CVector2f PrintHead(-1.f, 1.f); CVector2f PrintHead(-1.f, 1.f);
CTransform4f PtScale = CTransform4f::ScaleMatrix(PtsToFloat(1)); const CTransform4f PtScale = CTransform4f::ScaleMatrix(PtsToFloat(1));
SGlyph *pPrevGlyph = nullptr; SGlyph *pPrevGlyph = nullptr;
float Scale; float Scale;
if (FontSize == CFONT_DEFAULT_SIZE) Scale = 1.f; if (FontSize == CFONT_DEFAULT_SIZE)
else Scale = (float) FontSize / (mDefaultSize != 0 ? mDefaultSize : 18); Scale = 1.f;
else
Scale = static_cast<float>(FontSize) / (mDefaultSize != 0 ? mDefaultSize : 18);
for (uint32 iChar = 0; iChar < rkString.Length(); iChar++) for (uint32 iChar = 0; iChar < rkString.Length(); iChar++)
{ {
// Get character, check for newline // Get character, check for newline
char Char = rkString[iChar]; const char Char = rkString[iChar];
if (Char == '\n') if (Char == '\n')
{ {
@ -70,7 +71,8 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
// Get glyph // Get glyph
auto iGlyph = mGlyphs.find(Char); auto iGlyph = mGlyphs.find(Char);
if (iGlyph == mGlyphs.end()) continue; if (iGlyph == mGlyphs.end())
continue;
SGlyph *pGlyph = &iGlyph->second; SGlyph *pGlyph = &iGlyph->second;
// Apply left padding and kerning // Apply left padding and kerning
@ -78,7 +80,7 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
if (pPrevGlyph) if (pPrevGlyph)
{ {
if (pPrevGlyph->KerningIndex != -1) if (pPrevGlyph->KerningIndex != UINT32_MAX)
{ {
for (uint32 iKern = pPrevGlyph->KerningIndex; iKern < mKerningTable.size(); iKern++) for (uint32 iKern = pPrevGlyph->KerningIndex; iKern < mKerningTable.size(); iKern++)
{ {
@ -101,22 +103,24 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
if (Char == ' ') continue; if (Char == ' ') continue;
} }
float XTrans = PrintHead.X; const float XTrans = PrintHead.X;
float YTrans = PrintHead.Y + ((PtsToFloat(pGlyph->BaseOffset * 2) - PtsToFloat(mVerticalOffset * 2)) * Scale); const float YTrans = PrintHead.Y + ((PtsToFloat(pGlyph->BaseOffset * 2) - PtsToFloat(mVerticalOffset * 2)) * Scale);
CTransform4f GlyphTransform = PtScale; CTransform4f GlyphTransform = PtScale;
GlyphTransform.Scale(CVector3f((float) pGlyph->Width / 2, (float) pGlyph->Height, 1.f)); GlyphTransform.Scale(CVector3f(static_cast<float>(pGlyph->Width) / 2, static_cast<float>(pGlyph->Height), 1.f));
GlyphTransform.Scale(Scale); GlyphTransform.Scale(Scale);
GlyphTransform.Translate(CVector3f(XTrans, YTrans, 0.f)); GlyphTransform.Translate(CVector3f(XTrans, YTrans, 0.f));
// Get glyph layer // Get glyph layer
uint8 GlyphLayer = pGlyph->RGBAChannel; uint8 GlyphLayer = pGlyph->RGBAChannel;
if (mTextureFormat == 3) GlyphLayer *= 2; if (mTextureFormat == 3)
else if (mTextureFormat == 8) GlyphLayer = 3; GlyphLayer *= 2;
else if (mTextureFormat == 8)
GlyphLayer = 3;
// Load shader uniforms, buffer texture // Load shader uniforms, buffer texture
glUniformMatrix4fv(ModelMtxLoc, 1, GL_FALSE, (GLfloat*) &GlyphTransform); glUniformMatrix4fv(ModelMtxLoc, 1, GL_FALSE, (GLfloat*) &GlyphTransform);
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, &pGlyph->TexCoords); smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, pGlyph->TexCoords.data());
// Draw fill // Draw fill
glUniform1i(LayerLoc, GlyphLayer); glUniform1i(LayerLoc, GlyphLayer);
@ -124,12 +128,15 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
smGlyphIndices.DrawElements(); smGlyphIndices.DrawElements();
// Draw stroke // Draw stroke
if ((mTextureFormat == 1) || (mTextureFormat == 3) || (mTextureFormat == 8)) if (mTextureFormat == 1 || mTextureFormat == 3 || mTextureFormat == 8)
{ {
uint8 StrokeLayer; uint8 StrokeLayer = 0;
if (mTextureFormat == 1) StrokeLayer = 1; if (mTextureFormat == 1)
else if (mTextureFormat == 3) StrokeLayer = GlyphLayer + 1; StrokeLayer = 1;
else if (mTextureFormat == 8) StrokeLayer = GlyphLayer - 2; else if (mTextureFormat == 3)
StrokeLayer = GlyphLayer + 1;
else if (mTextureFormat == 8)
StrokeLayer = GlyphLayer - 2;
glUniform1i(LayerLoc, StrokeLayer); glUniform1i(LayerLoc, StrokeLayer);
glUniform4fv(ColorLoc, 1, &StrokeColor.R); glUniform4fv(ColorLoc, 1, &StrokeColor.R);
@ -152,21 +159,21 @@ void CFont::InitBuffers()
smGlyphVertices->SetActiveAttribs(EVertexAttribute::Position | EVertexAttribute::Tex0); smGlyphVertices->SetActiveAttribs(EVertexAttribute::Position | EVertexAttribute::Tex0);
smGlyphVertices->SetVertexCount(4); smGlyphVertices->SetVertexCount(4);
CVector3f Vertices[4] = { static constexpr std::array Vertices{
CVector3f( 0.f, 0.f, 0.f), CVector3f( 0.f, 0.f, 0.f),
CVector3f( 2.f, 0.f, 0.f), CVector3f( 2.f, 0.f, 0.f),
CVector3f( 0.f, -2.f, 0.f), CVector3f( 0.f, -2.f, 0.f),
CVector3f( 2.f, -2.f, 0.f) CVector3f( 2.f, -2.f, 0.f)
}; };
smGlyphVertices->BufferAttrib(EVertexAttribute::Position, Vertices); smGlyphVertices->BufferAttrib(EVertexAttribute::Position, Vertices.data());
CVector2f TexCoords[4] = { static constexpr std::array TexCoords{
CVector2f(0.f, 0.f), CVector2f(0.f, 0.f),
CVector2f(1.f, 0.f), CVector2f(1.f, 0.f),
CVector2f(0.f, 1.f), CVector2f(0.f, 1.f),
CVector2f(1.f, 1.f) CVector2f(1.f, 1.f)
}; };
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, TexCoords); smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, TexCoords.data());
smGlyphIndices.Reserve(4); smGlyphIndices.Reserve(4);
smGlyphIndices.AddIndex(0); smGlyphIndices.AddIndex(0);

View File

@ -9,11 +9,13 @@
#include "Core/OpenGL/CIndexBuffer.h" #include "Core/OpenGL/CIndexBuffer.h"
#include <Common/BasicTypes.h> #include <Common/BasicTypes.h>
#include <array>
#include <optional> #include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
#define CFONT_DEFAULT_SIZE -1 #define CFONT_DEFAULT_SIZE UINT32_MAX
class CRenderer; class CRenderer;
@ -25,27 +27,27 @@ class CFont : public CResource
static CIndexBuffer smGlyphIndices; // This is the index buffer used to draw glyphs. It uses a triangle strip. static CIndexBuffer smGlyphIndices; // This is the index buffer used to draw glyphs. It uses a triangle strip.
static bool smBuffersInitialized; // This bool indicates whether the vertex/index buffer have been initialized. Checked at the start of RenderString(). static bool smBuffersInitialized; // This bool indicates whether the vertex/index buffer have been initialized. Checked at the start of RenderString().
uint32 mUnknown; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes. uint32 mUnknown = 0; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes.
uint32 mLineHeight; // Height of each line, in points uint32 mLineHeight = 0; // Height of each line, in points
uint32 mLineMargin; // Gap between lines, in points - this is added to the line height uint32 mLineMargin = 0; // Gap between lines, in points - this is added to the line height
uint32 mVerticalOffset; // In points. This is used to reposition glyphs after the per-glyph vertical offset is applied uint32 mVerticalOffset = 0; // In points. This is used to reposition glyphs after the per-glyph vertical offset is applied
uint32 mDefaultSize; // In points. uint32 mDefaultSize = 0; // In points.
TString mFontName; // Self-explanatory TString mFontName; // Self-explanatory
TResPtr<CTexture> mpFontTexture; // The texture used by this font TResPtr<CTexture> mpFontTexture; // The texture used by this font
uint32 mTextureFormat; // Indicates which layers on the texture are for what - multiple glyph layers or fill/stroke uint32 mTextureFormat = 0; // Indicates which layers on the texture are for what - multiple glyph layers or fill/stroke
struct SGlyph struct SGlyph
{ {
uint16 Character; // The UTF-16 character that this glyph corresponds to uint16 Character; // The UTF-16 character that this glyph corresponds to
CVector2f TexCoords[4]; // The format only lists the min/max X/Y values; tracking absolute coordinates in memory is faster std::array<CVector2f, 4> TexCoords; // The format only lists the min/max X/Y values; tracking absolute coordinates in memory is faster
int32 LeftPadding; // The amount of padding applied left of this glyph, in points int32 LeftPadding; // The amount of padding applied left of this glyph, in points
int32 RightPadding; // The amount of padding applied right of this glyph, in points int32 RightPadding; // The amount of padding applied right of this glyph, in points
uint32 Width; // The width of the glyph, in points uint32 Width; // The width of the glyph, in points
uint32 Height; // The height of the glyph, in points uint32 Height; // The height of the glyph, in points
uint32 PrintAdvance; // How far the print head advances horizontally after printing this glyph, in points uint32 PrintAdvance; // How far the print head advances horizontally after printing this glyph, in points
uint32 BaseOffset; // Vertical offset for this glyph, in points; the font-wide offset is added to this uint32 BaseOffset; // Vertical offset for this glyph, in points; the font-wide offset is added to this
uint32 KerningIndex; // Index into the kerning table of the first kerning pair for this glyph. -1 if no pairs. uint32 KerningIndex; // Index into the kerning table of the first kerning pair for this glyph. -1 if no pairs.
uint8 RGBAChannel; // Fonts can store multiple glyphs in the same space on different RGBA channels. This value corresponds to R, G, B, or A. uint8 RGBAChannel; // Fonts can store multiple glyphs in the same space on different RGBA channels. This value corresponds to R, G, B, or A.
}; };
std::unordered_map<uint16, SGlyph> mGlyphs; std::unordered_map<uint16, SGlyph> mGlyphs;
@ -53,23 +55,23 @@ class CFont : public CResource
{ {
uint16 CharacterA; // Left character uint16 CharacterA; // Left character
uint16 CharacterB; // Right character uint16 CharacterB; // Right character
int32 Adjust; // The horizontal offset to apply to CharacterB if this pair is encountered, in points int32 Adjust; // The horizontal offset to apply to CharacterB if this pair is encountered, in points
}; };
std::vector<SKerningPair> mKerningTable; // The kerning table should be laid out in alphabetical order for the indices to work properly std::vector<SKerningPair> mKerningTable; // The kerning table should be laid out in alphabetical order for the indices to work properly
public: public:
CFont(CResourceEntry *pEntry = 0); explicit CFont(CResourceEntry *pEntry = nullptr);
~CFont(); ~CFont() override;
CDependencyTree* BuildDependencyTree() const; std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio, CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
CVector2f Position = CVector2f(0,0), CVector2f Position = CVector2f(0,0),
CColor FillColor = CColor::skWhite, CColor StrokeColor = CColor::skBlack, CColor FillColor = CColor::White(), CColor StrokeColor = CColor::Black(),
uint32 FontSize = CFONT_DEFAULT_SIZE); uint32 FontSize = CFONT_DEFAULT_SIZE);
// Accessors // Accessors
inline TString FontName() const { return mFontName; } TString FontName() const { return mFontName; }
inline CTexture* Texture() const { return mpFontTexture; } CTexture* Texture() const { return mpFontTexture; }
private: private:
static void InitBuffers(); static void InitBuffers();
static void ShutdownBuffers(); static void ShutdownBuffers();

View File

@ -1,20 +1,14 @@
#include "CLight.h" #include "CLight.h"
#include "Core/Render/CGraphics.h" #include "Core/Render/CGraphics.h"
#include <Common/Common.h> #include <Common/Common.h>
#include <cfloat>
#include <cmath> #include <cmath>
#include <float.h>
#define CLIGHT_NO_RADIUS 0x40 constexpr uint32_t CLIGHT_NO_RADIUS = 0x40;
#define CLIGHT_NO_INTENSITY 0x80 constexpr uint32_t CLIGHT_NO_INTENSITY = 0x80;
CLight::CLight() CLight::CLight()
: mPosition(skDefaultLightPos) : mDirtyFlags(CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY)
, mDirection(skDefaultLightDir)
, mDistAttenCoefficients(0.f, 1.f, 0.f)
, mAngleAttenCoefficients(0.f, 1.f, 0.f)
, mCachedRadius(0.f)
, mCachedIntensity(0.f)
, mDirtyFlags(CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY)
{ {
} }
@ -76,7 +70,7 @@ float CLight::CalculateIntensity() const
if (mType == ELightType::Custom) if (mType == ELightType::Custom)
coef = mAngleAttenCoefficients.X; coef = mAngleAttenCoefficients.X;
return coef * std::max(mColor.R, std::max(mColor.G, mColor.B)); return coef * std::max({mColor.R, mColor.G, mColor.B});
#if 0 #if 0
// Get the color component with the greatest numeric value // Get the color component with the greatest numeric value
float Greatest = (mColor.G >= mColor.B) ? mColor.G : mColor.B; float Greatest = (mColor.G >= mColor.B) ? mColor.G : mColor.B;
@ -88,13 +82,14 @@ float CLight::CalculateIntensity() const
} }
// As is this one... partly // As is this one... partly
CVector3f CLight::CalculateSpotAngleAtten() CVector3f CLight::CalculateSpotAngleAtten() const
{ {
if (mType != ELightType::Spot) return CVector3f(1.f, 0.f, 0.f); if (mType != ELightType::Spot)
return CVector3f(1.f, 0.f, 0.f);
float RadianCutoff = mSpotCutoff * (3.1415927f / 180.f); const float RadianCutoff = mSpotCutoff * (3.1415927f / 180.f);
float RadianCosine = cosf(RadianCutoff); const float RadianCosine = cosf(RadianCutoff);
float InvCosine = 1.f - RadianCosine; const float InvCosine = 1.f - RadianCosine;
return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine); return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine);
} }
@ -102,7 +97,7 @@ CVector3f CLight::CalculateSpotAngleAtten()
// ************ ACCESSORS ************ // ************ ACCESSORS ************
float CLight::GetRadius() const float CLight::GetRadius() const
{ {
if (mDirtyFlags & CLIGHT_NO_RADIUS) if ((mDirtyFlags & CLIGHT_NO_RADIUS) != 0)
{ {
mCachedRadius = CalculateRadius(); mCachedRadius = CalculateRadius();
mDirtyFlags &= ~CLIGHT_NO_RADIUS; mDirtyFlags &= ~CLIGHT_NO_RADIUS;
@ -113,7 +108,7 @@ float CLight::GetRadius() const
float CLight::GetIntensity() const float CLight::GetIntensity() const
{ {
if (mDirtyFlags & CLIGHT_NO_INTENSITY) if ((mDirtyFlags & CLIGHT_NO_INTENSITY) != 0)
{ {
mCachedIntensity = CalculateIntensity(); mCachedIntensity = CalculateIntensity();
mDirtyFlags &= ~CLIGHT_NO_INTENSITY; mDirtyFlags &= ~CLIGHT_NO_INTENSITY;
@ -131,7 +126,7 @@ void CLight::SetColor(const CColor& rkColor)
void CLight::SetSpotCutoff(float Cutoff) void CLight::SetSpotCutoff(float Cutoff)
{ {
mSpotCutoff = Cutoff * 0.5f; mSpotCutoff = Cutoff * 0.5f;
CalculateSpotAngleAtten(); mAngleAttenCoefficients = CalculateSpotAngleAtten();
} }
void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC) void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC)
@ -198,8 +193,9 @@ CStructProperty* CLight::GetProperties() const
// ************ OTHER ************ // ************ OTHER ************
void CLight::Load() const void CLight::Load() const
{ {
uint8 Index = (uint8) CGraphics::sNumLights; const auto Index = static_cast<uint8>(CGraphics::sNumLights);
if (Index >= 8) return; if (Index >= CGraphics::sLightBlock.Lights.size())
return;
CGraphics::SLightBlock::SGXLight *pLight = &CGraphics::sLightBlock.Lights[Index]; CGraphics::SLightBlock::SGXLight *pLight = &CGraphics::sLightBlock.Lights[Index];
@ -288,7 +284,3 @@ CLight CLight::BuildCustom(const CVector3f& rkPosition, const CVector3f& rkDirec
pLight.mAngleAttenCoefficients.Z = AngleAttenC * AngleAttenC; pLight.mAngleAttenCoefficients.Z = AngleAttenC * AngleAttenC;
return pLight; return pLight;
} }
// ************ CONSTANTS ************
const CVector3f CLight::skDefaultLightPos(0.f, 0.f, 0.f);
const CVector3f CLight::skDefaultLightDir(0.f,-1.f, 0.f);

View File

@ -19,17 +19,17 @@ enum class ELightType
class CLight class CLight
{ {
ELightType mType; ELightType mType{};
uint32 mLayerIndex; uint32 mLayerIndex = 0;
CVector3f mPosition; CVector3f mPosition{skDefaultLightPos};
CVector3f mDirection; CVector3f mDirection{skDefaultLightDir};
CColor mColor; CColor mColor;
float mSpotCutoff; float mSpotCutoff = 0.0f;
CVector3f mDistAttenCoefficients; CVector3f mDistAttenCoefficients{0.f, 1.f, 0.f};
CVector3f mAngleAttenCoefficients; CVector3f mAngleAttenCoefficients{0.f, 1.f, 0.f};
mutable float mCachedRadius; mutable float mCachedRadius = 0.0f;
mutable float mCachedIntensity; mutable float mCachedIntensity = 0.0f;
mutable uint8 mDirtyFlags; mutable uint8 mDirtyFlags;
public: public:
@ -39,21 +39,21 @@ private:
// Data Manipulation // Data Manipulation
float CalculateRadius() const; float CalculateRadius() const;
float CalculateIntensity() const; float CalculateIntensity() const;
CVector3f CalculateSpotAngleAtten(); CVector3f CalculateSpotAngleAtten() const;
public: public:
// Accessors // Accessors
inline ELightType Type() const { return mType; } ELightType Type() const { return mType; }
inline uint32 LayerIndex() const { return mLayerIndex; } uint32 LayerIndex() const { return mLayerIndex; }
inline CVector3f Position() const { return mPosition; } CVector3f Position() const { return mPosition; }
inline CVector3f Direction() const { return mDirection; } CVector3f Direction() const { return mDirection; }
inline CColor Color() const { return mColor; } CColor Color() const { return mColor; }
inline CVector3f DistAttenuation() const { return mDistAttenCoefficients; } CVector3f DistAttenuation() const { return mDistAttenCoefficients; }
inline CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; } CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; }
inline void SetLayer(uint32 Index) { mLayerIndex = Index; } void SetLayer(uint32 Index) { mLayerIndex = Index; }
inline void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; } void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; }
inline void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; } void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; }
float GetRadius() const; float GetRadius() const;
float GetIntensity() const; float GetIntensity() const;
@ -77,8 +77,8 @@ public:
float AngleAttenA, float AngleAttenB, float AngleAttenC); float AngleAttenA, float AngleAttenB, float AngleAttenC);
// Constants // Constants
static const CVector3f skDefaultLightPos; static constexpr CVector3f skDefaultLightPos{0.f, 0.f, 0.f};
static const CVector3f skDefaultLightDir; static constexpr CVector3f skDefaultLightDir{0.f, -1.f, 0.f};
}; };
#endif // CLIGHT_H #endif // CLIGHT_H

View File

@ -10,13 +10,13 @@ class CMapArea : public CResource
CAssetID mNameString; CAssetID mNameString;
public: public:
CMapArea(CResourceEntry *pEntry = 0) explicit CMapArea(CResourceEntry *pEntry = nullptr)
: CResource(pEntry) : CResource(pEntry)
{} {}
CDependencyTree* BuildDependencyTree() const std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{ {
CDependencyTree *pTree = new CDependencyTree(); auto pTree = std::make_unique<CDependencyTree>();
pTree->AddDependency(mNameString); pTree->AddDependency(mNameString);
return pTree; return pTree;
} }

View File

@ -6,45 +6,18 @@
#include "Core/OpenGL/CShaderGenerator.h" #include "Core/OpenGL/CShaderGenerator.h"
#include <Common/Hash/CFNV1A.h> #include <Common/Hash/CFNV1A.h>
#include <iostream>
#include <GL/glew.h> #include <GL/glew.h>
uint64 CMaterial::sCurrentMaterial = 0; uint64 CMaterial::sCurrentMaterial = 0;
CColor CMaterial::sCurrentTint = CColor::skWhite; CColor CMaterial::sCurrentTint = CColor::White();
std::map<uint64, CMaterial::SMaterialShader> CMaterial::smShaderMap; std::map<uint64, CMaterial::SMaterialShader> CMaterial::smShaderMap;
CMaterial::CMaterial() CMaterial::CMaterial() = default;
: mpShader(nullptr)
, mShaderStatus(EShaderStatus::NoShader)
, mRecalcHash(true)
, mVersion(EGame::Invalid)
, mOptions(EMaterialOption::None)
, mVtxDesc(EVertexAttribute::None)
, mBlendSrcFac(GL_ONE)
, mBlendDstFac(GL_ZERO)
, mLightingEnabled(true)
, mEchoesUnknownA(0)
, mEchoesUnknownB(0)
, mpIndirectTexture(nullptr)
, mpNextDrawPassMaterial(nullptr)
, mpBloomMaterial(nullptr)
{}
CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc) CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc)
: mpShader(nullptr) : mVersion(Version)
, mShaderStatus(EShaderStatus::NoShader)
, mRecalcHash(true)
, mVersion(Version)
, mOptions(EMaterialOption::DepthWrite | EMaterialOption::ColorWrite) , mOptions(EMaterialOption::DepthWrite | EMaterialOption::ColorWrite)
, mVtxDesc(VtxDesc) , mVtxDesc(VtxDesc)
, mBlendSrcFac(GL_ONE)
, mBlendDstFac(GL_ZERO)
, mLightingEnabled(true)
, mEchoesUnknownA(0)
, mEchoesUnknownB(0)
, mpIndirectTexture(nullptr)
, mpNextDrawPassMaterial(nullptr)
, mpBloomMaterial(nullptr)
{} {}
CMaterial::~CMaterial() CMaterial::~CMaterial()
@ -59,10 +32,8 @@ std::unique_ptr<CMaterial> CMaterial::Clone()
pOut->mVersion = mVersion; pOut->mVersion = mVersion;
pOut->mOptions = mOptions; pOut->mOptions = mOptions;
pOut->mVtxDesc = mVtxDesc; pOut->mVtxDesc = mVtxDesc;
for (uint32 iKonst = 0; iKonst < 4; iKonst++) pOut->mKonstColors = mKonstColors;
pOut->mKonstColors[iKonst] = mKonstColors[iKonst]; pOut->mTevColors = mTevColors;
for (uint32 iTev = 0; iTev < 4; iTev++)
pOut->mTevColors[iTev] = mTevColors[iTev];
pOut->mBlendSrcFac = mBlendSrcFac; pOut->mBlendSrcFac = mBlendSrcFac;
pOut->mBlendDstFac = mBlendDstFac; pOut->mBlendDstFac = mBlendDstFac;
pOut->mLightingEnabled = mLightingEnabled; pOut->mLightingEnabled = mLightingEnabled;
@ -126,25 +97,25 @@ void CMaterial::GenerateShader(bool AllowRegen /*= true*/)
void CMaterial::ClearShader() void CMaterial::ClearShader()
{ {
if (mpShader) if (mpShader == nullptr)
return;
const auto Find = smShaderMap.find(mParametersHash);
ASSERT(Find != smShaderMap.cend());
SMaterialShader& rShader = Find->second;
ASSERT(rShader.pShader == mpShader);
rShader.NumReferences--;
if (rShader.NumReferences == 0)
{ {
auto Find = smShaderMap.find(mParametersHash); delete mpShader;
ASSERT(Find != smShaderMap.end()); smShaderMap.erase(Find);
SMaterialShader& rShader = Find->second;
ASSERT(rShader.pShader == mpShader);
rShader.NumReferences--;
if (rShader.NumReferences == 0)
{
delete mpShader;
smShaderMap.erase(Find);
}
mpShader = nullptr;
mShaderStatus = EShaderStatus::NoShader;
} }
mpShader = nullptr;
mShaderStatus = EShaderStatus::NoShader;
} }
bool CMaterial::SetCurrent(FRenderOptions Options) bool CMaterial::SetCurrent(FRenderOptions Options)
@ -162,7 +133,7 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
// Set RGB blend equation - force to ZERO/ONE if alpha is disabled // Set RGB blend equation - force to ZERO/ONE if alpha is disabled
GLenum srcRGB, dstRGB, srcAlpha, dstAlpha; GLenum srcRGB, dstRGB, srcAlpha, dstAlpha;
if (Options & ERenderOption::NoAlpha) { if ((Options & ERenderOption::NoAlpha) != 0) {
srcRGB = GL_ONE; srcRGB = GL_ONE;
dstRGB = GL_ZERO; dstRGB = GL_ZERO;
} else { } else {
@ -170,7 +141,7 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
dstRGB = mBlendDstFac; dstRGB = mBlendDstFac;
} }
if (mOptions & EMaterialOption::ZeroDestAlpha) { if ((mOptions & EMaterialOption::ZeroDestAlpha) != 0) {
srcAlpha = GL_ZERO; srcAlpha = GL_ZERO;
dstAlpha = GL_ZERO; dstAlpha = GL_ZERO;
} else { } else {
@ -181,43 +152,45 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
// Set konst inputs // Set konst inputs
for (uint32 iKonst = 0; iKonst < 4; iKonst++) CGraphics::sPixelBlock.Konst = mKonstColors;
CGraphics::sPixelBlock.Konst[iKonst] = mKonstColors[iKonst];
// Set TEV registers // Set TEV registers
if (mVersion >= EGame::Corruption) if (mVersion >= EGame::Corruption)
for (uint32 iTev = 0; iTev < 4; iTev++) {
CGraphics::sPixelBlock.TevColor[iTev] = mTevColors[iTev]; CGraphics::sPixelBlock.TevColor = mTevColors;
}
// Set color channels // Set color channels
// COLOR0_Amb,Mat is initialized by the node instead of by the material // COLOR0_Amb,Mat is initialized by the node instead of by the material
// Set depth write - force on if alpha is disabled (lots of weird depth issues otherwise) // Set depth write - force on if alpha is disabled (lots of weird depth issues otherwise)
if ((mOptions & EMaterialOption::DepthWrite) || (Options & ERenderOption::NoAlpha)) glDepthMask(GL_TRUE); if ((mOptions & EMaterialOption::DepthWrite) != 0 || (Options & ERenderOption::NoAlpha) != 0)
else glDepthMask(GL_FALSE); glDepthMask(GL_TRUE);
else
glDepthMask(GL_FALSE);
// Set color/alpha write // Set color/alpha write
GLboolean bColorWrite = mOptions.HasFlag(EMaterialOption::ColorWrite); const GLboolean bColorWrite = mOptions.HasFlag(EMaterialOption::ColorWrite);
GLboolean bAlphaWrite = mOptions.HasFlag(EMaterialOption::AlphaWrite); const GLboolean bAlphaWrite = mOptions.HasFlag(EMaterialOption::AlphaWrite);
glColorMask(bColorWrite, bColorWrite, bColorWrite, bAlphaWrite); glColorMask(bColorWrite, bColorWrite, bColorWrite, bAlphaWrite);
// Load uniforms // Load uniforms
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++) for (size_t iPass = 0; iPass < mPasses.size(); iPass++)
mPasses[iPass]->SetAnimCurrent(Options, iPass); mPasses[iPass]->SetAnimCurrent(Options, iPass);
sCurrentMaterial = HashParameters(); sCurrentMaterial = HashParameters();
} }
else // If the passes are otherwise the same, update UV anims that use the model matrix
// If the passes are otherwise the same, update UV anims that use the model matrix
else
{ {
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++) for (size_t iPass = 0; iPass < mPasses.size(); iPass++)
{ {
EUVAnimMode mode = mPasses[iPass]->AnimMode(); const EUVAnimMode mode = mPasses[iPass]->AnimMode();
if ((mode == EUVAnimMode::InverseMV) || (mode == EUVAnimMode::InverseMVTranslated) || if (mode == EUVAnimMode::InverseMV || mode == EUVAnimMode::InverseMVTranslated ||
(mode == EUVAnimMode::ModelMatrix) || (mode == EUVAnimMode::SimpleMode)) mode == EUVAnimMode::ModelMatrix || mode == EUVAnimMode::SimpleMode)
{
mPasses[iPass]->SetAnimCurrent(Options, iPass); mPasses[iPass]->SetAnimCurrent(Options, iPass);
}
} }
} }
@ -240,23 +213,23 @@ uint64 CMaterial::HashParameters()
{ {
if (mRecalcHash) if (mRecalcHash)
{ {
CFNV1A Hash(CFNV1A::k64Bit); CFNV1A Hash(CFNV1A::EHashLength::k64Bit);
Hash.HashLong((int) mVersion); Hash.HashLong(static_cast<int>(mVersion));
Hash.HashLong(mOptions); Hash.HashLong(mOptions);
Hash.HashLong(mVtxDesc); Hash.HashLong(mVtxDesc);
Hash.HashData(mKonstColors, sizeof(CColor) * 4); Hash.HashData(mKonstColors.data(), sizeof(mKonstColors));
Hash.HashData(mTevColors, sizeof(CColor) * 4); Hash.HashData(mTevColors.data(), sizeof(mTevColors));
Hash.HashLong(mBlendSrcFac); Hash.HashLong(mBlendSrcFac);
Hash.HashLong(mBlendDstFac); Hash.HashLong(mBlendDstFac);
Hash.HashByte(mLightingEnabled); Hash.HashByte(mLightingEnabled);
Hash.HashLong(mEchoesUnknownA); Hash.HashLong(mEchoesUnknownA);
Hash.HashLong(mEchoesUnknownB); Hash.HashLong(mEchoesUnknownB);
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++) for (auto& pass : mPasses)
mPasses[iPass]->HashParameters(Hash); pass->HashParameters(Hash);
uint64 NewHash = Hash.GetHash64(); const uint64 NewHash = Hash.GetHash64();
if (mParametersHash != NewHash) if (mParametersHash != NewHash)
ClearShader(); ClearShader();
@ -274,15 +247,15 @@ void CMaterial::Update()
mShaderStatus = EShaderStatus::NoShader; mShaderStatus = EShaderStatus::NoShader;
} }
void CMaterial::SetNumPasses(uint32 NumPasses) void CMaterial::SetNumPasses(size_t NumPasses)
{ {
uint32 OldCount = mPasses.size(); const size_t OldCount = mPasses.size();
mPasses.resize(NumPasses); mPasses.resize(NumPasses);
if (NumPasses > OldCount) if (NumPasses > OldCount)
{ {
for (uint32 iPass = OldCount; iPass < NumPasses; iPass++) for (size_t i = OldCount; i < NumPasses; i++)
mPasses[iPass] = std::make_unique<CMaterialPass>(this); mPasses[i] = std::make_unique<CMaterialPass>(this);
} }
mRecalcHash = true; mRecalcHash = true;

View File

@ -74,23 +74,23 @@ private:
static CColor sCurrentTint; // The tint for the currently bound material static CColor sCurrentTint; // The tint for the currently bound material
// Members // Members
TString mName; // Name of the material TString mName; // Name of the material
CShader *mpShader; // This material's generated shader. Created with GenerateShader(). CShader *mpShader = nullptr; // This material's generated shader. Created with GenerateShader().
EShaderStatus mShaderStatus; // A status variable so that PWE won't crash if a shader fails to compile. EShaderStatus mShaderStatus{EShaderStatus::NoShader}; // A status variable so that PWE won't crash if a shader fails to compile.
uint64 mParametersHash; // A hash of all the parameters that can identify this TEV setup. uint64 mParametersHash = 0; // A hash of all the parameters that can identify this TEV setup.
bool mRecalcHash; // Indicates the hash needs to be recalculated. Set true when parameters are changed. bool mRecalcHash = true; // Indicates the hash needs to be recalculated. Set true when parameters are changed.
EGame mVersion; EGame mVersion{EGame::Invalid};
FMaterialOptions mOptions; // See the EMaterialOption enum above FMaterialOptions mOptions{EMaterialOption::None}; // See the EMaterialOption enum above
FVertexDescription mVtxDesc; // Descriptor of vertex attributes used by this material FVertexDescription mVtxDesc{EVertexAttribute::None}; // Descriptor of vertex attributes used by this material
CColor mKonstColors[4]; // Konst color values for TEV std::array<CColor, 4> mKonstColors; // Konst color values for TEV
CColor mTevColors[4]; // Initial TEV color register values (for MP3 materials only) std::array<CColor, 4> mTevColors; // Initial TEV color register values (for MP3 materials only)
GLenum mBlendSrcFac; // Source blend factor GLenum mBlendSrcFac{GL_ONE}; // Source blend factor
GLenum mBlendDstFac; // Dest blend factor GLenum mBlendDstFac{GL_ZERO}; // Dest blend factor
bool mLightingEnabled; // Color channel control flags; indicate whether lighting is enabled bool mLightingEnabled = true; // Color channel control flags; indicate whether lighting is enabled
uint32 mEchoesUnknownA; // First unknown value introduced in Echoes. Included for cooking. uint32 mEchoesUnknownA = 0; // First unknown value introduced in Echoes. Included for cooking.
uint32 mEchoesUnknownB; // Second unknown value introduced in Echoes. Included for cooking. uint32 mEchoesUnknownB = 0; // Second unknown value introduced in Echoes. Included for cooking.
TResPtr<CTexture> mpIndirectTexture; // Optional texture used for the indirect stage for reflections TResPtr<CTexture> mpIndirectTexture; // Optional texture used for the indirect stage for reflections
std::vector<std::unique_ptr<CMaterialPass>> mPasses; std::vector<std::unique_ptr<CMaterialPass>> mPasses;
@ -123,37 +123,37 @@ public:
bool SetCurrent(FRenderOptions Options); bool SetCurrent(FRenderOptions Options);
uint64 HashParameters(); uint64 HashParameters();
void Update(); void Update();
void SetNumPasses(uint32 NumPasses); void SetNumPasses(size_t NumPasses);
// Accessors // Accessors
inline TString Name() const { return mName; } TString Name() const { return mName; }
inline EGame Version() const { return mVersion; } EGame Version() const { return mVersion; }
inline FMaterialOptions Options() const { return mOptions; } FMaterialOptions Options() const { return mOptions; }
inline FVertexDescription VtxDesc() const { return mVtxDesc; } FVertexDescription VtxDesc() const { return mVtxDesc; }
inline GLenum BlendSrcFac() const { return mBlendSrcFac; } GLenum BlendSrcFac() const { return mBlendSrcFac; }
inline GLenum BlendDstFac() const { return mBlendDstFac; } GLenum BlendDstFac() const { return mBlendDstFac; }
inline CColor Konst(uint32 KIndex) const { return mKonstColors[KIndex]; } CColor Konst(size_t KIndex) const { return mKonstColors[KIndex]; }
inline CColor TevColor(ETevOutput Out) const { return mTevColors[int(Out)]; } CColor TevColor(ETevOutput Out) const { return mTevColors[static_cast<size_t>(Out)]; }
inline CTexture* IndTexture() const { return mpIndirectTexture; } CTexture* IndTexture() const { return mpIndirectTexture; }
inline bool IsLightingEnabled() const { return mLightingEnabled; } bool IsLightingEnabled() const { return mLightingEnabled; }
inline uint32 EchoesUnknownA() const { return mEchoesUnknownA; } uint32 EchoesUnknownA() const { return mEchoesUnknownA; }
inline uint32 EchoesUnknownB() const { return mEchoesUnknownB; } uint32 EchoesUnknownB() const { return mEchoesUnknownB; }
inline uint32 PassCount() const { return mPasses.size(); } uint32 PassCount() const { return mPasses.size(); }
inline CMaterialPass* Pass(uint32 PassIndex) const { return mPasses[PassIndex].get(); } CMaterialPass* Pass(size_t PassIndex) const { return mPasses[PassIndex].get(); }
inline CMaterial* GetNextDrawPass() const { return mpNextDrawPassMaterial.get(); } CMaterial* GetNextDrawPass() const { return mpNextDrawPassMaterial.get(); }
inline CMaterial* GetBloomVersion() const { return mpBloomMaterial.get(); } CMaterial* GetBloomVersion() const { return mpBloomMaterial.get(); }
inline void SetName(const TString& rkName) { mName = rkName; } void SetName(TString rkName) { mName = std::move(rkName); }
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); } void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); } void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; } void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
inline void SetKonst(const CColor& Konst, uint32 KIndex) { mKonstColors[KIndex] = Konst; Update(); } void SetKonst(const CColor& Konst, size_t KIndex) { mKonstColors[KIndex] = Konst; Update(); }
inline void SetTevColor(const CColor& Color, ETevOutput Out) { mTevColors[int(Out)] = Color; } void SetTevColor(const CColor& Color, ETevOutput Out) { mTevColors[static_cast<size_t>(Out)] = Color; }
inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; } void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); } void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }
// Static // Static
inline static void KillCachedMaterial() { sCurrentMaterial = 0; } static void KillCachedMaterial() { sCurrentMaterial = 0; }
}; };
#endif // MATERIAL_H #endif // MATERIAL_H

Some files were not shown because too many files have changed in this diff Show More