Merge branch 'master' of https://github.com/AxioDL/PrimeWorldEditor
This commit is contained in:
commit
ddba742c9a
|
@ -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")
|
||||
|
|
|
@ -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": []
|
||||
|
|
|
@ -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
|
||||
|
|
26
dew.cmake
26
dew.cmake
|
@ -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)
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"url": "https://github.com/AxioDL/nod",
|
||||
"type": "git",
|
||||
"head": "master",
|
||||
"ref": "a1284ae06586b958f36b8ecaba29390835ed2820"
|
||||
"ref": "f147e1235646b849f78a8574a6d554214b70792d"
|
||||
},
|
||||
{
|
||||
"name": "lzokay",
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 8524191df613b9149369ed8578a6c4ea3038552b
|
||||
Subproject commit 2c2e2bad43b4566e1de5452a23673f0c9d5202f7
|
|
@ -7,9 +7,7 @@ CAreaAttributes::CAreaAttributes(CScriptObject *pObj)
|
|||
SetObject(pObj);
|
||||
}
|
||||
|
||||
CAreaAttributes::~CAreaAttributes()
|
||||
{
|
||||
}
|
||||
CAreaAttributes::~CAreaAttributes() = default;
|
||||
|
||||
void CAreaAttributes::SetObject(CScriptObject *pObj)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -97,5 +96,4 @@ void CAudioManager::LogSoundInfo(uint32 SoundID)
|
|||
debugf("Define ID: 0x%04x", SoundInfo.DefineID);
|
||||
debugf("Audio Group: %s", *SoundInfo.pAudioGroup->Entry()->Name());
|
||||
debugf("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
CResourceEntry *pSample = pStore->FindEntry(SampleID);
|
||||
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,12 +586,14 @@ 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++)
|
||||
String = CStringTable::StripFormatting( pString->GetString(ELanguage::English, iStr) ).Trimmed();
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
||||
{
|
||||
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
|
||||
|
@ -284,7 +274,7 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
|
|||
{
|
||||
const SSetCharacter *pkChar = pkOwnerSet->Character(iChar);
|
||||
|
||||
if ( pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end() )
|
||||
if (pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end())
|
||||
pTree->mCharacterIndices.insert(iChar);
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
PakSections.push_back(SPakSection { Type, Size });
|
||||
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,24 +471,25 @@ 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 } );
|
||||
CompressedBlocks.push_back(SCompressedBlock{CompressedSize, UncompressedSize});
|
||||
}
|
||||
|
||||
rBuffer.resize(TotalUncompressedSize);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -81,16 +78,16 @@ bool CGameProject::Serialize(IArchive& rArc)
|
|||
|
||||
bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress)
|
||||
{
|
||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
||||
ASSERT( !IsWiiDeAsobu() && !IsTrilogy() );
|
||||
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())
|
||||
{
|
||||
|
@ -106,18 +103,18 @@ bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgre
|
|||
|
||||
bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress)
|
||||
{
|
||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
||||
ASSERT( IsWiiDeAsobu() || IsTrilogy() );
|
||||
ASSERT( pOriginalIso != nullptr );
|
||||
ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
|
||||
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 (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
||||
for (size_t iRes = 0; iRes < pkg->NumNamedResources(); iRes++)
|
||||
{
|
||||
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
||||
const SNamedResource& rkRes = pkg->NamedResourceByIndex(iRes);
|
||||
|
||||
if (rkRes.Name == rkName)
|
||||
if (rkRes.Name == name)
|
||||
return rkRes.ID;
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,26 +308,26 @@ 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;
|
||||
|
||||
Pak.WriteLong( rkInfo.Compressed ? 1 : 0 );
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,23 +11,17 @@
|
|||
#include <Common/Serialization/CXMLWriter.h>
|
||||
|
||||
CResourceEntry::CResourceEntry(CResourceStore *pStore)
|
||||
: mpResource(nullptr)
|
||||
, mpTypeInfo(nullptr)
|
||||
, mpStore(pStore)
|
||||
, mpDependencies(nullptr)
|
||||
, mID( CAssetID::InvalidID(pStore->Game()) )
|
||||
, mpDirectory(nullptr)
|
||||
, mMetadataDirty(false)
|
||||
, mCachedSize(-1)
|
||||
: mpStore(pStore)
|
||||
, mID(CAssetID::InvalidID(pStore->Game()))
|
||||
{}
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
ASSERT( FindEntry(pEntry->ID()) == nullptr );
|
||||
mResourceEntries[pEntry->ID()] = pEntry;
|
||||
auto pEntry = CResourceEntry::BuildFromArchive(this, rArc);
|
||||
ASSERT(FindEntry(pEntry->ID()) == nullptr);
|
||||
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,32 +184,34 @@ 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,10 +358,9 @@ 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() );
|
||||
TString RelPath = Path.ChopFront(ResDir.Size());
|
||||
|
||||
if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta"))
|
||||
{
|
||||
|
@ -382,11 +368,11 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
|
|||
TString DirPath = RelPath.GetFileDirectory();
|
||||
TString CookedFilename = RelPath.GetFileName(false); // This call removes the .rsmeta extension
|
||||
TString ResName = CookedFilename.GetFileName(false); // This call removes the cooked extension
|
||||
ASSERT( IsValidResourcePath(DirPath, ResName) );
|
||||
ASSERT(IsValidResourcePath(DirPath, ResName));
|
||||
|
||||
// Determine resource type
|
||||
TString CookedExtension = CookedFilename.GetFileExtension();
|
||||
CResTypeInfo *pTypeInfo = CResTypeInfo::TypeForCookedExtension( Game(), CFourCC(CookedExtension) );
|
||||
CResTypeInfo* pTypeInfo = CResTypeInfo::TypeForCookedExtension(Game(), CFourCC(CookedExtension));
|
||||
|
||||
if (!pTypeInfo)
|
||||
{
|
||||
|
@ -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() );
|
||||
ASSERT( ID.Length() == CAssetID::GameIDLength(mGame) );
|
||||
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/";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,40 +85,35 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (AllowCreate)
|
||||
{
|
||||
if ( AddChild(rkName, nullptr) )
|
||||
if (AddChild(rkName, nullptr))
|
||||
{
|
||||
CVirtualDirectory *pOut = FindChildDirectory(rkName, false);
|
||||
CVirtualDirectory* pOut = FindChildDirectory(rkName, false);
|
||||
ASSERT(pOut != nullptr);
|
||||
return pOut;
|
||||
}
|
||||
|
@ -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);
|
||||
CVirtualDirectory* pDir = FindChildDirectory(Dir, false);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,59 +120,59 @@ 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)
|
||||
{
|
||||
mStillLookingIDs.erase( mStillLookingIDs.find(ResID) );
|
||||
mStillLookingIDs.erase(mStillLookingIDs.find(ResID));
|
||||
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);
|
||||
CResourceEntry *pEntry = mpStore->FindEntry(pDep->ID());
|
||||
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,13 +231,16 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
|||
(ResType != EResourceType::World || !pCurEntry) &&
|
||||
(ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World);
|
||||
|
||||
if (!IsValid) return;
|
||||
|
||||
if ( ( mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) ||
|
||||
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ||
|
||||
(!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end() ) )
|
||||
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);
|
||||
mAreaUsedAssets.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,61 +400,63 @@ 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)
|
||||
{
|
||||
TString PropID = pDep->PropertyID();
|
||||
|
||||
if ( PropID == "0x846397A8" || PropID == "0x685A4C01" ||
|
||||
if (PropID == "0x846397A8" || PropID == "0x685A4C01" ||
|
||||
PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
|
||||
PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
|
||||
PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
|
||||
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
|
||||
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
|
||||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
|
||||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE" )
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
{}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
class CShaderGenerator
|
||||
{
|
||||
CShader *mpShader;
|
||||
CShader *mpShader = nullptr;
|
||||
|
||||
CShaderGenerator();
|
||||
~CShaderGenerator();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,8 +22,10 @@ CVertexArrayManager::~CVertexArrayManager()
|
|||
sVAManagers.erase(sVAManagers.begin() + mVectorIndex);
|
||||
|
||||
if (sVAManagers.size() > mVectorIndex)
|
||||
{
|
||||
for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++)
|
||||
(*it)->mVectorIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ PUBLIC ************
|
||||
|
@ -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,40 +53,41 @@ 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 ************
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -450,37 +417,37 @@ void CDrawUtil::InitSquare()
|
|||
EVertexAttribute::Tex4 |
|
||||
EVertexAttribute::Tex5 |
|
||||
EVertexAttribute::Tex6 |
|
||||
EVertexAttribute::Tex7 );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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] = {
|
||||
CLight::BuildDirectional(CVector3f(0), CVector3f (0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
||||
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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
{ 3, 0, 0, 0 },
|
||||
{ 1.f, 0.f, 0.f, 0.f }
|
||||
static constexpr SVertexWeights skNullWeights{
|
||||
{3, 0, 0, 0},
|
||||
{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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
CScriptObject* SpawnInstance(CScriptTemplate* pTemplate, CScriptLayer* pLayer,
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -4,27 +4,25 @@
|
|||
#include "Core/Render/CRenderer.h"
|
||||
|
||||
std::optional<CDynamicVertexBuffer> CFont::smGlyphVertices;
|
||||
CIndexBuffer CFont::smGlyphIndices;
|
||||
bool CFont::smBuffersInitialized = false;
|
||||
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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -144,7 +116,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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue