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)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
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)
add_compile_definitions(PUBLIC_RELEASE=1)
message(STATUS "Enabled public release mode")

View File

@ -7,7 +7,7 @@
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${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": "",
"ctestCommandArgs": "",
"variables": []
@ -19,7 +19,7 @@
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${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": "",
"ctestCommandArgs": "",
"variables": []

View File

@ -20,7 +20,7 @@ VS_VERSION_INFO VERSIONINFO
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "041904b0"
BLOCK "040904b0"
BEGIN
VALUE "Comments", PRODUCT_COMMENTS
VALUE "CompanyName", PRODUCT_COMPANY_NAME
@ -35,6 +35,6 @@ BEGIN
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x419, 1200
VALUE "Translation", 0x409, 1200
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
# integrate with Dew.
#
cmake_minimum_required(VERSION 3.2)
cmake_minimum_required(VERSION 3.12)
function(integrate_dew)
#
@ -17,6 +17,13 @@ function(integrate_dew)
return()
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
#
@ -41,7 +48,8 @@ function(integrate_dew)
message(FATAL_ERROR "Failed to install dew with pip: result: ${install_dew_result}.")
endif()
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}"
RESULT_VARIABLE dew_res)
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
#
set(needs_new_prefix TRUE)
foreach (path ${CMAKE_PREFIX_PATH})
if (path STREQUAL "${dew_cmake_prefix_path}")
if ("${dew_cmake_prefix_path}" IN_LIST CMAKE_PREFIX_PATH)
set(needs_new_prefix FALSE)
break()
endif()
endforeach()
#
# Check if we have already added the dew cmake module directory to CMAKE_MODULE_PATH
#
set(needs_new_module_path TRUE)
foreach (path ${CMAKE_MODULE_PATH})
if (path STREQUAL "${dew_cmake_module_path}")
if ("${dew_cmake_module_path}" IN_LIST CMAKE_MODULE_PATH)
set(needs_new_module_path FALSE)
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}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${dew_cmake_prefix_path}" CACHE PATH "" FORCE)
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}")
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",
"type": "git",
"head": "master",
"ref": "a1284ae06586b958f36b8ecaba29390835ed2820"
"ref": "f147e1235646b849f78a8574a6d554214b70792d"
},
{
"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);
}
CAreaAttributes::~CAreaAttributes()
{
}
CAreaAttributes::~CAreaAttributes() = default;
void CAreaAttributes::SetObject(CScriptObject *pObj)
{

View File

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

View File

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

View File

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

View File

@ -4,12 +4,12 @@
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Script/Property/Properties.h"
enum EWorldLightingOptions
enum class EWorldLightingOptions
{
eUnknown1 = 0,
eNormalLighting = 1,
eUnknown2 = 2,
eDisableWorldLighting = 3
Unknown1,
NormalLighting,
Unknown2,
DisableWorldLighting,
};
class CLightParameters
@ -35,14 +35,14 @@ public:
}
}
inline int LightLayerIndex() const
int LightLayerIndex() const
{
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)
find_package(tinyxml2 CONFIG REQUIRED)
find_package(nod CONFIG REQUIRED)
find_package(logvisor CONFIG REQUIRED)
find_package(nod CONFIG REQUIRED)
find_package(lzokay CONFIG REQUIRED)
find_package(OpenGL 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& kKnotB = kControlPoints[3];
CVector2f Range = kKnotB - kKnotA;
[[maybe_unused]] const CVector2f Range = kKnotB - kKnotA;
CVector2f KnotAToTangentA = kTangentA - kKnotA;
float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X);
const CVector2f KnotAToTangentA = kTangentA - kKnotA;
const float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X);
CVector2f KnotBToTangentB = kKnotB - kTangentB;
float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X);
const CVector2f KnotBToTangentB = kKnotB - kTangentB;
[[maybe_unused]] const float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X);
#if 0
// todo: better organization and better variable names

View File

@ -22,21 +22,21 @@ public:
class CMayaSpline
{
uint mPreInfinity; // 0x00
uint mPostInfinity; // 0x04
uint mPreInfinity = 0; // 0x00
uint mPostInfinity = 0; // 0x04
std::vector<CMayaSplineKnot> mKnots; // 0x08, 0x0C, 0x10
uint mClampMode; // 0x14 - clamp mode
float mMinAmplitude; // 0x18
float mMaxAmplitude; // 0x1C
uint mClampMode = 0; // 0x14 - clamp mode
float mMinAmplitude = 0.0f; // 0x18
float mMaxAmplitude = 0.0f; // 0x1C
mutable int mCachedKnotIndex; // 0x20
mutable int mUnknown1; // 0x24
mutable uint8 mDirtyFlags; // 0x28
mutable float mCachedMinTime; // 0x2C
mutable float mCachedHermiteCoefficients[4]; // 0x30, 0x34, 0x38, 0x3C
mutable int mCachedKnotIndex = 0; // 0x20
mutable int mUnknown1 = 0; // 0x24
mutable uint8 mDirtyFlags = 0; // 0x28
mutable float mCachedMinTime = 0.0f; // 0x2C
mutable float mCachedHermiteCoefficients[4] = {}; // 0x30, 0x34, 0x38, 0x3C
public:
CMayaSpline() {}
CMayaSpline() = default;
uint GetKnotCount() const;
const std::vector<CMayaSplineKnot>& GetKnots() 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)
{
mBoxIntersectList.emplace_back(SRayIntersection());
SRayIntersection& rIntersection = mBoxIntersectList.back();
SRayIntersection& rIntersection = mBoxIntersectList.emplace_back();
rIntersection.pNode = pNode;
rIntersection.ComponentIndex = ComponentIndex;
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
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)
AddNode(pNode, iSurf, SurfResult.second);
if (intersects)
AddNode(pNode, iSurf, distance);
}
}
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& rkViewInfo)
{
// Sort nodes by distance from ray
mBoxIntersectList.sort(
[](const SRayIntersection& rkLeft, const SRayIntersection& rkRight) -> bool
{
return (rkLeft.Distance < rkRight.Distance);
mBoxIntersectList.sort([](const auto& rkLeft, const auto& rkRight) {
return rkLeft.Distance < rkRight.Distance;
});
// Now do more precise intersection tests on geometry
SRayIntersection Result;
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
// 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;
// Otherwise, more intersection tests...
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 ((!Result.Hit) || (MidResult.Distance <= Result.Distance))
if (!Result.Hit || MidResult.Distance <= Result.Distance)
Result = MidResult;
}
}
if (Result.Hit) Result.HitPoint = mRay.PointOnRay(Result.Distance);
if (Result.Hit)
Result.HitPoint = mRay.PointOnRay(Result.Distance);
return Result;
}

View File

@ -109,11 +109,11 @@ void GenerateAssetNames(CGameProject *pProj)
// Generate names for package named resources
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);
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
if (rkRes.Name.EndsWith("NODEPEND")) continue;
@ -166,17 +166,17 @@ void GenerateAssetNames(CGameProject *pProj)
ApplyGeneratedName(pSkyEntry, WorldDir + "sky/cooked/", WorldName + "_sky");
// 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);
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())
ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + "sky/sourceimages/", pPass->Texture()->Entry()->Name());
@ -198,7 +198,7 @@ void GenerateAssetNames(CGameProject *pProj)
}
// Areas
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
{
// Determine area name
TString AreaName = pWorld->AreaInternalName(iArea);
@ -209,7 +209,9 @@ void GenerateAssetNames(CGameProject *pProj)
// Rename area stuff
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);
CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
@ -237,12 +239,12 @@ void GenerateAssetNames(CGameProject *pProj)
uint32 LightmapNum = 0;
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);
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);
@ -278,11 +280,11 @@ void GenerateAssetNames(CGameProject *pProj)
}
// 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);
for (uint32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
for (size_t iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
CStructProperty* pProperties = pInst->Template()->Properties();
@ -407,30 +409,31 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<EResourceType::Model> It(pStore); It; ++It)
{
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);
for (uint32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
for (size_t iMat = 0; iMat < pSet->NumMaterials(); iMat++)
{
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);
bool IsLightmap = ( (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) ||
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF") );
const bool IsLightmap = (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) ||
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF");
if (IsLightmap)
{
CTexture *pLightmapTex = pPass->Texture();
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);
pTexEntry->SetHidden(true);
LightmapNum++;
@ -463,23 +466,23 @@ void GenerateAssetNames(CGameProject *pProj)
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();
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);
if (pSample && !pSample->IsNamed())
if (pSample != nullptr && !pSample->IsNamed())
{
TString SampleName;
if (pMacro->NumSamples() == 1)
SampleName = MacroName;
else
SampleName = TString::Format("%s_%d", *MacroName, iSamp);
SampleName = TString::Format("%s_%zu", *MacroName, iSamp);
ApplyGeneratedName(pSample, kSfxDir, SampleName);
}
@ -500,9 +503,9 @@ void GenerateAssetNames(CGameProject *pProj)
{
TString SetDir = It->DirectoryPath();
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);
@ -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())
{
TString TypeName = (
@ -561,17 +562,16 @@ void GenerateAssetNames(CGameProject *pProj)
std::set<CAnimPrimitive> 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();
if (pAnim)
if (pAnim != nullptr)
{
ApplyGeneratedName(pAnim->Entry(), SetDir, rkPrim.Name());
CAnimEventData *pEvents = pAnim->EventData();
if (pEvents)
if (pEvents != nullptr)
ApplyGeneratedName(pEvents->Entry(), SetDir, rkPrim.Name());
}
}
@ -586,11 +586,13 @@ void GenerateAssetNames(CGameProject *pProj)
for (TResourceIterator<EResourceType::StringTable> It(pStore); It; ++It)
{
if (It->IsNamed()) continue;
CStringTable *pString = (CStringTable*) It->Load();
if (It->IsNamed())
continue;
auto *pString = static_cast<CStringTable*>(It->Load());
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();
if (!String.IsEmpty())
@ -611,31 +613,33 @@ void GenerateAssetNames(CGameProject *pProj)
debugf("Processing scans");
for (TResourceIterator<EResourceType::Scan> It(pStore); It; ++It)
{
if (It->IsNamed()) continue;
CScan *pScan = (CScan*) It->Load();
if (It->IsNamed())
continue;
auto* pScan = static_cast<CScan*>(It->Load());
TString ScanName;
if (ScanName.IsEmpty())
{
CAssetID StringID = pScan->ScanStringPropertyRef().Get();
CStringTable *pString = (CStringTable*) gpResourceStore->LoadResource(StringID, EResourceType::StringTable);
if (pString) ScanName = pString->Entry()->Name();
const CAssetID StringID = pScan->ScanStringPropertyRef().Get();
if (const auto* pString = static_cast<CStringTable*>(gpResourceStore->LoadResource(StringID, EResourceType::StringTable)))
ScanName = pString->Entry()->Name();
}
ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName);
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 (pEntry) ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), "ScanFrame");
if (CResourceEntry* pEntry = pStore->FindEntry(kParms.GuiFrame))
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;
CResourceEntry *pImgEntry = pStore->FindEntry(ImageID);
if (pImgEntry) ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%d", *ScanName, iImg));
const CAssetID ImageID = kParms.ScanImages[iImg].Texture;
if (CResourceEntry* pImgEntry = pStore->FindEntry(ImageID))
ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%zu", *ScanName, iImg));
}
}
}
@ -646,15 +650,12 @@ void GenerateAssetNames(CGameProject *pProj)
debugf("Processing fonts");
for (TResourceIterator<EResourceType::Font> It(pStore); It; ++It)
{
CFont *pFont = (CFont*) It->Load();
if (pFont)
if (auto* pFont = static_cast<CFont*>(It->Load()))
{
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");
}
}

View File

@ -1,5 +1,8 @@
#include "CAssetNameMap.h"
constexpr char gkAssetMapPath[] = "resources/gameinfo/AssetNameMap";
constexpr char gkAssetMapExt[] = "xml";
bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
{
if (Path.IsEmpty())
@ -19,8 +22,8 @@ bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
else
{
debugf("Failed to load asset names; expected %s IDs, got %s",
mIDLength == k32Bit ? "32-bit" : "64-bit",
FileIDLength == k32Bit ? "32-bit" : "64-bit" );
mIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit",
FileIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit" );
return false;
}
}
@ -36,7 +39,7 @@ bool CAssetNameMap::SaveAssetNames(TString Path /*= ""*/)
if (Path.IsEmpty())
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);
Serialize(Writer);
return Writer.Save();
@ -58,7 +61,7 @@ bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rO
else
{
EGame Game = (ID.Length() == k32Bit ? EGame::Prime : EGame::Corruption);
EGame Game = (ID.Length() == EIDLength::k32Bit ? EGame::Prime : EGame::Corruption);
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
rOutName = ID.ToString();
rOutAutoGenDir = true;
@ -146,13 +149,14 @@ void CAssetNameMap::PostLoadValidate()
mIsValid = false;
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;
if (mUsedSet.find(rkInfo) != mUsedSet.end())
{
Dupes.insert(rkInfo);
}
else
{
mUsedSet.insert(rkInfo);
@ -180,25 +184,32 @@ void CAssetNameMap::PostLoadValidate()
{
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();
}
else
{
mIsValid = !FoundErrors;
}
}
TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength)
{
ASSERT(IDLength != kInvalidIDLength);
TString Suffix = (IDLength == k32Bit ? "32" : "64");
return gDataDir + gkAssetMapPath + Suffix + "." + gkAssetMapExt;
const char* const Suffix = (IDLength == EIDLength::k32Bit ? "32" : "64");
return gDataDir + gkAssetMapPath + Suffix + '.' + gkAssetMapExt;
}
TString CAssetNameMap::DefaultNameMapPath(EGame Game)
{
return DefaultNameMapPath( CAssetID::GameIDLength(Game) );
}
TString CAssetNameMap::GetExtension()
{
return gkAssetMapExt;
}

View File

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

View File

@ -5,72 +5,62 @@
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h"
#include "Core/Resource/Script/NGameList.h"
#include <algorithm>
#include <array>
// ************ IDependencyNode ************
IDependencyNode::~IDependencyNode()
{
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
delete mChildren[iChild];
}
IDependencyNode::~IDependencyNode() = default;
bool IDependencyNode::HasDependency(const CAssetID& rkID) const
bool IDependencyNode::HasDependency(const CAssetID& id) const
{
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
{
if (mChildren[iChild]->HasDependency(rkID))
return true;
}
return false;
return std::any_of(mChildren.cbegin(), mChildren.cend(),
[&id](const auto& entry) { return entry->HasDependency(id); });
}
void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const
{
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
mChildren[iChild]->GetAllResourceReferences(rOutSet);
for (const auto& child : mChildren)
child->GetAllResourceReferences(rOutSet);
}
void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData)
{
// 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);
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
// to support it when there aren't any array properties that contain any asset references anyway...
if (Type == EPropertyType::Struct)
{
ParseProperties(pParentEntry, TPropCast<CStructProperty>(pProp), pData);
}
else if (Type == EPropertyType::Sound)
{
uint32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pData);
if (SoundID != -1)
if (SoundID != UINT32_MAX)
{
CGameProject* pProj = pParentEntry->Project();
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
if (Info.pAudioGroup)
{
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), Info.pAudioGroup->ID());
mChildren.push_back(pDep);
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), Info.pAudioGroup->ID()));
}
}
}
else if (Type == EPropertyType::Asset)
{
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pData);
if (ID.IsValid())
{
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID);
mChildren.push_back(pDep);
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
}
}
else if (Type == EPropertyType::AnimationSet)
{
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
if (pProperties->Game() <= EGame::Echoes)
{
CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex());
mChildren.push_back(pDep);
mChildren.push_back(std::make_unique<CCharPropertyDependency>(pProp->IDString(true), ID, Params.CharacterIndex()));
}
else
{
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID);
mChildren.push_back(pDep);
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
}
}
}
@ -123,22 +111,25 @@ void CDependencyTree::Serialize(IArchive& rArc)
rArc << SerialParameter("Children", mChildren);
}
void CDependencyTree::AddChild(IDependencyNode *pNode)
void CDependencyTree::AddChild(std::unique_ptr<IDependencyNode>&& pNode)
{
ASSERT(pNode);
mChildren.push_back(pNode);
mChildren.push_back(std::move(pNode));
}
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
{
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID))) return;
CResourceDependency *pDepend = new CResourceDependency(rkID);
mChildren.push_back(pDepend);
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID)))
return;
mChildren.push_back(std::make_unique<CResourceDependency>(rkID));
}
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
{
if (!pRes) return;
if (!pRes)
return;
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).
CAnimSet *pSet = rkAnimParams.AnimSet();
if (!pSet || rkAnimParams.CharacterIndex() == -1) return;
CCharPropertyDependency *pChar = new CCharPropertyDependency("NULL", pSet->ID(), rkAnimParams.CharacterIndex());
mChildren.push_back(pChar);
if (!pSet || rkAnimParams.CharacterIndex() == UINT32_MAX)
return;
mChildren.push_back(std::make_unique<CCharPropertyDependency>("NULL", pSet->ID(), rkAnimParams.CharacterIndex()));
}
// ************ CResourceDependency ************
@ -209,9 +201,9 @@ void CScriptInstanceDependency::Serialize(IArchive& rArc)
}
// 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->ParseProperties(pInstance->Area()->Entry(), pInstance->Template()->Properties(), pInstance->PropertyData());
return pInst;
@ -229,36 +221,34 @@ void CSetCharacterDependency::Serialize(IArchive& rArc)
<< 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.pSkeleton);
pTree->AddDependency(rkChar.pSkin);
pTree->AddDependency(rkChar.AnimDataID);
pTree->AddDependency(rkChar.CollisionPrimitivesID);
const std::vector<CAssetID> *pkParticleVectors[5] = {
const std::array<const std::vector<CAssetID>*, 5> particleVectors{
&rkChar.GenericParticles, &rkChar.ElectricParticles,
&rkChar.SwooshParticles, &rkChar.SpawnParticles,
&rkChar.EffectParticles
};
for (uint32 iVec = 0; iVec < 5; iVec++)
for (const auto& vec : particleVectors)
{
for (uint32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
for (const auto& dependency : *vec)
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(rkOverlay.ModelID);
pTree->AddDependency(rkOverlay.SkinID);
pTree->AddDependency(overlay.ModelID);
pTree->AddDependency(overlay.SkinID);
}
pTree->AddDependency(rkChar.SpatialPrimitives);
return pTree;
}
@ -274,9 +264,9 @@ void CSetAnimationDependency::Serialize(IArchive& rArc)
<< 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);
// Find relevant character indices
@ -292,16 +282,15 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
std::set<CAnimPrimitive> 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(rkPrim.Animation());
pTree->AddDependency(prim.Animation());
if (pkOwnerSet->Game() >= EGame::EchoesDemo)
{
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(rkPrim.ID());
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(prim.ID());
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)
{
if (!pLayer) return;
if (!pLayer)
return;
mLayerOffsets.push_back(mChildren.size());
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);
// 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)
{
mChildren.push_back(pTree);
pTree->GetAllResourceReferences(UsedIDs);
mChildren.push_back(std::move(pTree));
}
else
delete pTree;
}
for (uint32 iDep = 0; iDep < rkExtraDeps.size(); iDep++)
AddDependency(rkExtraDeps[iDep]);
for (const auto& dep : rkExtraDeps)
AddDependency(dep);
}
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
// 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];
uint32 EndIdx = (iLayer == mLayerOffsets.size() - 1 ? mChildren.size() : mLayerOffsets[iLayer + 1]);
const size_t StartIdx = mLayerOffsets[iLayer];
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);
// Keep track of which types we've already checked on this layer to speed things up a little...
std::set<uint32> UsedObjectTypes;
for (uint32 iInst = StartIdx; iInst < EndIdx; iInst++)
for (size_t iInst = StartIdx; iInst < EndIdx; iInst++)
{
IDependencyNode *pNode = mChildren[iInst];
if (pNode->Type() != EDependencyNodeType::ScriptInstance) continue;
const auto& pNode = mChildren[iInst];
if (pNode->Type() != EDependencyNodeType::ScriptInstance)
continue;
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
uint32 ObjType = pInst->ObjectType();
const auto *pInst = static_cast<CScriptInstanceDependency*>(pNode.get());
const uint32 ObjType = pInst->ObjectType();
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
CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
const CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
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;
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/FileIO.h>
#include <Common/Macros.h>
#include <memory>
class CScriptLayer;
class CScriptObject;
@ -31,34 +32,34 @@ enum class EDependencyNodeType
class IDependencyNode
{
protected:
std::vector<IDependencyNode*> mChildren;
std::vector<std::unique_ptr<IDependencyNode>> mChildren;
public:
virtual ~IDependencyNode();
virtual EDependencyNodeType Type() const = 0;
virtual void Serialize(IArchive& rArc) = 0;
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);
// Serialization constructor
static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type);
// Accessors
inline uint NumChildren() const { return mChildren.size(); }
inline IDependencyNode* ChildByIndex(uint Index) const { return mChildren[Index]; }
size_t NumChildren() const { return mChildren.size(); }
IDependencyNode* ChildByIndex(size_t Index) const { return mChildren[Index].get(); }
};
// Basic dependency tree; this class is sufficient for most resource types.
class CDependencyTree : public IDependencyNode
{
public:
CDependencyTree() {}
CDependencyTree() = default;
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
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(CResource *pRes, bool AvoidDuplicates = true);
void AddCharacterDependency(const CAnimationParameters& rkAnimParams);
@ -71,17 +72,17 @@ protected:
CAssetID mID;
public:
CResourceDependency() {}
CResourceDependency(const CAssetID& rkID) : mID(rkID) {}
CResourceDependency() = default;
explicit CResourceDependency(const CAssetID& rkID) : mID(rkID) {}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
virtual bool HasDependency(const CAssetID& rkID) const;
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const override;
bool HasDependency(const CAssetID& rkID) const override;
// Accessors
inline CAssetID ID() const { return mID; }
inline void SetID(const CAssetID& rkID) { mID = rkID; }
CAssetID ID() const { return mID; }
void SetID(const CAssetID& rkID) { mID = rkID; }
};
// Node representing a single resource dependency referenced by a script property.
@ -90,81 +91,76 @@ class CPropertyDependency : public CResourceDependency
TString mIDString;
public:
CPropertyDependency()
: CResourceDependency()
{}
CPropertyDependency() = default;
CPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID)
CPropertyDependency(TString rkPropID, const CAssetID& rkAssetID)
: CResourceDependency(rkAssetID)
, mIDString(rkPropID)
, mIDString(std::move(rkPropID))
{}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// 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.
class CCharPropertyDependency : public CPropertyDependency
{
protected:
int mUsedChar;
int mUsedChar = -1;
public:
CCharPropertyDependency()
: CPropertyDependency()
, mUsedChar(-1)
{}
CCharPropertyDependency() = default;
CCharPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID, int UsedChar)
: CPropertyDependency(rkPropID, rkAssetID)
CCharPropertyDependency(TString rkPropID, const CAssetID& rkAssetID, int UsedChar)
: CPropertyDependency(std::move(rkPropID), rkAssetID)
, mUsedChar(UsedChar)
{}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// Accessors
inline int UsedChar() const { return mUsedChar; }
int UsedChar() const { return mUsedChar; }
};
// Node representing a script object. Indicates the type of object.
class CScriptInstanceDependency : public IDependencyNode
{
protected:
uint mObjectType;
uint32 mObjectType = 0;
public:
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// Accessors
inline uint ObjectType() const { return mObjectType; }
uint32 ObjectType() const { return mObjectType; }
// 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.
class CSetCharacterDependency : public CDependencyTree
{
protected:
uint32 mCharSetIndex;
uint32 mCharSetIndex = 0;
public:
CSetCharacterDependency() : CDependencyTree() {}
CSetCharacterDependency(uint32 SetIndex) : CDependencyTree(), mCharSetIndex(SetIndex) {}
CSetCharacterDependency() = default;
explicit CSetCharacterDependency(uint32 SetIndex) : mCharSetIndex(SetIndex) {}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// Accessors
inline uint32 CharSetIndex() const { return mCharSetIndex; }
uint32 CharSetIndex() const { return mCharSetIndex; }
// 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.
@ -174,35 +170,35 @@ protected:
std::set<uint32> mCharacterIndices;
public:
CSetAnimationDependency() : CDependencyTree() {}
CSetAnimationDependency() = default;
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// Accessors
inline bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
inline bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); }
bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); }
// 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.
class CAnimEventDependency : public CResourceDependency
{
protected:
uint32 mCharIndex;
uint32 mCharIndex = 0;
public:
CAnimEventDependency() : CResourceDependency() {}
CAnimEventDependency() = default;
CAnimEventDependency(const CAssetID& rkID, uint32 CharIndex)
: CResourceDependency(rkID), mCharIndex(CharIndex) {}
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
// 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.
@ -212,17 +208,17 @@ protected:
std::vector<uint32> mLayerOffsets;
public:
CAreaDependencyTree() : CDependencyTree() {}
CAreaDependencyTree() = default;
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
EDependencyNodeType Type() const override;
void Serialize(IArchive& rArc) override;
void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps);
void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const;
// Accessors
inline uint32 NumScriptLayers() const { return mLayerOffsets.size(); }
inline uint32 ScriptLayerOffset(uint32 LayerIdx) const { return mLayerOffsets[LayerIdx]; }
size_t NumScriptLayers() const { return mLayerOffsets.size(); }
uint32 ScriptLayerOffset(size_t LayerIdx) const { return mLayerOffsets[LayerIdx]; }
};
#endif // CDEPENDENCYTREE

View File

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

View File

@ -9,7 +9,8 @@
#include <Common/Flags.h>
#include <Common/TString.h>
#include <map>
#include <nod/nod.hpp>
#include <memory>
#include <nod/DiscBase.hpp>
enum class EDiscType
{
@ -21,7 +22,7 @@ enum class EDiscType
class CGameExporter
{
// Project Data
CGameProject *mpProject;
std::unique_ptr<CGameProject> mpProject;
TString mProjectPath;
CResourceStore *mpStore;
EGame mGame;
@ -38,15 +39,15 @@ class CGameExporter
TString mWorldsDirName;
// Files
nod::DiscBase *mpDisc;
nod::DiscBase *mpDisc = nullptr;
EDiscType mDiscType;
bool mFrontEnd;
// Resources
TStringList mPaks;
std::map<CAssetID, bool> mAreaDuplicateMap;
CAssetNameMap *mpNameMap;
CGameInfo *mpGameInfo;
CAssetNameMap *mpNameMap = nullptr;
CGameInfo *mpGameInfo = nullptr;
struct SResourceInstance
{
@ -61,7 +62,7 @@ class CGameExporter
std::map<CAssetID, SResourceInstance> mResourceMap;
// Progress
IProgressNotifier *mpProgress;
IProgressNotifier *mpProgress = nullptr;
public:
enum EExportStep
@ -76,9 +77,9 @@ public:
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);
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:
bool ExtractDiscData();
@ -91,7 +92,7 @@ protected:
TString MakeWorldName(CAssetID WorldID);
// Convenience Functions
inline SResourceInstance* FindResourceInstance(const CAssetID& rkID)
SResourceInstance* FindResourceInstance(const CAssetID& rkID)
{
uint64 IntegralID = rkID.ToLongLong();
auto Found = mResourceMap.find(IntegralID);

View File

@ -1,6 +1,10 @@
#include "CGameInfo.h"
#include "CResourceStore.h"
#include <Common/FileUtil.h>
#include <algorithm>
constexpr char gkGameInfoDir[] = "resources/gameinfo";
constexpr char gkGameInfoExt[] = "xml";
bool CGameInfo::LoadGameInfo(EGame Game)
{
@ -11,7 +15,7 @@ bool CGameInfo::LoadGameInfo(EGame Game)
return LoadGameInfo(Path);
}
bool CGameInfo::LoadGameInfo(TString Path)
bool CGameInfo::LoadGameInfo(const TString& Path)
{
CXMLReader Reader(Path);
@ -20,14 +24,17 @@ bool CGameInfo::LoadGameInfo(TString Path)
Serialize(Reader);
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
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
if (Path.IsEmpty())
Path = GetDefaultGameInfoPath(mGame);
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
Serialize(Writer);
return Writer.Save();
@ -50,21 +57,19 @@ void CGameInfo::Serialize(IArchive& rArc)
TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const
{
for (uint32 iBuild = 0; iBuild < mBuilds.size(); iBuild++)
{
const SBuildInfo& rkBuildInfo = mBuilds[iBuild];
if (rkBuildInfo.Version == BuildVer && rkBuildInfo.Region == Region)
return rkBuildInfo.Name;
}
const auto it = std::find_if(mBuilds.cbegin(), mBuilds.cend(),
[=](const auto& entry) { return entry.Version == BuildVer && entry.Region == Region; });
if (it == mBuilds.cend())
return "Unknown Build";
return it->Name;
}
TString CGameInfo::GetAreaName(const CAssetID &rkID) const
{
auto Iter = mAreaNameMap.find(rkID);
return (Iter == mAreaNameMap.end() ? "" : Iter->second);
const auto Iter = mAreaNameMap.find(rkID);
return Iter == mAreaNameMap.cend() ? "" : Iter->second;
}
// ************ STATIC ************
@ -83,6 +88,11 @@ TString CGameInfo::GetDefaultGameInfoPath(EGame Game)
if (Game == EGame::Invalid)
return "";
TString GameName = GetGameShortName(Game);
return TString::Format("%s/%s/GameInfo%s.%s", *gDataDir, *gkGameInfoDir, *GameName, *gkGameInfoExt);
const TString GameName = GetGameShortName(Game);
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 <map>
const TString gkGameInfoDir = "resources/gameinfo";
const TString gkGameInfoExt = "xml";
//@todo merge this class into CGameTemplate
// they serve similar purposes, no real reason for them to be different classes
class CGameInfo
{
EGame mGame;
EGame mGame{EGame::Invalid};
// List of known builds of each game
struct SBuildInfo
@ -37,12 +34,10 @@ class CGameInfo
std::map<CAssetID, TString> mAreaNameMap;
public:
CGameInfo()
: mGame(EGame::Invalid)
{}
CGameInfo() = default;
bool LoadGameInfo(EGame Game);
bool LoadGameInfo(TString Path);
bool LoadGameInfo(const TString& Path);
bool SaveGameInfo(TString Path = "");
void Serialize(IArchive& rArc);
@ -50,14 +45,14 @@ public:
TString GetAreaName(const CAssetID& rkID) const;
// Accessors
inline EGame Game() const { return mGame; }
EGame Game() const { return mGame; }
// Static
static CGameInfo* GetGameInfo(EGame Game);
static EGame RoundGame(EGame Game);
static TString GetDefaultGameInfoPath(EGame Game);
inline static TString GetExtension() { return gkGameInfoExt; }
static TString GetExtension();
};
#endif // CGAMEINFO

View File

@ -3,7 +3,8 @@
#include "IUIRelay.h"
#include "Core/Resource/Script/CGameTemplate.h"
#include <Common/Serialization/XML.h>
#include <nod/nod.hpp>
#include <nod/DiscGCN.hpp>
#include <nod/DiscWii.hpp>
#if NOD_UCS2
#define TStringToNodString(string) ToWChar(string)
@ -13,25 +14,22 @@
CGameProject::~CGameProject()
{
if (mpResourceStore)
{
if (!mpResourceStore)
return;
ASSERT(!mpResourceStore->IsCacheDirty());
if (gpResourceStore == mpResourceStore.get())
gpResourceStore = nullptr;
}
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
delete mPackages[iPkg];
}
bool CGameProject::Save()
{
mProjFileLock.Release();
TString ProjPath = ProjectPath();
CXMLWriter Writer(ProjPath, "GameProject", (int) EProjectVersion::Current, mGame);
const TString ProjPath = ProjectPath();
CXMLWriter Writer(ProjPath, "GameProject", static_cast<int>(EProjectVersion::Current), mGame);
Serialize(Writer);
bool SaveSuccess = Writer.Save();
const bool SaveSuccess = Writer.Save();
mProjFileLock.Lock(*ProjPath);
return SaveSuccess;
}
@ -48,8 +46,8 @@ bool CGameProject::Serialize(IArchive& rArc)
if (!rArc.IsReader())
{
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
PackageList.push_back( mPackages[iPkg]->DefinitionPath(true) );
for (auto& package : mPackages)
PackageList.push_back(package->DefinitionPath(true));
}
rArc << SerialParameter("Packages", PackageList);
@ -59,15 +57,14 @@ bool CGameProject::Serialize(IArchive& rArc)
{
ASSERT(mPackages.empty());
for (uint32 iPkg = 0; iPkg < PackageList.size(); iPkg++)
for (const TString& packagePath : PackageList)
{
const TString& rkPackagePath = PackageList[iPkg];
TString PackageName = rkPackagePath.GetFileName(false);
TString PackageDir = rkPackagePath.GetFileDirectory();
TString PackageName = packagePath.GetFileName(false);
TString PackageDir = packagePath.GetFileDirectory();
CPackage *pPackage = new CPackage(this, PackageName, PackageDir);
bool PackageLoadSuccess = pPackage->Load();
mPackages.push_back(pPackage);
auto pPackage = std::make_unique<CPackage>(this, std::move(PackageName), std::move(PackageDir));
const bool PackageLoadSuccess = pPackage->Load();
mPackages.push_back(std::move(pPackage));
if (!PackageLoadSuccess)
{
@ -84,13 +81,13 @@ bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgre
ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
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());
TString DiscRoot = DiscDir(false);
const TString DiscRoot = DiscDir(false);
if (!IsWiiBuild())
{
@ -110,14 +107,14 @@ bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso
ASSERT(IsWiiDeAsobu() || IsTrilogy());
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());
TString DiscRoot = DiscFilesystemRoot(false);
const TString DiscRoot = DiscFilesystemRoot(false);
nod::DiscMergerWii Merger(TStringToNodString(rkIsoPath), *pOriginalIso, IsTrilogy(), ProgressCallback);
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
{
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...
// Construct a sorted list of worlds in this package
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);
@ -146,25 +141,22 @@ void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
});
// 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(pkRes->ID);
rOut.push_back(res->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++)
{
const SNamedResource& rkRes = pkg->NamedResourceByIndex(iRes);
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
if (rkRes.Name == rkName)
if (rkRes.Name == name)
return rkRes.ID;
}
}
@ -172,22 +164,18 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const
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++)
{
CPackage *pPackage = mPackages[iPkg];
if (pPackage->Name() == rkName)
{
return pPackage;
}
}
const auto iter = std::find_if(mPackages.begin(), mPackages.end(),
[name](const auto& package) { return package->Name() == name; });
if (iter == mPackages.cend())
return nullptr;
return iter->get();
}
CGameProject* CGameProject::CreateProjectForExport(
std::unique_ptr<CGameProject> CGameProject::CreateProjectForExport(
const TString& rkProjRootDir,
EGame Game,
ERegion Region,
@ -195,7 +183,7 @@ CGameProject* CGameProject::CreateProjectForExport(
float BuildVer
)
{
CGameProject *pProj = new CGameProject;
auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mGame = Game;
pProj->mRegion = Region;
pProj->mGameID = rkGameID;
@ -203,15 +191,15 @@ CGameProject* CGameProject::CreateProjectForExport(
pProj->mProjectRoot = rkProjRootDir;
pProj->mProjectRoot.Replace("\\", "/");
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj);
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
pProj->mpGameInfo->LoadGameInfo(Game);
return pProj;
}
CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
std::unique_ptr<CGameProject> CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
{
// Init project
CGameProject *pProj = new CGameProject;
auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mProjectRoot = rkProjPath.GetFileDirectory();
pProj->mProjectRoot.Replace("\\", "/");
@ -222,12 +210,11 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
pProgress->Report("Loading project settings");
bool LoadSuccess = false;
TString ProjPath = rkProjPath;
const TString ProjPath = rkProjPath;
CXMLReader Reader(ProjPath);
if (!Reader.IsValid())
{
delete pProj;
return nullptr;
}
@ -237,7 +224,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
{
// Load 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();
// 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)
{
delete pProj;
return nullptr;
}
@ -277,7 +263,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
// Perform update
if (Reader.FileVersion() < (uint16) EProjectVersion::Current)
if (Reader.FileVersion() < static_cast<uint16>(EProjectVersion::Current))
{
pProgress->Report("Updating project");
@ -304,7 +290,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
}
// Create hidden files directory, if needed
TString HiddenDir = pProj->HiddenFilesDir();
const TString HiddenDir = pProj->HiddenFilesDir();
if (!FileUtil::Exists(HiddenDir))
{

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ enum class EPackageDefinitionVersion
// Add new versions before this line
Max,
Current = EPackageDefinitionVersion::Max - 1
Current = Max - 1
};
struct SNamedResource
@ -34,24 +34,22 @@ struct SNamedResource
class CPackage
{
CGameProject *mpProject;
CGameProject *mpProject = nullptr;
TString mPakName;
TString mPakPath;
std::vector<SNamedResource> mResources;
bool mNeedsRecook;
bool mNeedsRecook = false;
// 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;
public:
CPackage() {}
CPackage(CGameProject *pProj, const TString& rkName, const TString& rkPath)
CPackage() = default;
CPackage(CGameProject *pProj, TString rkName, TString rkPath)
: mpProject(pProj)
, mPakName(rkName)
, mPakPath(rkPath)
, mNeedsRecook(false)
, mPakName(std::move(rkName))
, mPakPath(std::move(rkPath))
, mCacheDirty(true)
{}
@ -70,14 +68,14 @@ public:
TString CookedPackagePath(bool Relative) const;
// Accessors
inline TString Name() const { return mPakName; }
inline TString Path() const { return mPakPath; }
inline CGameProject* Project() const { return mpProject; }
inline uint32 NumNamedResources() const { return mResources.size(); }
inline const SNamedResource& NamedResourceByIndex(uint32 Idx) const { return mResources[Idx]; }
inline bool NeedsRecook() const { return mNeedsRecook; }
TString Name() const { return mPakName; }
TString Path() const { return mPakPath; }
CGameProject* Project() const { return mpProject; }
size_t NumNamedResources() const { return mResources.size(); }
const SNamedResource& NamedResourceByIndex(size_t Idx) const { return mResources[Idx]; }
bool NeedsRecook() const { return mNeedsRecook; }
inline void SetPakName(TString NewName) { mPakName = NewName; }
void SetPakName(TString NewName) { mPakName = std::move(NewName); }
};
#endif // CPACKAGE

View File

@ -11,23 +11,17 @@
#include <Common/Serialization/CXMLWriter.h>
CResourceEntry::CResourceEntry(CResourceStore *pStore)
: mpResource(nullptr)
, mpTypeInfo(nullptr)
, mpStore(pStore)
, mpDependencies(nullptr)
: mpStore(pStore)
, mID(CAssetID::InvalidID(pStore->Game()))
, mpDirectory(nullptr)
, mMetadataDirty(false)
, mCachedSize(-1)
{}
// 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,
EResourceType Type, bool ExistingResource /*= false*/)
EResourceType Type, bool ExistingResource)
{
// 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->mName = rkName;
pEntry->mCachedUppercaseName = rkName.ToUpper();
@ -37,7 +31,7 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDir, true);
ASSERT(pEntry->mpDirectory);
pEntry->mpDirectory->AddChild("", pEntry);
pEntry->mpDirectory->AddChild("", pEntry.get());
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.
if (!ExistingResource)
{
pEntry->mpResource = CResourceFactory::CreateResource(pEntry);
pEntry->mpResource = CResourceFactory::CreateResource(pEntry.get());
if (pEntry->mpResource)
{
@ -56,30 +50,30 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
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.
CResourceEntry *pEntry = new CResourceEntry(pStore);
auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
pEntry->SerializeEntryInfo(rArc, false);
ASSERT(pEntry->mpTypeInfo);
ASSERT(pEntry->mpDirectory);
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)
{
// Initialize as much entry info as possible from the input data, then load the rest from the metadata file.
ASSERT(pTypeInfo);
CResourceEntry *pEntry = new CResourceEntry(pStore);
auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
pEntry->mpTypeInfo = pTypeInfo;
pEntry->mName = rkName;
pEntry->mCachedUppercaseName = rkName.ToUpper();
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDirPath, true);
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
ASSERT(pEntry->HasCookedVersion() || pEntry->HasRawVersion());
@ -89,11 +83,7 @@ CResourceEntry* CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResT
return pEntry;
}
CResourceEntry::~CResourceEntry()
{
if (mpResource) delete mpResource;
if (mpDependencies) delete mpDependencies;
}
CResourceEntry::~CResourceEntry() = default;
bool CResourceEntry::LoadMetadata()
{
@ -171,15 +161,11 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly)
void CResourceEntry::UpdateDependencies()
{
if (mpDependencies)
{
delete mpDependencies;
mpDependencies = nullptr;
}
mpDependencies.reset();
if (!mpTypeInfo->CanHaveDependencies())
{
mpDependencies = new CDependencyTree();
mpDependencies = std::make_unique<CDependencyTree>();
return;
}
@ -191,7 +177,7 @@ void CResourceEntry::UpdateDependencies()
if (!mpResource)
{
errorf("Unable to update cached dependencies; failed to load resource");
mpDependencies = new CDependencyTree();
mpDependencies = std::make_unique<CDependencyTree>();
return;
}
@ -255,7 +241,7 @@ bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
uint64 CResourceEntry::Size() const
{
if (mCachedSize == -1)
if (mCachedSize == UINT64_MAX)
{
if (HasCookedVersion())
mCachedSize = FileUtil::FileSize(CookedAssetPath());
@ -344,7 +330,7 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/, bool FlagForRecook /*=
// Flag dirty any packages that contain this resource.
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);
@ -391,7 +377,8 @@ bool CResourceEntry::Cook()
CResource* CResourceEntry::Load()
{
// 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.
// 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())
{
errorf("Failed to load raw resource; falling back on cooked. Raw path: %s", *RawAssetPath());
delete mpResource;
mpResource = nullptr;
mpResource.reset();
}
else
@ -424,7 +410,7 @@ CResource* CResourceEntry::Load()
}
if (mpResource)
return mpResource;
return mpResource.get();
}
ASSERT(!mpResource);
@ -451,8 +437,11 @@ CResource* CResourceEntry::Load()
CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
{
// Overload to allow for load from an arbitrary input stream.
if (mpResource) return mpResource;
if (!rInput.IsValid()) return nullptr;
if (mpResource)
return mpResource.get();
if (!rInput.IsValid())
return nullptr;
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions
CResourceStore *pOldStore = gpResourceStore;
@ -463,22 +452,22 @@ CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
mpStore->TrackLoadedResource(this);
gpResourceStore = pOldStore;
return mpResource;
return mpResource.get();
}
bool CResourceEntry::Unload()
{
ASSERT(mpResource != nullptr);
ASSERT(!mpResource->IsReferenced());
delete mpResource;
mpResource = nullptr;
mpResource.reset();
return true;
}
bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName)
{
// 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
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(rkDir, false);

View File

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

View File

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

View File

@ -20,9 +20,6 @@ CResourceStore *gpEditorStore = nullptr;
// Constructor for editor store
CResourceStore::CResourceStore(const TString& rkDatabasePath)
: mpProj(nullptr)
, mGame(EGame::Prime)
, mDatabaseCacheDirty(false)
{
mpDatabaseRoot = new CVirtualDirectory(this);
mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory());
@ -32,10 +29,7 @@ CResourceStore::CResourceStore(const TString& rkDatabasePath)
// Main constructor for game projects and game exporter
CResourceStore::CResourceStore(CGameProject *pProject)
: mpProj(nullptr)
, mGame(EGame::Invalid)
, mpDatabaseRoot(nullptr)
, mDatabaseCacheDirty(false)
: mGame(EGame::Invalid)
{
SetProject(pProject);
}
@ -44,9 +38,6 @@ CResourceStore::~CResourceStore()
{
CloseProject();
DestroyUnreferencedResources();
for (auto It = mResourceEntries.begin(); It != mResourceEntries.end(); It++)
delete It->second;
}
void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rOutList)
@ -58,7 +49,7 @@ void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rO
}
else
{
for (uint32 SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++)
for (size_t SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++)
RecursiveGetListOfEmptyDirectories(pDir->SubdirectoryByIndex(SubIdx), rOutList);
}
}
@ -75,11 +66,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
{
// Make sure deleted resources aren't included in the count.
// 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 (pEntry->IsMarkedForDeletion())
if (entry.second->IsMarkedForDeletion())
{
ResourceCount--;
}
@ -94,9 +83,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
{
if (rArc.ParamBegin("Resource", 0))
{
CResourceEntry *pEntry = CResourceEntry::BuildFromArchive(this, rArc);
auto pEntry = CResourceEntry::BuildFromArchive(this, rArc);
ASSERT(FindEntry(pEntry->ID()) == nullptr);
mResourceEntries[pEntry->ID()] = pEntry;
mResourceEntries.insert_or_assign(pEntry->ID(), std::move(pEntry));
rArc.ParamEnd();
}
}
@ -128,13 +117,13 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
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
TString AbsPath = ResourcesDir() + *Iter;
const TString AbsPath = ResourcesDir() + dir;
if (FileUtil::Exists(AbsPath))
CreateVirtualDirectory(*Iter);
CreateVirtualDirectory(dir);
}
}
@ -159,7 +148,10 @@ bool CResourceStore::LoadDatabaseCache()
if (!BuildFromDirectory(true))
return false;
}
else return false;
else
{
return false;
}
}
else
{
@ -192,33 +184,35 @@ bool CResourceStore::SaveDatabaseCache()
void CResourceStore::ConditionalSaveStore()
{
if (mDatabaseCacheDirty) SaveDatabaseCache();
if (mDatabaseCacheDirty)
SaveDatabaseCache();
}
void CResourceStore::SetProject(CGameProject *pProj)
{
if (mpProj == pProj) return;
if (mpProj == pProj)
return;
if (mpProj)
CloseProject();
mpProj = pProj;
if (mpProj)
{
if (!mpProj)
return;
mDatabasePath = mpProj->ProjectRoot();
mpDatabaseRoot = new CVirtualDirectory(this);
mGame = mpProj->Game();
// Clear deleted files from previous runs
TString DeletedPath = DeletedResourcePath();
const TString DeletedPath = DeletedResourcePath();
if (FileUtil::Exists(DeletedPath))
{
FileUtil::ClearDirectory(DeletedPath);
}
}
}
void CResourceStore::CloseProject()
{
@ -232,9 +226,9 @@ void CResourceStore::CloseProject()
{
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());
}
@ -242,16 +236,10 @@ void CResourceStore::CloseProject()
}
// Delete all entries from old project
auto It = mResourceEntries.begin();
while (It != mResourceEntries.end())
{
delete It->second;
It = mResourceEntries.erase(It);
}
mResourceEntries.clear();
// Clear deleted files from previous runs
TString DeletedPath = DeletedResourcePath();
const TString DeletedPath = DeletedResourcePath();
if (FileUtil::Exists(DeletedPath))
{
@ -268,9 +256,10 @@ CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TString& rkPath, bo
{
if (rkPath.IsEmpty())
return mpDatabaseRoot;
else if (mpDatabaseRoot)
if (mpDatabaseRoot)
return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate);
else
return nullptr;
}
@ -308,14 +297,14 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
{
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())
return pEntry;
return pEntry.get();
}
}
@ -324,7 +313,7 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const
{
return (mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr);
return mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr;
}
bool CResourceStore::AreAllEntriesValid() const
@ -346,14 +335,12 @@ void CResourceStore::ClearDatabase()
if (!mLoadedResources.empty())
{
debugf("ERROR: Resources still loaded:");
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++)
debugf("\t[%s] %s", *Iter->first.ToString(), *Iter->second->CookedAssetPath(true));
for (const auto& [asset, entry] : mLoadedResources)
debugf("\t[%s] %s", *asset.ToString(), *entry->CookedAssetPath(true));
ASSERT(false);
}
// Clear out existing resource entries and directories
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
delete Iter->second;
mResourceEntries.clear();
delete mpDatabaseRoot;
@ -371,9 +358,8 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
TStringList 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());
if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta"))
@ -395,19 +381,20 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
}
// Create resource entry
CResourceEntry *pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName);
auto pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName);
// Validate the entry
CAssetID ID = pEntry->ID();
ASSERT( mResourceEntries.find(ID) == mResourceEntries.end() );
const CAssetID ID = pEntry->ID();
ASSERT(mResourceEntries.find(ID) == mResourceEntries.cend());
ASSERT(ID.Length() == CAssetID::GameIDLength(mGame));
mResourceEntries[ID] = pEntry;
mResourceEntries.insert_or_assign(ID, std::move(pEntry));
}
else if (FileUtil::IsDirectory(Path))
{
CreateVirtualDirectory(RelPath);
}
}
// Generate new cache file
if (ShouldGenerateCacheFile)
@ -454,29 +441,33 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
CResourceEntry *pEntry = FindEntry(rkID);
if (pEntry)
{
errorf("Attempted to register resource that's already tracked in the database: %s / %s / %s", *rkID.ToString(), *rkDir, *rkName);
}
else
{
// Validate directory
if (IsValidResourcePath(rkDir, rkName))
{
pEntry = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource);
mResourceEntries[rkID] = pEntry;
auto res = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource);
auto* resPtr = res.get();
mResourceEntries.insert_or_assign(rkID, std::move(res));
mDatabaseCacheDirty = true;
if (pEntry->IsLoaded())
if (resPtr->IsLoaded())
{
TrackLoadedResource(pEntry);
TrackLoadedResource(resPtr);
}
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);
}
@ -485,19 +476,18 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
CResource* CResourceStore::LoadResource(const CAssetID& rkID)
{
if (!rkID.IsValid()) return nullptr;
if (!rkID.IsValid())
return nullptr;
CResourceEntry *pEntry = FindEntry(rkID);
if (pEntry)
return pEntry->Load();
else
if (!pEntry)
{
// Resource doesn't seem to exist
warnf("Can't find requested resource with ID \"%s\"", *rkID.ToString());
return nullptr;
}
return pEntry->Load();
}
CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type)
@ -521,7 +511,6 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type
}
}
else
return nullptr;
}
@ -533,7 +522,7 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
if (pEntry)
{
// Verify extension matches the entry + load resource
TString Ext = rkPath.GetFileExtension();
const TString Ext = rkPath.GetFileExtension();
if (!Ext.IsEmpty())
{
@ -550,14 +539,14 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
return pEntry->Load();
}
else return nullptr;
return nullptr;
}
void CResourceStore::TrackLoadedResource(CResourceEntry *pEntry)
{
ASSERT(pEntry->IsLoaded());
ASSERT(mLoadedResources.find(pEntry->ID()) == mLoadedResources.end());
mLoadedResources[pEntry->ID()] = pEntry;
mLoadedResources.insert_or_assign(pEntry->ID(), pEntry);
}
void CResourceStore::DestroyUnreferencedResources()
@ -579,22 +568,24 @@ void CResourceStore::DestroyUnreferencedResources()
It = mLoadedResources.erase(It);
NumDeleted++;
}
else It++;
else
{
++It;
}
}
} while (NumDeleted > 0);
}
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
{
CAssetID ID = pEntry->ID();
const CAssetID ID = pEntry->ID();
if (pEntry->IsLoaded())
{
if (!pEntry->Unload())
return false;
auto It = mLoadedResources.find(ID);
const auto It = mLoadedResources.find(ID);
ASSERT(It != mLoadedResources.end());
mLoadedResources.erase(It);
}
@ -602,7 +593,7 @@ bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
if (pEntry->Directory())
pEntry->Directory()->RemoveChildResource(pEntry);
auto It = mResourceEntries.find(ID);
const auto It = mResourceEntries.find(ID);
ASSERT(It != mResourceEntries.end());
mResourceEntries.erase(It);
@ -667,7 +658,7 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
// Chop name to just after "x_rep"
uint32 RepStart = Path.IndexOfPhrase("_rep");
if (RepStart != -1)
if (RepStart != UINT32_MAX)
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.
@ -675,24 +666,24 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
else if (Path[1] == ':')
Path = Path.ChopFront(3);
PathMap[pEntry] = Path;
PathMap.insert_or_assign(pEntry, std::move(Path));
}
}
fclose(pContentsFile);
// Assign names
for (auto Iter = PathMap.begin(); Iter != PathMap.end(); Iter++)
for (auto& [entry, path] : PathMap)
{
CResourceEntry *pEntry = Iter->first;
if (UnnamedOnly && pEntry->IsNamed()) continue;
if (UnnamedOnly && entry->IsNamed())
continue;
TString Path = Iter->second;
TString Dir = Path.GetFileDirectory();
TString Name = Path.GetFileName(false);
if (Dir.IsEmpty()) Dir = pEntry->DirectoryPath();
TString Dir = path.GetFileDirectory();
TString Name = path.GetFileName(false);
if (Dir.IsEmpty())
Dir = entry->DirectoryPath();
pEntry->MoveAndRename(Dir, Name);
entry->MoveAndRename(Dir, Name);
}
// 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.
// Name must not be a path.
return ( CVirtualDirectory::IsValidDirectoryPath(rkPath) &&
return CVirtualDirectory::IsValidDirectoryPath(rkPath) &&
FileUtil::IsValidName(rkName, false) &&
!rkName.Contains('/') &&
!rkName.Contains('\\') );
!rkName.Contains('\\');
}
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/TString.h>
#include <map>
#include <memory>
#include <set>
class CGameExporter;
@ -20,27 +21,27 @@ enum class EDatabaseVersion
// Add new versions before this line
Max,
Current = EDatabaseVersion::Max - 1
Current = Max - 1
};
class CResourceStore
{
friend class CResourceIterator;
CGameProject *mpProj;
EGame mGame;
CVirtualDirectory *mpDatabaseRoot;
std::map<CAssetID, CResourceEntry*> mResourceEntries;
CGameProject *mpProj = nullptr;
EGame mGame{EGame::Prime};
CVirtualDirectory *mpDatabaseRoot = nullptr;
std::map<CAssetID, std::unique_ptr<CResourceEntry>> mResourceEntries;
std::map<CAssetID, CResourceEntry*> mLoadedResources;
bool mDatabaseCacheDirty;
bool mDatabaseCacheDirty = false;
// Directory paths
TString mDatabasePath;
bool mDatabasePathExists;
bool mDatabasePathExists = false;
public:
CResourceStore(const TString& rkDatabasePath);
CResourceStore(CGameProject *pProject);
explicit CResourceStore(const TString& rkDatabasePath);
explicit CResourceStore(CGameProject *pProject);
~CResourceStore();
bool SerializeDatabaseCache(IArchive& rArc);
bool LoadDatabaseCache();
@ -78,19 +79,19 @@ public:
static TString StaticDefaultResourceDirPath(EGame Game);
// Accessors
inline CGameProject* Project() const { return mpProj; }
inline EGame Game() const { return mGame; }
inline TString DatabaseRootPath() const { return mDatabasePath; }
inline bool DatabasePathExists() const { return mDatabasePathExists; }
inline TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; }
inline TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; }
inline CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
inline uint32 NumTotalResources() const { return mResourceEntries.size(); }
inline uint32 NumLoadedResources() const { return mLoadedResources.size(); }
inline bool IsCacheDirty() const { return mDatabaseCacheDirty; }
CGameProject* Project() const { return mpProj; }
EGame Game() const { return mGame; }
TString DatabaseRootPath() const { return mDatabasePath; }
bool DatabasePathExists() const { return mDatabasePathExists; }
TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; }
TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; }
CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
uint32 NumTotalResources() const { return mResourceEntries.size(); }
uint32 NumLoadedResources() const { return mLoadedResources.size(); }
bool IsCacheDirty() const { return mDatabaseCacheDirty; }
inline void SetCacheDirty() { mDatabaseCacheDirty = true; }
inline bool IsEditorStore() const { return mpProj == nullptr; }
void SetCacheDirty() { mDatabaseCacheDirty = true; }
bool IsEditorStore() const { return mpProj == nullptr; }
};
extern TString gDataDir;

View File

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

View File

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

View File

@ -1,21 +1,28 @@
#include "DependencyListBuilders.h"
// ************ 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;
auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.end()) return false;
if (mpStore->Game() >= EGame::CorruptionProto)
return true;
const auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.cend())
return false;
const std::vector<bool>& rkUsageList = Find->second;
if (CharacterIndex >= rkUsageList.size()) return false;
else return rkUsageList[CharacterIndex];
if (CharacterIndex >= rkUsageList.size())
return false;
return rkUsageList[CharacterIndex];
}
bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const
{
auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.end()) return false;
const auto Find = mUsageMap.find(rkID);
if (Find == mUsageMap.end())
return false;
const std::vector<bool>& rkUsageList = Find->second;
for (uint32 iChar = 0; iChar < rkUsageList.size(); iChar++)
@ -37,7 +44,7 @@ void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntr
{
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())
{
@ -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
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);
CAssetID AreaID = pWorld->AreaResourceID(iArea);
const CAssetID AreaID = pWorld->AreaResourceID(iArea);
CResourceEntry *pEntry = mpStore->FindEntry(AreaID);
ASSERT(pEntry && pEntry->ResourceType() == EResourceType::Area);
@ -75,11 +84,11 @@ void CCharacterUsageMap::FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 L
ASSERT(pTree->Type() == EDependencyNodeType::Area);
// Only examine dependencies of the particular layer specified by the caller
bool IsLastLayer = (mLayerIndex == pTree->NumScriptLayers() - 1);
uint32 StartIdx = pTree->ScriptLayerOffset(mLayerIndex);
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(mLayerIndex + 1));
const bool IsLastLayer = mLayerIndex == pTree->NumScriptLayers() - 1;
const size_t StartIdx = pTree->ScriptLayerOffset(mLayerIndex);
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));
}
@ -87,7 +96,7 @@ void CCharacterUsageMap::Clear()
{
mUsageMap.clear();
mStillLookingIDs.clear();
mLayerIndex = -1;
mLayerIndex = UINT32_MAX;
mIsInitialArea = true;
}
@ -95,17 +104,15 @@ void CCharacterUsageMap::Clear()
void CCharacterUsageMap::DebugPrintContents()
{
for (auto Iter = mUsageMap.begin(); Iter != mUsageMap.end(); Iter++)
for (const auto& [ID, usedList] : mUsageMap)
{
CAssetID ID = Iter->first;
std::vector<bool>& rUsedList = Iter->second;
CAnimSet *pSet = mpStore->LoadResource<CAnimSet>(ID);
const auto* 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]);
TString CharName = pSet->Character(iChar)->Name;
debugf("%s : Char %d : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED"));
const bool Used = usedList.size() > iChar && usedList[iChar];
const TString CharName = pSet->Character(iChar)->Name;
debugf("%s : Char %zu : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED"));
}
}
}
@ -113,19 +120,21 @@ void CCharacterUsageMap::DebugPrintContents()
// ************ PROTECTED ************
void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
{
if (!pNode) return;
EDependencyNodeType Type = pNode->Type();
if (!pNode)
return;
const EDependencyNodeType Type = pNode->Type();
if (Type == EDependencyNodeType::CharacterProperty)
{
CCharPropertyDependency *pDep = static_cast<CCharPropertyDependency*>(pNode);
CAssetID ResID = pDep->ID();
auto Find = mUsageMap.find(ResID);
auto *pDep = static_cast<CCharPropertyDependency*>(pNode);
const CAssetID ResID = pDep->ID();
const auto Find = mUsageMap.find(ResID);
if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.end())
if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.cend())
return;
if (Find != mUsageMap.end())
if (Find != mUsageMap.cend())
{
if (!mIsInitialArea && mCurrentAreaAllowsDupes)
{
@ -133,39 +142,37 @@ void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
return;
}
}
else
{
if (!mIsInitialArea) return;
mUsageMap[ResID] = std::vector<bool>();
if (!mIsInitialArea)
return;
mUsageMap.insert_or_assign(ResID, std::vector<bool>());
mStillLookingIDs.insert(ResID);
}
std::vector<bool>& rUsageList = mUsageMap[ResID];
uint32 UsedChar = pDep->UsedChar();
const uint32 UsedChar = pDep->UsedChar();
if (rUsageList.size() <= UsedChar)
rUsageList.resize(UsedChar + 1, false);
rUsageList[UsedChar] = true;
}
// Parse dependencies of the referenced resource if it's a type that can reference animsets
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());
if (pEntry && pEntry->ResourceType() == EResourceType::Scan)
if (pEntry != nullptr && pEntry->ResourceType() == EResourceType::Scan)
{
ParseDependencyNode(pEntry->Dependencies());
}
}
// Look for sub-dependencies of the current node
else
else // Look for sub-dependencies of the current node
{
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
ParseDependencyNode(pNode->ChildByIndex(iChild));
}
}
@ -177,11 +184,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
FindUniversalAreaAssets();
// 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);
CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID);
if (!pEntry) continue;
if (!pEntry)
continue;
if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG")
{
@ -189,16 +197,17 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
continue;
}
mIsUniversalAreaAsset = (mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.end());
mIsUniversalAreaAsset = mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.cend();
if (rkRes.Type == "MLVL")
{
mpWorld = (CWorld*) pEntry->Load();
mpWorld = static_cast<CWorld*>(pEntry->Load());
ASSERT(mpWorld);
}
else
{
mCharacterUsageMap.FindUsagesForAsset(pEntry);
}
AddDependency(nullptr, rkRes.ID, rOut);
mpWorld = nullptr;
@ -207,9 +216,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
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);
if (!pEntry) return;
if (!pEntry)
return;
EResourceType ResType = pEntry->ResourceType();
@ -219,12 +231,15 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
(ResType != EResourceType::World || !pCurEntry) &&
(ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World);
if (!IsValid) return;
if (!IsValid)
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
mPackageUsedAssets.insert(rkID);
@ -241,7 +256,7 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
if (mEnableDuplicates)
{
for (uint32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
for (size_t iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
{
if (mpWorld->AreaResourceID(iArea) == rkID)
{
@ -251,10 +266,11 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
}
}
}
// Animset - keep track of the current animset ID
else if (ResType == EResourceType::AnimSet)
{
mCurrentAnimSetID = rkID;
}
// Evaluate dependencies of this entry
CDependencyTree *pTree = pEntry->Dependencies();
@ -264,7 +280,6 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
// Revert current animset ID
if (ResType == EResourceType::AnimSet)
mCurrentAnimSetID = CAssetID::InvalidID(mGame);
// Revert duplicate flag
else if (ResType == EResourceType::Area)
mCurrentAreaHasDuplicates = false;
@ -272,54 +287,54 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
{
if (!pNode) return;
EDependencyNodeType Type = pNode->Type();
if (!pNode)
return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false;
// Straight resource dependencies should just be added to the tree directly
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);
}
// Anim events should be added if either they apply to characters, or their character index is used
else if (Type == EDependencyNodeType::AnimEvent)
{
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex();
const auto *pDep = static_cast<CAnimEventDependency*>(pNode);
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);
}
// Set characters should only be added if their character index is used
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;
}
// Set animations should only be added if they're being used by at least one used character
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());
}
else
{
ParseChildren = true;
}
// Analyze this node's children
if (ParseChildren)
{
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'));
}
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
if (Type == EDependencyNodeType::ScriptInstance)
@ -335,7 +350,7 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
if (pPackage)
{
// 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);
@ -351,22 +366,22 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
if (pUniverseWorld)
{
// 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())
mUniversalAreaAssets.insert(AreaID);
}
// Map IDs
CDependencyGroup *pMapWorld = (CDependencyGroup*) pUniverseWorld->MapWorld();
auto *pMapWorld = static_cast<CDependencyGroup*>(pUniverseWorld->MapWorld());
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())
mUniversalAreaAssets.insert(DepID);
@ -385,38 +400,38 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
// 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);
mBaseUsedAssets.insert(pRes->ID());
}
// Get dependencies of each layer
for (uint32 iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
for (size_t iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
{
mLayerUsedAssets.clear();
mCharacterUsageMap.FindUsagesForLayer(mpAreaEntry, iLyr);
rLayerOffsetsOut.push_back(rAssetsOut.size());
bool IsLastLayer = (iLyr == pTree->NumScriptLayers() - 1);
uint32 StartIdx = pTree->ScriptLayerOffset(iLyr);
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(iLyr + 1));
const bool IsLastLayer = iLyr == pTree->NumScriptLayers() - 1;
const size_t StartIdx = pTree->ScriptLayerOffset(iLyr);
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)
{
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
const auto* pInst = static_cast<const CScriptInstanceDependency*>(pNode);
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
if (mGame == EGame::Corruption && mIsPlayerActor)
@ -431,15 +446,17 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE")
{
continue;
}
}
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
}
}
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);
}
else
@ -454,9 +471,9 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
mLayerUsedAssets.clear();
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);
}
}
@ -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)
{
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 (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)
{
if (!pNode) return;
EDependencyNodeType Type = pNode->Type();
if (!pNode)
return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false;
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);
}
else if (Type == EDependencyNodeType::AnimEvent)
{
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex();
const auto* pDep = static_cast<const CAnimEventDependency*>(pNode);
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);
}
else if (Type == EDependencyNodeType::SetCharacter)
{
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
const uint32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5);
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
uint32 SetIndex = pChar->CharSetIndex();
const auto *pChar = static_cast<const CSetCharacterDependency*>(pNode);
const uint32 SetIndex = pChar->CharSetIndex();
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
}
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());
}
else
{
ParseChildren = true;
}
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);
}
}
@ -570,11 +588,12 @@ void CAssetDependencyListBuilder::BuildDependencyList(std::vector<CAssetID>& Out
void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector<CAssetID>& Out)
{
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;
// 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)
{
if (!pNode) return;
EDependencyNodeType Type = pNode->Type();
if (!pNode)
return;
const EDependencyNodeType Type = pNode->Type();
bool ParseChildren = false;
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);
}
else if (Type == EDependencyNodeType::AnimEvent)
{
CAnimEventDependency* pDep = static_cast<CAnimEventDependency*>(pNode);
uint32 CharIndex = pDep->CharIndex();
const auto* pDep = static_cast<CAnimEventDependency*>(pNode);
const uint32 CharIndex = pDep->CharIndex();
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
AddDependency(pDep->ID(), Out);
}
else if (Type == EDependencyNodeType::SetCharacter)
{
CSetCharacterDependency* pChar = static_cast<CSetCharacterDependency*>(pNode);
const auto* pChar = static_cast<CSetCharacterDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex());
}
else if (Type == EDependencyNodeType::SetAnimation)
{
CSetAnimationDependency* pAnim = static_cast<CSetAnimationDependency*>(pNode);
auto* pAnim = static_cast<CSetAnimationDependency*>(pNode);
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim);
}
else
{
ParseChildren = true;
}
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);
}
}

View File

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

View File

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

View File

@ -6,6 +6,7 @@
class IUIRelay
{
public:
virtual ~IUIRelay() = default;
virtual void ShowMessageBox(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;

View File

@ -1,16 +1,13 @@
#include "CDynamicVertexBuffer.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
};
CDynamicVertexBuffer::CDynamicVertexBuffer()
: mAttribFlags(EVertexAttribute::None)
, mBufferedFlags(EVertexAttribute::None)
, mNumVertices(0)
{
}
CDynamicVertexBuffer::CDynamicVertexBuffer() = default;
CDynamicVertexBuffer::~CDynamicVertexBuffer()
{
@ -44,7 +41,7 @@ void CDynamicVertexBuffer::SetActiveAttribs(FVertexDescription AttribFlags)
void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkData)
{
uint32 Index;
size_t Index;
switch (Attrib)
{
@ -69,9 +66,9 @@ void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkD
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)
glDeleteBuffers(1, &mAttribBuffers[iAttrib]);
@ -86,9 +83,9 @@ GLuint CDynamicVertexBuffer::CreateVAO()
glGenVertexArrays(1, &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)
{
@ -96,7 +93,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
GLuint NumComponents;
GLenum DataType;
if ((iAttrib == 2) || (iAttrib == 3))
if (iAttrib == 2 || iAttrib == 3)
{
NumComponents = 4;
DataType = GL_UNSIGNED_BYTE;
@ -107,7 +104,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
DataType = GL_FLOAT;
}
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, (void*) 0);
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(iAttrib);
}
}
@ -119,17 +116,18 @@ GLuint CDynamicVertexBuffer::CreateVAO()
// ************ PRIVATE ************
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)
{
glGenBuffers(1, &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;

View File

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

View File

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

View File

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

View File

@ -1,13 +1,9 @@
#include "CIndexBuffer.h"
CIndexBuffer::CIndexBuffer()
: mBuffered(false)
{
}
CIndexBuffer::CIndexBuffer() = default;
CIndexBuffer::CIndexBuffer(GLenum Type)
: mPrimitiveType(Type)
, mBuffered(false)
CIndexBuffer::CIndexBuffer(GLenum type)
: mPrimitiveType(type)
{
}
@ -17,21 +13,21 @@ CIndexBuffer::~CIndexBuffer()
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);
for (uint iIdx = 0; iIdx < Count; iIdx++)
mIndices.push_back(*pIndices++);
Reserve(count);
for (size_t i = 0; i < count; i++)
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()
@ -57,7 +53,9 @@ void CIndexBuffer::Buffer()
void CIndexBuffer::Bind()
{
if (!mBuffered) Buffer();
if (!mBuffered)
Buffer();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
}
@ -68,88 +66,88 @@ void CIndexBuffer::Unbind()
void CIndexBuffer::DrawElements()
{
Bind();
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, (void*) 0);
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, nullptr);
Unbind();
}
void CIndexBuffer::DrawElements(uint Offset, uint Size)
void CIndexBuffer::DrawElements(uint offset, uint size)
{
Bind();
glDrawElements(mPrimitiveType, Size, GL_UNSIGNED_SHORT, (char*)0 + (Offset * 2));
glDrawElements(mPrimitiveType, size, GL_UNSIGNED_SHORT, (char*)0 + (offset * 2));
Unbind();
}
bool CIndexBuffer::IsBuffered()
bool CIndexBuffer::IsBuffered() const
{
return mBuffered;
}
uint CIndexBuffer::GetSize()
uint CIndexBuffer::GetSize() const
{
return mIndices.size();
}
GLenum CIndexBuffer::GetPrimitiveType()
GLenum CIndexBuffer::GetPrimitiveType() const
{
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(*pIndices++);
mIndices.push_back(*pIndices++);
mIndices.push_back(*indices++);
mIndices.push_back(*indices++);
mIndices.push_back(*indices++);
mIndices.push_back(0xFFFF);
}
}
void CIndexBuffer::FansToStrips(uint16 *pIndices, uint Count)
void CIndexBuffer::FansToStrips(uint16 *indices, size_t count)
{
Reserve(Count);
uint16 FirstIndex = *pIndices;
Reserve(count);
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(pIndices[iIdx]);
mIndices.push_back(FirstIndex);
if (iIdx + 1 < Count)
mIndices.push_back(pIndices[iIdx + 1]);
if (iIdx + 2 < Count)
mIndices.push_back(pIndices[iIdx + 2]);
mIndices.push_back(indices[i - 1]);
mIndices.push_back(indices[i]);
mIndices.push_back(firstIndex);
if (i + 1 < count)
mIndices.push_back(indices[i + 1]);
if (i + 2 < count)
mIndices.push_back(indices[i + 2]);
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;
for (; iIdx < Count; iIdx += 4)
size_t i = 3;
for (; i < count; i += 4)
{
mIndices.push_back(pIndices[iIdx - 2]);
mIndices.push_back(pIndices[iIdx - 1]);
mIndices.push_back(pIndices[iIdx - 3]);
mIndices.push_back(pIndices[iIdx]);
mIndices.push_back(indices[i - 2]);
mIndices.push_back(indices[i - 1]);
mIndices.push_back(indices[i - 3]);
mIndices.push_back(indices[i]);
mIndices.push_back(0xFFFF);
}
// 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(pIndices[iIdx - 2]);
mIndices.push_back(pIndices[iIdx - 1]);
mIndices.push_back(indices[i - 3]);
mIndices.push_back(indices[i - 2]);
mIndices.push_back(indices[i - 1]);
mIndices.push_back(0xFFFF);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@
CVertexBuffer::CVertexBuffer()
{
mBuffered = false;
SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal |
EVertexAttribute::Tex0 | EVertexAttribute::Tex1 |
EVertexAttribute::Tex2 | EVertexAttribute::Tex3 |
@ -22,72 +21,103 @@ CVertexBuffer::~CVertexBuffer()
CVertexArrayManager::DeleteAllArraysForVBO(this);
if (mBuffered)
glDeleteBuffers(14, mAttribBuffers);
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
}
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::Normal) mNormals.push_back(rkVtx.Normal);
if (mVtxDesc & EVertexAttribute::Color0) mColors[0].push_back(rkVtx.Color[0]);
if (mVtxDesc & EVertexAttribute::Color1) mColors[1].push_back(rkVtx.Color[1]);
if ((mVtxDesc & EVertexAttribute::Position) != 0)
mPositions.emplace_back(rkVtx.Position);
if ((mVtxDesc & EVertexAttribute::Normal) != 0)
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++)
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)
for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
{
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
if (mVtxDesc & EVertexAttribute::BoneIndices) mBoneIndices.push_back(rkWeights.Indices);
if (mVtxDesc & EVertexAttribute::BoneWeights) mBoneWeights.push_back(rkWeights.Weights);
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
mTexCoords[iTex].emplace_back(rkVtx.Tex[iTex]);
}
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)
{
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
bool Unique = false;
if (mVtxDesc & EVertexAttribute::Position)
if (rkVtx.Position != mPositions[iVert]) Unique = true;
if ((mVtxDesc & EVertexAttribute::Position) != 0)
{
if (rkVtx.Position != mPositions[iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Normal))
if (rkVtx.Normal != mNormals[iVert]) Unique = true;
if (!Unique && (mVtxDesc & EVertexAttribute::Normal) != 0)
{
if (rkVtx.Normal != mNormals[iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Color0))
if (rkVtx.Color[0] != mColors[0][iVert]) Unique = true;
if (!Unique && (mVtxDesc & EVertexAttribute::Color0) != 0)
{
if (rkVtx.Color[0] != mColors[0][iVert])
Unique = true;
}
if (!Unique && (mVtxDesc & EVertexAttribute::Color1))
if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true;
if (!Unique && (mVtxDesc & EVertexAttribute::Color1) != 0)
{
if (rkVtx.Color[1] != mColors[1][iVert])
Unique = true;
}
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])
{
Unique = true;
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);
for (uint32 iWgt = 0; iWgt < 4; iWgt++)
{
if ( ((mVtxDesc & EVertexAttribute::BoneIndices) && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
((mVtxDesc & EVertexAttribute::BoneWeights) && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])) )
if (((mVtxDesc & EVertexAttribute::BoneIndices) != 0 && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
((mVtxDesc & EVertexAttribute::BoneWeights) != 0 && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])))
{
Unique = true;
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);
}
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);
if (mVtxDesc & EVertexAttribute::Normal)
if ((mVtxDesc & EVertexAttribute::Normal) != 0)
mNormals.reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::Color0)
if ((mVtxDesc & EVertexAttribute::Color0) != 0)
mColors[0].reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::Color1)
if ((mVtxDesc & EVertexAttribute::Color1) != 0)
mColors[1].reserve(ReserveSize);
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)
mTexCoords[iTex].reserve(ReserveSize);
}
if (mVtxDesc & EVertexAttribute::BoneIndices)
if ((mVtxDesc & EVertexAttribute::BoneIndices) != 0)
mBoneIndices.reserve(ReserveSize);
if (mVtxDesc & EVertexAttribute::BoneWeights)
if ((mVtxDesc & EVertexAttribute::BoneWeights) != 0)
mBoneWeights.reserve(ReserveSize);
}
void CVertexBuffer::Clear()
{
if (mBuffered)
glDeleteBuffers(14, mAttribBuffers);
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
mBuffered = false;
mPositions.clear();
@ -140,8 +173,8 @@ void CVertexBuffer::Clear()
mColors[0].clear();
mColors[1].clear();
for (uint32 iTex = 0; iTex < 8; iTex++)
mTexCoords[iTex].clear();
for (auto& coord : mTexCoords)
coord.clear();
mBoneIndices.clear();
mBoneWeights.clear();
@ -152,49 +185,46 @@ void CVertexBuffer::Buffer()
// Make sure we don't end up with two buffers for the same data...
if (mBuffered)
{
glDeleteBuffers(14, mAttribBuffers);
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
mBuffered = false;
}
// 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);
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
if (!HasAttrib) continue;
const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
const bool HasAttrib = (mVtxDesc & Attrib) != 0;
if (!HasAttrib)
continue;
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]);
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)
{
uint8 Index = (uint8) (iAttrib - 2);
const auto Index = static_cast<uint8>(iAttrib - 2);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW);
}
else if (iAttrib < 12)
{
uint8 Index = (uint8) (iAttrib - 4);
const auto Index = static_cast<uint8>(iAttrib - 4);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW);
}
else if (iAttrib == 12)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW);
}
else if (iAttrib == 13)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
@ -207,7 +237,9 @@ void CVertexBuffer::Buffer()
void CVertexBuffer::Bind()
{
if (!mBuffered) Buffer();
if (!mBuffered)
Buffer();
CVertexArrayManager::Current()->BindVAO(this);
}
@ -216,12 +248,12 @@ void CVertexBuffer::Unbind()
glBindVertexArray(0);
}
bool CVertexBuffer::IsBuffered()
bool CVertexBuffer::IsBuffered() const
{
return mBuffered;
}
FVertexDescription CVertexBuffer::VertexDesc()
FVertexDescription CVertexBuffer::VertexDesc() const
{
return mVtxDesc;
}
@ -238,7 +270,7 @@ void CVertexBuffer::SetSkin(CSkin *pSkin)
mpSkin = pSkin;
}
uint32 CVertexBuffer::Size()
size_t CVertexBuffer::Size() const
{
return mPositions.size();
}
@ -249,44 +281,40 @@ GLuint CVertexBuffer::CreateVAO()
glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray);
for (uint32 iAttrib = 0; iAttrib < 14; iAttrib++)
for (size_t iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
{
int Attrib = (EVertexAttribute::Position << iAttrib);
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
const bool HasAttrib = (mVtxDesc & Attrib) != 0;
if (!HasAttrib) continue;
if (iAttrib < 2)
{
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);
}
else if (iAttrib < 4)
{
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);
}
else if (iAttrib < 12)
{
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);
}
else if (iAttrib == 12)
{
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);
}
else if (iAttrib == 13)
{
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);
}
}

View File

@ -5,38 +5,39 @@
#include "Core/Resource/Animation/CSkin.h"
#include "Core/Resource/Model/CVertex.h"
#include "Core/Resource/Model/EVertexAttribute.h"
#include <array>
#include <vector>
#include <GL/glew.h>
class CVertexBuffer
{
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;
std::vector<CVector3f> mPositions; // Vector of vertex positions
std::vector<CVector3f> mNormals; // Vector of vertex normals
std::vector<CColor> mColors[2]; // Vectors of vertex colors
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates
std::array<std::vector<CColor>, 2> mColors; // Vectors of vertex colors
std::array<std::vector<CVector2f>, 8> mTexCoords; // Vectors of texture coordinates
std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices
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:
CVertexBuffer();
CVertexBuffer(FVertexDescription Desc);
explicit CVertexBuffer(FVertexDescription Desc);
~CVertexBuffer();
uint16 AddVertex(const CVertex& rkVtx);
uint16 AddIfUnique(const CVertex& rkVtx, uint16 Start);
void Reserve(uint16 Size);
void Reserve(size_t Size);
void Clear();
void Buffer();
void Bind();
void Unbind();
bool IsBuffered();
FVertexDescription VertexDesc();
bool IsBuffered() const;
FVertexDescription VertexDesc() const;
void SetVertexDesc(FVertexDescription Desc);
void SetSkin(CSkin *pSkin);
uint32 Size();
size_t Size() const;
GLuint CreateVAO();
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,42 +3,6 @@
#include "Core/GameProject/CResourceStore.h"
#include <Common/Log.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 ************
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)
{
DrawLine(PointA, PointB, CColor::skWhite);
DrawLine(PointA, PointB, CColor::White());
}
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB)
{
// 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)
@ -317,7 +281,7 @@ void CDrawUtil::UseColorShaderLighting(const CColor& kColor)
void CDrawUtil::UseTextureShader()
{
UseTextureShader(CColor::skWhite);
UseTextureShader(CColor::White());
}
void CDrawUtil::UseTextureShader(const CColor& TintColor)
@ -354,7 +318,7 @@ void CDrawUtil::UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColo
CShader* CDrawUtil::GetTextShader()
{
Init();
return mpTextShader;
return mpTextShader.get();
}
void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
@ -366,13 +330,13 @@ void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
CTexture* CDrawUtil::GetLightTexture(ELightType Type)
{
Init();
return mpLightTextures[(int) Type];
return mpLightTextures[static_cast<size_t>(Type)];
}
CTexture* CDrawUtil::GetLightMask(ELightType Type)
{
Init();
return mpLightMasks[(int) Type];
return mpLightMasks[static_cast<size_t>(Type)];
}
CModel* CDrawUtil::GetCubeModel()
@ -410,16 +374,18 @@ void CDrawUtil::InitGrid()
const int kGridSize = 501; // must be odd
const float kGridSpacing = 1.f;
int MinIdx = (kGridSize - 1) / -2;
int MaxIdx = (kGridSize - 1) / 2;
const int MinIdx = (kGridSize - 1) / -2;
const int MaxIdx = (kGridSize - 1) / 2;
mGridVertices.emplace();
mGridVertices->SetVertexDesc(EVertexAttribute::Position);
mGridVertices->Reserve(kGridSize * 4);
mGridVertices->Reserve(static_cast<size_t>(kGridSize * 4));
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(MaxIdx * kGridSpacing, i * 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, MaxIdx * kGridSpacing, 0.0f));
int NumIndices = kGridSize * 4;
const auto NumIndices = static_cast<size_t>(kGridSize * 4);
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);
}
@ -453,34 +420,34 @@ void CDrawUtil::InitSquare()
EVertexAttribute::Tex7);
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 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)
};
CVector2f SquareTexCoords[] = {
static constexpr std::array SquareTexCoords{
CVector2f(0.f, 1.f),
CVector2f(1.f, 1.f),
CVector2f(1.f, 0.f),
CVector2f(0.f, 0.f)
};
mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices);
mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals);
mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices.data());
mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals.data());
for (uint32 iTex = 0; iTex < 8; iTex++)
{
EVertexAttribute Attrib = (EVertexAttribute) (EVertexAttribute::Tex0 << iTex);
mSquareVertices->BufferAttrib(Attrib, SquareTexCoords);
const auto Attrib = static_cast<EVertexAttribute>(EVertexAttribute::Tex0 << iTex);
mSquareVertices->BufferAttrib(Attrib, SquareTexCoords.data());
}
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));
uint16 Indices[] = {
static constexpr std::array<uint16, 24> Indices{
0, 1,
1, 2,
2, 3,
@ -539,7 +506,7 @@ void CDrawUtil::InitWireCube()
2, 6,
3, 5
};
mWireCubeIndices.AddIndices(Indices, sizeof(Indices) / sizeof(uint16));
mWireCubeIndices.AddIndices(Indices.data(), Indices.size());
mWireCubeIndices.SetPrimitiveType(GL_LINES);
}
@ -586,18 +553,18 @@ void CDrawUtil::InitTextures()
void CDrawUtil::Shutdown()
{
if (mDrawUtilInitialized)
{
if (!mDrawUtilInitialized)
return;
debugf("Shutting down");
mGridVertices = std::nullopt;
mSquareVertices = std::nullopt;
mLineVertices = std::nullopt;
mWireCubeVertices = std::nullopt;
delete mpColorShader;
delete mpColorShaderLighting;
delete mpTextureShader;
delete mpCollisionShader;
delete mpTextShader;
mGridVertices.reset();
mSquareVertices.reset();
mLineVertices.reset();
mWireCubeVertices.reset();
mpColorShader.reset();
mpColorShaderLighting.reset();
mpTextureShader.reset();
mpCollisionShader.reset();
mpTextShader.reset();
mDrawUtilInitialized = false;
}
}

View File

@ -7,6 +7,7 @@
#include "Core/Resource/Model/CModel.h"
#include "Core/Resource/CLight.h"
#include <array>
#include <optional>
/**
@ -19,48 +20,48 @@
class CDrawUtil
{
// 7x7 Grid
static std::optional<CVertexBuffer> mGridVertices;
static CIndexBuffer mGridIndices;
static inline std::optional<CVertexBuffer> mGridVertices;
static inline CIndexBuffer mGridIndices;
// Square
static std::optional<CDynamicVertexBuffer> mSquareVertices;
static CIndexBuffer mSquareIndices;
static inline std::optional<CDynamicVertexBuffer> mSquareVertices;
static inline CIndexBuffer mSquareIndices;
// Line
static std::optional<CDynamicVertexBuffer> mLineVertices;
static CIndexBuffer mLineIndices;
static inline std::optional<CDynamicVertexBuffer> mLineVertices;
static inline CIndexBuffer mLineIndices;
// Cube
static TResPtr<CModel> mpCubeModel;
static inline TResPtr<CModel> mpCubeModel;
// Wire Cube
static std::optional<CVertexBuffer> mWireCubeVertices;
static CIndexBuffer mWireCubeIndices;
static inline std::optional<CVertexBuffer> mWireCubeVertices;
static inline CIndexBuffer mWireCubeIndices;
// Sphere
static TResPtr<CModel> mpSphereModel;
static TResPtr<CModel> mpDoubleSidedSphereModel;
static inline TResPtr<CModel> mpSphereModel;
static inline TResPtr<CModel> mpDoubleSidedSphereModel;
// Wire Sphere
static TResPtr<CModel> mpWireSphereModel;
static inline TResPtr<CModel> mpWireSphereModel;
// Shaders
static CShader *mpColorShader;
static CShader *mpColorShaderLighting;
static CShader *mpBillboardShader;
static CShader *mpLightBillboardShader;
static CShader *mpTextureShader;
static CShader *mpCollisionShader;
static CShader *mpTextShader;
static inline std::unique_ptr<CShader> mpColorShader;
static inline std::unique_ptr<CShader> mpColorShaderLighting;
static inline std::unique_ptr<CShader> mpBillboardShader;
static inline std::unique_ptr<CShader> mpLightBillboardShader;
static inline std::unique_ptr<CShader> mpTextureShader;
static inline std::unique_ptr<CShader> mpCollisionShader;
static inline std::unique_ptr<CShader> mpTextShader;
// Textures
static TResPtr<CTexture> mpCheckerTexture;
static inline TResPtr<CTexture> mpCheckerTexture;
static TResPtr<CTexture> mpLightTextures[4];
static TResPtr<CTexture> mpLightMasks[4];
static inline std::array<TResPtr<CTexture>, 4> mpLightTextures;
static inline std::array<TResPtr<CTexture>, 4> mpLightMasks;
// Have all the above members been initialized?
static bool mDrawUtilInitialized;
static inline bool mDrawUtilInitialized = false;
public:
static void DrawGrid(CColor LineColor, CColor BoldLineColor);
@ -85,17 +86,17 @@ public:
static void DrawSphere(bool DoubleSided = false);
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 UseColorShaderLighting(const CColor& Color);
static void UseTextureShader();
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 void LoadCheckerboardTexture(uint32 GLTextureUnit);

View File

@ -22,14 +22,13 @@ CGraphics::SLightBlock CGraphics::sLightBlock;
CGraphics::ELightingMode CGraphics::sLightMode;
uint32 CGraphics::sNumLights;
const CColor CGraphics::skDefaultAmbientColor = CColor(0.5f, 0.5f, 0.5f, 0.0f);
CColor CGraphics::sAreaAmbientColor = CColor::skTransparentBlack;
CColor CGraphics::sAreaAmbientColor = CColor::TransparentBlack();
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.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 ************
void CGraphics::Initialize()
@ -170,8 +169,8 @@ void CGraphics::SetDefaultLighting()
sNumLights = 0;
UpdateLightBlock();
sVertexBlock.COLOR0_Amb = CColor::skGray;
sVertexBlock.COLOR0_Mat = CColor::skWhite;
sVertexBlock.COLOR0_Amb = CColor::Gray();
sVertexBlock.COLOR0_Mat = CColor::White();
UpdateVertexBlock();
}
@ -182,7 +181,7 @@ void CGraphics::SetupAmbientColor()
else if (sLightMode == ELightingMode::Basic)
sVertexBlock.COLOR0_Amb = skDefaultAmbientColor;
else
sVertexBlock.COLOR0_Amb = CColor::skTransparentWhite;
sVertexBlock.COLOR0_Amb = CColor::TransparentWhite();
}
void CGraphics::SetIdentityMVP()

View File

@ -9,6 +9,7 @@
#include <Common/Math/CMatrix4f.h>
#include <Common/Math/CVector3f.h>
#include <Common/Math/CVector4f.h>
#include <array>
/**
* todo: this entire thing needs to be further abstracted, other classes shouldn't
@ -43,8 +44,8 @@ public:
// SVertexBlock
struct SVertexBlock
{
CMatrix4f TexMatrices[10];
CMatrix4f PostMatrices[20];
std::array<CMatrix4f, 10> TexMatrices;
std::array<CMatrix4f, 20> PostMatrices;
CColor COLOR0_Amb;
CColor COLOR0_Mat;
CColor COLOR1_Amb;
@ -55,15 +56,15 @@ public:
// SPixelBlock
struct SPixelBlock
{
CColor Konst[4];
CColor TevColor[4];
std::array<CColor, 4> Konst;
std::array<CColor, 4> TevColor;
CColor TintColor;
float LightmapMultiplier;
float Padding[3];
std::array<float, 3> Padding;
void SetAllTevColors(const CColor& color)
{
std::fill(std::begin(TevColor), std::end(TevColor), color);
TevColor.fill(color);
}
};
static SPixelBlock sPixelBlock;
@ -79,7 +80,7 @@ public:
CVector4f DistAtten;
CVector4f AngleAtten;
};
SGXLight Lights[8];
std::array<SGXLight, 8> Lights;
};
static SLightBlock sLightBlock;
@ -87,10 +88,10 @@ public:
enum class ELightingMode { None, Basic, World };
static ELightingMode sLightMode;
static uint32 sNumLights;
static const CColor skDefaultAmbientColor;
static constexpr CColor skDefaultAmbientColor{0.5f, 0.5f, 0.5f, 0.0f};
static CColor sAreaAmbientColor;
static float sWorldLightMultiplier;
static CLight sDefaultDirectionalLights[3];
static std::array<CLight, 3> sDefaultDirectionalLights;
// Functions
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)
{
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize,
[&, pkCamera](const SRenderablePtr& rkLeft, const SRenderablePtr& rkRight) -> bool
{
CVector3f CamPos = pkCamera->Position();
CVector3f CamDir = pkCamera->Direction();
[&, pkCamera](const auto& rkLeft, const auto& rkRight) {
const CVector3f CamPos = pkCamera->Position();
const CVector3f CamDir = pkCamera->Direction();
CVector3f DistL = rkLeft.AABox.ClosestPointAlongVector(CamDir) - CamPos;
CVector3f DistR = rkRight.AABox.ClosestPointAlongVector(CamDir) - CamPos;
float DotL = DistL.Dot(CamDir);
float DotR = DistR.Dot(CamDir);
return (DotL > DotR);
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)
{
for (uint32 iPtr = 0; iPtr < mSize; iPtr++)
{
SRenderablePtr *pPtr = &mRenderables[iPtr];
CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::skWhite);
if (!DebugVisualization)
return;
CVector3f Dist = Point - pkCamera->Position();
for (size_t iPtr = 0; iPtr < mSize; iPtr++)
{
const SRenderablePtr *pPtr = &mRenderables[iPtr];
const CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::White());
const 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);
if (Dot < 0.f)
Dot = -Dot;
Dot = std::min(Dot, 50.f);
const float Intensity = 1.f - (Dot / 50.f);
const CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Point);
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawCube(CubeColor);
}
}
}
void CRenderBucket::CSubBucket::Clear()
{
mEstSize = mSize;
if (mRenderables.size() > mSize) mRenderables.resize(mSize);
if (mRenderables.size() > mSize)
mRenderables.resize(mSize);
mSize = 0;
}
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];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,8 @@
#include "Core/Resource/Model/CModel.h"
#include <Common/BasicTypes.h>
#include <memory>
#include <set>
#include <vector>
// Animation structures
@ -27,7 +29,7 @@ struct SAdditiveAnim
struct SAnimation
{
TString Name;
IMetaAnimation *pMetaAnim;
std::unique_ptr<IMetaAnimation> pMetaAnim;
};
struct STransition
@ -35,13 +37,13 @@ struct STransition
uint32 Unknown;
uint32 AnimIdA;
uint32 AnimIdB;
IMetaTransition *pMetaTrans;
std::unique_ptr<IMetaTransition> pMetaTrans;
};
struct SHalfTransition
{
uint32 AnimID;
IMetaTransition *pMetaTrans;
std::unique_ptr<IMetaTransition> pMetaTrans;
};
// Character structures
@ -94,50 +96,37 @@ class CAnimSet : public CResource
std::vector<CAnimPrimitive> mAnimPrimitives;
std::vector<SAnimation> mAnimations;
std::vector<STransition> mTransitions;
IMetaTransition *mpDefaultTransition;
std::unique_ptr<IMetaTransition> mpDefaultTransition;
std::vector<SAdditiveAnim> mAdditiveAnims;
float mDefaultAdditiveFadeIn;
float mDefaultAdditiveFadeOut;
float mDefaultAdditiveFadeIn = 0.0f;
float mDefaultAdditiveFadeOut = 0.0f;
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:
CAnimSet(CResourceEntry *pEntry = 0)
explicit CAnimSet(CResourceEntry *pEntry = nullptr)
: 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 (uint32 iEvent = 0; iEvent < mAnimEvents.size(); iEvent++)
for ([[maybe_unused]] const auto& event : mAnimEvents)
{
ASSERT(mAnimEvents[iEvent] && !mAnimEvents[iEvent]->Entry());
delete mAnimEvents[iEvent];
ASSERT(event != nullptr && !event->Entry());
}
}
CDependencyTree* BuildDependencyTree() const
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
{
CDependencyTree *pTree = new CDependencyTree();
auto pTree = std::make_unique<CDependencyTree>();
// 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);
pTree->AddChild(pCharTree);
pTree->AddChild(std::move(pCharTree));
}
// Animation dependencies
@ -145,58 +134,52 @@ public:
{
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
auto pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
ASSERT(pAnimTree);
pTree->AddChild(pAnimTree);
pTree->AddChild(std::move(pAnimTree));
}
}
else if (Game() <= EGame::Corruption)
{
const SSetCharacter& rkChar = mCharacters[0];
std::set<CAnimPrimitive> PrimitiveSet;
// Animations
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
for (const auto& anim : mAnimations)
{
const SAnimation& rkAnim = mAnimations[iAnim];
rkAnim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
anim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
}
CSourceAnimData *pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID);
if (pAnimData)
pAnimData->AddTransitionDependencies(pTree);
if (auto* pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID))
pAnimData->AddTransitionDependencies(pTree.get());
for (auto Iter = PrimitiveSet.begin(); Iter != PrimitiveSet.end(); Iter++)
for (const auto& prim : PrimitiveSet)
{
const CAnimPrimitive& rkPrim = *Iter;
pTree->AddDependency(rkPrim.Animation());
pTree->AddDependency(prim.Animation());
}
// 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
{
const SSetCharacter& rkChar = mCharacters[0];
for (uint32 iDep = 0; iDep < rkChar.DKDependencies.size(); iDep++)
pTree->AddDependency(rkChar.DKDependencies[iDep]);
for (const auto& dep : rkChar.DKDependencies)
pTree->AddDependency(dep);
}
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 Prim.Animation();
return mAnimPrimitives[AnimID].Animation();
}
return nullptr;
@ -204,39 +187,37 @@ public:
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
{
for (uint32 iAnim = 0; iAnim < mAnimPrimitives.size(); iAnim++)
rPrimSet.insert(mAnimPrimitives[iAnim]);
rPrimSet.insert(mAnimPrimitives.cbegin(), mAnimPrimitives.cend());
}
// Accessors
inline uint32 NumCharacters() const { return mCharacters.size(); }
inline uint32 NumAnimations() const { return mAnimations.size(); }
size_t NumCharacters() const { return mCharacters.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];
}
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];
}
CAnimEventData* AnimationEventData(uint32 Index) const
CAnimEventData* AnimationEventData(size_t Index) const
{
ASSERT(Index >= 0 && Index < NumAnimations());
ASSERT(Index < NumAnimations());
if (Game() <= EGame::Prime)
{
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
return rkPrim.Animation() ? rkPrim.Animation()->EventData() : nullptr;
return rkPrim.Animation() != nullptr ? rkPrim.Animation()->EventData() : nullptr;
}
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*/)
: 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);
return pTree;
}

View File

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

View File

@ -2,33 +2,16 @@
#include "CAnimSet.h"
#include "Core/GameProject/CResourceStore.h"
#include <Common/Log.h>
#include <iostream>
CAnimationParameters::CAnimationParameters()
: mGame(EGame::Prime)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
}
CAnimationParameters::CAnimationParameters() = default;
CAnimationParameters::CAnimationParameters(EGame Game)
: mGame(Game)
, mCharacterID( CAssetID::InvalidID(Game) )
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
: mGame(Game), mCharacterID(CAssetID::InvalidID(Game))
{
}
CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
: mGame(Game)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
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)
NodeIndex = mCharIndex;
if (mCharIndex != -1 && pSet->NumCharacters() > (uint32) NodeIndex)
if (mCharIndex != UINT32_MAX && pSet->NumCharacters() > static_cast<uint32>(NodeIndex))
return pSet->Character(NodeIndex);
}
return nullptr;
}
CModel* CAnimationParameters::GetCurrentModel(int32 NodeIndex /*= -1*/)
CModel* CAnimationParameters::GetCurrentModel(int32 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);
return pkChar ? pkChar->Name : "";
return pkChar != nullptr ? pkChar->Name : "";
}
// ************ 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
// 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)
{
case 0: mAnimIndex = Value;
case 1: mUnknown2 = Value;
case 2: mUnknown3 = Value;
case 0:
mAnimIndex = Value;
break;
case 1:
mUnknown2 = Value;
break;
case 2:
mUnknown3 = Value;
break;
}
}

View File

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

View File

@ -5,12 +5,12 @@
#include <Common/Macros.h>
#include <Common/Math/MathUtil.h>
#include <algorithm>
#include <cfloat>
// ************ CBone ************
CBone::CBone(CSkeleton *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);
if (AnchorRoot && IsRoot())
TransformInfo.Position = CVector3f::skZero;
TransformInfo.Position = CVector3f::Zero();
// Apply parent transform
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position));
@ -39,8 +39,8 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo&
rTransform *= mInvBind;
// Calculate children
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
for (auto* child : mChildren)
child->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
}
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
// actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton),
// so we need to account for both
return (mpParent == nullptr || mpParent->Parent() == nullptr);
return mpParent == nullptr || mpParent->Parent() == nullptr;
}
// ************ CSkeleton ************
const float CSkeleton::skSphereRadius = 0.025f;
CSkeleton::CSkeleton(CResourceEntry *pEntry /*= 0*/)
CSkeleton::CSkeleton(CResourceEntry *pEntry)
: CResource(pEntry)
, mpRootBone(nullptr)
{
}
CSkeleton::~CSkeleton()
{
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
delete mBones[iBone];
}
CSkeleton::~CSkeleton() = default;
CBone* CSkeleton::BoneByID(uint32 BoneID) const
{
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
{
if (mBones[iBone]->ID() == BoneID)
return mBones[iBone];
}
const auto iter = std::find_if(mBones.begin(), mBones.end(),
[BoneID](const auto& bone) { return bone->ID() == BoneID; });
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++)
{
if (mBones[iBone]->Name() == rkBoneName)
return mBones[iBone];
}
const auto iter = std::find_if(mBones.begin(), mBones.end(),
[&name](const auto& bone) { return bone->Name() == name; });
if (iter == mBones.cend())
return nullptr;
return iter->get();
}
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)
ID = mBones[iBone]->ID();
return 0;
}
return ID;
return (*iter)->ID();
}
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);
// 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];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw the bone's local XYZ axes for selected bones
if (pBone->IsSelected())
{
CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::skRed);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::skGreen);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::skBlue);
const CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::Red());
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::Green());
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::Blue());
}
// 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);
CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
const CBone *pChild = pBone->ChildByIndex(iChild);
const CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
CDrawUtil::DrawLine(BonePos, ChildPos);
}
}
// 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];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
CTransform4f Transform;
Transform.Scale(skSphereRadius);
Transform.Translate(BonePos);
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
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);
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
for (const auto& pBone : mBones)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pBone->TransformedPosition(rkData);
std::pair<bool,float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
const CVector3f BonePos = pBone->TransformedPosition(rkData);
const std::pair<bool, float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
if (Intersect.first && Intersect.second < Out.second)
{

View File

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

View File

@ -23,24 +23,24 @@ class CSkin : public CResource
std::vector<SVertGroup> mVertGroups;
public:
CSkin(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
explicit CSkin(CResourceEntry *pEntry = nullptr) : CResource(pEntry) {}
const SVertexWeights& WeightsForVertex(uint32 VertIdx)
{
// 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},
{ 1.f, 0.f, 0.f, 0.f }
{1.f, 0.f, 0.f, 0.f},
};
uint32 Index = 0;
for (uint32 iGrp = 0; iGrp < mVertGroups.size(); iGrp++)
for (const auto& group : mVertGroups)
{
if (VertIdx < Index + mVertGroups[iGrp].NumVertices)
return mVertGroups[iGrp].Weights;
if (VertIdx < Index + group.NumVertices)
return group.Weights;
Index += mVertGroups[iGrp].NumVertices;
Index += group.NumVertices;
}
return skNullWeights;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,37 +2,26 @@
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Render/CRenderer.h"
CGameArea::CGameArea(CResourceEntry *pEntry /*= 0*/)
CGameArea::CGameArea(CResourceEntry *pEntry)
: CResource(pEntry)
, mWorldIndex(-1)
, mVertexCount(0)
, mTriangleCount(0)
, mTerrainMerged(false)
, mOriginalWorldMeshCount(0)
, mUsesCompression(false)
, mpMaterialSet(nullptr)
, mpCollision(nullptr)
{
}
CGameArea::~CGameArea()
{
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
CAreaDependencyTree *pTree = new CAreaDependencyTree();
auto pTree = std::make_unique<CAreaDependencyTree>();
std::set<CAssetID> MatTextures;
mpMaterialSet->GetUsedTextureIDs(MatTextures);
for (auto Iter = MatTextures.begin(); Iter != MatTextures.end(); Iter++)
pTree->AddDependency(*Iter);
for (const auto& id : MatTextures)
pTree->AddDependency(id);
pTree->AddDependency(mPathID);
@ -43,8 +32,8 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
}
// Extra deps
for (uint32 iDep = 0; iDep < mExtraAreaDeps.size(); iDep++)
pTree->AddDependency(mExtraAreaDeps[iDep]);
for (const auto& dep : mExtraAreaDeps)
pTree->AddDependency(dep);
// Layer dependencies
std::vector<CAssetID> DummyDeps;
@ -52,18 +41,19 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
for (uint32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
{
const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps);
pTree->AddScriptLayer(mScriptLayers[iLayer], rkExtras);
pTree->AddScriptLayer(mScriptLayers[iLayer].get(), rkExtras);
}
return pTree;
}
void CGameArea::AddWorldModel(CModel *pModel)
void CGameArea::AddWorldModel(std::unique_ptr<CModel>&& pModel)
{
mWorldModels.push_back(pModel);
mVertexCount += pModel->GetVertexCount();
mTriangleCount += pModel->GetTriangleCount();
mAABox.ExpandBounds(pModel->AABox());
mWorldModels.push_back(std::move(pModel));
}
void CGameArea::MergeTerrain()
@ -71,18 +61,17 @@ void CGameArea::MergeTerrain()
if (mTerrainMerged) return;
// 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];
uint32 SubmeshCount = pMdl->GetSurfaceCount();
const size_t SubmeshCount = pMdl->GetSurfaceCount();
for (uint32 iSurf = 0; iSurf < SubmeshCount; iSurf++)
for (size_t iSurf = 0; iSurf < SubmeshCount; iSurf++)
{
SSurface *pSurf = pMdl->GetSurface(iSurf);
CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID, false);
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)
{
@ -91,10 +80,10 @@ void CGameArea::MergeTerrain()
// (particularly with multi-layered transparent meshes)
// so we need to at least try to maintain it.
// 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);
mStaticWorldModels.erase(it);
mStaticWorldModels.push_back(pStatic);
mStaticWorldModels.push_back(std::move(pStatic));
NewMat = false;
break;
}
@ -102,9 +91,9 @@ void CGameArea::MergeTerrain()
if (NewMat)
{
CStaticModel *pStatic = new CStaticModel(pMat);
auto pStatic = std::make_unique<CStaticModel>(pMat);
pStatic->AddSurface(pSurf);
mStaticWorldModels.push_back(pStatic);
mStaticWorldModels.push_back(std::move(pStatic));
}
}
}
@ -112,44 +101,41 @@ void CGameArea::MergeTerrain()
void CGameArea::ClearTerrain()
{
for (uint32 iModel = 0; iModel < mWorldModels.size(); iModel++)
delete mWorldModels[iModel];
mWorldModels.clear();
for (uint32 iStatic = 0; iStatic < mStaticWorldModels.size(); iStatic++)
delete mStaticWorldModels[iStatic];
mStaticWorldModels.clear();
if (mpMaterialSet) delete mpMaterialSet;
if (mpMaterialSet)
delete mpMaterialSet;
mVertexCount = 0;
mTriangleCount = 0;
mTerrainMerged = false;
mAABox = CAABox::skInfinite;
mAABox = CAABox::Infinite();
}
void CGameArea::ClearScriptLayers()
{
for (auto it = mScriptLayers.begin(); it != mScriptLayers.end(); it++)
delete *it;
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++)
Num += mScriptLayers[iLyr]->NumInstances();
for (const auto& layer : mScriptLayers)
Num += layer->NumInstances();
return Num;
}
CScriptObject* CGameArea::InstanceByID(uint32 InstanceID)
{
auto it = mObjectMap.find(InstanceID);
if (it != mObjectMap.end()) return it->second;
else return nullptr;
const auto it = mObjectMap.find(InstanceID);
if (it != mObjectMap.cend())
return it->second;
return nullptr;
}
uint32 CGameArea::FindUnusedInstanceID() const
@ -178,30 +164,30 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
uint32 SuggestedLayerIndex /*= -1*/ )
{
// Verify we can fit another instance in this area.
uint32 NumInstances = TotalInstanceCount();
const size_t NumInstances = TotalInstanceCount();
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;
}
// Check whether the suggested instance ID is valid
uint32 InstanceID = SuggestedID;
if (InstanceID != -1)
if (InstanceID != UINT32_MAX)
{
if (mObjectMap.find(InstanceID) == mObjectMap.end())
InstanceID = -1;
if (mObjectMap.find(InstanceID) == mObjectMap.cend())
InstanceID = UINT32_MAX;
}
// 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
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");
return nullptr;
@ -212,13 +198,14 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
}
// Spawn instance
CScriptObject *pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate);
auto* pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate);
pInstance->EvaluateProperties();
pInstance->SetPosition(rkPosition);
pInstance->SetRotation(rkRotation.ToEuler());
pInstance->SetScale(rkScale);
pInstance->SetName(pTemplate->Name());
if (pTemplate->Game() < EGame::EchoesDemo) pInstance->SetActive(true);
if (pTemplate->Game() < EGame::EchoesDemo)
pInstance->SetActive(true);
pLayer->AddInstance(pInstance, SuggestedLayerIndex);
mObjectMap[InstanceID] = pInstance;
return pInstance;

View File

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

View File

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

View File

@ -2,6 +2,7 @@
#define CAUDIOLOOKUPTABLE
#include "CResource.h"
#include <vector>
class CAudioLookupTable : public CResource
{
@ -10,13 +11,15 @@ class CAudioLookupTable : public CResource
std::vector<uint16> mDefineIDs;
public:
CAudioLookupTable(CResourceEntry *pEntry = 0)
explicit CAudioLookupTable(CResourceEntry *pEntry = nullptr)
: 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];
}
};

View File

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

View File

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

View File

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

View File

@ -9,11 +9,13 @@
#include "Core/OpenGL/CIndexBuffer.h"
#include <Common/BasicTypes.h>
#include <array>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#define CFONT_DEFAULT_SIZE -1
#define CFONT_DEFAULT_SIZE UINT32_MAX
class CRenderer;
@ -25,19 +27,19 @@ class CFont : public CResource
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().
uint32 mUnknown; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes.
uint32 mLineHeight; // Height of each line, in points
uint32 mLineMargin; // 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 mDefaultSize; // In points.
uint32 mUnknown = 0; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes.
uint32 mLineHeight = 0; // Height of each line, in points
uint32 mLineMargin = 0; // Gap between lines, in points - this is added to the line height
uint32 mVerticalOffset = 0; // In points. This is used to reposition glyphs after the per-glyph vertical offset is applied
uint32 mDefaultSize = 0; // In points.
TString mFontName; // Self-explanatory
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
{
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 RightPadding; // The amount of padding applied right of this glyph, in points
uint32 Width; // The width of the glyph, in points
@ -59,17 +61,17 @@ class CFont : public CResource
public:
CFont(CResourceEntry *pEntry = 0);
~CFont();
CDependencyTree* BuildDependencyTree() const;
explicit CFont(CResourceEntry *pEntry = nullptr);
~CFont() override;
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
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);
// Accessors
inline TString FontName() const { return mFontName; }
inline CTexture* Texture() const { return mpFontTexture; }
TString FontName() const { return mFontName; }
CTexture* Texture() const { return mpFontTexture; }
private:
static void InitBuffers();
static void ShutdownBuffers();

View File

@ -1,20 +1,14 @@
#include "CLight.h"
#include "Core/Render/CGraphics.h"
#include <Common/Common.h>
#include <cfloat>
#include <cmath>
#include <float.h>
#define CLIGHT_NO_RADIUS 0x40
#define CLIGHT_NO_INTENSITY 0x80
constexpr uint32_t CLIGHT_NO_RADIUS = 0x40;
constexpr uint32_t CLIGHT_NO_INTENSITY = 0x80;
CLight::CLight()
: mPosition(skDefaultLightPos)
, 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)
: mDirtyFlags(CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY)
{
}
@ -76,7 +70,7 @@ float CLight::CalculateIntensity() const
if (mType == ELightType::Custom)
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
// Get the color component with the greatest numeric value
float Greatest = (mColor.G >= mColor.B) ? mColor.G : mColor.B;
@ -88,13 +82,14 @@ float CLight::CalculateIntensity() const
}
// 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);
float RadianCosine = cosf(RadianCutoff);
float InvCosine = 1.f - RadianCosine;
const float RadianCutoff = mSpotCutoff * (3.1415927f / 180.f);
const float RadianCosine = cosf(RadianCutoff);
const float InvCosine = 1.f - RadianCosine;
return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine);
}
@ -102,7 +97,7 @@ CVector3f CLight::CalculateSpotAngleAtten()
// ************ ACCESSORS ************
float CLight::GetRadius() const
{
if (mDirtyFlags & CLIGHT_NO_RADIUS)
if ((mDirtyFlags & CLIGHT_NO_RADIUS) != 0)
{
mCachedRadius = CalculateRadius();
mDirtyFlags &= ~CLIGHT_NO_RADIUS;
@ -113,7 +108,7 @@ float CLight::GetRadius() const
float CLight::GetIntensity() const
{
if (mDirtyFlags & CLIGHT_NO_INTENSITY)
if ((mDirtyFlags & CLIGHT_NO_INTENSITY) != 0)
{
mCachedIntensity = CalculateIntensity();
mDirtyFlags &= ~CLIGHT_NO_INTENSITY;
@ -131,7 +126,7 @@ void CLight::SetColor(const CColor& rkColor)
void CLight::SetSpotCutoff(float Cutoff)
{
mSpotCutoff = Cutoff * 0.5f;
CalculateSpotAngleAtten();
mAngleAttenCoefficients = CalculateSpotAngleAtten();
}
void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC)
@ -198,8 +193,9 @@ CStructProperty* CLight::GetProperties() const
// ************ OTHER ************
void CLight::Load() const
{
uint8 Index = (uint8) CGraphics::sNumLights;
if (Index >= 8) return;
const auto Index = static_cast<uint8>(CGraphics::sNumLights);
if (Index >= CGraphics::sLightBlock.Lights.size())
return;
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;
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
{
ELightType mType;
uint32 mLayerIndex;
CVector3f mPosition;
CVector3f mDirection;
ELightType mType{};
uint32 mLayerIndex = 0;
CVector3f mPosition{skDefaultLightPos};
CVector3f mDirection{skDefaultLightDir};
CColor mColor;
float mSpotCutoff;
CVector3f mDistAttenCoefficients;
CVector3f mAngleAttenCoefficients;
float mSpotCutoff = 0.0f;
CVector3f mDistAttenCoefficients{0.f, 1.f, 0.f};
CVector3f mAngleAttenCoefficients{0.f, 1.f, 0.f};
mutable float mCachedRadius;
mutable float mCachedIntensity;
mutable float mCachedRadius = 0.0f;
mutable float mCachedIntensity = 0.0f;
mutable uint8 mDirtyFlags;
public:
@ -39,21 +39,21 @@ private:
// Data Manipulation
float CalculateRadius() const;
float CalculateIntensity() const;
CVector3f CalculateSpotAngleAtten();
CVector3f CalculateSpotAngleAtten() const;
public:
// Accessors
inline ELightType Type() const { return mType; }
inline uint32 LayerIndex() const { return mLayerIndex; }
inline CVector3f Position() const { return mPosition; }
inline CVector3f Direction() const { return mDirection; }
inline CColor Color() const { return mColor; }
inline CVector3f DistAttenuation() const { return mDistAttenCoefficients; }
inline CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; }
ELightType Type() const { return mType; }
uint32 LayerIndex() const { return mLayerIndex; }
CVector3f Position() const { return mPosition; }
CVector3f Direction() const { return mDirection; }
CColor Color() const { return mColor; }
CVector3f DistAttenuation() const { return mDistAttenCoefficients; }
CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; }
inline void SetLayer(uint32 Index) { mLayerIndex = Index; }
inline void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; }
inline void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; }
void SetLayer(uint32 Index) { mLayerIndex = Index; }
void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; }
void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; }
float GetRadius() const;
float GetIntensity() const;
@ -77,8 +77,8 @@ public:
float AngleAttenA, float AngleAttenB, float AngleAttenC);
// Constants
static const CVector3f skDefaultLightPos;
static const CVector3f skDefaultLightDir;
static constexpr CVector3f skDefaultLightPos{0.f, 0.f, 0.f};
static constexpr CVector3f skDefaultLightDir{0.f, -1.f, 0.f};
};
#endif // CLIGHT_H

View File

@ -10,13 +10,13 @@ class CMapArea : public CResource
CAssetID mNameString;
public:
CMapArea(CResourceEntry *pEntry = 0)
explicit CMapArea(CResourceEntry *pEntry = nullptr)
: 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);
return pTree;
}

View File

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

View File

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

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