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)
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
endif()
|
endif()
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
|
||||||
|
|
||||||
project(PrimeWorldEditor CXX)
|
project(PrimeWorldEditor CXX)
|
||||||
|
|
||||||
option(PWE_PUBLIC_RELEASE "Enable end-user deployment configuration for PWE" OFF)
|
option(PWE_PUBLIC_RELEASE "Enable end-user deployment configuration for PWE" ON)
|
||||||
if (PWE_PUBLIC_RELEASE)
|
if (PWE_PUBLIC_RELEASE)
|
||||||
add_compile_definitions(PUBLIC_RELEASE=1)
|
add_compile_definitions(PUBLIC_RELEASE=1)
|
||||||
message(STATUS "Enabled public release mode")
|
message(STATUS "Enabled public release mode")
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||||
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
||||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||||
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.12.6/msvc2017_64/lib/cmake/Qt5",
|
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.14.1/msvc2017_64/lib/cmake/Qt5",
|
||||||
"buildCommandArgs": "",
|
"buildCommandArgs": "",
|
||||||
"ctestCommandArgs": "",
|
"ctestCommandArgs": "",
|
||||||
"variables": []
|
"variables": []
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||||
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
|
||||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||||
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.12.6/msvc2017_64/lib/cmake/Qt5",
|
"cmakeCommandArgs": "-DCMAKE_PREFIX_PATH=C:/Qt/5.14.1/msvc2017_64/lib/cmake/Qt5",
|
||||||
"buildCommandArgs": "",
|
"buildCommandArgs": "",
|
||||||
"ctestCommandArgs": "",
|
"ctestCommandArgs": "",
|
||||||
"variables": []
|
"variables": []
|
||||||
|
|
|
@ -20,7 +20,7 @@ VS_VERSION_INFO VERSIONINFO
|
||||||
BEGIN
|
BEGIN
|
||||||
BLOCK "StringFileInfo"
|
BLOCK "StringFileInfo"
|
||||||
BEGIN
|
BEGIN
|
||||||
BLOCK "041904b0"
|
BLOCK "040904b0"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "Comments", PRODUCT_COMMENTS
|
VALUE "Comments", PRODUCT_COMMENTS
|
||||||
VALUE "CompanyName", PRODUCT_COMPANY_NAME
|
VALUE "CompanyName", PRODUCT_COMPANY_NAME
|
||||||
|
@ -35,6 +35,6 @@ BEGIN
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "Translation", 0x419, 1200
|
VALUE "Translation", 0x409, 1200
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
34
dew.cmake
34
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
|
# It is encouraged to check this file into your project's VCS. Doing so will allow your cmake project to easily
|
||||||
# integrate with Dew.
|
# integrate with Dew.
|
||||||
#
|
#
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
function(integrate_dew)
|
function(integrate_dew)
|
||||||
#
|
#
|
||||||
|
@ -17,6 +17,13 @@ function(integrate_dew)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Advise the user that setting the build type is necessary for debug dependencies.
|
||||||
|
#
|
||||||
|
if (NOT CMAKE_BUILD_TYPE)
|
||||||
|
message(WARNING "CMAKE_BUILD_TYPE is not set. Dew will build release dependencies by default.")
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Acquaint CMake with dew prefix
|
# Acquaint CMake with dew prefix
|
||||||
#
|
#
|
||||||
|
@ -41,7 +48,8 @@ function(integrate_dew)
|
||||||
message(FATAL_ERROR "Failed to install dew with pip: result: ${install_dew_result}.")
|
message(FATAL_ERROR "Failed to install dew with pip: result: ${install_dew_result}.")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "Building dew dependencies")
|
message(STATUS "Building dew dependencies")
|
||||||
execute_process(COMMAND "${Python3_EXECUTABLE}" -m dew update --build-type ${dew_cmake_prefix_suffix}
|
execute_process(COMMAND "${Python3_EXECUTABLE}" -m dew update --CC "${CMAKE_C_COMPILER}"
|
||||||
|
--CXX "${CMAKE_CXX_COMPILER}" --build-type ${dew_cmake_prefix_suffix}
|
||||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||||
RESULT_VARIABLE dew_res)
|
RESULT_VARIABLE dew_res)
|
||||||
if(NOT dew_res EQUAL 0)
|
if(NOT dew_res EQUAL 0)
|
||||||
|
@ -65,33 +73,27 @@ function(integrate_dew)
|
||||||
# Check if we have already added the dew directory to CMAKE_PREFIX_PATH
|
# Check if we have already added the dew directory to CMAKE_PREFIX_PATH
|
||||||
#
|
#
|
||||||
set(needs_new_prefix TRUE)
|
set(needs_new_prefix TRUE)
|
||||||
foreach (path ${CMAKE_PREFIX_PATH})
|
if ("${dew_cmake_prefix_path}" IN_LIST CMAKE_PREFIX_PATH)
|
||||||
if (path STREQUAL "${dew_cmake_prefix_path}")
|
set(needs_new_prefix FALSE)
|
||||||
set(needs_new_prefix FALSE)
|
endif()
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check if we have already added the dew cmake module directory to CMAKE_MODULE_PATH
|
# Check if we have already added the dew cmake module directory to CMAKE_MODULE_PATH
|
||||||
#
|
#
|
||||||
set(needs_new_module_path TRUE)
|
set(needs_new_module_path TRUE)
|
||||||
foreach (path ${CMAKE_MODULE_PATH})
|
if ("${dew_cmake_module_path}" IN_LIST CMAKE_MODULE_PATH)
|
||||||
if (path STREQUAL "${dew_cmake_module_path}")
|
set(needs_new_module_path FALSE)
|
||||||
set(needs_new_module_path FALSE)
|
endif()
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Add dew directory to CMAKE_PREFIX_PATH if necesary
|
# Add dew directory to CMAKE_PREFIX_PATH if necessary
|
||||||
#
|
#
|
||||||
if ("${needs_new_prefix}")
|
if ("${needs_new_prefix}")
|
||||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${dew_cmake_prefix_path}" CACHE PATH "" FORCE)
|
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${dew_cmake_prefix_path}" CACHE PATH "" FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Add dew cmake module directory to CMAKE_MODULE_PATH if necesary
|
# Add dew cmake module directory to CMAKE_MODULE_PATH if necessary
|
||||||
#
|
#
|
||||||
if ("${needs_new_module_path}")
|
if ("${needs_new_module_path}")
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${dew_cmake_module_path}" CACHE PATH "" FORCE)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${dew_cmake_module_path}" CACHE PATH "" FORCE)
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
"url": "https://github.com/AxioDL/nod",
|
"url": "https://github.com/AxioDL/nod",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"head": "master",
|
"head": "master",
|
||||||
"ref": "a1284ae06586b958f36b8ecaba29390835ed2820"
|
"ref": "f147e1235646b849f78a8574a6d554214b70792d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "lzokay",
|
"name": "lzokay",
|
||||||
|
|
|
@ -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);
|
SetObject(pObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
CAreaAttributes::~CAreaAttributes()
|
CAreaAttributes::~CAreaAttributes() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAreaAttributes::SetObject(CScriptObject *pObj)
|
void CAreaAttributes::SetObject(CScriptObject *pObj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,14 +13,14 @@ class CAreaAttributes
|
||||||
CAssetRef mOverrideSky;
|
CAssetRef mOverrideSky;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAreaAttributes(CScriptObject *pObj);
|
explicit CAreaAttributes(CScriptObject *pObj);
|
||||||
~CAreaAttributes();
|
~CAreaAttributes();
|
||||||
void SetObject(CScriptObject *pObj);
|
void SetObject(CScriptObject *pObj);
|
||||||
bool IsLayerEnabled() const;
|
bool IsLayerEnabled() const;
|
||||||
bool IsSkyEnabled() const;
|
bool IsSkyEnabled() const;
|
||||||
CModel* SkyModel() const;
|
CModel* SkyModel() const;
|
||||||
|
|
||||||
inline CScriptObject* Instance() const { return mpObject; }
|
CScriptObject* Instance() const { return mpObject; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CAREAATTRIBUTES_H
|
#endif // CAREAATTRIBUTES_H
|
||||||
|
|
|
@ -19,37 +19,35 @@ void CAudioManager::LoadAssets()
|
||||||
// Load/sort all audio groups
|
// Load/sort all audio groups
|
||||||
for (TResourceIterator<EResourceType::AudioGroup> It(mpProject->ResourceStore()); It; ++It)
|
for (TResourceIterator<EResourceType::AudioGroup> It(mpProject->ResourceStore()); It; ++It)
|
||||||
{
|
{
|
||||||
CAudioGroup *pGroup = (CAudioGroup*) It->Load();
|
if (auto* pGroup = static_cast<CAudioGroup*>(It->Load()))
|
||||||
if (pGroup) mAudioGroups.push_back(pGroup);
|
mAudioGroups.emplace_back(pGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(mAudioGroups.begin(), mAudioGroups.end(), [](CAudioGroup *pLeft, CAudioGroup *pRight) -> bool {
|
std::sort(mAudioGroups.begin(), mAudioGroups.end(), [](const CAudioGroup *pLeft, const CAudioGroup *pRight) {
|
||||||
return pLeft->GroupID() < pRight->GroupID();
|
return pLeft->GroupID() < pRight->GroupID();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create SFX Define ID -> AGSC map
|
// Create SFX Define ID -> AGSC map
|
||||||
for (uint iGrp = 0; iGrp < mAudioGroups.size(); iGrp++)
|
for (CAudioGroup* group : mAudioGroups)
|
||||||
{
|
{
|
||||||
CAudioGroup *pGroup = mAudioGroups[iGrp];
|
for (size_t iSnd = 0; iSnd < group->NumSoundDefineIDs(); iSnd++)
|
||||||
|
|
||||||
for (uint iSnd = 0; iSnd < pGroup->NumSoundDefineIDs(); iSnd++)
|
|
||||||
{
|
{
|
||||||
uint16 DefineID = pGroup->SoundDefineIDByIndex(iSnd);
|
const uint16 DefineID = group->SoundDefineIDByIndex(iSnd);
|
||||||
ASSERT(mSfxIdMap.find(DefineID) == mSfxIdMap.end());
|
ASSERT(mSfxIdMap.find(DefineID) == mSfxIdMap.cend());
|
||||||
mSfxIdMap[DefineID] = pGroup;
|
mSfxIdMap.insert_or_assign(DefineID, group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load audio lookup table + sfx name list
|
// Load audio lookup table + sfx name list
|
||||||
TString AudioLookupName = (mpProject->Game() < EGame::EchoesDemo ? "sound_lookup" : "sound_lookup_ATBL");
|
const std::string_view AudioLookupName = mpProject->Game() < EGame::EchoesDemo ? "sound_lookup" : "sound_lookup_ATBL";
|
||||||
CAssetID AudioLookupID = mpProject->FindNamedResource(AudioLookupName);
|
const CAssetID AudioLookupID = mpProject->FindNamedResource(AudioLookupName);
|
||||||
|
|
||||||
if (AudioLookupID.IsValid())
|
if (AudioLookupID.IsValid())
|
||||||
mpAudioLookupTable = mpProject->ResourceStore()->LoadResource<CAudioLookupTable>(AudioLookupID);
|
mpAudioLookupTable = mpProject->ResourceStore()->LoadResource<CAudioLookupTable>(AudioLookupID);
|
||||||
|
|
||||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||||
{
|
{
|
||||||
CAssetID SfxNameListID = mpProject->FindNamedResource("audio_name_lookup_STLC");
|
const CAssetID SfxNameListID = mpProject->FindNamedResource("audio_name_lookup_STLC");
|
||||||
|
|
||||||
if (SfxNameListID.IsValid())
|
if (SfxNameListID.IsValid())
|
||||||
mpSfxNameList = mpProject->ResourceStore()->LoadResource<CStringList>(SfxNameListID);
|
mpSfxNameList = mpProject->ResourceStore()->LoadResource<CStringList>(SfxNameListID);
|
||||||
|
@ -64,7 +62,7 @@ void CAudioManager::ClearAssets()
|
||||||
mSfxIdMap.clear();
|
mSfxIdMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID)
|
SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID) const
|
||||||
{
|
{
|
||||||
SSoundInfo Out;
|
SSoundInfo Out;
|
||||||
Out.SoundID = SoundID;
|
Out.SoundID = SoundID;
|
||||||
|
@ -73,8 +71,8 @@ SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID)
|
||||||
|
|
||||||
if (Out.DefineID != 0xFFFF)
|
if (Out.DefineID != 0xFFFF)
|
||||||
{
|
{
|
||||||
auto Iter = mSfxIdMap.find(Out.DefineID);
|
const auto Iter = mSfxIdMap.find(Out.DefineID);
|
||||||
if (Iter != mSfxIdMap.end())
|
if (Iter != mSfxIdMap.cend())
|
||||||
Out.pAudioGroup = Iter->second;
|
Out.pAudioGroup = Iter->second;
|
||||||
|
|
||||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||||
|
@ -84,18 +82,18 @@ SSoundInfo CAudioManager::GetSoundInfo(uint32 SoundID)
|
||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAudioManager::LogSoundInfo(uint32 SoundID)
|
void CAudioManager::LogSoundInfo(uint32 SoundID) const
|
||||||
{
|
{
|
||||||
SSoundInfo SoundInfo = GetSoundInfo(SoundID);
|
const SSoundInfo SoundInfo = GetSoundInfo(SoundID);
|
||||||
|
|
||||||
if (SoundInfo.DefineID != 0xFFFF)
|
if (SoundInfo.DefineID == 0xFFFF)
|
||||||
{
|
return;
|
||||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
|
||||||
debugf("Sound Name: %s", *SoundInfo.Name);
|
|
||||||
|
|
||||||
debugf("Sound ID: 0x%04x", SoundInfo.SoundID);
|
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||||
debugf("Define ID: 0x%04x", SoundInfo.DefineID);
|
debugf("Sound Name: %s", *SoundInfo.Name);
|
||||||
debugf("Audio Group: %s", *SoundInfo.pAudioGroup->Entry()->Name());
|
|
||||||
debugf("");
|
debugf("Sound ID: 0x%04x", SoundInfo.SoundID);
|
||||||
}
|
debugf("Define ID: 0x%04x", SoundInfo.DefineID);
|
||||||
|
debugf("Audio Group: %s", *SoundInfo.pAudioGroup->Entry()->Name());
|
||||||
|
debugf("");
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ class CAudioManager
|
||||||
std::unordered_map<uint16, CAudioGroup*> mSfxIdMap;
|
std::unordered_map<uint16, CAudioGroup*> mSfxIdMap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAudioManager(CGameProject *pProj);
|
explicit CAudioManager(CGameProject *pProj);
|
||||||
void LoadAssets();
|
void LoadAssets();
|
||||||
void ClearAssets();
|
void ClearAssets();
|
||||||
SSoundInfo GetSoundInfo(uint32 SoundID);
|
SSoundInfo GetSoundInfo(uint32 SoundID) const;
|
||||||
void LogSoundInfo(uint32 SoundID);
|
void LogSoundInfo(uint32 SoundID) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CAUDIOMANAGER
|
#endif // CAUDIOMANAGER
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
#include "Core/Resource/Area/CGameArea.h"
|
#include "Core/Resource/Area/CGameArea.h"
|
||||||
#include "Core/Resource/Script/Property/Properties.h"
|
#include "Core/Resource/Script/Property/Properties.h"
|
||||||
|
|
||||||
enum EWorldLightingOptions
|
enum class EWorldLightingOptions
|
||||||
{
|
{
|
||||||
eUnknown1 = 0,
|
Unknown1,
|
||||||
eNormalLighting = 1,
|
NormalLighting,
|
||||||
eUnknown2 = 2,
|
Unknown2,
|
||||||
eDisableWorldLighting = 3
|
DisableWorldLighting,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CLightParameters
|
class CLightParameters
|
||||||
|
@ -35,14 +35,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int LightLayerIndex() const
|
int LightLayerIndex() const
|
||||||
{
|
{
|
||||||
return mLightLayer.IsValid() ? mLightLayer.Get() : 0;
|
return mLightLayer.IsValid() ? mLightLayer.Get() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EWorldLightingOptions WorldLightingOptions() const
|
EWorldLightingOptions WorldLightingOptions() const
|
||||||
{
|
{
|
||||||
return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : eNormalLighting;
|
return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : EWorldLightingOptions::NormalLighting;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.12)
|
||||||
project(pwe_core CXX C)
|
project(pwe_core CXX C)
|
||||||
|
|
||||||
find_package(tinyxml2 CONFIG REQUIRED)
|
find_package(tinyxml2 CONFIG REQUIRED)
|
||||||
find_package(nod CONFIG REQUIRED)
|
|
||||||
find_package(logvisor CONFIG REQUIRED)
|
find_package(logvisor CONFIG REQUIRED)
|
||||||
|
find_package(nod CONFIG REQUIRED)
|
||||||
find_package(lzokay CONFIG REQUIRED)
|
find_package(lzokay CONFIG REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
find_package(assimp CONFIG REQUIRED)
|
find_package(assimp CONFIG REQUIRED)
|
||||||
|
|
|
@ -310,13 +310,13 @@ void CMayaSpline::CalculateHermiteCoefficients(const std::vector<CVector2f>& kCo
|
||||||
const CVector2f& kTangentB = kControlPoints[2];
|
const CVector2f& kTangentB = kControlPoints[2];
|
||||||
const CVector2f& kKnotB = kControlPoints[3];
|
const CVector2f& kKnotB = kControlPoints[3];
|
||||||
|
|
||||||
CVector2f Range = kKnotB - kKnotA;
|
[[maybe_unused]] const CVector2f Range = kKnotB - kKnotA;
|
||||||
|
|
||||||
CVector2f KnotAToTangentA = kTangentA - kKnotA;
|
const CVector2f KnotAToTangentA = kTangentA - kKnotA;
|
||||||
float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X);
|
const float MulA = (KnotAToTangentA.X == 0 ? 5729578.f : KnotAToTangentA.Y / KnotAToTangentA.X);
|
||||||
|
|
||||||
CVector2f KnotBToTangentB = kKnotB - kTangentB;
|
const CVector2f KnotBToTangentB = kKnotB - kTangentB;
|
||||||
float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X);
|
[[maybe_unused]] const float MulB = (KnotBToTangentB.X == 0 ? 5729578.f : KnotBToTangentB.Y / KnotBToTangentB.X);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// todo: better organization and better variable names
|
// todo: better organization and better variable names
|
||||||
|
|
|
@ -22,21 +22,21 @@ public:
|
||||||
|
|
||||||
class CMayaSpline
|
class CMayaSpline
|
||||||
{
|
{
|
||||||
uint mPreInfinity; // 0x00
|
uint mPreInfinity = 0; // 0x00
|
||||||
uint mPostInfinity; // 0x04
|
uint mPostInfinity = 0; // 0x04
|
||||||
std::vector<CMayaSplineKnot> mKnots; // 0x08, 0x0C, 0x10
|
std::vector<CMayaSplineKnot> mKnots; // 0x08, 0x0C, 0x10
|
||||||
uint mClampMode; // 0x14 - clamp mode
|
uint mClampMode = 0; // 0x14 - clamp mode
|
||||||
float mMinAmplitude; // 0x18
|
float mMinAmplitude = 0.0f; // 0x18
|
||||||
float mMaxAmplitude; // 0x1C
|
float mMaxAmplitude = 0.0f; // 0x1C
|
||||||
|
|
||||||
mutable int mCachedKnotIndex; // 0x20
|
mutable int mCachedKnotIndex = 0; // 0x20
|
||||||
mutable int mUnknown1; // 0x24
|
mutable int mUnknown1 = 0; // 0x24
|
||||||
mutable uint8 mDirtyFlags; // 0x28
|
mutable uint8 mDirtyFlags = 0; // 0x28
|
||||||
mutable float mCachedMinTime; // 0x2C
|
mutable float mCachedMinTime = 0.0f; // 0x2C
|
||||||
mutable float mCachedHermiteCoefficients[4]; // 0x30, 0x34, 0x38, 0x3C
|
mutable float mCachedHermiteCoefficients[4] = {}; // 0x30, 0x34, 0x38, 0x3C
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMayaSpline() {}
|
CMayaSpline() = default;
|
||||||
uint GetKnotCount() const;
|
uint GetKnotCount() const;
|
||||||
const std::vector<CMayaSplineKnot>& GetKnots() const;
|
const std::vector<CMayaSplineKnot>& GetKnots() const;
|
||||||
float GetMinTime() const;
|
float GetMinTime() const;
|
||||||
|
|
|
@ -6,14 +6,11 @@ CRayCollisionTester::CRayCollisionTester(const CRay& rkRay)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CRayCollisionTester::~CRayCollisionTester()
|
CRayCollisionTester::~CRayCollisionTester() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CRayCollisionTester::AddNode(CSceneNode *pNode, uint32 ComponentIndex, float Distance)
|
void CRayCollisionTester::AddNode(CSceneNode *pNode, uint32 ComponentIndex, float Distance)
|
||||||
{
|
{
|
||||||
mBoxIntersectList.emplace_back(SRayIntersection());
|
SRayIntersection& rIntersection = mBoxIntersectList.emplace_back();
|
||||||
SRayIntersection& rIntersection = mBoxIntersectList.back();
|
|
||||||
rIntersection.pNode = pNode;
|
rIntersection.pNode = pNode;
|
||||||
rIntersection.ComponentIndex = ComponentIndex;
|
rIntersection.ComponentIndex = ComponentIndex;
|
||||||
rIntersection.Distance = Distance;
|
rIntersection.Distance = Distance;
|
||||||
|
@ -24,46 +21,44 @@ void CRayCollisionTester::AddNodeModel(CSceneNode *pNode, CBasicModel *pModel)
|
||||||
// Check each of the model's surfaces and queue them for further testing if they hit
|
// Check each of the model's surfaces and queue them for further testing if they hit
|
||||||
for (uint32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
|
for (uint32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
|
||||||
{
|
{
|
||||||
std::pair<bool,float> SurfResult = pModel->GetSurfaceAABox(iSurf).Transformed(pNode->Transform()).IntersectsRay(mRay);
|
const auto [intersects, distance] = pModel->GetSurfaceAABox(iSurf).Transformed(pNode->Transform()).IntersectsRay(mRay);
|
||||||
|
|
||||||
if (SurfResult.first)
|
if (intersects)
|
||||||
AddNode(pNode, iSurf, SurfResult.second);
|
AddNode(pNode, iSurf, distance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& rkViewInfo)
|
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& rkViewInfo)
|
||||||
{
|
{
|
||||||
// Sort nodes by distance from ray
|
// Sort nodes by distance from ray
|
||||||
mBoxIntersectList.sort(
|
mBoxIntersectList.sort([](const auto& rkLeft, const auto& rkRight) {
|
||||||
[](const SRayIntersection& rkLeft, const SRayIntersection& rkRight) -> bool
|
return rkLeft.Distance < rkRight.Distance;
|
||||||
{
|
|
||||||
return (rkLeft.Distance < rkRight.Distance);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now do more precise intersection tests on geometry
|
// Now do more precise intersection tests on geometry
|
||||||
SRayIntersection Result;
|
SRayIntersection Result;
|
||||||
Result.Hit = false;
|
Result.Hit = false;
|
||||||
|
|
||||||
for (auto iNode = mBoxIntersectList.begin(); iNode != mBoxIntersectList.end(); iNode++)
|
for (const auto& rIntersection : mBoxIntersectList)
|
||||||
{
|
{
|
||||||
SRayIntersection& rIntersection = *iNode;
|
|
||||||
|
|
||||||
// If we have a result, and the distance for the bounding box hit is further than the current result distance
|
// If we have a result, and the distance for the bounding box hit is further than the current result distance
|
||||||
// then we know that every remaining node is further away and there is no chance of finding a closer hit.
|
// then we know that every remaining node is further away and there is no chance of finding a closer hit.
|
||||||
if ((Result.Hit) && (Result.Distance < rIntersection.Distance))
|
if (Result.Hit && Result.Distance < rIntersection.Distance)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Otherwise, more intersection tests...
|
// Otherwise, more intersection tests...
|
||||||
CSceneNode *pNode = rIntersection.pNode;
|
CSceneNode *pNode = rIntersection.pNode;
|
||||||
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, rIntersection.ComponentIndex, rkViewInfo);
|
const SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, rIntersection.ComponentIndex, rkViewInfo);
|
||||||
|
|
||||||
if (MidResult.Hit)
|
if (MidResult.Hit)
|
||||||
{
|
{
|
||||||
if ((!Result.Hit) || (MidResult.Distance <= Result.Distance))
|
if (!Result.Hit || MidResult.Distance <= Result.Distance)
|
||||||
Result = MidResult;
|
Result = MidResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Result.Hit) Result.HitPoint = mRay.PointOnRay(Result.Distance);
|
if (Result.Hit)
|
||||||
|
Result.HitPoint = mRay.PointOnRay(Result.Distance);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,11 +109,11 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
// Generate names for package named resources
|
// Generate names for package named resources
|
||||||
debugf("Processing packages");
|
debugf("Processing packages");
|
||||||
|
|
||||||
for (uint32 iPkg = 0; iPkg < pProj->NumPackages(); iPkg++)
|
for (size_t iPkg = 0; iPkg < pProj->NumPackages(); iPkg++)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = pProj->PackageByIndex(iPkg);
|
CPackage *pPkg = pProj->PackageByIndex(iPkg);
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
||||||
if (rkRes.Name.EndsWith("NODEPEND")) continue;
|
if (rkRes.Name.EndsWith("NODEPEND")) continue;
|
||||||
|
@ -166,17 +166,17 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
ApplyGeneratedName(pSkyEntry, WorldDir + "sky/cooked/", WorldName + "_sky");
|
ApplyGeneratedName(pSkyEntry, WorldDir + "sky/cooked/", WorldName + "_sky");
|
||||||
|
|
||||||
// Move sky textures
|
// Move sky textures
|
||||||
for (uint32 iSet = 0; iSet < pSkyModel->GetMatSetCount(); iSet++)
|
for (size_t iSet = 0; iSet < pSkyModel->GetMatSetCount(); iSet++)
|
||||||
{
|
{
|
||||||
CMaterialSet *pSet = pSkyModel->GetMatSet(iSet);
|
CMaterialSet *pSet = pSkyModel->GetMatSet(iSet);
|
||||||
|
|
||||||
for (uint32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
for (size_t mat = 0; mat < pSet->NumMaterials(); mat++)
|
||||||
{
|
{
|
||||||
CMaterial *pMat = pSet->MaterialByIndex(iMat, true);
|
CMaterial *pMat = pSet->MaterialByIndex(mat, true);
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
for (size_t pass = 0; pass < pMat->PassCount(); pass++)
|
||||||
{
|
{
|
||||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
CMaterialPass *pPass = pMat->Pass(pass);
|
||||||
|
|
||||||
if (pPass->Texture())
|
if (pPass->Texture())
|
||||||
ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + "sky/sourceimages/", pPass->Texture()->Entry()->Name());
|
ApplyGeneratedName(pPass->Texture()->Entry(), WorldDir + "sky/sourceimages/", pPass->Texture()->Entry()->Name());
|
||||||
|
@ -198,7 +198,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Areas
|
// Areas
|
||||||
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
// Determine area name
|
// Determine area name
|
||||||
TString AreaName = pWorld->AreaInternalName(iArea);
|
TString AreaName = pWorld->AreaInternalName(iArea);
|
||||||
|
@ -209,7 +209,9 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
|
|
||||||
// Rename area stuff
|
// Rename area stuff
|
||||||
CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID);
|
CResourceEntry *pAreaEntry = pStore->FindEntry(AreaID);
|
||||||
if (!pAreaEntry) continue; // Some DKCR worlds reference areas that don't exist
|
// Some DKCR worlds reference areas that don't exist
|
||||||
|
if (!pAreaEntry)
|
||||||
|
continue;
|
||||||
ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName);
|
ApplyGeneratedName(pAreaEntry, WorldMasterDir, AreaName);
|
||||||
|
|
||||||
CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
|
CStringTable *pAreaNameTable = pWorld->AreaName(iArea);
|
||||||
|
@ -237,12 +239,12 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
uint32 LightmapNum = 0;
|
uint32 LightmapNum = 0;
|
||||||
CMaterialSet *pMaterials = pArea->Materials();
|
CMaterialSet *pMaterials = pArea->Materials();
|
||||||
|
|
||||||
for (uint32 iMat = 0; iMat < pMaterials->NumMaterials(); iMat++)
|
for (size_t iMat = 0; iMat < pMaterials->NumMaterials(); iMat++)
|
||||||
{
|
{
|
||||||
CMaterial *pMat = pMaterials->MaterialByIndex(iMat, true);
|
CMaterial *pMat = pMaterials->MaterialByIndex(iMat, true);
|
||||||
bool FoundLightmap = false;
|
bool FoundLightmap = false;
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
for (size_t iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
{
|
{
|
||||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||||
|
|
||||||
|
@ -278,11 +280,11 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate names from script instance names
|
// Generate names from script instance names
|
||||||
for (uint32 iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++)
|
for (size_t iLyr = 0; iLyr < pArea->NumScriptLayers(); iLyr++)
|
||||||
{
|
{
|
||||||
CScriptLayer *pLayer = pArea->ScriptLayer(iLyr);
|
CScriptLayer *pLayer = pArea->ScriptLayer(iLyr);
|
||||||
|
|
||||||
for (uint32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
for (size_t iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||||
{
|
{
|
||||||
CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
|
CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
|
||||||
CStructProperty* pProperties = pInst->Template()->Properties();
|
CStructProperty* pProperties = pInst->Template()->Properties();
|
||||||
|
@ -407,30 +409,31 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
for (TResourceIterator<EResourceType::Model> It(pStore); It; ++It)
|
for (TResourceIterator<EResourceType::Model> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
CModel *pModel = (CModel*) It->Load();
|
CModel *pModel = (CModel*) It->Load();
|
||||||
uint32 LightmapNum = 0;
|
size_t LightmapNum = 0;
|
||||||
|
|
||||||
for (uint32 iSet = 0; iSet < pModel->GetMatSetCount(); iSet++)
|
for (size_t iSet = 0; iSet < pModel->GetMatSetCount(); iSet++)
|
||||||
{
|
{
|
||||||
CMaterialSet *pSet = pModel->GetMatSet(iSet);
|
CMaterialSet *pSet = pModel->GetMatSet(iSet);
|
||||||
|
|
||||||
for (uint32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
for (size_t iMat = 0; iMat < pSet->NumMaterials(); iMat++)
|
||||||
{
|
{
|
||||||
CMaterial *pMat = pSet->MaterialByIndex(iMat, true);
|
CMaterial *pMat = pSet->MaterialByIndex(iMat, true);
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < pMat->PassCount(); iPass++)
|
for (size_t iPass = 0; iPass < pMat->PassCount(); iPass++)
|
||||||
{
|
{
|
||||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||||
|
|
||||||
bool IsLightmap = ( (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) ||
|
const bool IsLightmap = (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(EMaterialOption::Lightmap) && iPass == 0) ||
|
||||||
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF") );
|
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF");
|
||||||
|
|
||||||
if (IsLightmap)
|
if (IsLightmap)
|
||||||
{
|
{
|
||||||
CTexture *pLightmapTex = pPass->Texture();
|
CTexture *pLightmapTex = pPass->Texture();
|
||||||
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
CResourceEntry *pTexEntry = pLightmapTex->Entry();
|
||||||
if (pTexEntry->IsNamed() || pTexEntry->IsCategorized()) continue;
|
if (pTexEntry->IsNamed() || pTexEntry->IsCategorized())
|
||||||
|
continue;
|
||||||
|
|
||||||
TString TexName = TString::Format("%s_lightmap%d", *It->Name(), LightmapNum);
|
TString TexName = TString::Format("%s_lightmap%zu", *It->Name(), LightmapNum);
|
||||||
ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName);
|
ApplyGeneratedName(pTexEntry, pModel->Entry()->DirectoryPath(), TexName);
|
||||||
pTexEntry->SetHidden(true);
|
pTexEntry->SetHidden(true);
|
||||||
LightmapNum++;
|
LightmapNum++;
|
||||||
|
@ -463,23 +466,23 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
|
|
||||||
for (TResourceIterator<EResourceType::AudioMacro> It(pStore); It; ++It)
|
for (TResourceIterator<EResourceType::AudioMacro> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
CAudioMacro *pMacro = (CAudioMacro*) It->Load();
|
const auto* pMacro = static_cast<CAudioMacro*>(It->Load());
|
||||||
TString MacroName = pMacro->MacroName();
|
TString MacroName = pMacro->MacroName();
|
||||||
ApplyGeneratedName(*It, kSfxDir, MacroName);
|
ApplyGeneratedName(*It, kSfxDir, MacroName);
|
||||||
|
|
||||||
for (uint32 iSamp = 0; iSamp < pMacro->NumSamples(); iSamp++)
|
for (size_t iSamp = 0; iSamp < pMacro->NumSamples(); iSamp++)
|
||||||
{
|
{
|
||||||
CAssetID SampleID = pMacro->SampleByIndex(iSamp);
|
const CAssetID SampleID = pMacro->SampleByIndex(iSamp);
|
||||||
CResourceEntry *pSample = pStore->FindEntry(SampleID);
|
CResourceEntry* pSample = pStore->FindEntry(SampleID);
|
||||||
|
|
||||||
if (pSample && !pSample->IsNamed())
|
if (pSample != nullptr && !pSample->IsNamed())
|
||||||
{
|
{
|
||||||
TString SampleName;
|
TString SampleName;
|
||||||
|
|
||||||
if (pMacro->NumSamples() == 1)
|
if (pMacro->NumSamples() == 1)
|
||||||
SampleName = MacroName;
|
SampleName = MacroName;
|
||||||
else
|
else
|
||||||
SampleName = TString::Format("%s_%d", *MacroName, iSamp);
|
SampleName = TString::Format("%s_%zu", *MacroName, iSamp);
|
||||||
|
|
||||||
ApplyGeneratedName(pSample, kSfxDir, SampleName);
|
ApplyGeneratedName(pSample, kSfxDir, SampleName);
|
||||||
}
|
}
|
||||||
|
@ -500,9 +503,9 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
{
|
{
|
||||||
TString SetDir = It->DirectoryPath();
|
TString SetDir = It->DirectoryPath();
|
||||||
TString NewSetName;
|
TString NewSetName;
|
||||||
CAnimSet *pSet = (CAnimSet*) It->Load();
|
auto* pSet = static_cast<CAnimSet*>(It->Load());
|
||||||
|
|
||||||
for (uint32 iChar = 0; iChar < pSet->NumCharacters(); iChar++)
|
for (size_t iChar = 0; iChar < pSet->NumCharacters(); iChar++)
|
||||||
{
|
{
|
||||||
const SSetCharacter *pkChar = pSet->Character(iChar);
|
const SSetCharacter *pkChar = pSet->Character(iChar);
|
||||||
|
|
||||||
|
@ -524,10 +527,8 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 iOverlay = 0; iOverlay < pkChar->OverlayModels.size(); iOverlay++)
|
for (const auto& rkOverlay : pkChar->OverlayModels)
|
||||||
{
|
{
|
||||||
const SOverlayModel& rkOverlay = pkChar->OverlayModels[iOverlay];
|
|
||||||
|
|
||||||
if (rkOverlay.ModelID.IsValid() || rkOverlay.SkinID.IsValid())
|
if (rkOverlay.ModelID.IsValid() || rkOverlay.SkinID.IsValid())
|
||||||
{
|
{
|
||||||
TString TypeName = (
|
TString TypeName = (
|
||||||
|
@ -561,17 +562,16 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
std::set<CAnimPrimitive> AnimPrimitives;
|
std::set<CAnimPrimitive> AnimPrimitives;
|
||||||
pSet->GetUniquePrimitives(AnimPrimitives);
|
pSet->GetUniquePrimitives(AnimPrimitives);
|
||||||
|
|
||||||
for (auto It = AnimPrimitives.begin(); It != AnimPrimitives.end(); It++)
|
for (const auto& rkPrim : AnimPrimitives)
|
||||||
{
|
{
|
||||||
const CAnimPrimitive& rkPrim = *It;
|
|
||||||
CAnimation *pAnim = rkPrim.Animation();
|
CAnimation *pAnim = rkPrim.Animation();
|
||||||
|
|
||||||
if (pAnim)
|
if (pAnim != nullptr)
|
||||||
{
|
{
|
||||||
ApplyGeneratedName(pAnim->Entry(), SetDir, rkPrim.Name());
|
ApplyGeneratedName(pAnim->Entry(), SetDir, rkPrim.Name());
|
||||||
CAnimEventData *pEvents = pAnim->EventData();
|
CAnimEventData *pEvents = pAnim->EventData();
|
||||||
|
|
||||||
if (pEvents)
|
if (pEvents != nullptr)
|
||||||
ApplyGeneratedName(pEvents->Entry(), SetDir, rkPrim.Name());
|
ApplyGeneratedName(pEvents->Entry(), SetDir, rkPrim.Name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,12 +586,14 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
|
|
||||||
for (TResourceIterator<EResourceType::StringTable> It(pStore); It; ++It)
|
for (TResourceIterator<EResourceType::StringTable> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
if (It->IsNamed()) continue;
|
if (It->IsNamed())
|
||||||
CStringTable *pString = (CStringTable*) It->Load();
|
continue;
|
||||||
|
|
||||||
|
auto *pString = static_cast<CStringTable*>(It->Load());
|
||||||
TString String;
|
TString String;
|
||||||
|
|
||||||
for (uint32 iStr = 0; iStr < pString->NumStrings() && String.IsEmpty(); iStr++)
|
for (size_t iStr = 0; iStr < pString->NumStrings() && String.IsEmpty(); iStr++)
|
||||||
String = CStringTable::StripFormatting( pString->GetString(ELanguage::English, iStr) ).Trimmed();
|
String = CStringTable::StripFormatting(pString->GetString(ELanguage::English, iStr)).Trimmed();
|
||||||
|
|
||||||
if (!String.IsEmpty())
|
if (!String.IsEmpty())
|
||||||
{
|
{
|
||||||
|
@ -611,31 +613,33 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
debugf("Processing scans");
|
debugf("Processing scans");
|
||||||
for (TResourceIterator<EResourceType::Scan> It(pStore); It; ++It)
|
for (TResourceIterator<EResourceType::Scan> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
if (It->IsNamed()) continue;
|
if (It->IsNamed())
|
||||||
CScan *pScan = (CScan*) It->Load();
|
continue;
|
||||||
|
|
||||||
|
auto* pScan = static_cast<CScan*>(It->Load());
|
||||||
TString ScanName;
|
TString ScanName;
|
||||||
|
|
||||||
if (ScanName.IsEmpty())
|
if (ScanName.IsEmpty())
|
||||||
{
|
{
|
||||||
CAssetID StringID = pScan->ScanStringPropertyRef().Get();
|
const CAssetID StringID = pScan->ScanStringPropertyRef().Get();
|
||||||
CStringTable *pString = (CStringTable*) gpResourceStore->LoadResource(StringID, EResourceType::StringTable);
|
if (const auto* pString = static_cast<CStringTable*>(gpResourceStore->LoadResource(StringID, EResourceType::StringTable)))
|
||||||
if (pString) ScanName = pString->Entry()->Name();
|
ScanName = pString->Entry()->Name();
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName);
|
ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName);
|
||||||
|
|
||||||
if (!ScanName.IsEmpty() && pProj->Game() <= EGame::Prime)
|
if (!ScanName.IsEmpty() && pProj->Game() <= EGame::Prime)
|
||||||
{
|
{
|
||||||
const SScanParametersMP1& kParms = *static_cast<SScanParametersMP1*>(pScan->ScanData().DataPointer());
|
const auto& kParms = *static_cast<SScanParametersMP1*>(pScan->ScanData().DataPointer());
|
||||||
|
|
||||||
CResourceEntry *pEntry = pStore->FindEntry(kParms.GuiFrame);
|
if (CResourceEntry* pEntry = pStore->FindEntry(kParms.GuiFrame))
|
||||||
if (pEntry) ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), "ScanFrame");
|
ApplyGeneratedName(pEntry, pEntry->DirectoryPath(), "ScanFrame");
|
||||||
|
|
||||||
for (uint32 iImg = 0; iImg < 4; iImg++)
|
for (size_t iImg = 0; iImg < kParms.ScanImages.size(); iImg++)
|
||||||
{
|
{
|
||||||
CAssetID ImageID = kParms.ScanImages[iImg].Texture;
|
const CAssetID ImageID = kParms.ScanImages[iImg].Texture;
|
||||||
CResourceEntry *pImgEntry = pStore->FindEntry(ImageID);
|
if (CResourceEntry* pImgEntry = pStore->FindEntry(ImageID))
|
||||||
if (pImgEntry) ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%d", *ScanName, iImg));
|
ApplyGeneratedName(pImgEntry, pImgEntry->DirectoryPath(), TString::Format("%s_Image%zu", *ScanName, iImg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,15 +650,12 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||||
debugf("Processing fonts");
|
debugf("Processing fonts");
|
||||||
for (TResourceIterator<EResourceType::Font> It(pStore); It; ++It)
|
for (TResourceIterator<EResourceType::Font> It(pStore); It; ++It)
|
||||||
{
|
{
|
||||||
CFont *pFont = (CFont*) It->Load();
|
if (auto* pFont = static_cast<CFont*>(It->Load()))
|
||||||
|
|
||||||
if (pFont)
|
|
||||||
{
|
{
|
||||||
ApplyGeneratedName(pFont->Entry(), pFont->Entry()->DirectoryPath(), pFont->FontName());
|
ApplyGeneratedName(pFont->Entry(), pFont->Entry()->DirectoryPath(), pFont->FontName());
|
||||||
|
|
||||||
CTexture *pFontTex = pFont->Texture();
|
|
||||||
|
|
||||||
if (pFontTex)
|
if (CTexture* pFontTex = pFont->Texture())
|
||||||
ApplyGeneratedName(pFontTex->Entry(), pFont->Entry()->DirectoryPath(), pFont->Entry()->Name() + "_tex");
|
ApplyGeneratedName(pFontTex->Entry(), pFont->Entry()->DirectoryPath(), pFont->Entry()->Name() + "_tex");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "CAssetNameMap.h"
|
#include "CAssetNameMap.h"
|
||||||
|
|
||||||
|
constexpr char gkAssetMapPath[] = "resources/gameinfo/AssetNameMap";
|
||||||
|
constexpr char gkAssetMapExt[] = "xml";
|
||||||
|
|
||||||
bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
|
bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
|
||||||
{
|
{
|
||||||
if (Path.IsEmpty())
|
if (Path.IsEmpty())
|
||||||
|
@ -19,8 +22,8 @@ bool CAssetNameMap::LoadAssetNames(TString Path /*= ""*/)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debugf("Failed to load asset names; expected %s IDs, got %s",
|
debugf("Failed to load asset names; expected %s IDs, got %s",
|
||||||
mIDLength == k32Bit ? "32-bit" : "64-bit",
|
mIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit",
|
||||||
FileIDLength == k32Bit ? "32-bit" : "64-bit" );
|
FileIDLength == EIDLength::k32Bit ? "32-bit" : "64-bit" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +39,7 @@ bool CAssetNameMap::SaveAssetNames(TString Path /*= ""*/)
|
||||||
if (Path.IsEmpty())
|
if (Path.IsEmpty())
|
||||||
Path = DefaultNameMapPath(mIDLength);
|
Path = DefaultNameMapPath(mIDLength);
|
||||||
|
|
||||||
EGame Game = (mIDLength == k32Bit ? EGame::Prime : EGame::Corruption);
|
EGame Game = (mIDLength == EIDLength::k32Bit ? EGame::Prime : EGame::Corruption);
|
||||||
CXMLWriter Writer(Path, "AssetNameMap", 0, Game);
|
CXMLWriter Writer(Path, "AssetNameMap", 0, Game);
|
||||||
Serialize(Writer);
|
Serialize(Writer);
|
||||||
return Writer.Save();
|
return Writer.Save();
|
||||||
|
@ -58,7 +61,7 @@ bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rO
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EGame Game = (ID.Length() == k32Bit ? EGame::Prime : EGame::Corruption);
|
EGame Game = (ID.Length() == EIDLength::k32Bit ? EGame::Prime : EGame::Corruption);
|
||||||
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
|
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
|
||||||
rOutName = ID.ToString();
|
rOutName = ID.ToString();
|
||||||
rOutAutoGenDir = true;
|
rOutAutoGenDir = true;
|
||||||
|
@ -146,13 +149,14 @@ void CAssetNameMap::PostLoadValidate()
|
||||||
mIsValid = false;
|
mIsValid = false;
|
||||||
std::set<SAssetNameInfo> Dupes;
|
std::set<SAssetNameInfo> Dupes;
|
||||||
|
|
||||||
for (auto Iter = mMap.begin(); Iter != mMap.end(); Iter++)
|
for (auto Iter = mMap.begin(); Iter != mMap.end(); ++Iter)
|
||||||
{
|
{
|
||||||
const SAssetNameInfo& rkInfo = Iter->second;
|
const SAssetNameInfo& rkInfo = Iter->second;
|
||||||
|
|
||||||
if (mUsedSet.find(rkInfo) != mUsedSet.end())
|
if (mUsedSet.find(rkInfo) != mUsedSet.end())
|
||||||
|
{
|
||||||
Dupes.insert(rkInfo);
|
Dupes.insert(rkInfo);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mUsedSet.insert(rkInfo);
|
mUsedSet.insert(rkInfo);
|
||||||
|
@ -180,25 +184,32 @@ void CAssetNameMap::PostLoadValidate()
|
||||||
{
|
{
|
||||||
errorf("Asset name map is invalid and cannot be used! Duplicate asset entries detected:");
|
errorf("Asset name map is invalid and cannot be used! Duplicate asset entries detected:");
|
||||||
|
|
||||||
for (auto Iter = Dupes.begin(); Iter != Dupes.end(); Iter++)
|
for (const auto& dupe : Dupes)
|
||||||
{
|
{
|
||||||
warnf("\t%s", *Iter->FullPath());
|
warnf("\t%s", *dupe.FullPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
mMap.clear();
|
mMap.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
mIsValid = !FoundErrors;
|
mIsValid = !FoundErrors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength)
|
TString CAssetNameMap::DefaultNameMapPath(EIDLength IDLength)
|
||||||
{
|
{
|
||||||
ASSERT(IDLength != kInvalidIDLength);
|
ASSERT(IDLength != kInvalidIDLength);
|
||||||
TString Suffix = (IDLength == k32Bit ? "32" : "64");
|
const char* const Suffix = (IDLength == EIDLength::k32Bit ? "32" : "64");
|
||||||
return gDataDir + gkAssetMapPath + Suffix + "." + gkAssetMapExt;
|
return gDataDir + gkAssetMapPath + Suffix + '.' + gkAssetMapExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CAssetNameMap::DefaultNameMapPath(EGame Game)
|
TString CAssetNameMap::DefaultNameMapPath(EGame Game)
|
||||||
{
|
{
|
||||||
return DefaultNameMapPath( CAssetID::GameIDLength(Game) );
|
return DefaultNameMapPath( CAssetID::GameIDLength(Game) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TString CAssetNameMap::GetExtension()
|
||||||
|
{
|
||||||
|
return gkAssetMapExt;
|
||||||
|
}
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
const TString gkAssetMapPath = "resources/gameinfo/AssetNameMap";
|
|
||||||
const TString gkAssetMapExt = "xml";
|
|
||||||
|
|
||||||
class CAssetNameMap
|
class CAssetNameMap
|
||||||
{
|
{
|
||||||
struct SAssetNameInfo
|
struct SAssetNameInfo
|
||||||
|
@ -66,8 +63,8 @@ public:
|
||||||
static TString DefaultNameMapPath(EIDLength IDLength);
|
static TString DefaultNameMapPath(EIDLength IDLength);
|
||||||
static TString DefaultNameMapPath(EGame Game);
|
static TString DefaultNameMapPath(EGame Game);
|
||||||
|
|
||||||
inline bool IsValid() const { return mIsValid; }
|
bool IsValid() const { return mIsValid; }
|
||||||
inline static TString GetExtension() { return gkAssetMapExt; }
|
static TString GetExtension();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CASSETNAMEMAP
|
#endif // CASSETNAMEMAP
|
||||||
|
|
|
@ -5,72 +5,62 @@
|
||||||
#include "Core/Resource/Script/CScriptLayer.h"
|
#include "Core/Resource/Script/CScriptLayer.h"
|
||||||
#include "Core/Resource/Script/CScriptObject.h"
|
#include "Core/Resource/Script/CScriptObject.h"
|
||||||
#include "Core/Resource/Script/NGameList.h"
|
#include "Core/Resource/Script/NGameList.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
// ************ IDependencyNode ************
|
// ************ IDependencyNode ************
|
||||||
IDependencyNode::~IDependencyNode()
|
IDependencyNode::~IDependencyNode() = default;
|
||||||
{
|
|
||||||
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
|
|
||||||
delete mChildren[iChild];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDependencyNode::HasDependency(const CAssetID& rkID) const
|
bool IDependencyNode::HasDependency(const CAssetID& id) const
|
||||||
{
|
{
|
||||||
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
|
return std::any_of(mChildren.cbegin(), mChildren.cend(),
|
||||||
{
|
[&id](const auto& entry) { return entry->HasDependency(id); });
|
||||||
if (mChildren[iChild]->HasDependency(rkID))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const
|
void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const
|
||||||
{
|
{
|
||||||
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
|
for (const auto& child : mChildren)
|
||||||
mChildren[iChild]->GetAllResourceReferences(rOutSet);
|
child->GetAllResourceReferences(rOutSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData)
|
void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData)
|
||||||
{
|
{
|
||||||
// Recursive function for parsing dependencies in properties
|
// Recursive function for parsing dependencies in properties
|
||||||
for (uint32 PropertyIdx = 0; PropertyIdx < pProperties->NumChildren(); PropertyIdx++)
|
for (size_t PropertyIdx = 0; PropertyIdx < pProperties->NumChildren(); PropertyIdx++)
|
||||||
{
|
{
|
||||||
IProperty* pProp = pProperties->ChildByIndex(PropertyIdx);
|
IProperty* pProp = pProperties->ChildByIndex(PropertyIdx);
|
||||||
EPropertyType Type = pProp->Type();
|
const EPropertyType Type = pProp->Type();
|
||||||
|
|
||||||
// Technically we aren't parsing array children, but it's not really worth refactoring this function
|
// Technically we aren't parsing array children, but it's not really worth refactoring this function
|
||||||
// to support it when there aren't any array properties that contain any asset references anyway...
|
// to support it when there aren't any array properties that contain any asset references anyway...
|
||||||
if (Type == EPropertyType::Struct)
|
if (Type == EPropertyType::Struct)
|
||||||
ParseProperties( pParentEntry, TPropCast<CStructProperty>(pProp), pData );
|
{
|
||||||
|
ParseProperties(pParentEntry, TPropCast<CStructProperty>(pProp), pData);
|
||||||
|
}
|
||||||
else if (Type == EPropertyType::Sound)
|
else if (Type == EPropertyType::Sound)
|
||||||
{
|
{
|
||||||
uint32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pData);
|
uint32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pData);
|
||||||
|
|
||||||
if (SoundID != -1)
|
if (SoundID != UINT32_MAX)
|
||||||
{
|
{
|
||||||
CGameProject* pProj = pParentEntry->Project();
|
CGameProject* pProj = pParentEntry->Project();
|
||||||
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
|
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
|
||||||
|
|
||||||
if (Info.pAudioGroup)
|
if (Info.pAudioGroup)
|
||||||
{
|
{
|
||||||
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), Info.pAudioGroup->ID());
|
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), Info.pAudioGroup->ID()));
|
||||||
mChildren.push_back(pDep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EPropertyType::Asset)
|
else if (Type == EPropertyType::Asset)
|
||||||
{
|
{
|
||||||
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pData);
|
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pData);
|
||||||
|
|
||||||
if (ID.IsValid())
|
if (ID.IsValid())
|
||||||
{
|
{
|
||||||
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID);
|
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
|
||||||
mChildren.push_back(pDep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EPropertyType::AnimationSet)
|
else if (Type == EPropertyType::AnimationSet)
|
||||||
{
|
{
|
||||||
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pData);
|
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pData);
|
||||||
|
@ -81,13 +71,11 @@ void IDependencyNode::ParseProperties(CResourceEntry* pParentEntry, CStructPrope
|
||||||
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier
|
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier
|
||||||
if (pProperties->Game() <= EGame::Echoes)
|
if (pProperties->Game() <= EGame::Echoes)
|
||||||
{
|
{
|
||||||
CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex());
|
mChildren.push_back(std::make_unique<CCharPropertyDependency>(pProp->IDString(true), ID, Params.CharacterIndex()));
|
||||||
mChildren.push_back(pDep);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), ID);
|
mChildren.push_back(std::make_unique<CPropertyDependency>(pProp->IDString(true), ID));
|
||||||
mChildren.push_back(pDep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,22 +111,25 @@ void CDependencyTree::Serialize(IArchive& rArc)
|
||||||
rArc << SerialParameter("Children", mChildren);
|
rArc << SerialParameter("Children", mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddChild(IDependencyNode *pNode)
|
void CDependencyTree::AddChild(std::unique_ptr<IDependencyNode>&& pNode)
|
||||||
{
|
{
|
||||||
ASSERT(pNode);
|
ASSERT(pNode);
|
||||||
mChildren.push_back(pNode);
|
mChildren.push_back(std::move(pNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
|
void CDependencyTree::AddDependency(const CAssetID& rkID, bool AvoidDuplicates /*= true*/)
|
||||||
{
|
{
|
||||||
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID))) return;
|
if (!rkID.IsValid() || (AvoidDuplicates && HasDependency(rkID)))
|
||||||
CResourceDependency *pDepend = new CResourceDependency(rkID);
|
return;
|
||||||
mChildren.push_back(pDepend);
|
|
||||||
|
mChildren.push_back(std::make_unique<CResourceDependency>(rkID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
|
void CDependencyTree::AddDependency(CResource *pRes, bool AvoidDuplicates /*= true*/)
|
||||||
{
|
{
|
||||||
if (!pRes) return;
|
if (!pRes)
|
||||||
|
return;
|
||||||
|
|
||||||
AddDependency(pRes->ID(), AvoidDuplicates);
|
AddDependency(pRes->ID(), AvoidDuplicates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,9 +137,10 @@ void CDependencyTree::AddCharacterDependency(const CAnimationParameters& rkAnimP
|
||||||
{
|
{
|
||||||
// This is for formats other than MREA that use AnimationParameters (such as SCAN).
|
// This is for formats other than MREA that use AnimationParameters (such as SCAN).
|
||||||
CAnimSet *pSet = rkAnimParams.AnimSet();
|
CAnimSet *pSet = rkAnimParams.AnimSet();
|
||||||
if (!pSet || rkAnimParams.CharacterIndex() == -1) return;
|
if (!pSet || rkAnimParams.CharacterIndex() == UINT32_MAX)
|
||||||
CCharPropertyDependency *pChar = new CCharPropertyDependency("NULL", pSet->ID(), rkAnimParams.CharacterIndex());
|
return;
|
||||||
mChildren.push_back(pChar);
|
|
||||||
|
mChildren.push_back(std::make_unique<CCharPropertyDependency>("NULL", pSet->ID(), rkAnimParams.CharacterIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CResourceDependency ************
|
// ************ CResourceDependency ************
|
||||||
|
@ -209,9 +201,9 @@ void CScriptInstanceDependency::Serialize(IArchive& rArc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
CScriptInstanceDependency* CScriptInstanceDependency::BuildTree(CScriptObject *pInstance)
|
std::unique_ptr<CScriptInstanceDependency> CScriptInstanceDependency::BuildTree(CScriptObject *pInstance)
|
||||||
{
|
{
|
||||||
CScriptInstanceDependency *pInst = new CScriptInstanceDependency();
|
auto pInst = std::make_unique<CScriptInstanceDependency>();
|
||||||
pInst->mObjectType = pInstance->ObjectTypeID();
|
pInst->mObjectType = pInstance->ObjectTypeID();
|
||||||
pInst->ParseProperties(pInstance->Area()->Entry(), pInstance->Template()->Properties(), pInstance->PropertyData());
|
pInst->ParseProperties(pInstance->Area()->Entry(), pInstance->Template()->Properties(), pInstance->PropertyData());
|
||||||
return pInst;
|
return pInst;
|
||||||
|
@ -229,36 +221,34 @@ void CSetCharacterDependency::Serialize(IArchive& rArc)
|
||||||
<< SerialParameter("Children", mChildren);
|
<< SerialParameter("Children", mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar)
|
std::unique_ptr<CSetCharacterDependency> CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar)
|
||||||
{
|
{
|
||||||
CSetCharacterDependency *pTree = new CSetCharacterDependency(rkChar.ID);
|
auto pTree = std::make_unique<CSetCharacterDependency>(rkChar.ID);
|
||||||
pTree->AddDependency(rkChar.pModel);
|
pTree->AddDependency(rkChar.pModel);
|
||||||
pTree->AddDependency(rkChar.pSkeleton);
|
pTree->AddDependency(rkChar.pSkeleton);
|
||||||
pTree->AddDependency(rkChar.pSkin);
|
pTree->AddDependency(rkChar.pSkin);
|
||||||
pTree->AddDependency(rkChar.AnimDataID);
|
pTree->AddDependency(rkChar.AnimDataID);
|
||||||
pTree->AddDependency(rkChar.CollisionPrimitivesID);
|
pTree->AddDependency(rkChar.CollisionPrimitivesID);
|
||||||
|
|
||||||
const std::vector<CAssetID> *pkParticleVectors[5] = {
|
const std::array<const std::vector<CAssetID>*, 5> particleVectors{
|
||||||
&rkChar.GenericParticles, &rkChar.ElectricParticles,
|
&rkChar.GenericParticles, &rkChar.ElectricParticles,
|
||||||
&rkChar.SwooshParticles, &rkChar.SpawnParticles,
|
&rkChar.SwooshParticles, &rkChar.SpawnParticles,
|
||||||
&rkChar.EffectParticles
|
&rkChar.EffectParticles
|
||||||
};
|
};
|
||||||
|
|
||||||
for (uint32 iVec = 0; iVec < 5; iVec++)
|
for (const auto& vec : particleVectors)
|
||||||
{
|
{
|
||||||
for (uint32 iPart = 0; iPart < pkParticleVectors[iVec]->size(); iPart++)
|
for (const auto& dependency : *vec)
|
||||||
pTree->AddDependency(pkParticleVectors[iVec]->at(iPart));
|
pTree->AddDependency(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 iOverlay = 0; iOverlay < rkChar.OverlayModels.size(); iOverlay++)
|
for (const SOverlayModel& overlay : rkChar.OverlayModels)
|
||||||
{
|
{
|
||||||
const SOverlayModel& rkOverlay = rkChar.OverlayModels[iOverlay];
|
pTree->AddDependency(overlay.ModelID);
|
||||||
pTree->AddDependency(rkOverlay.ModelID);
|
pTree->AddDependency(overlay.SkinID);
|
||||||
pTree->AddDependency(rkOverlay.SkinID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pTree->AddDependency(rkChar.SpatialPrimitives);
|
pTree->AddDependency(rkChar.SpatialPrimitives);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,9 +264,9 @@ void CSetAnimationDependency::Serialize(IArchive& rArc)
|
||||||
<< SerialParameter("Children", mChildren);
|
<< SerialParameter("Children", mChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex)
|
std::unique_ptr<CSetAnimationDependency> CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex)
|
||||||
{
|
{
|
||||||
CSetAnimationDependency *pTree = new CSetAnimationDependency;
|
auto pTree = std::make_unique<CSetAnimationDependency>();
|
||||||
const SAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
|
const SAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
|
||||||
|
|
||||||
// Find relevant character indices
|
// Find relevant character indices
|
||||||
|
@ -284,7 +274,7 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
|
||||||
{
|
{
|
||||||
const SSetCharacter *pkChar = pkOwnerSet->Character(iChar);
|
const SSetCharacter *pkChar = pkOwnerSet->Character(iChar);
|
||||||
|
|
||||||
if ( pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end() )
|
if (pkChar->UsedAnimationIndices.find(AnimIndex) != pkChar->UsedAnimationIndices.end())
|
||||||
pTree->mCharacterIndices.insert(iChar);
|
pTree->mCharacterIndices.insert(iChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,16 +282,15 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
|
||||||
std::set<CAnimPrimitive> UsedPrimitives;
|
std::set<CAnimPrimitive> UsedPrimitives;
|
||||||
pkAnim->pMetaAnim->GetUniquePrimitives(UsedPrimitives);
|
pkAnim->pMetaAnim->GetUniquePrimitives(UsedPrimitives);
|
||||||
|
|
||||||
for (auto Iter = UsedPrimitives.begin(); Iter != UsedPrimitives.end(); Iter++)
|
for (const CAnimPrimitive& prim : UsedPrimitives)
|
||||||
{
|
{
|
||||||
const CAnimPrimitive& rkPrim = *Iter;
|
pTree->AddDependency(prim.Animation());
|
||||||
pTree->AddDependency(rkPrim.Animation());
|
|
||||||
|
|
||||||
if (pkOwnerSet->Game() >= EGame::EchoesDemo)
|
if (pkOwnerSet->Game() >= EGame::EchoesDemo)
|
||||||
{
|
{
|
||||||
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(rkPrim.ID());
|
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(prim.ID());
|
||||||
ASSERT(pEvents && !pEvents->Entry());
|
ASSERT(pEvents && !pEvents->Entry());
|
||||||
pEvents->AddDependenciesToTree(pTree);
|
pEvents->AddDependenciesToTree(pTree.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,27 +323,27 @@ void CAreaDependencyTree::Serialize(IArchive& rArc)
|
||||||
|
|
||||||
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps)
|
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps)
|
||||||
{
|
{
|
||||||
if (!pLayer) return;
|
if (!pLayer)
|
||||||
|
return;
|
||||||
|
|
||||||
mLayerOffsets.push_back(mChildren.size());
|
mLayerOffsets.push_back(mChildren.size());
|
||||||
std::set<CAssetID> UsedIDs;
|
std::set<CAssetID> UsedIDs;
|
||||||
|
|
||||||
for (uint32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
for (size_t iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||||
{
|
{
|
||||||
CScriptInstanceDependency *pTree = CScriptInstanceDependency::BuildTree( pLayer->InstanceByIndex(iInst) );
|
auto pTree = CScriptInstanceDependency::BuildTree(pLayer->InstanceByIndex(iInst));
|
||||||
ASSERT(pTree != nullptr);
|
ASSERT(pTree != nullptr);
|
||||||
|
|
||||||
// Note: MP2+ need to track all instances (not just instances with dependencies) to be able to build the layer module list
|
// Note: MP2+ need to track all instances (not just instances with dependencies) to be able to build the layer module list
|
||||||
if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= EGame::EchoesDemo)
|
if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= EGame::EchoesDemo)
|
||||||
{
|
{
|
||||||
mChildren.push_back(pTree);
|
|
||||||
pTree->GetAllResourceReferences(UsedIDs);
|
pTree->GetAllResourceReferences(UsedIDs);
|
||||||
|
mChildren.push_back(std::move(pTree));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
delete pTree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 iDep = 0; iDep < rkExtraDeps.size(); iDep++)
|
for (const auto& dep : rkExtraDeps)
|
||||||
AddDependency(rkExtraDeps[iDep]);
|
AddDependency(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const
|
void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const
|
||||||
|
@ -363,34 +352,34 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
|
||||||
|
|
||||||
// Output module list will be split per-script layer
|
// Output module list will be split per-script layer
|
||||||
// The output offset list contains two offsets per layer - start index and end index
|
// The output offset list contains two offsets per layer - start index and end index
|
||||||
for (uint32 iLayer = 0; iLayer < mLayerOffsets.size(); iLayer++)
|
for (size_t iLayer = 0; iLayer < mLayerOffsets.size(); iLayer++)
|
||||||
{
|
{
|
||||||
uint32 StartIdx = mLayerOffsets[iLayer];
|
const size_t StartIdx = mLayerOffsets[iLayer];
|
||||||
uint32 EndIdx = (iLayer == mLayerOffsets.size() - 1 ? mChildren.size() : mLayerOffsets[iLayer + 1]);
|
const size_t EndIdx = (iLayer == mLayerOffsets.size() - 1 ? mChildren.size() : mLayerOffsets[iLayer + 1]);
|
||||||
|
|
||||||
uint32 ModuleStartIdx = rModuleDepsOut.size();
|
const auto ModuleStartIdx = static_cast<uint32>(rModuleDepsOut.size());
|
||||||
rModuleLayerOffsetsOut.push_back(ModuleStartIdx);
|
rModuleLayerOffsetsOut.push_back(ModuleStartIdx);
|
||||||
|
|
||||||
// Keep track of which types we've already checked on this layer to speed things up a little...
|
// Keep track of which types we've already checked on this layer to speed things up a little...
|
||||||
std::set<uint32> UsedObjectTypes;
|
std::set<uint32> UsedObjectTypes;
|
||||||
|
|
||||||
for (uint32 iInst = StartIdx; iInst < EndIdx; iInst++)
|
for (size_t iInst = StartIdx; iInst < EndIdx; iInst++)
|
||||||
{
|
{
|
||||||
IDependencyNode *pNode = mChildren[iInst];
|
const auto& pNode = mChildren[iInst];
|
||||||
if (pNode->Type() != EDependencyNodeType::ScriptInstance) continue;
|
if (pNode->Type() != EDependencyNodeType::ScriptInstance)
|
||||||
|
continue;
|
||||||
|
|
||||||
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
|
const auto *pInst = static_cast<CScriptInstanceDependency*>(pNode.get());
|
||||||
uint32 ObjType = pInst->ObjectType();
|
const uint32 ObjType = pInst->ObjectType();
|
||||||
|
|
||||||
if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end())
|
if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end())
|
||||||
{
|
{
|
||||||
// Get the module list for this object type and check whether any of them are new before adding them to the output list
|
// Get the module list for this object type and check whether any of them are new before adding them to the output list
|
||||||
CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
|
const CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
|
||||||
const std::vector<TString>& rkModules = pTemplate->RequiredModules();
|
const std::vector<TString>& rkModules = pTemplate->RequiredModules();
|
||||||
|
|
||||||
for (uint32 iMod = 0; iMod < rkModules.size(); iMod++)
|
for (const auto& ModuleName : rkModules)
|
||||||
{
|
{
|
||||||
TString ModuleName = rkModules[iMod];
|
|
||||||
bool NewModule = true;
|
bool NewModule = true;
|
||||||
|
|
||||||
for (uint32 iUsed = ModuleStartIdx; iUsed < rModuleDepsOut.size(); iUsed++)
|
for (uint32 iUsed = ModuleStartIdx; iUsed < rModuleDepsOut.size(); iUsed++)
|
||||||
|
@ -410,6 +399,6 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rModuleLayerOffsetsOut.push_back(rModuleDepsOut.size());
|
rModuleLayerOffsetsOut.push_back(static_cast<uint32>(rModuleDepsOut.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <Common/CAssetID.h>
|
#include <Common/CAssetID.h>
|
||||||
#include <Common/FileIO.h>
|
#include <Common/FileIO.h>
|
||||||
#include <Common/Macros.h>
|
#include <Common/Macros.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class CScriptLayer;
|
class CScriptLayer;
|
||||||
class CScriptObject;
|
class CScriptObject;
|
||||||
|
@ -31,34 +32,34 @@ enum class EDependencyNodeType
|
||||||
class IDependencyNode
|
class IDependencyNode
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<IDependencyNode*> mChildren;
|
std::vector<std::unique_ptr<IDependencyNode>> mChildren;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~IDependencyNode();
|
virtual ~IDependencyNode();
|
||||||
virtual EDependencyNodeType Type() const = 0;
|
virtual EDependencyNodeType Type() const = 0;
|
||||||
virtual void Serialize(IArchive& rArc) = 0;
|
virtual void Serialize(IArchive& rArc) = 0;
|
||||||
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
|
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
|
||||||
virtual bool HasDependency(const CAssetID& rkID) const;
|
virtual bool HasDependency(const CAssetID& id) const;
|
||||||
void ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData);
|
void ParseProperties(CResourceEntry* pParentEntry, CStructProperty* pProperties, void* pData);
|
||||||
|
|
||||||
// Serialization constructor
|
// Serialization constructor
|
||||||
static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type);
|
static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint NumChildren() const { return mChildren.size(); }
|
size_t NumChildren() const { return mChildren.size(); }
|
||||||
inline IDependencyNode* ChildByIndex(uint Index) const { return mChildren[Index]; }
|
IDependencyNode* ChildByIndex(size_t Index) const { return mChildren[Index].get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic dependency tree; this class is sufficient for most resource types.
|
// Basic dependency tree; this class is sufficient for most resource types.
|
||||||
class CDependencyTree : public IDependencyNode
|
class CDependencyTree : public IDependencyNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDependencyTree() {}
|
CDependencyTree() = default;
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
void AddChild(IDependencyNode *pNode);
|
void AddChild(std::unique_ptr<IDependencyNode>&& pNode);
|
||||||
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
|
void AddDependency(const CAssetID& rkID, bool AvoidDuplicates = true);
|
||||||
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
|
void AddDependency(CResource *pRes, bool AvoidDuplicates = true);
|
||||||
void AddCharacterDependency(const CAnimationParameters& rkAnimParams);
|
void AddCharacterDependency(const CAnimationParameters& rkAnimParams);
|
||||||
|
@ -71,17 +72,17 @@ protected:
|
||||||
CAssetID mID;
|
CAssetID mID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceDependency() {}
|
CResourceDependency() = default;
|
||||||
CResourceDependency(const CAssetID& rkID) : mID(rkID) {}
|
explicit CResourceDependency(const CAssetID& rkID) : mID(rkID) {}
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
|
void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const override;
|
||||||
virtual bool HasDependency(const CAssetID& rkID) const;
|
bool HasDependency(const CAssetID& rkID) const override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CAssetID ID() const { return mID; }
|
CAssetID ID() const { return mID; }
|
||||||
inline void SetID(const CAssetID& rkID) { mID = rkID; }
|
void SetID(const CAssetID& rkID) { mID = rkID; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing a single resource dependency referenced by a script property.
|
// Node representing a single resource dependency referenced by a script property.
|
||||||
|
@ -90,81 +91,76 @@ class CPropertyDependency : public CResourceDependency
|
||||||
TString mIDString;
|
TString mIDString;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPropertyDependency()
|
CPropertyDependency() = default;
|
||||||
: CResourceDependency()
|
|
||||||
{}
|
|
||||||
|
|
||||||
CPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID)
|
CPropertyDependency(TString rkPropID, const CAssetID& rkAssetID)
|
||||||
: CResourceDependency(rkAssetID)
|
: CResourceDependency(rkAssetID)
|
||||||
, mIDString(rkPropID)
|
, mIDString(std::move(rkPropID))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString PropertyID() const { return mIDString; }
|
TString PropertyID() const { return mIDString; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing a single animset dependency referenced by a script property. Indicates which character is being used.
|
// Node representing a single animset dependency referenced by a script property. Indicates which character is being used.
|
||||||
class CCharPropertyDependency : public CPropertyDependency
|
class CCharPropertyDependency : public CPropertyDependency
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
int mUsedChar;
|
int mUsedChar = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCharPropertyDependency()
|
CCharPropertyDependency() = default;
|
||||||
: CPropertyDependency()
|
|
||||||
, mUsedChar(-1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
CCharPropertyDependency(const TString& rkPropID, const CAssetID& rkAssetID, int UsedChar)
|
CCharPropertyDependency(TString rkPropID, const CAssetID& rkAssetID, int UsedChar)
|
||||||
: CPropertyDependency(rkPropID, rkAssetID)
|
: CPropertyDependency(std::move(rkPropID), rkAssetID)
|
||||||
, mUsedChar(UsedChar)
|
, mUsedChar(UsedChar)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline int UsedChar() const { return mUsedChar; }
|
int UsedChar() const { return mUsedChar; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing a script object. Indicates the type of object.
|
// Node representing a script object. Indicates the type of object.
|
||||||
class CScriptInstanceDependency : public IDependencyNode
|
class CScriptInstanceDependency : public IDependencyNode
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
uint mObjectType;
|
uint32 mObjectType = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint ObjectType() const { return mObjectType; }
|
uint32 ObjectType() const { return mObjectType; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance);
|
static std::unique_ptr<CScriptInstanceDependency> BuildTree(CScriptObject *pInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing an animset character. Indicates what index the character is within the animset.
|
// Node representing an animset character. Indicates what index the character is within the animset.
|
||||||
class CSetCharacterDependency : public CDependencyTree
|
class CSetCharacterDependency : public CDependencyTree
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
uint32 mCharSetIndex;
|
uint32 mCharSetIndex = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSetCharacterDependency() : CDependencyTree() {}
|
CSetCharacterDependency() = default;
|
||||||
CSetCharacterDependency(uint32 SetIndex) : CDependencyTree(), mCharSetIndex(SetIndex) {}
|
explicit CSetCharacterDependency(uint32 SetIndex) : mCharSetIndex(SetIndex) {}
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint32 CharSetIndex() const { return mCharSetIndex; }
|
uint32 CharSetIndex() const { return mCharSetIndex; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CSetCharacterDependency* BuildTree(const SSetCharacter& rkChar);
|
static std::unique_ptr<CSetCharacterDependency> BuildTree(const SSetCharacter& rkChar);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing a character animation. Indicates which character indices use this animation.
|
// Node representing a character animation. Indicates which character indices use this animation.
|
||||||
|
@ -174,35 +170,35 @@ protected:
|
||||||
std::set<uint32> mCharacterIndices;
|
std::set<uint32> mCharacterIndices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSetAnimationDependency() : CDependencyTree() {}
|
CSetAnimationDependency() = default;
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
|
bool IsUsedByCharacter(uint32 CharIdx) const { return mCharacterIndices.find(CharIdx) != mCharacterIndices.end(); }
|
||||||
inline bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); }
|
bool IsUsedByAnyCharacter() const { return !mCharacterIndices.empty(); }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CSetAnimationDependency* BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex);
|
static std::unique_ptr<CSetAnimationDependency> BuildTree(const CAnimSet *pkOwnerSet, uint32 AnimIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing an animation event. Indicates which character index uses this event.
|
// Node representing an animation event. Indicates which character index uses this event.
|
||||||
class CAnimEventDependency : public CResourceDependency
|
class CAnimEventDependency : public CResourceDependency
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
uint32 mCharIndex;
|
uint32 mCharIndex = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimEventDependency() : CResourceDependency() {}
|
CAnimEventDependency() = default;
|
||||||
CAnimEventDependency(const CAssetID& rkID, uint32 CharIndex)
|
CAnimEventDependency(const CAssetID& rkID, uint32 CharIndex)
|
||||||
: CResourceDependency(rkID), mCharIndex(CharIndex) {}
|
: CResourceDependency(rkID), mCharIndex(CharIndex) {}
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint32 CharIndex() const { return mCharIndex; }
|
uint32 CharIndex() const { return mCharIndex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
|
// Node representing an area. Tracks dependencies on a per-instance basis and can separate dependencies of different script layers.
|
||||||
|
@ -212,17 +208,17 @@ protected:
|
||||||
std::vector<uint32> mLayerOffsets;
|
std::vector<uint32> mLayerOffsets;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAreaDependencyTree() : CDependencyTree() {}
|
CAreaDependencyTree() = default;
|
||||||
|
|
||||||
virtual EDependencyNodeType Type() const;
|
EDependencyNodeType Type() const override;
|
||||||
virtual void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc) override;
|
||||||
|
|
||||||
void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps);
|
void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps);
|
||||||
void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const;
|
void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<uint32>& rModuleLayerOffsetsOut) const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint32 NumScriptLayers() const { return mLayerOffsets.size(); }
|
size_t NumScriptLayers() const { return mLayerOffsets.size(); }
|
||||||
inline uint32 ScriptLayerOffset(uint32 LayerIdx) const { return mLayerOffsets[LayerIdx]; }
|
uint32 ScriptLayerOffset(size_t LayerIdx) const { return mLayerOffsets[LayerIdx]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CDEPENDENCYTREE
|
#endif // CDEPENDENCYTREE
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <Common/Serialization/CXMLWriter.h>
|
#include <Common/Serialization/CXMLWriter.h>
|
||||||
|
|
||||||
#include <nod/nod.hpp>
|
#include <nod/nod.hpp>
|
||||||
|
#include <nod/DiscBase.hpp>
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
|
||||||
#define LOAD_PAKS 1
|
#define LOAD_PAKS 1
|
||||||
|
@ -33,7 +34,6 @@ CGameExporter::CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, EReg
|
||||||
, mBuildVersion(BuildVersion)
|
, mBuildVersion(BuildVersion)
|
||||||
, mDiscType(DiscType)
|
, mDiscType(DiscType)
|
||||||
, mFrontEnd(FrontEnd)
|
, mFrontEnd(FrontEnd)
|
||||||
, mpProgress(nullptr)
|
|
||||||
{
|
{
|
||||||
ASSERT(mGame != EGame::Invalid);
|
ASSERT(mGame != EGame::Invalid);
|
||||||
ASSERT(mRegion != ERegion::Unknown);
|
ASSERT(mRegion != ERegion::Unknown);
|
||||||
|
@ -93,18 +93,20 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs
|
||||||
|
|
||||||
// Export finished!
|
// Export finished!
|
||||||
mProjectPath = mpProject->ProjectPath();
|
mProjectPath = mpProject->ProjectPath();
|
||||||
delete mpProject;
|
mpProject.reset();
|
||||||
if (pOldStore) gpResourceStore = pOldStore;
|
if (pOldStore != nullptr)
|
||||||
|
gpResourceStore = pOldStore;
|
||||||
return !mpProgress->ShouldCancel();
|
return !mpProgress->ShouldCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer)
|
void CGameExporter::LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer)
|
||||||
{
|
{
|
||||||
SResourceInstance *pInst = FindResourceInstance(rkID);
|
SResourceInstance *pInst = FindResourceInstance(rkID);
|
||||||
if (pInst) LoadResource(*pInst, rBuffer);
|
if (pInst != nullptr)
|
||||||
|
LoadResource(*pInst, rBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
|
bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot) const
|
||||||
{
|
{
|
||||||
if (IsInRoot && mDiscType != EDiscType::Normal)
|
if (IsInRoot && mDiscType != EDiscType::Normal)
|
||||||
{
|
{
|
||||||
|
@ -115,49 +117,47 @@ bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
|
||||||
if (pkNode->getName() == "fe")
|
if (pkNode->getName() == "fe")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
else if (mFrontEnd)
|
if (mFrontEnd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (mGame)
|
switch (mGame)
|
||||||
{
|
{
|
||||||
case EGame::Prime:
|
case EGame::Prime:
|
||||||
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP1JPN") ||
|
return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP1JPN" ||
|
||||||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP1") );
|
mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP1";
|
||||||
|
|
||||||
case EGame::Echoes:
|
case EGame::Echoes:
|
||||||
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP2JPN") ||
|
return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "MP2JPN" ||
|
||||||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP2") );
|
mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP2";
|
||||||
|
|
||||||
case EGame::Corruption:
|
case EGame::Corruption:
|
||||||
return (mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP3");
|
return mDiscType == EDiscType::Trilogy && pkNode->getName() == "MP3";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Files - exclude the DOLs for other games
|
||||||
// Files - exclude the DOLs for other games
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Again - always include frontend. Always include opening.bnr as well.
|
// Again - always include frontend. Always include opening.bnr as well.
|
||||||
if (pkNode->getName() == "rs5fe_p.dol" || pkNode->getName() == "opening.bnr")
|
if (pkNode->getName() == "rs5fe_p.dol" || pkNode->getName() == "opening.bnr")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
else if (mFrontEnd)
|
if (mFrontEnd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (mGame)
|
switch (mGame)
|
||||||
{
|
{
|
||||||
case EGame::Prime:
|
case EGame::Prime:
|
||||||
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol") ||
|
return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol" ||
|
||||||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp1_p.dol") );
|
mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp1_p.dol";
|
||||||
|
|
||||||
case EGame::Echoes:
|
case EGame::Echoes:
|
||||||
return ( (mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol") ||
|
return mDiscType == EDiscType::WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol" ||
|
||||||
(mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp2_p.dol") );
|
mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp2_p.dol";
|
||||||
|
|
||||||
case EGame::Corruption:
|
case EGame::Corruption:
|
||||||
return (mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp3_p.dol");
|
return mDiscType == EDiscType::Trilogy && pkNode->getName() == "rs5mp3_p.dol";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -233,7 +233,8 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
|
||||||
{
|
{
|
||||||
TString FilePath = rkDir + Iter->getName().data();
|
TString FilePath = rkDir + Iter->getName().data();
|
||||||
bool Success = Iter->extractToDirectory(TStringToNodString(rkDir), rkContext);
|
bool Success = Iter->extractToDirectory(TStringToNodString(rkDir), rkContext);
|
||||||
if (!Success) return false;
|
if (!Success)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (FilePath.GetFileExtension().CaseInsensitiveCompare("pak"))
|
if (FilePath.GetFileExtension().CaseInsensitiveCompare("pak"))
|
||||||
{
|
{
|
||||||
|
@ -247,10 +248,12 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
|
||||||
{
|
{
|
||||||
TString Subdir = rkDir + Iter->getName().data() + "/";
|
TString Subdir = rkDir + Iter->getName().data() + "/";
|
||||||
bool Success = FileUtil::MakeDirectory(Subdir);
|
bool Success = FileUtil::MakeDirectory(Subdir);
|
||||||
if (!Success) return false;
|
if (!Success)
|
||||||
|
return false;
|
||||||
|
|
||||||
Success = ExtractDiscNodeRecursive(&*Iter, Subdir, false, rkContext);
|
Success = ExtractDiscNodeRecursive(&*Iter, Subdir, false, rkContext);
|
||||||
if (!Success) return false;
|
if (!Success)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,27 +282,27 @@ void CGameExporter::LoadPaks()
|
||||||
}
|
}
|
||||||
|
|
||||||
TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false));
|
TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false));
|
||||||
CPackage *pPackage = new CPackage(mpProject, PakPath.GetFileName(false), RelPakPath);
|
auto pPackage = std::make_unique<CPackage>(mpProject.get(), PakPath.GetFileName(false), RelPakPath);
|
||||||
|
|
||||||
// MP1-MP3Proto
|
// MP1-MP3Proto
|
||||||
if (mGame < EGame::Corruption)
|
if (mGame < EGame::Corruption)
|
||||||
{
|
{
|
||||||
uint32 PakVersion = Pak.ReadLong();
|
[[maybe_unused]] const uint32 PakVersion = Pak.ReadULong();
|
||||||
Pak.Seek(0x4, SEEK_CUR);
|
Pak.Seek(0x4, SEEK_CUR);
|
||||||
ASSERT(PakVersion == 0x00030005);
|
ASSERT(PakVersion == 0x00030005);
|
||||||
|
|
||||||
// Echoes demo disc has a pak that ends right here.
|
// Echoes demo disc has a pak that ends right here.
|
||||||
if (!Pak.EoF())
|
if (!Pak.EoF())
|
||||||
{
|
{
|
||||||
uint32 NumNamedResources = Pak.ReadLong();
|
uint32 NumNamedResources = Pak.ReadULong();
|
||||||
ASSERT(NumNamedResources > 0);
|
ASSERT(NumNamedResources > 0);
|
||||||
|
|
||||||
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
||||||
{
|
{
|
||||||
CFourCC ResType = Pak.ReadLong();
|
const CFourCC ResType = Pak.ReadULong();
|
||||||
CAssetID ResID(Pak, mGame);
|
const CAssetID ResID(Pak, mGame);
|
||||||
uint32 NameLen = Pak.ReadLong();
|
const uint32 NameLen = Pak.ReadULong();
|
||||||
TString Name = Pak.ReadString(NameLen);
|
const TString Name = Pak.ReadString(NameLen);
|
||||||
pPackage->AddResource(Name, ResID, ResType);
|
pPackage->AddResource(Name, ResID, ResType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,14 +314,14 @@ void CGameExporter::LoadPaks()
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
bool Compressed = (Pak.ReadLong() == 1);
|
const bool Compressed = Pak.ReadULong() == 1;
|
||||||
CFourCC ResType = Pak.ReadLong();
|
const CFourCC ResType = Pak.ReadULong();
|
||||||
CAssetID ResID(Pak, mGame);
|
const CAssetID ResID(Pak, mGame);
|
||||||
uint32 ResSize = Pak.ReadLong();
|
const uint32 ResSize = Pak.ReadULong();
|
||||||
uint32 ResOffset = Pak.ReadLong();
|
const uint32 ResOffset = Pak.ReadULong();
|
||||||
|
|
||||||
if (mResourceMap.find(ResID) == mResourceMap.end())
|
if (mResourceMap.find(ResID) == mResourceMap.cend())
|
||||||
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false };
|
mResourceMap.insert_or_assign(ResID, SResourceInstance{PakPath, ResID, ResType, ResOffset, ResSize, Compressed, false});
|
||||||
|
|
||||||
// Check for duplicate resources
|
// Check for duplicate resources
|
||||||
if (ResType == "MREA")
|
if (ResType == "MREA")
|
||||||
|
@ -326,63 +329,63 @@ void CGameExporter::LoadPaks()
|
||||||
mAreaDuplicateMap[ResID] = AreaHasDuplicates;
|
mAreaDuplicateMap[ResID] = AreaHasDuplicates;
|
||||||
AreaHasDuplicates = false;
|
AreaHasDuplicates = false;
|
||||||
}
|
}
|
||||||
|
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.cend())
|
||||||
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end())
|
{
|
||||||
AreaHasDuplicates = true;
|
AreaHasDuplicates = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
PakResourceSet.insert(ResID);
|
PakResourceSet.insert(ResID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // MP3 + DKCR
|
||||||
// MP3 + DKCR
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
uint32 PakVersion = Pak.ReadLong();
|
[[maybe_unused]] const uint32 PakVersion = Pak.ReadULong();
|
||||||
uint32 PakHeaderLen = Pak.ReadLong();
|
const uint32 PakHeaderLen = Pak.ReadULong();
|
||||||
Pak.Seek(PakHeaderLen - 0x8, SEEK_CUR);
|
Pak.Seek(PakHeaderLen - 0x8, SEEK_CUR);
|
||||||
ASSERT(PakVersion == 2);
|
ASSERT(PakVersion == 2);
|
||||||
|
|
||||||
struct SPakSection {
|
struct SPakSection {
|
||||||
CFourCC Type; uint32 Size;
|
CFourCC Type;
|
||||||
|
uint32 Size;
|
||||||
};
|
};
|
||||||
std::vector<SPakSection> PakSections;
|
std::vector<SPakSection> PakSections;
|
||||||
|
|
||||||
uint32 NumPakSections = Pak.ReadLong();
|
const uint32 NumPakSections = Pak.ReadULong();
|
||||||
ASSERT(NumPakSections == 3);
|
ASSERT(NumPakSections == 3);
|
||||||
|
|
||||||
for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
|
for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
|
||||||
{
|
{
|
||||||
CFourCC Type = Pak.ReadLong();
|
const CFourCC Type = Pak.ReadULong();
|
||||||
uint32 Size = Pak.ReadLong();
|
const uint32 Size = Pak.ReadULong();
|
||||||
PakSections.push_back(SPakSection { Type, Size });
|
PakSections.push_back(SPakSection{Type, Size});
|
||||||
}
|
}
|
||||||
Pak.SeekToBoundary(64);
|
Pak.SeekToBoundary(64);
|
||||||
|
|
||||||
for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
|
for (uint32 iSec = 0; iSec < NumPakSections; iSec++)
|
||||||
{
|
{
|
||||||
uint32 Next = Pak.Tell() + PakSections[iSec].Size;
|
const uint32 Next = Pak.Tell() + PakSections[iSec].Size;
|
||||||
|
|
||||||
// Named Resources
|
// Named Resources
|
||||||
if (PakSections[iSec].Type == "STRG")
|
if (PakSections[iSec].Type == "STRG")
|
||||||
{
|
{
|
||||||
uint32 NumNamedResources = Pak.ReadLong();
|
const uint32 NumNamedResources = Pak.ReadULong();
|
||||||
|
|
||||||
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
||||||
{
|
{
|
||||||
TString Name = Pak.ReadString();
|
const TString Name = Pak.ReadString();
|
||||||
CFourCC ResType = Pak.ReadLong();
|
const CFourCC ResType = Pak.ReadULong();
|
||||||
CAssetID ResID(Pak, mGame);
|
const CAssetID ResID(Pak, mGame);
|
||||||
pPackage->AddResource(Name, ResID, ResType);
|
pPackage->AddResource(Name, ResID, ResType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (PakSections[iSec].Type == "RSHD")
|
else if (PakSections[iSec].Type == "RSHD")
|
||||||
{
|
{
|
||||||
ASSERT(PakSections[iSec + 1].Type == "DATA");
|
ASSERT(PakSections[iSec + 1].Type == "DATA");
|
||||||
uint32 DataStart = Next;
|
const uint32 DataStart = Next;
|
||||||
uint32 NumResources = Pak.ReadLong();
|
const uint32 NumResources = Pak.ReadULong();
|
||||||
|
|
||||||
// Keep track of which areas have duplicate resources
|
// Keep track of which areas have duplicate resources
|
||||||
std::set<CAssetID> PakResourceSet;
|
std::set<CAssetID> PakResourceSet;
|
||||||
|
@ -390,29 +393,31 @@ void CGameExporter::LoadPaks()
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
bool Compressed = (Pak.ReadLong() == 1);
|
const bool Compressed = Pak.ReadULong() == 1;
|
||||||
CFourCC Type = Pak.ReadLong();
|
const CFourCC Type = Pak.ReadULong();
|
||||||
CAssetID ResID(Pak, mGame);
|
const CAssetID ResID(Pak, mGame);
|
||||||
uint32 Size = Pak.ReadLong();
|
const uint32 Size = Pak.ReadULong();
|
||||||
uint32 Offset = DataStart + Pak.ReadLong();
|
const uint32 Offset = DataStart + Pak.ReadULong();
|
||||||
|
|
||||||
if (mResourceMap.find(ResID) == mResourceMap.end())
|
if (mResourceMap.find(ResID) == mResourceMap.cend())
|
||||||
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
|
mResourceMap.insert_or_assign(ResID, SResourceInstance{PakPath, ResID, Type, Offset, Size, Compressed, false});
|
||||||
|
|
||||||
// Check for duplicate resources (unnecessary for DKCR)
|
// Check for duplicate resources (unnecessary for DKCR)
|
||||||
if (mGame != EGame::DKCReturns)
|
if (mGame != EGame::DKCReturns)
|
||||||
{
|
{
|
||||||
if (Type == "MREA")
|
if (Type == "MREA")
|
||||||
{
|
{
|
||||||
mAreaDuplicateMap[ResID] = AreaHasDuplicates;
|
mAreaDuplicateMap.insert_or_assign(ResID, AreaHasDuplicates);
|
||||||
AreaHasDuplicates = false;
|
AreaHasDuplicates = false;
|
||||||
}
|
}
|
||||||
|
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.cend())
|
||||||
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end())
|
{
|
||||||
AreaHasDuplicates = true;
|
AreaHasDuplicates = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
PakResourceSet.insert(ResID);
|
PakResourceSet.insert(ResID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,11 +427,12 @@ void CGameExporter::LoadPaks()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add package to project and save
|
// Add package to project and save
|
||||||
mpProject->AddPackage(pPackage);
|
|
||||||
#if SAVE_PACKAGE_DEFINITIONS
|
#if SAVE_PACKAGE_DEFINITIONS
|
||||||
bool SaveSuccess = pPackage->Save();
|
[[maybe_unused]] const bool SaveSuccess = pPackage->Save();
|
||||||
ASSERT(SaveSuccess);
|
ASSERT(SaveSuccess);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mpProject->AddPackage(std::move(pPackage));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -448,7 +454,7 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||||
{
|
{
|
||||||
std::vector<uint8> CompressedData(rkResource.PakSize);
|
std::vector<uint8> CompressedData(rkResource.PakSize);
|
||||||
|
|
||||||
uint32 UncompressedSize = Pak.ReadLong();
|
const uint32 UncompressedSize = Pak.ReadULong();
|
||||||
rBuffer.resize(UncompressedSize);
|
rBuffer.resize(UncompressedSize);
|
||||||
Pak.ReadBytes(CompressedData.data(), CompressedData.size());
|
Pak.ReadBytes(CompressedData.data(), CompressedData.size());
|
||||||
|
|
||||||
|
@ -465,24 +471,25 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CFourCC Magic = Pak.ReadLong();
|
[[maybe_unused]] const CFourCC Magic = Pak.ReadULong();
|
||||||
ASSERT(Magic == "CMPD");
|
ASSERT(Magic == "CMPD");
|
||||||
|
|
||||||
uint32 NumBlocks = Pak.ReadLong();
|
const uint32 NumBlocks = Pak.ReadULong();
|
||||||
|
|
||||||
struct SCompressedBlock {
|
struct SCompressedBlock {
|
||||||
uint32 CompressedSize; uint32 UncompressedSize;
|
uint32 CompressedSize;
|
||||||
|
uint32 UncompressedSize;
|
||||||
};
|
};
|
||||||
std::vector<SCompressedBlock> CompressedBlocks;
|
std::vector<SCompressedBlock> CompressedBlocks;
|
||||||
|
|
||||||
uint32 TotalUncompressedSize = 0;
|
uint32 TotalUncompressedSize = 0;
|
||||||
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
|
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
|
||||||
{
|
{
|
||||||
uint32 CompressedSize = (Pak.ReadLong() & 0x00FFFFFF);
|
const uint32 CompressedSize = (Pak.ReadULong() & 0x00FFFFFF);
|
||||||
uint32 UncompressedSize = Pak.ReadLong();
|
const uint32 UncompressedSize = Pak.ReadULong();
|
||||||
|
|
||||||
TotalUncompressedSize += UncompressedSize;
|
TotalUncompressedSize += UncompressedSize;
|
||||||
CompressedBlocks.push_back( SCompressedBlock { CompressedSize, UncompressedSize } );
|
CompressedBlocks.push_back(SCompressedBlock{CompressedSize, UncompressedSize});
|
||||||
}
|
}
|
||||||
|
|
||||||
rBuffer.resize(TotalUncompressedSize);
|
rBuffer.resize(TotalUncompressedSize);
|
||||||
|
@ -490,8 +497,8 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||||
|
|
||||||
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
|
for (uint32 iBlock = 0; iBlock < NumBlocks; iBlock++)
|
||||||
{
|
{
|
||||||
uint32 CompressedSize = CompressedBlocks[iBlock].CompressedSize;
|
const uint32 CompressedSize = CompressedBlocks[iBlock].CompressedSize;
|
||||||
uint32 UncompressedSize = CompressedBlocks[iBlock].UncompressedSize;
|
const uint32 UncompressedSize = CompressedBlocks[iBlock].UncompressedSize;
|
||||||
|
|
||||||
// Block is compressed
|
// Block is compressed
|
||||||
if (CompressedSize != UncompressedSize)
|
if (CompressedSize != UncompressedSize)
|
||||||
|
@ -509,17 +516,16 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||||
CompressionUtil::DecompressSegmentedData(CompressedData.data(), CompressedData.size(), rBuffer.data() + Offset, UncompressedSize);
|
CompressionUtil::DecompressSegmentedData(CompressedData.data(), CompressedData.size(), rBuffer.data() + Offset, UncompressedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Block is uncompressed
|
else // Block is uncompressed
|
||||||
else
|
{
|
||||||
Pak.ReadBytes(rBuffer.data() + Offset, UncompressedSize);
|
Pak.ReadBytes(rBuffer.data() + Offset, UncompressedSize);
|
||||||
|
}
|
||||||
|
|
||||||
Offset += UncompressedSize;
|
Offset += UncompressedSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Handle uncompressed
|
||||||
// Handle uncompressed
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
rBuffer.resize(rkResource.PakSize);
|
rBuffer.resize(rkResource.PakSize);
|
||||||
Pak.ReadBytes(rBuffer.data(), rBuffer.size());
|
Pak.ReadBytes(rBuffer.data(), rBuffer.size());
|
||||||
|
@ -535,7 +541,7 @@ void CGameExporter::ExportCookedResources()
|
||||||
mpProgress->SetTask(eES_ExportCooked, "Unpacking cooked assets");
|
mpProgress->SetTask(eES_ExportCooked, "Unpacking cooked assets");
|
||||||
int ResIndex = 0;
|
int ResIndex = 0;
|
||||||
|
|
||||||
for (auto It = mResourceMap.begin(); It != mResourceMap.end() && !mpProgress->ShouldCancel(); It++, ResIndex++)
|
for (auto It = mResourceMap.begin(); It != mResourceMap.end() && !mpProgress->ShouldCancel(); ++It, ResIndex++)
|
||||||
{
|
{
|
||||||
SResourceInstance& rRes = It->second;
|
SResourceInstance& rRes = It->second;
|
||||||
|
|
||||||
|
@ -566,28 +572,29 @@ void CGameExporter::ExportResourceEditorData()
|
||||||
{
|
{
|
||||||
// Update progress
|
// Update progress
|
||||||
if ((ResIndex & 0x3) == 0 || It->ResourceType() == EResourceType::Area)
|
if ((ResIndex & 0x3) == 0 || It->ResourceType() == EResourceType::Area)
|
||||||
mpProgress->Report(ResIndex, mpStore->NumTotalResources(), TString::Format("Processing asset %d/%d: %s",
|
{
|
||||||
ResIndex, mpStore->NumTotalResources(), *It->CookedAssetPath(true).GetFileName()) );
|
mpProgress->Report(ResIndex, mpStore->NumTotalResources(), TString::Format("Processing asset %u/%u: %s", ResIndex, mpStore->NumTotalResources(), *It->CookedAssetPath(true).GetFileName()));
|
||||||
|
}
|
||||||
|
|
||||||
// Worlds need some info we can only get from the pak at export time; namely, which areas can
|
// Worlds need some info we can only get from the pak at export time; namely, which areas can
|
||||||
// have duplicates, as well as the world's internal name.
|
// have duplicates, as well as the world's internal name.
|
||||||
if (It->ResourceType() == EResourceType::World)
|
if (It->ResourceType() == EResourceType::World)
|
||||||
{
|
{
|
||||||
CWorld *pWorld = (CWorld*) It->Load();
|
auto* pWorld = static_cast<CWorld*>(It->Load());
|
||||||
|
|
||||||
// Set area duplicate flags
|
// Set area duplicate flags
|
||||||
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
const CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
||||||
auto Find = mAreaDuplicateMap.find(AreaID);
|
const auto Find = mAreaDuplicateMap.find(AreaID);
|
||||||
|
|
||||||
if (Find != mAreaDuplicateMap.end())
|
if (Find != mAreaDuplicateMap.cend())
|
||||||
pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second);
|
pWorld->SetAreaAllowsPakDuplicates(iArea, Find->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set world name
|
// Set world name
|
||||||
TString WorldName = MakeWorldName(pWorld->ID());
|
TString WorldName = MakeWorldName(pWorld->ID());
|
||||||
pWorld->SetName(WorldName);
|
pWorld->SetName(std::move(WorldName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save raw resource + generate dependencies
|
// Save raw resource + generate dependencies
|
||||||
|
@ -606,10 +613,10 @@ void CGameExporter::ExportResourceEditorData()
|
||||||
// All resources should have dependencies generated, so save the project files
|
// All resources should have dependencies generated, so save the project files
|
||||||
SCOPED_TIMER(SaveResourceDatabase);
|
SCOPED_TIMER(SaveResourceDatabase);
|
||||||
#if EXPORT_COOKED
|
#if EXPORT_COOKED
|
||||||
bool ResDBSaveSuccess = mpStore->SaveDatabaseCache();
|
[[maybe_unused]] const bool ResDBSaveSuccess = mpStore->SaveDatabaseCache();
|
||||||
ASSERT(ResDBSaveSuccess);
|
ASSERT(ResDBSaveSuccess);
|
||||||
#endif
|
#endif
|
||||||
bool ProjectSaveSuccess = mpProject->Save();
|
[[maybe_unused]] const bool ProjectSaveSuccess = mpProject->Save();
|
||||||
ASSERT(ProjectSaveSuccess);
|
ASSERT(ProjectSaveSuccess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,7 +650,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
|
|
||||||
#if EXPORT_COOKED
|
#if EXPORT_COOKED
|
||||||
// Save cooked asset
|
// Save cooked asset
|
||||||
TString OutCookedPath = pEntry->CookedAssetPath();
|
const TString OutCookedPath = pEntry->CookedAssetPath();
|
||||||
FileUtil::MakeDirectory(OutCookedPath.GetFileDirectory());
|
FileUtil::MakeDirectory(OutCookedPath.GetFileDirectory());
|
||||||
CFileOutStream Out(OutCookedPath, EEndian::BigEndian);
|
CFileOutStream Out(OutCookedPath, EEndian::BigEndian);
|
||||||
|
|
||||||
|
@ -659,17 +666,17 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
|
|
||||||
TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||||
{
|
{
|
||||||
CResourceEntry *pWorldEntry = mpStore->FindEntry(WorldID);
|
[[maybe_unused]] const CResourceEntry *pWorldEntry = mpStore->FindEntry(WorldID);
|
||||||
ASSERT(pWorldEntry && pWorldEntry->ResourceType() == EResourceType::World);
|
ASSERT(pWorldEntry && pWorldEntry->ResourceType() == EResourceType::World);
|
||||||
|
|
||||||
// Find the original world name in the package resource names
|
// Find the original world name in the package resource names
|
||||||
TString WorldName;
|
TString WorldName;
|
||||||
|
|
||||||
for (uint32 iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++)
|
for (size_t iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = mpProject->PackageByIndex(iPkg);
|
CPackage *pPkg = mpProject->PackageByIndex(iPkg);
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
||||||
|
|
||||||
|
@ -684,7 +691,8 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WorldName.IsEmpty()) break;
|
if (!WorldName.IsEmpty())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix up the name; remove date/time, leading exclamation points, etc
|
// Fix up the name; remove date/time, leading exclamation points, etc
|
||||||
|
@ -697,7 +705,6 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||||
if (WorldName.StartsWith('!'))
|
if (WorldName.StartsWith('!'))
|
||||||
WorldName = WorldName.ChopFront(1);
|
WorldName = WorldName.ChopFront(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MP1 - Remove prefix characters and ending date
|
// MP1 - Remove prefix characters and ending date
|
||||||
else if (mGame == EGame::Prime)
|
else if (mGame == EGame::Prime)
|
||||||
{
|
{
|
||||||
|
@ -706,7 +713,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||||
|
|
||||||
while (!WorldName.IsEmpty())
|
while (!WorldName.IsEmpty())
|
||||||
{
|
{
|
||||||
char Chr = WorldName.Back();
|
const char Chr = WorldName.Back();
|
||||||
|
|
||||||
if (!StartedDate && Chr >= '0' && Chr <= '9')
|
if (!StartedDate && Chr >= '0' && Chr <= '9')
|
||||||
StartedDate = true;
|
StartedDate = true;
|
||||||
|
@ -716,54 +723,49 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||||
WorldName = WorldName.ChopBack(1);
|
WorldName = WorldName.ChopBack(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MP2 demo - Use text between the first and second underscores
|
// MP2 demo - Use text between the first and second underscores
|
||||||
else if (mGame == EGame::EchoesDemo)
|
else if (mGame == EGame::EchoesDemo)
|
||||||
{
|
{
|
||||||
uint32 UnderscoreA = WorldName.IndexOf('_');
|
const uint32 UnderscoreA = WorldName.IndexOf('_');
|
||||||
uint32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1);
|
const uint32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1);
|
||||||
|
|
||||||
if (UnderscoreA != UnderscoreB && UnderscoreA != -1 && UnderscoreB != -1)
|
if (UnderscoreA != UnderscoreB && UnderscoreA != UINT32_MAX && UnderscoreB != UINT32_MAX)
|
||||||
WorldName = WorldName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
|
WorldName = WorldName.SubString(UnderscoreA + 1, UnderscoreB - UnderscoreA - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
|
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
|
||||||
else if (mGame == EGame::Echoes)
|
else if (mGame == EGame::Echoes)
|
||||||
{
|
{
|
||||||
uint32 FirstUnderscore = WorldName.IndexOf('_');
|
const uint32 FirstUnderscore = WorldName.IndexOf('_');
|
||||||
uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
const uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
||||||
|
|
||||||
if (FirstUnderscore != LastUnderscore && FirstUnderscore != -1 && LastUnderscore != -1)
|
if (FirstUnderscore != LastUnderscore && FirstUnderscore != UINT32_MAX && LastUnderscore != UINT32_MAX)
|
||||||
{
|
{
|
||||||
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
||||||
WorldName = WorldName.ChopFront(FirstUnderscore + 1);
|
WorldName = WorldName.ChopFront(FirstUnderscore + 1);
|
||||||
WorldName.Remove('_');
|
WorldName.Remove('_');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MP3 proto - Remove ! from the beginning and all text after last underscore
|
// MP3 proto - Remove ! from the beginning and all text after last underscore
|
||||||
else if (mGame == EGame::CorruptionProto)
|
else if (mGame == EGame::CorruptionProto)
|
||||||
{
|
{
|
||||||
if (WorldName.StartsWith('!'))
|
if (WorldName.StartsWith('!'))
|
||||||
WorldName = WorldName.ChopFront(1);
|
WorldName = WorldName.ChopFront(1);
|
||||||
|
|
||||||
uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
const uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
||||||
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MP3 - Remove text after last underscore
|
// MP3 - Remove text after last underscore
|
||||||
else if (mGame == EGame::Corruption)
|
else if (mGame == EGame::Corruption)
|
||||||
{
|
{
|
||||||
uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
const uint32 LastUnderscore = WorldName.LastIndexOf('_');
|
||||||
|
|
||||||
if (LastUnderscore != -1 && !WorldName.StartsWith("front_end_"))
|
if (LastUnderscore != UINT32_MAX && !WorldName.StartsWith("front_end_"))
|
||||||
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
WorldName = WorldName.ChopBack(WorldName.Size() - LastUnderscore);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DKCR - Remove text prior to first underscore
|
// DKCR - Remove text prior to first underscore
|
||||||
else if (mGame == EGame::DKCReturns)
|
else if (mGame == EGame::DKCReturns)
|
||||||
{
|
{
|
||||||
uint32 Underscore = WorldName.IndexOf('_');
|
const uint32 Underscore = WorldName.IndexOf('_');
|
||||||
WorldName = WorldName.ChopFront(Underscore + 1);
|
WorldName = WorldName.ChopFront(Underscore + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#include <Common/Flags.h>
|
#include <Common/Flags.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <nod/nod.hpp>
|
#include <memory>
|
||||||
|
#include <nod/DiscBase.hpp>
|
||||||
|
|
||||||
enum class EDiscType
|
enum class EDiscType
|
||||||
{
|
{
|
||||||
|
@ -21,7 +22,7 @@ enum class EDiscType
|
||||||
class CGameExporter
|
class CGameExporter
|
||||||
{
|
{
|
||||||
// Project Data
|
// Project Data
|
||||||
CGameProject *mpProject;
|
std::unique_ptr<CGameProject> mpProject;
|
||||||
TString mProjectPath;
|
TString mProjectPath;
|
||||||
CResourceStore *mpStore;
|
CResourceStore *mpStore;
|
||||||
EGame mGame;
|
EGame mGame;
|
||||||
|
@ -38,15 +39,15 @@ class CGameExporter
|
||||||
TString mWorldsDirName;
|
TString mWorldsDirName;
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
nod::DiscBase *mpDisc;
|
nod::DiscBase *mpDisc = nullptr;
|
||||||
EDiscType mDiscType;
|
EDiscType mDiscType;
|
||||||
bool mFrontEnd;
|
bool mFrontEnd;
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
TStringList mPaks;
|
TStringList mPaks;
|
||||||
std::map<CAssetID, bool> mAreaDuplicateMap;
|
std::map<CAssetID, bool> mAreaDuplicateMap;
|
||||||
CAssetNameMap *mpNameMap;
|
CAssetNameMap *mpNameMap = nullptr;
|
||||||
CGameInfo *mpGameInfo;
|
CGameInfo *mpGameInfo = nullptr;
|
||||||
|
|
||||||
struct SResourceInstance
|
struct SResourceInstance
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ class CGameExporter
|
||||||
std::map<CAssetID, SResourceInstance> mResourceMap;
|
std::map<CAssetID, SResourceInstance> mResourceMap;
|
||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
IProgressNotifier *mpProgress;
|
IProgressNotifier *mpProgress = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum EExportStep
|
enum EExportStep
|
||||||
|
@ -76,9 +77,9 @@ public:
|
||||||
CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
|
CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, ERegion Region, const TString& rkGameName, const TString& rkGameID, float BuildVersion);
|
||||||
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress);
|
bool Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress);
|
||||||
void LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer);
|
void LoadResource(const CAssetID& rkID, std::vector<uint8>& rBuffer);
|
||||||
bool ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot);
|
bool ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot) const;
|
||||||
|
|
||||||
inline TString ProjectPath() const { return mProjectPath; }
|
TString ProjectPath() const { return mProjectPath; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ExtractDiscData();
|
bool ExtractDiscData();
|
||||||
|
@ -91,7 +92,7 @@ protected:
|
||||||
TString MakeWorldName(CAssetID WorldID);
|
TString MakeWorldName(CAssetID WorldID);
|
||||||
|
|
||||||
// Convenience Functions
|
// Convenience Functions
|
||||||
inline SResourceInstance* FindResourceInstance(const CAssetID& rkID)
|
SResourceInstance* FindResourceInstance(const CAssetID& rkID)
|
||||||
{
|
{
|
||||||
uint64 IntegralID = rkID.ToLongLong();
|
uint64 IntegralID = rkID.ToLongLong();
|
||||||
auto Found = mResourceMap.find(IntegralID);
|
auto Found = mResourceMap.find(IntegralID);
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#include "CGameInfo.h"
|
#include "CGameInfo.h"
|
||||||
#include "CResourceStore.h"
|
#include "CResourceStore.h"
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
constexpr char gkGameInfoDir[] = "resources/gameinfo";
|
||||||
|
constexpr char gkGameInfoExt[] = "xml";
|
||||||
|
|
||||||
bool CGameInfo::LoadGameInfo(EGame Game)
|
bool CGameInfo::LoadGameInfo(EGame Game)
|
||||||
{
|
{
|
||||||
|
@ -11,7 +15,7 @@ bool CGameInfo::LoadGameInfo(EGame Game)
|
||||||
return LoadGameInfo(Path);
|
return LoadGameInfo(Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameInfo::LoadGameInfo(TString Path)
|
bool CGameInfo::LoadGameInfo(const TString& Path)
|
||||||
{
|
{
|
||||||
CXMLReader Reader(Path);
|
CXMLReader Reader(Path);
|
||||||
|
|
||||||
|
@ -20,14 +24,17 @@ bool CGameInfo::LoadGameInfo(TString Path)
|
||||||
Serialize(Reader);
|
Serialize(Reader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
bool CGameInfo::SaveGameInfo(TString Path)
|
||||||
{
|
{
|
||||||
ASSERT(mGame != EGame::Invalid); // can't save game info that was never loaded
|
ASSERT(mGame != EGame::Invalid); // can't save game info that was never loaded
|
||||||
|
|
||||||
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
|
if (Path.IsEmpty())
|
||||||
|
Path = GetDefaultGameInfoPath(mGame);
|
||||||
|
|
||||||
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
|
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
|
||||||
Serialize(Writer);
|
Serialize(Writer);
|
||||||
return Writer.Save();
|
return Writer.Save();
|
||||||
|
@ -50,21 +57,19 @@ void CGameInfo::Serialize(IArchive& rArc)
|
||||||
|
|
||||||
TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const
|
TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const
|
||||||
{
|
{
|
||||||
for (uint32 iBuild = 0; iBuild < mBuilds.size(); iBuild++)
|
const auto it = std::find_if(mBuilds.cbegin(), mBuilds.cend(),
|
||||||
{
|
[=](const auto& entry) { return entry.Version == BuildVer && entry.Region == Region; });
|
||||||
const SBuildInfo& rkBuildInfo = mBuilds[iBuild];
|
|
||||||
|
|
||||||
if (rkBuildInfo.Version == BuildVer && rkBuildInfo.Region == Region)
|
if (it == mBuilds.cend())
|
||||||
return rkBuildInfo.Name;
|
return "Unknown Build";
|
||||||
}
|
|
||||||
|
|
||||||
return "Unknown Build";
|
return it->Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CGameInfo::GetAreaName(const CAssetID &rkID) const
|
TString CGameInfo::GetAreaName(const CAssetID &rkID) const
|
||||||
{
|
{
|
||||||
auto Iter = mAreaNameMap.find(rkID);
|
const auto Iter = mAreaNameMap.find(rkID);
|
||||||
return (Iter == mAreaNameMap.end() ? "" : Iter->second);
|
return Iter == mAreaNameMap.cend() ? "" : Iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
|
@ -83,6 +88,11 @@ TString CGameInfo::GetDefaultGameInfoPath(EGame Game)
|
||||||
if (Game == EGame::Invalid)
|
if (Game == EGame::Invalid)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
TString GameName = GetGameShortName(Game);
|
const TString GameName = GetGameShortName(Game);
|
||||||
return TString::Format("%s/%s/GameInfo%s.%s", *gDataDir, *gkGameInfoDir, *GameName, *gkGameInfoExt);
|
return TString::Format("%s/%s/GameInfo%s.%s", gDataDir.ToStdString().c_str(), gkGameInfoDir, GameName.ToStdString().c_str(), gkGameInfoExt);
|
||||||
|
}
|
||||||
|
|
||||||
|
TString CGameInfo::GetExtension()
|
||||||
|
{
|
||||||
|
return gkGameInfoExt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,11 @@
|
||||||
#include <Common/Serialization/XML.h>
|
#include <Common/Serialization/XML.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
const TString gkGameInfoDir = "resources/gameinfo";
|
|
||||||
const TString gkGameInfoExt = "xml";
|
|
||||||
|
|
||||||
//@todo merge this class into CGameTemplate
|
//@todo merge this class into CGameTemplate
|
||||||
// they serve similar purposes, no real reason for them to be different classes
|
// they serve similar purposes, no real reason for them to be different classes
|
||||||
class CGameInfo
|
class CGameInfo
|
||||||
{
|
{
|
||||||
EGame mGame;
|
EGame mGame{EGame::Invalid};
|
||||||
|
|
||||||
// List of known builds of each game
|
// List of known builds of each game
|
||||||
struct SBuildInfo
|
struct SBuildInfo
|
||||||
|
@ -37,12 +34,10 @@ class CGameInfo
|
||||||
std::map<CAssetID, TString> mAreaNameMap;
|
std::map<CAssetID, TString> mAreaNameMap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGameInfo()
|
CGameInfo() = default;
|
||||||
: mGame(EGame::Invalid)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool LoadGameInfo(EGame Game);
|
bool LoadGameInfo(EGame Game);
|
||||||
bool LoadGameInfo(TString Path);
|
bool LoadGameInfo(const TString& Path);
|
||||||
bool SaveGameInfo(TString Path = "");
|
bool SaveGameInfo(TString Path = "");
|
||||||
void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
|
@ -50,14 +45,14 @@ public:
|
||||||
TString GetAreaName(const CAssetID& rkID) const;
|
TString GetAreaName(const CAssetID& rkID) const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline EGame Game() const { return mGame; }
|
EGame Game() const { return mGame; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CGameInfo* GetGameInfo(EGame Game);
|
static CGameInfo* GetGameInfo(EGame Game);
|
||||||
static EGame RoundGame(EGame Game);
|
static EGame RoundGame(EGame Game);
|
||||||
static TString GetDefaultGameInfoPath(EGame Game);
|
static TString GetDefaultGameInfoPath(EGame Game);
|
||||||
|
|
||||||
inline static TString GetExtension() { return gkGameInfoExt; }
|
static TString GetExtension();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CGAMEINFO
|
#endif // CGAMEINFO
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
#include "IUIRelay.h"
|
#include "IUIRelay.h"
|
||||||
#include "Core/Resource/Script/CGameTemplate.h"
|
#include "Core/Resource/Script/CGameTemplate.h"
|
||||||
#include <Common/Serialization/XML.h>
|
#include <Common/Serialization/XML.h>
|
||||||
#include <nod/nod.hpp>
|
#include <nod/DiscGCN.hpp>
|
||||||
|
#include <nod/DiscWii.hpp>
|
||||||
|
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
#define TStringToNodString(string) ToWChar(string)
|
#define TStringToNodString(string) ToWChar(string)
|
||||||
|
@ -13,25 +14,22 @@
|
||||||
|
|
||||||
CGameProject::~CGameProject()
|
CGameProject::~CGameProject()
|
||||||
{
|
{
|
||||||
if (mpResourceStore)
|
if (!mpResourceStore)
|
||||||
{
|
return;
|
||||||
ASSERT(!mpResourceStore->IsCacheDirty());
|
|
||||||
|
|
||||||
if (gpResourceStore == mpResourceStore.get())
|
ASSERT(!mpResourceStore->IsCacheDirty());
|
||||||
gpResourceStore = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
if (gpResourceStore == mpResourceStore.get())
|
||||||
delete mPackages[iPkg];
|
gpResourceStore = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameProject::Save()
|
bool CGameProject::Save()
|
||||||
{
|
{
|
||||||
mProjFileLock.Release();
|
mProjFileLock.Release();
|
||||||
TString ProjPath = ProjectPath();
|
const TString ProjPath = ProjectPath();
|
||||||
CXMLWriter Writer(ProjPath, "GameProject", (int) EProjectVersion::Current, mGame);
|
CXMLWriter Writer(ProjPath, "GameProject", static_cast<int>(EProjectVersion::Current), mGame);
|
||||||
Serialize(Writer);
|
Serialize(Writer);
|
||||||
bool SaveSuccess = Writer.Save();
|
const bool SaveSuccess = Writer.Save();
|
||||||
mProjFileLock.Lock(*ProjPath);
|
mProjFileLock.Lock(*ProjPath);
|
||||||
return SaveSuccess;
|
return SaveSuccess;
|
||||||
}
|
}
|
||||||
|
@ -48,8 +46,8 @@ bool CGameProject::Serialize(IArchive& rArc)
|
||||||
|
|
||||||
if (!rArc.IsReader())
|
if (!rArc.IsReader())
|
||||||
{
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
for (auto& package : mPackages)
|
||||||
PackageList.push_back( mPackages[iPkg]->DefinitionPath(true) );
|
PackageList.push_back(package->DefinitionPath(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
rArc << SerialParameter("Packages", PackageList);
|
rArc << SerialParameter("Packages", PackageList);
|
||||||
|
@ -59,15 +57,14 @@ bool CGameProject::Serialize(IArchive& rArc)
|
||||||
{
|
{
|
||||||
ASSERT(mPackages.empty());
|
ASSERT(mPackages.empty());
|
||||||
|
|
||||||
for (uint32 iPkg = 0; iPkg < PackageList.size(); iPkg++)
|
for (const TString& packagePath : PackageList)
|
||||||
{
|
{
|
||||||
const TString& rkPackagePath = PackageList[iPkg];
|
TString PackageName = packagePath.GetFileName(false);
|
||||||
TString PackageName = rkPackagePath.GetFileName(false);
|
TString PackageDir = packagePath.GetFileDirectory();
|
||||||
TString PackageDir = rkPackagePath.GetFileDirectory();
|
|
||||||
|
|
||||||
CPackage *pPackage = new CPackage(this, PackageName, PackageDir);
|
auto pPackage = std::make_unique<CPackage>(this, std::move(PackageName), std::move(PackageDir));
|
||||||
bool PackageLoadSuccess = pPackage->Load();
|
const bool PackageLoadSuccess = pPackage->Load();
|
||||||
mPackages.push_back(pPackage);
|
mPackages.push_back(std::move(pPackage));
|
||||||
|
|
||||||
if (!PackageLoadSuccess)
|
if (!PackageLoadSuccess)
|
||||||
{
|
{
|
||||||
|
@ -81,16 +78,16 @@ bool CGameProject::Serialize(IArchive& rArc)
|
||||||
|
|
||||||
bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress)
|
bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
|
||||||
ASSERT( !IsWiiDeAsobu() && !IsTrilogy() );
|
ASSERT(!IsWiiDeAsobu() && !IsTrilogy());
|
||||||
|
|
||||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
const auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
||||||
{
|
{
|
||||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
|
pProgress->Report(static_cast<int>(ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
||||||
TString DiscRoot = DiscDir(false);
|
const TString DiscRoot = DiscDir(false);
|
||||||
|
|
||||||
if (!IsWiiBuild())
|
if (!IsWiiBuild())
|
||||||
{
|
{
|
||||||
|
@ -106,18 +103,18 @@ bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgre
|
||||||
|
|
||||||
bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress)
|
bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
ASSERT(FileUtil::IsValidPath(rkIsoPath, false));
|
||||||
ASSERT( IsWiiDeAsobu() || IsTrilogy() );
|
ASSERT(IsWiiDeAsobu() || IsTrilogy());
|
||||||
ASSERT( pOriginalIso != nullptr );
|
ASSERT(pOriginalIso != nullptr);
|
||||||
|
|
||||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
const auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
||||||
{
|
{
|
||||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
|
pProgress->Report(static_cast<int>(ProgressPercent * 10000), 10000, nod::SystemUTF8Conv(rkInfoString).c_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
||||||
|
|
||||||
TString DiscRoot = DiscFilesystemRoot(false);
|
const TString DiscRoot = DiscFilesystemRoot(false);
|
||||||
|
|
||||||
nod::DiscMergerWii Merger(TStringToNodString(rkIsoPath), *pOriginalIso, IsTrilogy(), ProgressCallback);
|
nod::DiscMergerWii Merger(TStringToNodString(rkIsoPath), *pOriginalIso, IsTrilogy(), ProgressCallback);
|
||||||
return Merger.mergeFromDirectory(TStringToNodString(DiscRoot)) == nod::EBuildResult::Success;
|
return Merger.mergeFromDirectory(TStringToNodString(DiscRoot)) == nod::EBuildResult::Success;
|
||||||
|
@ -125,15 +122,13 @@ bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso
|
||||||
|
|
||||||
void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
|
void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
|
||||||
{
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
for (const auto& pPkg : mPackages)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = mPackages[iPkg];
|
|
||||||
|
|
||||||
// Little workaround to fix some of Retro's paks having worlds listed in the wrong order...
|
// Little workaround to fix some of Retro's paks having worlds listed in the wrong order...
|
||||||
// Construct a sorted list of worlds in this package
|
// Construct a sorted list of worlds in this package
|
||||||
std::list<const SNamedResource*> PackageWorlds;
|
std::list<const SNamedResource*> PackageWorlds;
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
for (size_t iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
||||||
|
|
||||||
|
@ -146,25 +141,22 @@ void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add sorted worlds to the output world list
|
// Add sorted worlds to the output world list
|
||||||
for (auto Iter = PackageWorlds.begin(); Iter != PackageWorlds.end(); Iter++)
|
for (const auto* res : PackageWorlds)
|
||||||
{
|
{
|
||||||
const SNamedResource *pkRes = *Iter;
|
rOut.push_back(res->ID);
|
||||||
rOut.push_back(pkRes->ID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CAssetID CGameProject::FindNamedResource(const TString& rkName) const
|
CAssetID CGameProject::FindNamedResource(std::string_view name) const
|
||||||
{
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
for (const auto& pkg : mPackages)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = mPackages[iPkg];
|
for (size_t iRes = 0; iRes < pkg->NumNamedResources(); iRes++)
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
|
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes);
|
const SNamedResource& rkRes = pkg->NamedResourceByIndex(iRes);
|
||||||
|
|
||||||
if (rkRes.Name == rkName)
|
if (rkRes.Name == name)
|
||||||
return rkRes.ID;
|
return rkRes.ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,22 +164,18 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const
|
||||||
return CAssetID::InvalidID(mGame);
|
return CAssetID::InvalidID(mGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
CPackage* CGameProject::FindPackage(const TString& rkName) const
|
CPackage* CGameProject::FindPackage(std::string_view name) const
|
||||||
{
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
const auto iter = std::find_if(mPackages.begin(), mPackages.end(),
|
||||||
{
|
[name](const auto& package) { return package->Name() == name; });
|
||||||
CPackage *pPackage = mPackages[iPkg];
|
|
||||||
|
|
||||||
if (pPackage->Name() == rkName)
|
if (iter == mPackages.cend())
|
||||||
{
|
return nullptr;
|
||||||
return pPackage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return iter->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameProject* CGameProject::CreateProjectForExport(
|
std::unique_ptr<CGameProject> CGameProject::CreateProjectForExport(
|
||||||
const TString& rkProjRootDir,
|
const TString& rkProjRootDir,
|
||||||
EGame Game,
|
EGame Game,
|
||||||
ERegion Region,
|
ERegion Region,
|
||||||
|
@ -195,7 +183,7 @@ CGameProject* CGameProject::CreateProjectForExport(
|
||||||
float BuildVer
|
float BuildVer
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
CGameProject *pProj = new CGameProject;
|
auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
|
||||||
pProj->mGame = Game;
|
pProj->mGame = Game;
|
||||||
pProj->mRegion = Region;
|
pProj->mRegion = Region;
|
||||||
pProj->mGameID = rkGameID;
|
pProj->mGameID = rkGameID;
|
||||||
|
@ -203,15 +191,15 @@ CGameProject* CGameProject::CreateProjectForExport(
|
||||||
|
|
||||||
pProj->mProjectRoot = rkProjRootDir;
|
pProj->mProjectRoot = rkProjRootDir;
|
||||||
pProj->mProjectRoot.Replace("\\", "/");
|
pProj->mProjectRoot.Replace("\\", "/");
|
||||||
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj);
|
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
|
||||||
pProj->mpGameInfo->LoadGameInfo(Game);
|
pProj->mpGameInfo->LoadGameInfo(Game);
|
||||||
return pProj;
|
return pProj;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
|
std::unique_ptr<CGameProject> CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
// Init project
|
// Init project
|
||||||
CGameProject *pProj = new CGameProject;
|
auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
|
||||||
pProj->mProjectRoot = rkProjPath.GetFileDirectory();
|
pProj->mProjectRoot = rkProjPath.GetFileDirectory();
|
||||||
pProj->mProjectRoot.Replace("\\", "/");
|
pProj->mProjectRoot.Replace("\\", "/");
|
||||||
|
|
||||||
|
@ -222,12 +210,11 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
pProgress->Report("Loading project settings");
|
pProgress->Report("Loading project settings");
|
||||||
bool LoadSuccess = false;
|
bool LoadSuccess = false;
|
||||||
|
|
||||||
TString ProjPath = rkProjPath;
|
const TString ProjPath = rkProjPath;
|
||||||
CXMLReader Reader(ProjPath);
|
CXMLReader Reader(ProjPath);
|
||||||
|
|
||||||
if (!Reader.IsValid())
|
if (!Reader.IsValid())
|
||||||
{
|
{
|
||||||
delete pProj;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +224,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
{
|
{
|
||||||
// Load resource database
|
// Load resource database
|
||||||
pProgress->Report("Loading resource database");
|
pProgress->Report("Loading resource database");
|
||||||
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj);
|
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
|
||||||
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
|
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
|
||||||
|
|
||||||
// Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long
|
// Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long
|
||||||
|
@ -269,7 +256,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
|
|
||||||
if (!LoadSuccess)
|
if (!LoadSuccess)
|
||||||
{
|
{
|
||||||
delete pProj;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +263,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
||||||
|
|
||||||
// Perform update
|
// Perform update
|
||||||
if (Reader.FileVersion() < (uint16) EProjectVersion::Current)
|
if (Reader.FileVersion() < static_cast<uint16>(EProjectVersion::Current))
|
||||||
{
|
{
|
||||||
pProgress->Report("Updating project");
|
pProgress->Report("Updating project");
|
||||||
|
|
||||||
|
@ -304,7 +290,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create hidden files directory, if needed
|
// Create hidden files directory, if needed
|
||||||
TString HiddenDir = pProj->HiddenFilesDir();
|
const TString HiddenDir = pProj->HiddenFilesDir();
|
||||||
|
|
||||||
if (!FileUtil::Exists(HiddenDir))
|
if (!FileUtil::Exists(HiddenDir))
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <Common/FileIO/CFileLock.h>
|
#include <Common/FileIO/CFileLock.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace nod { class DiscWii; }
|
namespace nod { class DiscWii; }
|
||||||
|
|
||||||
|
@ -23,41 +25,30 @@ enum class EProjectVersion
|
||||||
// Add new versions before this line
|
// Add new versions before this line
|
||||||
|
|
||||||
Max,
|
Max,
|
||||||
Current = EProjectVersion::Max - 1
|
Current = Max - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
class CGameProject
|
class CGameProject
|
||||||
{
|
{
|
||||||
TString mProjectName;
|
TString mProjectName{"Unnamed Project"};
|
||||||
EGame mGame;
|
EGame mGame{EGame::Invalid};
|
||||||
ERegion mRegion;
|
ERegion mRegion{ERegion::Unknown};
|
||||||
TString mGameID;
|
TString mGameID{"000000"};
|
||||||
float mBuildVersion;
|
float mBuildVersion = 0.f;
|
||||||
|
|
||||||
TString mProjectRoot;
|
TString mProjectRoot;
|
||||||
std::vector<CPackage*> mPackages;
|
std::vector<std::unique_ptr<CPackage>> mPackages;
|
||||||
std::unique_ptr<CResourceStore> mpResourceStore;
|
std::unique_ptr<CResourceStore> mpResourceStore;
|
||||||
std::unique_ptr<CGameInfo> mpGameInfo;
|
std::unique_ptr<CGameInfo> mpGameInfo = std::make_unique<CGameInfo>();
|
||||||
std::unique_ptr<CAudioManager> mpAudioManager;
|
std::unique_ptr<CAudioManager> mpAudioManager = std::make_unique<CAudioManager>(this);
|
||||||
std::unique_ptr<CTweakManager> mpTweakManager;
|
std::unique_ptr<CTweakManager> mpTweakManager = std::make_unique<CTweakManager>(this);
|
||||||
|
|
||||||
// Keep file handle open for the .prj file to prevent users from opening the same project
|
// Keep file handle open for the .prj file to prevent users from opening the same project
|
||||||
// in multiple instances of PWE
|
// in multiple instances of PWE
|
||||||
CFileLock mProjFileLock;
|
CFileLock mProjFileLock;
|
||||||
|
|
||||||
// Private Constructor
|
// Private Constructor
|
||||||
CGameProject()
|
CGameProject() = default;
|
||||||
: mProjectName("Unnamed Project")
|
|
||||||
, mGame(EGame::Invalid)
|
|
||||||
, mRegion(ERegion::Unknown)
|
|
||||||
, mGameID("000000")
|
|
||||||
, mBuildVersion(0.f)
|
|
||||||
, mpResourceStore(nullptr)
|
|
||||||
{
|
|
||||||
mpGameInfo = std::make_unique<CGameInfo>();
|
|
||||||
mpAudioManager = std::make_unique<CAudioManager>(this);
|
|
||||||
mpTweakManager = std::make_unique<CTweakManager>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~CGameProject();
|
~CGameProject();
|
||||||
|
@ -67,11 +58,11 @@ public:
|
||||||
bool BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress);
|
bool BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgress);
|
||||||
bool MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress);
|
bool MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso, IProgressNotifier *pProgress);
|
||||||
void GetWorldList(std::list<CAssetID>& rOut) const;
|
void GetWorldList(std::list<CAssetID>& rOut) const;
|
||||||
CAssetID FindNamedResource(const TString& rkName) const;
|
CAssetID FindNamedResource(std::string_view name) const;
|
||||||
CPackage* FindPackage(const TString& rkName) const;
|
CPackage* FindPackage(std::string_view name) const;
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CGameProject* CreateProjectForExport(
|
static std::unique_ptr<CGameProject> CreateProjectForExport(
|
||||||
const TString& rkProjRootDir,
|
const TString& rkProjRootDir,
|
||||||
EGame Game,
|
EGame Game,
|
||||||
ERegion Region,
|
ERegion Region,
|
||||||
|
@ -79,37 +70,37 @@ public:
|
||||||
float BuildVer
|
float BuildVer
|
||||||
);
|
);
|
||||||
|
|
||||||
static CGameProject* LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress);
|
static std::unique_ptr<CGameProject> LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress);
|
||||||
|
|
||||||
// Directory Handling
|
// Directory Handling
|
||||||
inline TString ProjectRoot() const { return mProjectRoot; }
|
TString ProjectRoot() const { return mProjectRoot; }
|
||||||
inline TString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName, false) + ".prj"; }
|
TString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName, false) + ".prj"; }
|
||||||
inline TString HiddenFilesDir() const { return mProjectRoot + ".project/"; }
|
TString HiddenFilesDir() const { return mProjectRoot + ".project/"; }
|
||||||
inline TString DiscDir(bool Relative) const { return Relative ? "Disc/" : mProjectRoot + "Disc/"; }
|
TString DiscDir(bool Relative) const { return Relative ? "Disc/" : mProjectRoot + "Disc/"; }
|
||||||
inline TString PackagesDir(bool Relative) const { return Relative ? "Packages/" : mProjectRoot + "Packages/"; }
|
TString PackagesDir(bool Relative) const { return Relative ? "Packages/" : mProjectRoot + "Packages/"; }
|
||||||
inline TString ResourcesDir(bool Relative) const { return Relative ? "Resources/" : mProjectRoot + "Resources/"; }
|
TString ResourcesDir(bool Relative) const { return Relative ? "Resources/" : mProjectRoot + "Resources/"; }
|
||||||
|
|
||||||
// Disc Filesystem Management
|
// Disc Filesystem Management
|
||||||
inline TString DiscFilesystemRoot(bool Relative) const { return DiscDir(Relative) + (IsWiiBuild() ? "DATA/" : "") + "files/"; }
|
TString DiscFilesystemRoot(bool Relative) const { return DiscDir(Relative) + (IsWiiBuild() ? "DATA/" : "") + "files/"; }
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; }
|
void SetProjectName(TString name) { mProjectName = std::move(name); }
|
||||||
|
|
||||||
inline TString Name() const { return mProjectName; }
|
TString Name() const { return mProjectName; }
|
||||||
inline uint32 NumPackages() const { return mPackages.size(); }
|
size_t NumPackages() const { return mPackages.size(); }
|
||||||
inline CPackage* PackageByIndex(uint32 Index) const { return mPackages[Index]; }
|
CPackage* PackageByIndex(size_t Index) const { return mPackages[Index].get(); }
|
||||||
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); }
|
void AddPackage(std::unique_ptr<CPackage>&& package) { mPackages.push_back(std::move(package)); }
|
||||||
inline CResourceStore* ResourceStore() const { return mpResourceStore.get(); }
|
CResourceStore* ResourceStore() const { return mpResourceStore.get(); }
|
||||||
inline CGameInfo* GameInfo() const { return mpGameInfo.get(); }
|
CGameInfo* GameInfo() const { return mpGameInfo.get(); }
|
||||||
inline CAudioManager* AudioManager() const { return mpAudioManager.get(); }
|
CAudioManager* AudioManager() const { return mpAudioManager.get(); }
|
||||||
inline CTweakManager* TweakManager() const { return mpTweakManager.get(); }
|
CTweakManager* TweakManager() const { return mpTweakManager.get(); }
|
||||||
inline EGame Game() const { return mGame; }
|
EGame Game() const { return mGame; }
|
||||||
inline ERegion Region() const { return mRegion; }
|
ERegion Region() const { return mRegion; }
|
||||||
inline TString GameID() const { return mGameID; }
|
TString GameID() const { return mGameID; }
|
||||||
inline float BuildVersion() const { return mBuildVersion; }
|
float BuildVersion() const { return mBuildVersion; }
|
||||||
inline bool IsWiiBuild() const { return mBuildVersion >= 3.f; }
|
bool IsWiiBuild() const { return mBuildVersion >= 3.f; }
|
||||||
inline bool IsTrilogy() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.593f; }
|
bool IsTrilogy() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.593f; }
|
||||||
inline bool IsWiiDeAsobu() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; }
|
bool IsWiiDeAsobu() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CGAMEPROJECT_H
|
#endif // CGAMEPROJECT_H
|
||||||
|
|
|
@ -13,7 +13,7 @@ class COpeningBanner
|
||||||
bool mWii;
|
bool mWii;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
COpeningBanner(CGameProject *pProj);
|
explicit COpeningBanner(CGameProject *pProj);
|
||||||
TString EnglishGameName() const;
|
TString EnglishGameName() const;
|
||||||
void SetEnglishGameName(const TString& rkName);
|
void SetEnglishGameName(const TString& rkName);
|
||||||
void Save();
|
void Save();
|
||||||
|
|
|
@ -12,7 +12,7 @@ using namespace tinyxml2;
|
||||||
|
|
||||||
bool CPackage::Load()
|
bool CPackage::Load()
|
||||||
{
|
{
|
||||||
TString DefPath = DefinitionPath(false);
|
const TString DefPath = DefinitionPath(false);
|
||||||
CXMLReader Reader(DefPath);
|
CXMLReader Reader(DefPath);
|
||||||
|
|
||||||
if (Reader.IsValid())
|
if (Reader.IsValid())
|
||||||
|
@ -21,12 +21,13 @@ bool CPackage::Load()
|
||||||
mCacheDirty = true;
|
mCacheDirty = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPackage::Save()
|
bool CPackage::Save()
|
||||||
{
|
{
|
||||||
TString DefPath = DefinitionPath(false);
|
const TString DefPath = DefinitionPath(false);
|
||||||
FileUtil::MakeDirectory(DefPath.GetFileDirectory());
|
FileUtil::MakeDirectory(DefPath.GetFileDirectory());
|
||||||
|
|
||||||
CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : EGame::Invalid);
|
CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : EGame::Invalid);
|
||||||
|
@ -53,8 +54,8 @@ void CPackage::UpdateDependencyCache() const
|
||||||
Builder.BuildDependencyList(false, AssetList);
|
Builder.BuildDependencyList(false, AssetList);
|
||||||
|
|
||||||
mCachedDependencies.clear();
|
mCachedDependencies.clear();
|
||||||
for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++)
|
for (const auto& asset : AssetList)
|
||||||
mCachedDependencies.insert(*Iter);
|
mCachedDependencies.insert(asset);
|
||||||
|
|
||||||
mCacheDirty = false;
|
mCacheDirty = false;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
debugf("%d assets in %s.pak", AssetList.size(), *Name());
|
debugf("%d assets in %s.pak", AssetList.size(), *Name());
|
||||||
|
|
||||||
// Write new pak
|
// Write new pak
|
||||||
TString PakPath = CookedPackagePath(false);
|
const TString PakPath = CookedPackagePath(false);
|
||||||
CFileOutStream Pak(PakPath, EEndian::BigEndian);
|
CFileOutStream Pak(PakPath, EEndian::BigEndian);
|
||||||
|
|
||||||
if (!Pak.IsValid())
|
if (!Pak.IsValid())
|
||||||
|
@ -91,9 +92,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EGame Game = mpProject->Game();
|
const EGame Game = mpProject->Game();
|
||||||
uint32 Alignment = (Game <= EGame::CorruptionProto ? 0x20 : 0x40);
|
const uint32 Alignment = (Game <= EGame::CorruptionProto ? 0x20 : 0x40);
|
||||||
uint32 AlignmentMinusOne = Alignment - 1;
|
const uint32 AlignmentMinusOne = Alignment - 1;
|
||||||
|
|
||||||
uint32 TocOffset = 0;
|
uint32 TocOffset = 0;
|
||||||
uint32 NamesSize = 0;
|
uint32 NamesSize = 0;
|
||||||
|
@ -110,17 +111,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// Named Resources
|
// Named Resources
|
||||||
Pak.WriteLong(mResources.size());
|
Pak.WriteLong(mResources.size());
|
||||||
|
|
||||||
for (auto Iter = mResources.begin(); Iter != mResources.end(); Iter++)
|
for (const auto& res : mResources)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = *Iter;
|
res.Type.Write(Pak);
|
||||||
rkRes.Type.Write(Pak);
|
res.ID.Write(Pak);
|
||||||
rkRes.ID.Write(Pak);
|
Pak.WriteSizedString(res.Name);
|
||||||
Pak.WriteSizedString(rkRes.Name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Write MP3 pak header
|
||||||
// Write MP3 pak header
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Header
|
// Header
|
||||||
Pak.WriteLong(2); // Version
|
Pak.WriteLong(2); // Version
|
||||||
|
@ -133,15 +131,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
Pak.WriteToBoundary(0x40, 0);
|
Pak.WriteToBoundary(0x40, 0);
|
||||||
|
|
||||||
// Named Resources
|
// Named Resources
|
||||||
uint32 NamesStart = Pak.Tell();
|
const uint32 NamesStart = Pak.Tell();
|
||||||
Pak.WriteLong(mResources.size());
|
Pak.WriteULong(static_cast<uint32>(mResources.size()));
|
||||||
|
|
||||||
for (auto Iter = mResources.begin(); Iter != mResources.end(); Iter++)
|
for (const auto& res : mResources)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = *Iter;
|
Pak.WriteString(res.Name);
|
||||||
Pak.WriteString(rkRes.Name);
|
res.Type.Write(Pak);
|
||||||
rkRes.Type.Write(Pak);
|
res.ID.Write(Pak);
|
||||||
rkRes.ID.Write(Pak);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pak.WriteToBoundary(0x40, 0);
|
Pak.WriteToBoundary(0x40, 0);
|
||||||
|
@ -151,9 +148,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// Fill in resource table with junk, write later
|
// Fill in resource table with junk, write later
|
||||||
ResTableOffset = Pak.Tell();
|
ResTableOffset = Pak.Tell();
|
||||||
Pak.WriteLong(AssetList.size());
|
Pak.WriteLong(AssetList.size());
|
||||||
CAssetID Dummy = CAssetID::InvalidID(Game);
|
const CAssetID Dummy = CAssetID::InvalidID(Game);
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < AssetList.size(); iRes++)
|
for (size_t iRes = 0; iRes < AssetList.size(); iRes++)
|
||||||
{
|
{
|
||||||
Pak.WriteLongLong(0);
|
Pak.WriteLongLong(0);
|
||||||
Dummy.Write(Pak);
|
Dummy.Write(Pak);
|
||||||
|
@ -173,13 +170,13 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
};
|
};
|
||||||
std::vector<SResourceTableInfo> ResourceTableData(AssetList.size());
|
std::vector<SResourceTableInfo> ResourceTableData(AssetList.size());
|
||||||
uint32 ResIdx = 0;
|
uint32 ResIdx = 0;
|
||||||
uint32 ResDataOffset = Pak.Tell();
|
const uint32 ResDataOffset = Pak.Tell();
|
||||||
|
|
||||||
for (auto Iter = AssetList.begin(); Iter != AssetList.end() && !pProgress->ShouldCancel(); Iter++, ResIdx++)
|
for (auto Iter = AssetList.begin(); Iter != AssetList.end() && !pProgress->ShouldCancel(); Iter++, ResIdx++)
|
||||||
{
|
{
|
||||||
// Initialize entry, recook assets if needed
|
// Initialize entry, recook assets if needed
|
||||||
uint32 AssetOffset = Pak.Tell();
|
const uint32 AssetOffset = Pak.Tell();
|
||||||
CAssetID ID = *Iter;
|
const CAssetID ID = *Iter;
|
||||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
ASSERT(pEntry != nullptr);
|
ASSERT(pEntry != nullptr);
|
||||||
|
|
||||||
|
@ -190,7 +187,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update progress bar
|
// Update progress bar
|
||||||
if (ResIdx & 0x1 || ResIdx == AssetList.size() - 1)
|
if ((ResIdx & 1) != 0 || ResIdx == AssetList.size() - 1)
|
||||||
{
|
{
|
||||||
pProgress->Report(ResIdx, AssetList.size(), TString::Format("Writing asset %d/%d: %s", ResIdx+1, AssetList.size(), *(pEntry->Name() + "." + pEntry->CookedExtension())));
|
pProgress->Report(ResIdx, AssetList.size(), TString::Format("Writing asset %d/%d: %s", ResIdx+1, AssetList.size(), *(pEntry->Name() + "." + pEntry->CookedExtension())));
|
||||||
}
|
}
|
||||||
|
@ -203,15 +200,15 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// Load resource data
|
// Load resource data
|
||||||
CFileInStream CookedAsset(pEntry->CookedAssetPath(), EEndian::BigEndian);
|
CFileInStream CookedAsset(pEntry->CookedAssetPath(), EEndian::BigEndian);
|
||||||
ASSERT(CookedAsset.IsValid());
|
ASSERT(CookedAsset.IsValid());
|
||||||
uint32 ResourceSize = CookedAsset.Size();
|
const uint32 ResourceSize = CookedAsset.Size();
|
||||||
|
|
||||||
std::vector<uint8> ResourceData(ResourceSize);
|
std::vector<uint8> ResourceData(ResourceSize);
|
||||||
CookedAsset.ReadBytes(ResourceData.data(), ResourceData.size());
|
CookedAsset.ReadBytes(ResourceData.data(), ResourceData.size());
|
||||||
|
|
||||||
// Check if this asset should be compressed; there are a few resource types that are
|
// Check if this asset should be compressed; there are a few resource types that are
|
||||||
// always compressed, and some types that are compressed if they're over a certain size
|
// always compressed, and some types that are compressed if they're over a certain size
|
||||||
EResourceType Type = pEntry->ResourceType();
|
const EResourceType Type = pEntry->ResourceType();
|
||||||
uint32 CompressThreshold = (Game <= EGame::CorruptionProto ? 0x400 : 0x80);
|
const uint32 CompressThreshold = (Game <= EGame::CorruptionProto ? 0x400 : 0x80);
|
||||||
|
|
||||||
bool ShouldAlwaysCompress = (Type == EResourceType::Texture || Type == EResourceType::Model ||
|
bool ShouldAlwaysCompress = (Type == EResourceType::Texture || Type == EResourceType::Model ||
|
||||||
Type == EResourceType::Skin || Type == EResourceType::AnimSet ||
|
Type == EResourceType::Skin || Type == EResourceType::AnimSet ||
|
||||||
|
@ -226,14 +223,14 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
Type == EResourceType::DynamicCollision);
|
Type == EResourceType::DynamicCollision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldCompressConditional = !ShouldAlwaysCompress &&
|
const bool ShouldCompressConditional = !ShouldAlwaysCompress &&
|
||||||
(Type == EResourceType::Particle || Type == EResourceType::ParticleElectric ||
|
(Type == EResourceType::Particle || Type == EResourceType::ParticleElectric ||
|
||||||
Type == EResourceType::ParticleSwoosh || Type == EResourceType::ParticleWeapon ||
|
Type == EResourceType::ParticleSwoosh || Type == EResourceType::ParticleWeapon ||
|
||||||
Type == EResourceType::ParticleDecal || Type == EResourceType::ParticleCollisionResponse ||
|
Type == EResourceType::ParticleDecal || Type == EResourceType::ParticleCollisionResponse ||
|
||||||
Type == EResourceType::ParticleSpawn || Type == EResourceType::ParticleSorted ||
|
Type == EResourceType::ParticleSpawn || Type == EResourceType::ParticleSorted ||
|
||||||
Type == EResourceType::BurstFireData);
|
Type == EResourceType::BurstFireData);
|
||||||
|
|
||||||
bool ShouldCompress = ShouldAlwaysCompress || (ShouldCompressConditional && ResourceSize >= CompressThreshold);
|
const bool ShouldCompress = ShouldAlwaysCompress || (ShouldCompressConditional && ResourceSize >= CompressThreshold);
|
||||||
|
|
||||||
// Write resource data to pak
|
// Write resource data to pak
|
||||||
if (!ShouldCompress)
|
if (!ShouldCompress)
|
||||||
|
@ -241,7 +238,6 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
||||||
rTableInfo.Compressed = false;
|
rTableInfo.Compressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32 CompressedSize;
|
uint32 CompressedSize;
|
||||||
|
@ -256,9 +252,9 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value
|
// Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value
|
||||||
if (Success)
|
if (Success)
|
||||||
{
|
{
|
||||||
uint32 CompressionHeaderSize = (Game <= EGame::CorruptionProto ? 4 : 0x10);
|
const uint32 CompressionHeaderSize = (Game <= EGame::CorruptionProto ? 4 : 0x10);
|
||||||
uint32 PaddedUncompressedSize = (ResourceSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
const uint32 PaddedUncompressedSize = (ResourceSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
||||||
uint32 PaddedCompressedSize = (CompressedSize + CompressionHeaderSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
const uint32 PaddedCompressedSize = (CompressedSize + CompressionHeaderSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
||||||
Success = (PaddedCompressedSize < PaddedUncompressedSize);
|
Success = (PaddedCompressedSize < PaddedUncompressedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +264,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// Write MP1/2 compressed asset
|
// Write MP1/2 compressed asset
|
||||||
if (Game <= EGame::CorruptionProto)
|
if (Game <= EGame::CorruptionProto)
|
||||||
{
|
{
|
||||||
Pak.WriteLong(ResourceSize);
|
Pak.WriteULong(ResourceSize);
|
||||||
}
|
}
|
||||||
// Write MP3/DKCR compressed asset
|
// Write MP3/DKCR compressed asset
|
||||||
else
|
else
|
||||||
|
@ -279,13 +275,15 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
// multiple blocks or not, so for the sake of simplicity we compress everything to one block.
|
// multiple blocks or not, so for the sake of simplicity we compress everything to one block.
|
||||||
Pak.WriteFourCC( FOURCC('CMPD') );
|
Pak.WriteFourCC( FOURCC('CMPD') );
|
||||||
Pak.WriteLong(1);
|
Pak.WriteLong(1);
|
||||||
Pak.WriteLong(0xA0000000 | CompressedSize);
|
Pak.WriteULong(0xA0000000 | CompressedSize);
|
||||||
Pak.WriteLong(ResourceSize);
|
Pak.WriteULong(ResourceSize);
|
||||||
}
|
}
|
||||||
Pak.WriteBytes(CompressedData.data(), CompressedSize);
|
Pak.WriteBytes(CompressedData.data(), CompressedSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
Pak.WriteBytes(ResourceData.data(), ResourceSize);
|
||||||
|
}
|
||||||
|
|
||||||
rTableInfo.Compressed = Success;
|
rTableInfo.Compressed = Success;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +300,6 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
FileUtil::DeleteFile(PakPath);
|
FileUtil::DeleteFile(PakPath);
|
||||||
mNeedsRecook = true;
|
mNeedsRecook = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Write table of contents for real
|
// Write table of contents for real
|
||||||
|
@ -311,26 +308,26 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
Pak.Seek(TocOffset, SEEK_SET);
|
Pak.Seek(TocOffset, SEEK_SET);
|
||||||
Pak.WriteLong(3); // Always 3 pak sections
|
Pak.WriteLong(3); // Always 3 pak sections
|
||||||
Pak.WriteFourCC( FOURCC('STRG') );
|
Pak.WriteFourCC( FOURCC('STRG') );
|
||||||
Pak.WriteLong(NamesSize);
|
Pak.WriteULong(NamesSize);
|
||||||
Pak.WriteFourCC( FOURCC('RSHD') );
|
Pak.WriteFourCC( FOURCC('RSHD') );
|
||||||
Pak.WriteLong(ResTableSize);
|
Pak.WriteULong(ResTableSize);
|
||||||
Pak.WriteFourCC( FOURCC('DATA') );
|
Pak.WriteFourCC( FOURCC('DATA') );
|
||||||
Pak.WriteLong(ResDataSize);
|
Pak.WriteULong(ResDataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write resource table for real
|
// Write resource table for real
|
||||||
Pak.Seek(ResTableOffset+4, SEEK_SET);
|
Pak.Seek(ResTableOffset+4, SEEK_SET);
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < AssetList.size(); iRes++)
|
for (size_t iRes = 0; iRes < AssetList.size(); iRes++)
|
||||||
{
|
{
|
||||||
const SResourceTableInfo& rkInfo = ResourceTableData[iRes];
|
const SResourceTableInfo& rkInfo = ResourceTableData[iRes];
|
||||||
CResourceEntry *pEntry = rkInfo.pEntry;
|
CResourceEntry *pEntry = rkInfo.pEntry;
|
||||||
|
|
||||||
Pak.WriteLong( rkInfo.Compressed ? 1 : 0 );
|
Pak.WriteLong(rkInfo.Compressed ? 1 : 0);
|
||||||
pEntry->CookedExtension().Write(Pak);
|
pEntry->CookedExtension().Write(Pak);
|
||||||
pEntry->ID().Write(Pak);
|
pEntry->ID().Write(Pak);
|
||||||
Pak.WriteLong(rkInfo.Size);
|
Pak.WriteULong(rkInfo.Size);
|
||||||
Pak.WriteLong(rkInfo.Offset);
|
Pak.WriteULong(rkInfo.Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear recook flag
|
// Clear recook flag
|
||||||
|
@ -351,11 +348,11 @@ void CPackage::CompareOriginalAssetList(const std::list<CAssetID>& rkNewList)
|
||||||
// Build a set out of the generated list
|
// Build a set out of the generated list
|
||||||
std::set<CAssetID> NewListSet;
|
std::set<CAssetID> NewListSet;
|
||||||
|
|
||||||
for (auto Iter = rkNewList.begin(); Iter != rkNewList.end(); Iter++)
|
for (const auto& id : rkNewList)
|
||||||
NewListSet.insert(*Iter);
|
NewListSet.insert(id);
|
||||||
|
|
||||||
// Read the original pak
|
// Read the original pak
|
||||||
TString CookedPath = CookedPackagePath(false);
|
const TString CookedPath = CookedPackagePath(false);
|
||||||
CFileInStream Pak(CookedPath, EEndian::BigEndian);
|
CFileInStream Pak(CookedPath, EEndian::BigEndian);
|
||||||
|
|
||||||
if (!Pak.IsValid() || Pak.Size() == 0)
|
if (!Pak.IsValid() || Pak.Size() == 0)
|
||||||
|
@ -365,79 +362,73 @@ void CPackage::CompareOriginalAssetList(const std::list<CAssetID>& rkNewList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine pak version
|
// Determine pak version
|
||||||
uint32 PakVersion = Pak.ReadLong();
|
const uint32 PakVersion = Pak.ReadULong();
|
||||||
std::set<CAssetID> OldListSet;
|
std::set<CAssetID> OldListSet;
|
||||||
|
|
||||||
// Read MP1/2 pak
|
// Read MP1/2 pak
|
||||||
if (PakVersion == 0x00030005)
|
if (PakVersion == 0x00030005)
|
||||||
{
|
{
|
||||||
Pak.Seek(0x4, SEEK_CUR);
|
Pak.Seek(0x4, SEEK_CUR);
|
||||||
uint32 NumNamedResources = Pak.ReadLong();
|
const uint32 NumNamedResources = Pak.ReadULong();
|
||||||
|
|
||||||
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
for (uint32 iName = 0; iName < NumNamedResources; iName++)
|
||||||
{
|
{
|
||||||
Pak.Seek(0x8, SEEK_CUR);
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
uint32 NameLen = Pak.ReadLong();
|
const uint32 NameLen = Pak.ReadULong();
|
||||||
Pak.Seek(NameLen, SEEK_CUR);
|
Pak.Seek(NameLen, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a set out of the original pak resource list
|
// Build a set out of the original pak resource list
|
||||||
uint32 NumResources = Pak.ReadLong();
|
const uint32 NumResources = Pak.ReadULong();
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
Pak.Seek(0x8, SEEK_CUR);
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
OldListSet.insert( CAssetID(Pak, k32Bit) );
|
OldListSet.insert(CAssetID(Pak, EIDLength::k32Bit));
|
||||||
Pak.Seek(0x8, SEEK_CUR);
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Read MP3/DKCR pak
|
||||||
// Read MP3/DKCR pak
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
ASSERT(PakVersion == 0x2);
|
ASSERT(PakVersion == 0x2);
|
||||||
|
|
||||||
// Skip named resources
|
// Skip named resources
|
||||||
Pak.Seek(0x44, SEEK_SET);
|
Pak.Seek(0x44, SEEK_SET);
|
||||||
CFourCC StringSecType = Pak.ReadLong();
|
[[maybe_unused]] const CFourCC StringSecType = Pak.ReadULong();
|
||||||
uint32 StringSecSize = Pak.ReadLong();
|
const uint32 StringSecSize = Pak.ReadULong();
|
||||||
ASSERT(StringSecType == "STRG");
|
ASSERT(StringSecType == "STRG");
|
||||||
|
|
||||||
Pak.Seek(0x80 + StringSecSize, SEEK_SET);
|
Pak.Seek(0x80 + StringSecSize, SEEK_SET);
|
||||||
|
|
||||||
// Read resource table
|
// Read resource table
|
||||||
uint32 NumResources = Pak.ReadLong();
|
const uint32 NumResources = Pak.ReadULong();
|
||||||
|
|
||||||
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
for (uint32 iRes = 0; iRes < NumResources; iRes++)
|
||||||
{
|
{
|
||||||
Pak.Seek(0x8, SEEK_CUR);
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
OldListSet.insert( CAssetID(Pak, k64Bit) );
|
OldListSet.insert(CAssetID(Pak, EIDLength::k64Bit));
|
||||||
Pak.Seek(0x8, SEEK_CUR);
|
Pak.Seek(0x8, SEEK_CUR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for missing resources in the new list
|
// Check for missing resources in the new list
|
||||||
for (auto Iter = OldListSet.begin(); Iter != OldListSet.end(); Iter++)
|
for (const auto& ID : OldListSet)
|
||||||
{
|
{
|
||||||
CAssetID ID = *Iter;
|
|
||||||
|
|
||||||
if (NewListSet.find(ID) == NewListSet.end())
|
if (NewListSet.find(ID) == NewListSet.end())
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
const CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
TString Extension = (pEntry ? "." + pEntry->CookedExtension() : "");
|
const TString Extension = (pEntry != nullptr ? "." + pEntry->CookedExtension() : "");
|
||||||
warnf("Missing resource: %s%s", *ID.ToString(), *Extension);
|
warnf("Missing resource: %s%s", *ID.ToString(), *Extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for extra resources in the new list
|
// Check for extra resources in the new list
|
||||||
for (auto Iter = NewListSet.begin(); Iter != NewListSet.end(); Iter++)
|
for (const auto& ID : NewListSet)
|
||||||
{
|
{
|
||||||
CAssetID ID = *Iter;
|
|
||||||
|
|
||||||
if (OldListSet.find(ID) == OldListSet.end())
|
if (OldListSet.find(ID) == OldListSet.end())
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
const CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||||
TString Extension = (pEntry ? "." + pEntry->CookedExtension() : "");
|
const TString Extension = (pEntry != nullptr ? "." + pEntry->CookedExtension() : "");
|
||||||
warnf("Extra resource: %s%s", *ID.ToString(), *Extension);
|
warnf("Extra resource: %s%s", *ID.ToString(), *Extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ enum class EPackageDefinitionVersion
|
||||||
// Add new versions before this line
|
// Add new versions before this line
|
||||||
|
|
||||||
Max,
|
Max,
|
||||||
Current = EPackageDefinitionVersion::Max - 1
|
Current = Max - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SNamedResource
|
struct SNamedResource
|
||||||
|
@ -34,24 +34,22 @@ struct SNamedResource
|
||||||
|
|
||||||
class CPackage
|
class CPackage
|
||||||
{
|
{
|
||||||
CGameProject *mpProject;
|
CGameProject *mpProject = nullptr;
|
||||||
TString mPakName;
|
TString mPakName;
|
||||||
TString mPakPath;
|
TString mPakPath;
|
||||||
std::vector<SNamedResource> mResources;
|
std::vector<SNamedResource> mResources;
|
||||||
bool mNeedsRecook;
|
bool mNeedsRecook = false;
|
||||||
|
|
||||||
// Cached dependency list; used to figure out if a given resource is in this package
|
// Cached dependency list; used to figure out if a given resource is in this package
|
||||||
mutable bool mCacheDirty;
|
mutable bool mCacheDirty = false;
|
||||||
mutable std::set<CAssetID> mCachedDependencies;
|
mutable std::set<CAssetID> mCachedDependencies;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPackage() {}
|
CPackage() = default;
|
||||||
|
CPackage(CGameProject *pProj, TString rkName, TString rkPath)
|
||||||
CPackage(CGameProject *pProj, const TString& rkName, const TString& rkPath)
|
|
||||||
: mpProject(pProj)
|
: mpProject(pProj)
|
||||||
, mPakName(rkName)
|
, mPakName(std::move(rkName))
|
||||||
, mPakPath(rkPath)
|
, mPakPath(std::move(rkPath))
|
||||||
, mNeedsRecook(false)
|
|
||||||
, mCacheDirty(true)
|
, mCacheDirty(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -70,14 +68,14 @@ public:
|
||||||
TString CookedPackagePath(bool Relative) const;
|
TString CookedPackagePath(bool Relative) const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString Name() const { return mPakName; }
|
TString Name() const { return mPakName; }
|
||||||
inline TString Path() const { return mPakPath; }
|
TString Path() const { return mPakPath; }
|
||||||
inline CGameProject* Project() const { return mpProject; }
|
CGameProject* Project() const { return mpProject; }
|
||||||
inline uint32 NumNamedResources() const { return mResources.size(); }
|
size_t NumNamedResources() const { return mResources.size(); }
|
||||||
inline const SNamedResource& NamedResourceByIndex(uint32 Idx) const { return mResources[Idx]; }
|
const SNamedResource& NamedResourceByIndex(size_t Idx) const { return mResources[Idx]; }
|
||||||
inline bool NeedsRecook() const { return mNeedsRecook; }
|
bool NeedsRecook() const { return mNeedsRecook; }
|
||||||
|
|
||||||
inline void SetPakName(TString NewName) { mPakName = NewName; }
|
void SetPakName(TString NewName) { mPakName = std::move(NewName); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPACKAGE
|
#endif // CPACKAGE
|
||||||
|
|
|
@ -11,23 +11,17 @@
|
||||||
#include <Common/Serialization/CXMLWriter.h>
|
#include <Common/Serialization/CXMLWriter.h>
|
||||||
|
|
||||||
CResourceEntry::CResourceEntry(CResourceStore *pStore)
|
CResourceEntry::CResourceEntry(CResourceStore *pStore)
|
||||||
: mpResource(nullptr)
|
: mpStore(pStore)
|
||||||
, mpTypeInfo(nullptr)
|
, mID(CAssetID::InvalidID(pStore->Game()))
|
||||||
, mpStore(pStore)
|
|
||||||
, mpDependencies(nullptr)
|
|
||||||
, mID( CAssetID::InvalidID(pStore->Game()) )
|
|
||||||
, mpDirectory(nullptr)
|
|
||||||
, mMetadataDirty(false)
|
|
||||||
, mCachedSize(-1)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Static constructors
|
// Static constructors
|
||||||
CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
|
std::unique_ptr<CResourceEntry> CResourceEntry::CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
|
||||||
const TString& rkDir, const TString& rkName,
|
const TString& rkDir, const TString& rkName,
|
||||||
EResourceType Type, bool ExistingResource /*= false*/)
|
EResourceType Type, bool ExistingResource)
|
||||||
{
|
{
|
||||||
// Initialize all entry info with the input data.
|
// Initialize all entry info with the input data.
|
||||||
CResourceEntry *pEntry = new CResourceEntry(pStore);
|
auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
|
||||||
pEntry->mID = rkID;
|
pEntry->mID = rkID;
|
||||||
pEntry->mName = rkName;
|
pEntry->mName = rkName;
|
||||||
pEntry->mCachedUppercaseName = rkName.ToUpper();
|
pEntry->mCachedUppercaseName = rkName.ToUpper();
|
||||||
|
@ -37,7 +31,7 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
|
||||||
|
|
||||||
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDir, true);
|
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDir, true);
|
||||||
ASSERT(pEntry->mpDirectory);
|
ASSERT(pEntry->mpDirectory);
|
||||||
pEntry->mpDirectory->AddChild("", pEntry);
|
pEntry->mpDirectory->AddChild("", pEntry.get());
|
||||||
|
|
||||||
pEntry->mMetadataDirty = true;
|
pEntry->mMetadataDirty = true;
|
||||||
|
|
||||||
|
@ -45,7 +39,7 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
|
||||||
// then instantiate the new resource data so it can be saved as soon as possible.
|
// then instantiate the new resource data so it can be saved as soon as possible.
|
||||||
if (!ExistingResource)
|
if (!ExistingResource)
|
||||||
{
|
{
|
||||||
pEntry->mpResource = CResourceFactory::CreateResource(pEntry);
|
pEntry->mpResource = CResourceFactory::CreateResource(pEntry.get());
|
||||||
|
|
||||||
if (pEntry->mpResource)
|
if (pEntry->mpResource)
|
||||||
{
|
{
|
||||||
|
@ -56,30 +50,30 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceEntry* CResourceEntry::BuildFromArchive(CResourceStore *pStore, IArchive& rArc)
|
std::unique_ptr<CResourceEntry> CResourceEntry::BuildFromArchive(CResourceStore *pStore, IArchive& rArc)
|
||||||
{
|
{
|
||||||
// Load all entry info from the archive.
|
// Load all entry info from the archive.
|
||||||
CResourceEntry *pEntry = new CResourceEntry(pStore);
|
auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
|
||||||
pEntry->SerializeEntryInfo(rArc, false);
|
pEntry->SerializeEntryInfo(rArc, false);
|
||||||
ASSERT(pEntry->mpTypeInfo);
|
ASSERT(pEntry->mpTypeInfo);
|
||||||
ASSERT(pEntry->mpDirectory);
|
ASSERT(pEntry->mpDirectory);
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceEntry* CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
|
std::unique_ptr<CResourceEntry> CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
|
||||||
const TString& rkDirPath, const TString& rkName)
|
const TString& rkDirPath, const TString& rkName)
|
||||||
{
|
{
|
||||||
// Initialize as much entry info as possible from the input data, then load the rest from the metadata file.
|
// Initialize as much entry info as possible from the input data, then load the rest from the metadata file.
|
||||||
ASSERT(pTypeInfo);
|
ASSERT(pTypeInfo);
|
||||||
|
|
||||||
CResourceEntry *pEntry = new CResourceEntry(pStore);
|
auto pEntry = std::unique_ptr<CResourceEntry>(new CResourceEntry(pStore));
|
||||||
pEntry->mpTypeInfo = pTypeInfo;
|
pEntry->mpTypeInfo = pTypeInfo;
|
||||||
pEntry->mName = rkName;
|
pEntry->mName = rkName;
|
||||||
pEntry->mCachedUppercaseName = rkName.ToUpper();
|
pEntry->mCachedUppercaseName = rkName.ToUpper();
|
||||||
|
|
||||||
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDirPath, true);
|
pEntry->mpDirectory = pStore->GetVirtualDirectory(rkDirPath, true);
|
||||||
ASSERT(pEntry->mpDirectory);
|
ASSERT(pEntry->mpDirectory);
|
||||||
pEntry->mpDirectory->AddChild("", pEntry);
|
pEntry->mpDirectory->AddChild("", pEntry.get());
|
||||||
|
|
||||||
// Make sure we're valid, then load the remaining data from the metadata file
|
// Make sure we're valid, then load the remaining data from the metadata file
|
||||||
ASSERT(pEntry->HasCookedVersion() || pEntry->HasRawVersion());
|
ASSERT(pEntry->HasCookedVersion() || pEntry->HasRawVersion());
|
||||||
|
@ -89,11 +83,7 @@ CResourceEntry* CResourceEntry::BuildFromDirectory(CResourceStore *pStore, CResT
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceEntry::~CResourceEntry()
|
CResourceEntry::~CResourceEntry() = default;
|
||||||
{
|
|
||||||
if (mpResource) delete mpResource;
|
|
||||||
if (mpDependencies) delete mpDependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CResourceEntry::LoadMetadata()
|
bool CResourceEntry::LoadMetadata()
|
||||||
{
|
{
|
||||||
|
@ -171,15 +161,11 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly)
|
||||||
|
|
||||||
void CResourceEntry::UpdateDependencies()
|
void CResourceEntry::UpdateDependencies()
|
||||||
{
|
{
|
||||||
if (mpDependencies)
|
mpDependencies.reset();
|
||||||
{
|
|
||||||
delete mpDependencies;
|
|
||||||
mpDependencies = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mpTypeInfo->CanHaveDependencies())
|
if (!mpTypeInfo->CanHaveDependencies())
|
||||||
{
|
{
|
||||||
mpDependencies = new CDependencyTree();
|
mpDependencies = std::make_unique<CDependencyTree>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +177,7 @@ void CResourceEntry::UpdateDependencies()
|
||||||
if (!mpResource)
|
if (!mpResource)
|
||||||
{
|
{
|
||||||
errorf("Unable to update cached dependencies; failed to load resource");
|
errorf("Unable to update cached dependencies; failed to load resource");
|
||||||
mpDependencies = new CDependencyTree();
|
mpDependencies = std::make_unique<CDependencyTree>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +241,7 @@ bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
|
||||||
|
|
||||||
uint64 CResourceEntry::Size() const
|
uint64 CResourceEntry::Size() const
|
||||||
{
|
{
|
||||||
if (mCachedSize == -1)
|
if (mCachedSize == UINT64_MAX)
|
||||||
{
|
{
|
||||||
if (HasCookedVersion())
|
if (HasCookedVersion())
|
||||||
mCachedSize = FileUtil::FileSize(CookedAssetPath());
|
mCachedSize = FileUtil::FileSize(CookedAssetPath());
|
||||||
|
@ -344,7 +330,7 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/, bool FlagForRecook /*=
|
||||||
// Flag dirty any packages that contain this resource.
|
// Flag dirty any packages that contain this resource.
|
||||||
if (FlagForRecook)
|
if (FlagForRecook)
|
||||||
{
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++)
|
for (size_t iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg);
|
CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg);
|
||||||
|
|
||||||
|
@ -391,7 +377,8 @@ bool CResourceEntry::Cook()
|
||||||
CResource* CResourceEntry::Load()
|
CResource* CResourceEntry::Load()
|
||||||
{
|
{
|
||||||
// If the asset is already loaded then just return it immediately
|
// If the asset is already loaded then just return it immediately
|
||||||
if (mpResource) return mpResource;
|
if (mpResource)
|
||||||
|
return mpResource.get();
|
||||||
|
|
||||||
// Always try to load raw version as the raw version contains extra editor-only data.
|
// Always try to load raw version as the raw version contains extra editor-only data.
|
||||||
// If there is no raw version (which will be the case for resource types that don't
|
// If there is no raw version (which will be the case for resource types that don't
|
||||||
|
@ -411,8 +398,7 @@ CResource* CResourceEntry::Load()
|
||||||
if (!Reader.IsValid())
|
if (!Reader.IsValid())
|
||||||
{
|
{
|
||||||
errorf("Failed to load raw resource; falling back on cooked. Raw path: %s", *RawAssetPath());
|
errorf("Failed to load raw resource; falling back on cooked. Raw path: %s", *RawAssetPath());
|
||||||
delete mpResource;
|
mpResource.reset();
|
||||||
mpResource = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -424,7 +410,7 @@ CResource* CResourceEntry::Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mpResource)
|
if (mpResource)
|
||||||
return mpResource;
|
return mpResource.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(!mpResource);
|
ASSERT(!mpResource);
|
||||||
|
@ -451,8 +437,11 @@ CResource* CResourceEntry::Load()
|
||||||
CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
|
CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
|
||||||
{
|
{
|
||||||
// Overload to allow for load from an arbitrary input stream.
|
// Overload to allow for load from an arbitrary input stream.
|
||||||
if (mpResource) return mpResource;
|
if (mpResource)
|
||||||
if (!rInput.IsValid()) return nullptr;
|
return mpResource.get();
|
||||||
|
|
||||||
|
if (!rInput.IsValid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions
|
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions
|
||||||
CResourceStore *pOldStore = gpResourceStore;
|
CResourceStore *pOldStore = gpResourceStore;
|
||||||
|
@ -463,22 +452,22 @@ CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
|
||||||
mpStore->TrackLoadedResource(this);
|
mpStore->TrackLoadedResource(this);
|
||||||
|
|
||||||
gpResourceStore = pOldStore;
|
gpResourceStore = pOldStore;
|
||||||
return mpResource;
|
return mpResource.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceEntry::Unload()
|
bool CResourceEntry::Unload()
|
||||||
{
|
{
|
||||||
ASSERT(mpResource != nullptr);
|
ASSERT(mpResource != nullptr);
|
||||||
ASSERT(!mpResource->IsReferenced());
|
ASSERT(!mpResource->IsReferenced());
|
||||||
delete mpResource;
|
mpResource.reset();
|
||||||
mpResource = nullptr;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName)
|
bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName)
|
||||||
{
|
{
|
||||||
// Validate that the path/name are valid
|
// Validate that the path/name are valid
|
||||||
if (!mpStore->IsValidResourcePath(rkDir, rkName)) return false;
|
if (!CResourceStore::IsValidResourcePath(rkDir, rkName))
|
||||||
|
return false;
|
||||||
|
|
||||||
// We need to validate the path isn't taken already - either the directory doesn't exist, or doesn't have a resource by this name
|
// We need to validate the path isn't taken already - either the directory doesn't exist, or doesn't have a resource by this name
|
||||||
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(rkDir, false);
|
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(rkDir, false);
|
||||||
|
|
|
@ -8,10 +8,12 @@
|
||||||
#include <Common/CAssetID.h>
|
#include <Common/CAssetID.h>
|
||||||
#include <Common/CFourCC.h>
|
#include <Common/CFourCC.h>
|
||||||
#include <Common/Flags.h>
|
#include <Common/Flags.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class CResource;
|
|
||||||
class CGameProject;
|
|
||||||
class CDependencyTree;
|
class CDependencyTree;
|
||||||
|
class CGameProject;
|
||||||
|
class CResource;
|
||||||
|
class IInputStream;
|
||||||
|
|
||||||
enum class EResEntryFlag
|
enum class EResEntryFlag
|
||||||
{
|
{
|
||||||
|
@ -27,29 +29,29 @@ DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
||||||
|
|
||||||
class CResourceEntry
|
class CResourceEntry
|
||||||
{
|
{
|
||||||
CResource *mpResource;
|
std::unique_ptr<CResource> mpResource;
|
||||||
CResTypeInfo *mpTypeInfo;
|
CResTypeInfo *mpTypeInfo = nullptr;
|
||||||
CResourceStore *mpStore;
|
CResourceStore *mpStore;
|
||||||
CDependencyTree *mpDependencies;
|
std::unique_ptr<CDependencyTree> mpDependencies;
|
||||||
CAssetID mID;
|
CAssetID mID;
|
||||||
CVirtualDirectory *mpDirectory;
|
CVirtualDirectory *mpDirectory = nullptr;
|
||||||
TString mName;
|
TString mName;
|
||||||
FResEntryFlags mFlags;
|
FResEntryFlags mFlags;
|
||||||
|
|
||||||
mutable bool mMetadataDirty;
|
mutable bool mMetadataDirty = false;
|
||||||
mutable uint64 mCachedSize;
|
mutable uint64 mCachedSize = UINT64_MAX;
|
||||||
mutable TString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering.
|
mutable TString mCachedUppercaseName; // This is used to speed up case-insensitive sorting and filtering.
|
||||||
|
|
||||||
// Private constructor
|
// Private constructor
|
||||||
CResourceEntry(CResourceStore *pStore);
|
explicit CResourceEntry(CResourceStore *pStore);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CResourceEntry* CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
|
static std::unique_ptr<CResourceEntry> CreateNewResource(CResourceStore *pStore, const CAssetID& rkID,
|
||||||
const TString& rkDir, const TString& rkName,
|
const TString& rkDir, const TString& rkName,
|
||||||
EResourceType Type, bool ExistingResource = false);
|
EResourceType Type, bool ExistingResource = false);
|
||||||
static CResourceEntry* BuildFromArchive(CResourceStore *pStore, IArchive& rArc);
|
static std::unique_ptr<CResourceEntry> BuildFromArchive(CResourceStore *pStore, IArchive& rArc);
|
||||||
static CResourceEntry* BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
|
static std::unique_ptr<CResourceEntry> BuildFromDirectory(CResourceStore *pStore, CResTypeInfo *pTypeInfo,
|
||||||
const TString& rkDirPath, const TString& rkName);
|
const TString& rkDirPath, const TString& rkName);
|
||||||
~CResourceEntry();
|
~CResourceEntry();
|
||||||
|
|
||||||
bool LoadMetadata();
|
bool LoadMetadata();
|
||||||
|
@ -86,27 +88,27 @@ public:
|
||||||
void ClearFlag(EResEntryFlag Flag);
|
void ClearFlag(EResEntryFlag Flag);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); }
|
void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); }
|
||||||
|
|
||||||
inline void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); }
|
void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); }
|
||||||
inline void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); }
|
void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); }
|
||||||
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
||||||
inline bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
|
bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
|
||||||
inline bool IsMarkedForDeletion() const { return HasFlag(EResEntryFlag::MarkedForDeletion); }
|
bool IsMarkedForDeletion() const { return HasFlag(EResEntryFlag::MarkedForDeletion); }
|
||||||
|
|
||||||
inline bool IsLoaded() const { return mpResource != nullptr; }
|
bool IsLoaded() const { return mpResource != nullptr; }
|
||||||
inline bool IsCategorized() const { return mpDirectory && !mpDirectory->FullPath().CaseInsensitiveCompare( mpStore->DefaultResourceDirPath() ); }
|
bool IsCategorized() const { return mpDirectory && !mpDirectory->FullPath().CaseInsensitiveCompare( mpStore->DefaultResourceDirPath() ); }
|
||||||
inline bool IsNamed() const { return mName != mID.ToString(); }
|
bool IsNamed() const { return mName != mID.ToString(); }
|
||||||
inline CResource* Resource() const { return mpResource; }
|
CResource* Resource() const { return mpResource.get(); }
|
||||||
inline CResTypeInfo* TypeInfo() const { return mpTypeInfo; }
|
CResTypeInfo* TypeInfo() const { return mpTypeInfo; }
|
||||||
inline CResourceStore* ResourceStore() const { return mpStore; }
|
CResourceStore* ResourceStore() const { return mpStore; }
|
||||||
inline CDependencyTree* Dependencies() const { return mpDependencies; }
|
CDependencyTree* Dependencies() const { return mpDependencies.get(); }
|
||||||
inline CAssetID ID() const { return mID; }
|
CAssetID ID() const { return mID; }
|
||||||
inline CVirtualDirectory* Directory() const { return mpDirectory; }
|
CVirtualDirectory* Directory() const { return mpDirectory; }
|
||||||
inline TString DirectoryPath() const { return mpDirectory->FullPath(); }
|
TString DirectoryPath() const { return mpDirectory->FullPath(); }
|
||||||
inline TString Name() const { return mName; }
|
TString Name() const { return mName; }
|
||||||
inline const TString& UppercaseName() const { return mCachedUppercaseName; }
|
const TString& UppercaseName() const { return mCachedUppercaseName; }
|
||||||
inline EResourceType ResourceType() const { return mpTypeInfo->Type(); }
|
EResourceType ResourceType() const { return mpTypeInfo->Type(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CResource* InternalLoad(IInputStream& rInput);
|
CResource* InternalLoad(IInputStream& rInput);
|
||||||
|
|
|
@ -8,26 +8,27 @@ class CResourceIterator
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const CResourceStore *mpkStore;
|
const CResourceStore *mpkStore;
|
||||||
std::map<CAssetID, CResourceEntry*>::const_iterator mIter;
|
std::map<CAssetID, std::unique_ptr<CResourceEntry>>::const_iterator mIter;
|
||||||
CResourceEntry *mpCurEntry;
|
CResourceEntry *mpCurEntry = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceIterator(const CResourceStore *pkStore = gpResourceStore)
|
explicit CResourceIterator(const CResourceStore *pkStore = gpResourceStore)
|
||||||
: mpkStore(pkStore)
|
: mpkStore(pkStore)
|
||||||
, mpCurEntry(nullptr)
|
|
||||||
{
|
{
|
||||||
mIter = mpkStore->mResourceEntries.begin();
|
mIter = mpkStore->mResourceEntries.cbegin();
|
||||||
Next();
|
Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~CResourceIterator() = default;
|
||||||
|
|
||||||
virtual CResourceEntry* Next()
|
virtual CResourceEntry* Next()
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (mIter != mpkStore->mResourceEntries.end())
|
if (mIter != mpkStore->mResourceEntries.cend())
|
||||||
{
|
{
|
||||||
mpCurEntry = mIter->second;
|
mpCurEntry = mIter->second.get();
|
||||||
mIter++;
|
++mIter;
|
||||||
}
|
}
|
||||||
else mpCurEntry = nullptr;
|
else mpCurEntry = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -36,33 +37,33 @@ public:
|
||||||
return mpCurEntry;
|
return mpCurEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool DoneIterating() const
|
bool DoneIterating() const
|
||||||
{
|
{
|
||||||
return mpCurEntry == nullptr;
|
return mpCurEntry == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline operator bool() const
|
explicit operator bool() const
|
||||||
{
|
{
|
||||||
return !DoneIterating();
|
return !DoneIterating();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CResourceEntry* operator*() const
|
CResourceEntry* operator*() const
|
||||||
{
|
{
|
||||||
return mpCurEntry;
|
return mpCurEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CResourceEntry* operator->() const
|
CResourceEntry* operator->() const
|
||||||
{
|
{
|
||||||
return mpCurEntry;
|
return mpCurEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CResourceIterator& operator++()
|
CResourceIterator& operator++()
|
||||||
{
|
{
|
||||||
Next();
|
Next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CResourceIterator operator++(int)
|
CResourceIterator operator++(int)
|
||||||
{
|
{
|
||||||
CResourceIterator Copy = *this;
|
CResourceIterator Copy = *this;
|
||||||
Next();
|
Next();
|
||||||
|
@ -74,14 +75,14 @@ template<EResourceType ResType>
|
||||||
class TResourceIterator : public CResourceIterator
|
class TResourceIterator : public CResourceIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TResourceIterator(CResourceStore *pStore = gpResourceStore)
|
explicit TResourceIterator(CResourceStore *pStore = gpResourceStore)
|
||||||
: CResourceIterator(pStore)
|
: CResourceIterator(pStore)
|
||||||
{
|
{
|
||||||
if (mpCurEntry && mpCurEntry->ResourceType() != ResType)
|
if (mpCurEntry && mpCurEntry->ResourceType() != ResType)
|
||||||
Next();
|
Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual CResourceEntry* Next()
|
CResourceEntry* Next() override
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
CResourceIterator::Next();
|
CResourceIterator::Next();
|
||||||
|
|
|
@ -20,9 +20,6 @@ CResourceStore *gpEditorStore = nullptr;
|
||||||
|
|
||||||
// Constructor for editor store
|
// Constructor for editor store
|
||||||
CResourceStore::CResourceStore(const TString& rkDatabasePath)
|
CResourceStore::CResourceStore(const TString& rkDatabasePath)
|
||||||
: mpProj(nullptr)
|
|
||||||
, mGame(EGame::Prime)
|
|
||||||
, mDatabaseCacheDirty(false)
|
|
||||||
{
|
{
|
||||||
mpDatabaseRoot = new CVirtualDirectory(this);
|
mpDatabaseRoot = new CVirtualDirectory(this);
|
||||||
mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory());
|
mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory());
|
||||||
|
@ -32,10 +29,7 @@ CResourceStore::CResourceStore(const TString& rkDatabasePath)
|
||||||
|
|
||||||
// Main constructor for game projects and game exporter
|
// Main constructor for game projects and game exporter
|
||||||
CResourceStore::CResourceStore(CGameProject *pProject)
|
CResourceStore::CResourceStore(CGameProject *pProject)
|
||||||
: mpProj(nullptr)
|
: mGame(EGame::Invalid)
|
||||||
, mGame(EGame::Invalid)
|
|
||||||
, mpDatabaseRoot(nullptr)
|
|
||||||
, mDatabaseCacheDirty(false)
|
|
||||||
{
|
{
|
||||||
SetProject(pProject);
|
SetProject(pProject);
|
||||||
}
|
}
|
||||||
|
@ -44,9 +38,6 @@ CResourceStore::~CResourceStore()
|
||||||
{
|
{
|
||||||
CloseProject();
|
CloseProject();
|
||||||
DestroyUnreferencedResources();
|
DestroyUnreferencedResources();
|
||||||
|
|
||||||
for (auto It = mResourceEntries.begin(); It != mResourceEntries.end(); It++)
|
|
||||||
delete It->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rOutList)
|
void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rOutList)
|
||||||
|
@ -58,7 +49,7 @@ void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rO
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (uint32 SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++)
|
for (size_t SubIdx = 0; SubIdx < pDir->NumSubdirectories(); SubIdx++)
|
||||||
RecursiveGetListOfEmptyDirectories(pDir->SubdirectoryByIndex(SubIdx), rOutList);
|
RecursiveGetListOfEmptyDirectories(pDir->SubdirectoryByIndex(SubIdx), rOutList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,11 +66,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||||
{
|
{
|
||||||
// Make sure deleted resources aren't included in the count.
|
// Make sure deleted resources aren't included in the count.
|
||||||
// We can't use CResourceIterator because it skips MarkedForDeletion resources.
|
// We can't use CResourceIterator because it skips MarkedForDeletion resources.
|
||||||
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
|
for (const auto& entry : mResourceEntries)
|
||||||
{
|
{
|
||||||
CResourceEntry* pEntry = Iter->second;
|
if (entry.second->IsMarkedForDeletion())
|
||||||
|
|
||||||
if (pEntry->IsMarkedForDeletion())
|
|
||||||
{
|
{
|
||||||
ResourceCount--;
|
ResourceCount--;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +83,9 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||||
{
|
{
|
||||||
if (rArc.ParamBegin("Resource", 0))
|
if (rArc.ParamBegin("Resource", 0))
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = CResourceEntry::BuildFromArchive(this, rArc);
|
auto pEntry = CResourceEntry::BuildFromArchive(this, rArc);
|
||||||
ASSERT( FindEntry(pEntry->ID()) == nullptr );
|
ASSERT(FindEntry(pEntry->ID()) == nullptr);
|
||||||
mResourceEntries[pEntry->ID()] = pEntry;
|
mResourceEntries.insert_or_assign(pEntry->ID(), std::move(pEntry));
|
||||||
rArc.ParamEnd();
|
rArc.ParamEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,13 +117,13 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||||
|
|
||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
for (auto Iter = EmptyDirectories.begin(); Iter != EmptyDirectories.end(); Iter++)
|
for (const auto& dir : EmptyDirectories)
|
||||||
{
|
{
|
||||||
// Don't create empty virtual directories that don't actually exist in the filesystem
|
// Don't create empty virtual directories that don't actually exist in the filesystem
|
||||||
TString AbsPath = ResourcesDir() + *Iter;
|
const TString AbsPath = ResourcesDir() + dir;
|
||||||
|
|
||||||
if (FileUtil::Exists(AbsPath))
|
if (FileUtil::Exists(AbsPath))
|
||||||
CreateVirtualDirectory(*Iter);
|
CreateVirtualDirectory(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +148,10 @@ bool CResourceStore::LoadDatabaseCache()
|
||||||
if (!BuildFromDirectory(true))
|
if (!BuildFromDirectory(true))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else return false;
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -192,31 +184,33 @@ bool CResourceStore::SaveDatabaseCache()
|
||||||
|
|
||||||
void CResourceStore::ConditionalSaveStore()
|
void CResourceStore::ConditionalSaveStore()
|
||||||
{
|
{
|
||||||
if (mDatabaseCacheDirty) SaveDatabaseCache();
|
if (mDatabaseCacheDirty)
|
||||||
|
SaveDatabaseCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceStore::SetProject(CGameProject *pProj)
|
void CResourceStore::SetProject(CGameProject *pProj)
|
||||||
{
|
{
|
||||||
if (mpProj == pProj) return;
|
if (mpProj == pProj)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mpProj)
|
if (mpProj)
|
||||||
CloseProject();
|
CloseProject();
|
||||||
|
|
||||||
mpProj = pProj;
|
mpProj = pProj;
|
||||||
|
|
||||||
if (mpProj)
|
if (!mpProj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mDatabasePath = mpProj->ProjectRoot();
|
||||||
|
mpDatabaseRoot = new CVirtualDirectory(this);
|
||||||
|
mGame = mpProj->Game();
|
||||||
|
|
||||||
|
// Clear deleted files from previous runs
|
||||||
|
const TString DeletedPath = DeletedResourcePath();
|
||||||
|
|
||||||
|
if (FileUtil::Exists(DeletedPath))
|
||||||
{
|
{
|
||||||
mDatabasePath = mpProj->ProjectRoot();
|
FileUtil::ClearDirectory(DeletedPath);
|
||||||
mpDatabaseRoot = new CVirtualDirectory(this);
|
|
||||||
mGame = mpProj->Game();
|
|
||||||
|
|
||||||
// Clear deleted files from previous runs
|
|
||||||
TString DeletedPath = DeletedResourcePath();
|
|
||||||
|
|
||||||
if (FileUtil::Exists(DeletedPath))
|
|
||||||
{
|
|
||||||
FileUtil::ClearDirectory(DeletedPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +226,9 @@ void CResourceStore::CloseProject()
|
||||||
{
|
{
|
||||||
warnf("%d resources still loaded on project close:", mLoadedResources.size());
|
warnf("%d resources still loaded on project close:", mLoadedResources.size());
|
||||||
|
|
||||||
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++)
|
for (const auto& entry : mLoadedResources)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = Iter->second;
|
const CResourceEntry *pEntry = entry.second;
|
||||||
warnf("\t%s.%s", *pEntry->Name(), *pEntry->CookedExtension().ToString());
|
warnf("\t%s.%s", *pEntry->Name(), *pEntry->CookedExtension().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,16 +236,10 @@ void CResourceStore::CloseProject()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all entries from old project
|
// Delete all entries from old project
|
||||||
auto It = mResourceEntries.begin();
|
mResourceEntries.clear();
|
||||||
|
|
||||||
while (It != mResourceEntries.end())
|
|
||||||
{
|
|
||||||
delete It->second;
|
|
||||||
It = mResourceEntries.erase(It);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear deleted files from previous runs
|
// Clear deleted files from previous runs
|
||||||
TString DeletedPath = DeletedResourcePath();
|
const TString DeletedPath = DeletedResourcePath();
|
||||||
|
|
||||||
if (FileUtil::Exists(DeletedPath))
|
if (FileUtil::Exists(DeletedPath))
|
||||||
{
|
{
|
||||||
|
@ -268,10 +256,11 @@ CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TString& rkPath, bo
|
||||||
{
|
{
|
||||||
if (rkPath.IsEmpty())
|
if (rkPath.IsEmpty())
|
||||||
return mpDatabaseRoot;
|
return mpDatabaseRoot;
|
||||||
else if (mpDatabaseRoot)
|
|
||||||
|
if (mpDatabaseRoot)
|
||||||
return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate);
|
return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate);
|
||||||
else
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceStore::CreateVirtualDirectory(const TString& rkPath)
|
void CResourceStore::CreateVirtualDirectory(const TString& rkPath)
|
||||||
|
@ -308,14 +297,14 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
|
||||||
{
|
{
|
||||||
if (rkID.IsValid())
|
if (rkID.IsValid())
|
||||||
{
|
{
|
||||||
auto Found = mResourceEntries.find(rkID);
|
const auto Found = mResourceEntries.find(rkID);
|
||||||
|
|
||||||
if (Found != mResourceEntries.end())
|
if (Found != mResourceEntries.cend())
|
||||||
{
|
{
|
||||||
CResourceEntry* pEntry = Found->second;
|
const auto& pEntry = Found->second;
|
||||||
|
|
||||||
if (!pEntry->IsMarkedForDeletion())
|
if (!pEntry->IsMarkedForDeletion())
|
||||||
return pEntry;
|
return pEntry.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +313,7 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
|
||||||
|
|
||||||
CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const
|
CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const
|
||||||
{
|
{
|
||||||
return (mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr);
|
return mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceStore::AreAllEntriesValid() const
|
bool CResourceStore::AreAllEntriesValid() const
|
||||||
|
@ -346,14 +335,12 @@ void CResourceStore::ClearDatabase()
|
||||||
if (!mLoadedResources.empty())
|
if (!mLoadedResources.empty())
|
||||||
{
|
{
|
||||||
debugf("ERROR: Resources still loaded:");
|
debugf("ERROR: Resources still loaded:");
|
||||||
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++)
|
for (const auto& [asset, entry] : mLoadedResources)
|
||||||
debugf("\t[%s] %s", *Iter->first.ToString(), *Iter->second->CookedAssetPath(true));
|
debugf("\t[%s] %s", *asset.ToString(), *entry->CookedAssetPath(true));
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear out existing resource entries and directories
|
// Clear out existing resource entries and directories
|
||||||
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
|
|
||||||
delete Iter->second;
|
|
||||||
mResourceEntries.clear();
|
mResourceEntries.clear();
|
||||||
|
|
||||||
delete mpDatabaseRoot;
|
delete mpDatabaseRoot;
|
||||||
|
@ -371,10 +358,9 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
|
||||||
TStringList ResourceList;
|
TStringList ResourceList;
|
||||||
FileUtil::GetDirectoryContents(ResDir, ResourceList);
|
FileUtil::GetDirectoryContents(ResDir, ResourceList);
|
||||||
|
|
||||||
for (auto Iter = ResourceList.begin(); Iter != ResourceList.end(); Iter++)
|
for (const auto& Path : ResourceList)
|
||||||
{
|
{
|
||||||
TString Path = *Iter;
|
TString RelPath = Path.ChopFront(ResDir.Size());
|
||||||
TString RelPath = Path.ChopFront( ResDir.Size() );
|
|
||||||
|
|
||||||
if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta"))
|
if (FileUtil::IsFile(Path) && Path.EndsWith(".rsmeta"))
|
||||||
{
|
{
|
||||||
|
@ -382,11 +368,11 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
|
||||||
TString DirPath = RelPath.GetFileDirectory();
|
TString DirPath = RelPath.GetFileDirectory();
|
||||||
TString CookedFilename = RelPath.GetFileName(false); // This call removes the .rsmeta extension
|
TString CookedFilename = RelPath.GetFileName(false); // This call removes the .rsmeta extension
|
||||||
TString ResName = CookedFilename.GetFileName(false); // This call removes the cooked extension
|
TString ResName = CookedFilename.GetFileName(false); // This call removes the cooked extension
|
||||||
ASSERT( IsValidResourcePath(DirPath, ResName) );
|
ASSERT(IsValidResourcePath(DirPath, ResName));
|
||||||
|
|
||||||
// Determine resource type
|
// Determine resource type
|
||||||
TString CookedExtension = CookedFilename.GetFileExtension();
|
TString CookedExtension = CookedFilename.GetFileExtension();
|
||||||
CResTypeInfo *pTypeInfo = CResTypeInfo::TypeForCookedExtension( Game(), CFourCC(CookedExtension) );
|
CResTypeInfo* pTypeInfo = CResTypeInfo::TypeForCookedExtension(Game(), CFourCC(CookedExtension));
|
||||||
|
|
||||||
if (!pTypeInfo)
|
if (!pTypeInfo)
|
||||||
{
|
{
|
||||||
|
@ -395,18 +381,19 @@ bool CResourceStore::BuildFromDirectory(bool ShouldGenerateCacheFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create resource entry
|
// Create resource entry
|
||||||
CResourceEntry *pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName);
|
auto pEntry = CResourceEntry::BuildFromDirectory(this, pTypeInfo, DirPath, ResName);
|
||||||
|
|
||||||
// Validate the entry
|
// Validate the entry
|
||||||
CAssetID ID = pEntry->ID();
|
const CAssetID ID = pEntry->ID();
|
||||||
ASSERT( mResourceEntries.find(ID) == mResourceEntries.end() );
|
ASSERT(mResourceEntries.find(ID) == mResourceEntries.cend());
|
||||||
ASSERT( ID.Length() == CAssetID::GameIDLength(mGame) );
|
ASSERT(ID.Length() == CAssetID::GameIDLength(mGame));
|
||||||
|
|
||||||
mResourceEntries[ID] = pEntry;
|
mResourceEntries.insert_or_assign(ID, std::move(pEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (FileUtil::IsDirectory(Path))
|
else if (FileUtil::IsDirectory(Path))
|
||||||
|
{
|
||||||
CreateVirtualDirectory(RelPath);
|
CreateVirtualDirectory(RelPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate new cache file
|
// Generate new cache file
|
||||||
|
@ -454,30 +441,34 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
|
||||||
CResourceEntry *pEntry = FindEntry(rkID);
|
CResourceEntry *pEntry = FindEntry(rkID);
|
||||||
|
|
||||||
if (pEntry)
|
if (pEntry)
|
||||||
|
{
|
||||||
errorf("Attempted to register resource that's already tracked in the database: %s / %s / %s", *rkID.ToString(), *rkDir, *rkName);
|
errorf("Attempted to register resource that's already tracked in the database: %s / %s / %s", *rkID.ToString(), *rkDir, *rkName);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Validate directory
|
// Validate directory
|
||||||
if (IsValidResourcePath(rkDir, rkName))
|
if (IsValidResourcePath(rkDir, rkName))
|
||||||
{
|
{
|
||||||
pEntry = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource);
|
auto res = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type, ExistingResource);
|
||||||
mResourceEntries[rkID] = pEntry;
|
auto* resPtr = res.get();
|
||||||
|
|
||||||
|
mResourceEntries.insert_or_assign(rkID, std::move(res));
|
||||||
mDatabaseCacheDirty = true;
|
mDatabaseCacheDirty = true;
|
||||||
|
|
||||||
if (pEntry->IsLoaded())
|
if (resPtr->IsLoaded())
|
||||||
{
|
{
|
||||||
TrackLoadedResource(pEntry);
|
TrackLoadedResource(resPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ExistingResource)
|
if (!ExistingResource)
|
||||||
{
|
{
|
||||||
debugf("CREATED NEW RESOURCE: [%s] %s", *rkID.ToString(), *pEntry->CookedAssetPath());
|
debugf("CREATED NEW RESOURCE: [%s] %s", *rkID.ToString(), *resPtr->CookedAssetPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return resPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
errorf("Invalid resource path, failed to register: %s%s", *rkDir, *rkName);
|
||||||
errorf("Invalid resource path, failed to register: %s%s", *rkDir, *rkName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pEntry;
|
return pEntry;
|
||||||
|
@ -485,19 +476,18 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
|
||||||
|
|
||||||
CResource* CResourceStore::LoadResource(const CAssetID& rkID)
|
CResource* CResourceStore::LoadResource(const CAssetID& rkID)
|
||||||
{
|
{
|
||||||
if (!rkID.IsValid()) return nullptr;
|
if (!rkID.IsValid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
CResourceEntry *pEntry = FindEntry(rkID);
|
CResourceEntry *pEntry = FindEntry(rkID);
|
||||||
|
if (!pEntry)
|
||||||
if (pEntry)
|
|
||||||
return pEntry->Load();
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Resource doesn't seem to exist
|
// Resource doesn't seem to exist
|
||||||
warnf("Can't find requested resource with ID \"%s\"", *rkID.ToString());
|
warnf("Can't find requested resource with ID \"%s\"", *rkID.ToString());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return pEntry->Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type)
|
CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type)
|
||||||
|
@ -521,8 +511,7 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, EResourceType Type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
return nullptr;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CResource* CResourceStore::LoadResource(const TString& rkPath)
|
CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||||
|
@ -533,7 +522,7 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||||
if (pEntry)
|
if (pEntry)
|
||||||
{
|
{
|
||||||
// Verify extension matches the entry + load resource
|
// Verify extension matches the entry + load resource
|
||||||
TString Ext = rkPath.GetFileExtension();
|
const TString Ext = rkPath.GetFileExtension();
|
||||||
|
|
||||||
if (!Ext.IsEmpty())
|
if (!Ext.IsEmpty())
|
||||||
{
|
{
|
||||||
|
@ -550,14 +539,14 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||||
return pEntry->Load();
|
return pEntry->Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
else return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceStore::TrackLoadedResource(CResourceEntry *pEntry)
|
void CResourceStore::TrackLoadedResource(CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
ASSERT(pEntry->IsLoaded());
|
ASSERT(pEntry->IsLoaded());
|
||||||
ASSERT(mLoadedResources.find(pEntry->ID()) == mLoadedResources.end());
|
ASSERT(mLoadedResources.find(pEntry->ID()) == mLoadedResources.end());
|
||||||
mLoadedResources[pEntry->ID()] = pEntry;
|
mLoadedResources.insert_or_assign(pEntry->ID(), pEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceStore::DestroyUnreferencedResources()
|
void CResourceStore::DestroyUnreferencedResources()
|
||||||
|
@ -579,22 +568,24 @@ void CResourceStore::DestroyUnreferencedResources()
|
||||||
It = mLoadedResources.erase(It);
|
It = mLoadedResources.erase(It);
|
||||||
NumDeleted++;
|
NumDeleted++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
else It++;
|
{
|
||||||
|
++It;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (NumDeleted > 0);
|
} while (NumDeleted > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
|
bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
CAssetID ID = pEntry->ID();
|
const CAssetID ID = pEntry->ID();
|
||||||
|
|
||||||
if (pEntry->IsLoaded())
|
if (pEntry->IsLoaded())
|
||||||
{
|
{
|
||||||
if (!pEntry->Unload())
|
if (!pEntry->Unload())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto It = mLoadedResources.find(ID);
|
const auto It = mLoadedResources.find(ID);
|
||||||
ASSERT(It != mLoadedResources.end());
|
ASSERT(It != mLoadedResources.end());
|
||||||
mLoadedResources.erase(It);
|
mLoadedResources.erase(It);
|
||||||
}
|
}
|
||||||
|
@ -602,7 +593,7 @@ bool CResourceStore::DeleteResourceEntry(CResourceEntry *pEntry)
|
||||||
if (pEntry->Directory())
|
if (pEntry->Directory())
|
||||||
pEntry->Directory()->RemoveChildResource(pEntry);
|
pEntry->Directory()->RemoveChildResource(pEntry);
|
||||||
|
|
||||||
auto It = mResourceEntries.find(ID);
|
const auto It = mResourceEntries.find(ID);
|
||||||
ASSERT(It != mResourceEntries.end());
|
ASSERT(It != mResourceEntries.end());
|
||||||
mResourceEntries.erase(It);
|
mResourceEntries.erase(It);
|
||||||
|
|
||||||
|
@ -667,7 +658,7 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
|
||||||
// Chop name to just after "x_rep"
|
// Chop name to just after "x_rep"
|
||||||
uint32 RepStart = Path.IndexOfPhrase("_rep");
|
uint32 RepStart = Path.IndexOfPhrase("_rep");
|
||||||
|
|
||||||
if (RepStart != -1)
|
if (RepStart != UINT32_MAX)
|
||||||
Path = Path.ChopFront(RepStart + 5);
|
Path = Path.ChopFront(RepStart + 5);
|
||||||
|
|
||||||
// If the "x_rep" folder doesn't exist in this path for some reason, but this is still a path, then just chop off the drive letter.
|
// If the "x_rep" folder doesn't exist in this path for some reason, but this is still a path, then just chop off the drive letter.
|
||||||
|
@ -675,24 +666,24 @@ void CResourceStore::ImportNamesFromPakContentsTxt(const TString& rkTxtPath, boo
|
||||||
else if (Path[1] == ':')
|
else if (Path[1] == ':')
|
||||||
Path = Path.ChopFront(3);
|
Path = Path.ChopFront(3);
|
||||||
|
|
||||||
PathMap[pEntry] = Path;
|
PathMap.insert_or_assign(pEntry, std::move(Path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(pContentsFile);
|
fclose(pContentsFile);
|
||||||
|
|
||||||
// Assign names
|
// Assign names
|
||||||
for (auto Iter = PathMap.begin(); Iter != PathMap.end(); Iter++)
|
for (auto& [entry, path] : PathMap)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = Iter->first;
|
if (UnnamedOnly && entry->IsNamed())
|
||||||
if (UnnamedOnly && pEntry->IsNamed()) continue;
|
continue;
|
||||||
|
|
||||||
TString Path = Iter->second;
|
TString Dir = path.GetFileDirectory();
|
||||||
TString Dir = Path.GetFileDirectory();
|
TString Name = path.GetFileName(false);
|
||||||
TString Name = Path.GetFileName(false);
|
if (Dir.IsEmpty())
|
||||||
if (Dir.IsEmpty()) Dir = pEntry->DirectoryPath();
|
Dir = entry->DirectoryPath();
|
||||||
|
|
||||||
pEntry->MoveAndRename(Dir, Name);
|
entry->MoveAndRename(Dir, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
|
@ -703,13 +694,13 @@ bool CResourceStore::IsValidResourcePath(const TString& rkPath, const TString& r
|
||||||
{
|
{
|
||||||
// Path must not be an absolute path and must not go outside the project structure.
|
// Path must not be an absolute path and must not go outside the project structure.
|
||||||
// Name must not be a path.
|
// Name must not be a path.
|
||||||
return ( CVirtualDirectory::IsValidDirectoryPath(rkPath) &&
|
return CVirtualDirectory::IsValidDirectoryPath(rkPath) &&
|
||||||
FileUtil::IsValidName(rkName, false) &&
|
FileUtil::IsValidName(rkName, false) &&
|
||||||
!rkName.Contains('/') &&
|
!rkName.Contains('/') &&
|
||||||
!rkName.Contains('\\') );
|
!rkName.Contains('\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CResourceStore::StaticDefaultResourceDirPath(EGame Game)
|
TString CResourceStore::StaticDefaultResourceDirPath(EGame Game)
|
||||||
{
|
{
|
||||||
return (Game < EGame::CorruptionProto ? "Uncategorized/" : "uncategorized/");
|
return Game < EGame::CorruptionProto ? "Uncategorized/" : "uncategorized/";
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <Common/FileUtil.h>
|
#include <Common/FileUtil.h>
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
class CGameExporter;
|
class CGameExporter;
|
||||||
|
@ -20,27 +21,27 @@ enum class EDatabaseVersion
|
||||||
// Add new versions before this line
|
// Add new versions before this line
|
||||||
|
|
||||||
Max,
|
Max,
|
||||||
Current = EDatabaseVersion::Max - 1
|
Current = Max - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
class CResourceStore
|
class CResourceStore
|
||||||
{
|
{
|
||||||
friend class CResourceIterator;
|
friend class CResourceIterator;
|
||||||
|
|
||||||
CGameProject *mpProj;
|
CGameProject *mpProj = nullptr;
|
||||||
EGame mGame;
|
EGame mGame{EGame::Prime};
|
||||||
CVirtualDirectory *mpDatabaseRoot;
|
CVirtualDirectory *mpDatabaseRoot = nullptr;
|
||||||
std::map<CAssetID, CResourceEntry*> mResourceEntries;
|
std::map<CAssetID, std::unique_ptr<CResourceEntry>> mResourceEntries;
|
||||||
std::map<CAssetID, CResourceEntry*> mLoadedResources;
|
std::map<CAssetID, CResourceEntry*> mLoadedResources;
|
||||||
bool mDatabaseCacheDirty;
|
bool mDatabaseCacheDirty = false;
|
||||||
|
|
||||||
// Directory paths
|
// Directory paths
|
||||||
TString mDatabasePath;
|
TString mDatabasePath;
|
||||||
bool mDatabasePathExists;
|
bool mDatabasePathExists = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceStore(const TString& rkDatabasePath);
|
explicit CResourceStore(const TString& rkDatabasePath);
|
||||||
CResourceStore(CGameProject *pProject);
|
explicit CResourceStore(CGameProject *pProject);
|
||||||
~CResourceStore();
|
~CResourceStore();
|
||||||
bool SerializeDatabaseCache(IArchive& rArc);
|
bool SerializeDatabaseCache(IArchive& rArc);
|
||||||
bool LoadDatabaseCache();
|
bool LoadDatabaseCache();
|
||||||
|
@ -78,19 +79,19 @@ public:
|
||||||
static TString StaticDefaultResourceDirPath(EGame Game);
|
static TString StaticDefaultResourceDirPath(EGame Game);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CGameProject* Project() const { return mpProj; }
|
CGameProject* Project() const { return mpProj; }
|
||||||
inline EGame Game() const { return mGame; }
|
EGame Game() const { return mGame; }
|
||||||
inline TString DatabaseRootPath() const { return mDatabasePath; }
|
TString DatabaseRootPath() const { return mDatabasePath; }
|
||||||
inline bool DatabasePathExists() const { return mDatabasePathExists; }
|
bool DatabasePathExists() const { return mDatabasePathExists; }
|
||||||
inline TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; }
|
TString ResourcesDir() const { return IsEditorStore() ? DatabaseRootPath() : DatabaseRootPath() + "Resources/"; }
|
||||||
inline TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; }
|
TString DatabasePath() const { return DatabaseRootPath() + "ResourceDatabaseCache.bin"; }
|
||||||
inline CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
|
CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
|
||||||
inline uint32 NumTotalResources() const { return mResourceEntries.size(); }
|
uint32 NumTotalResources() const { return mResourceEntries.size(); }
|
||||||
inline uint32 NumLoadedResources() const { return mLoadedResources.size(); }
|
uint32 NumLoadedResources() const { return mLoadedResources.size(); }
|
||||||
inline bool IsCacheDirty() const { return mDatabaseCacheDirty; }
|
bool IsCacheDirty() const { return mDatabaseCacheDirty; }
|
||||||
|
|
||||||
inline void SetCacheDirty() { mDatabaseCacheDirty = true; }
|
void SetCacheDirty() { mDatabaseCacheDirty = true; }
|
||||||
inline bool IsEditorStore() const { return mpProj == nullptr; }
|
bool IsEditorStore() const { return mpProj == nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TString gDataDir;
|
extern TString gDataDir;
|
||||||
|
|
|
@ -5,25 +5,25 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
CVirtualDirectory::CVirtualDirectory(CResourceStore *pStore)
|
CVirtualDirectory::CVirtualDirectory(CResourceStore *pStore)
|
||||||
: mpParent(nullptr), mpStore(pStore)
|
: mpStore(pStore)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CVirtualDirectory::CVirtualDirectory(const TString& rkName, CResourceStore *pStore)
|
CVirtualDirectory::CVirtualDirectory(const TString& rkName, CResourceStore *pStore)
|
||||||
: mpParent(nullptr), mName(rkName), mpStore(pStore)
|
: mpStore(pStore), mName(rkName)
|
||||||
{
|
{
|
||||||
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
|
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
CVirtualDirectory::CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore)
|
CVirtualDirectory::CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore)
|
||||||
: mpParent(pParent), mName(rkName), mpStore(pStore)
|
: mpParent(pParent), mpStore(pStore), mName(rkName)
|
||||||
{
|
{
|
||||||
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
|
ASSERT(!mName.IsEmpty() && FileUtil::IsValidName(mName, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
CVirtualDirectory::~CVirtualDirectory()
|
CVirtualDirectory::~CVirtualDirectory()
|
||||||
{
|
{
|
||||||
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++)
|
for (auto* subdirectory : mSubdirectories)
|
||||||
delete mSubdirectories[iSub];
|
delete subdirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
|
bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
|
||||||
|
@ -31,9 +31,11 @@ bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
|
||||||
if (!mResources.empty())
|
if (!mResources.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++)
|
for (auto* subdirectory : mSubdirectories)
|
||||||
if (!mSubdirectories[iSub]->IsEmpty(CheckFilesystem))
|
{
|
||||||
|
if (!subdirectory->IsEmpty(CheckFilesystem))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (CheckFilesystem && !FileUtil::IsEmpty( AbsolutePath() ))
|
if (CheckFilesystem && !FileUtil::IsEmpty( AbsolutePath() ))
|
||||||
return false;
|
return false;
|
||||||
|
@ -43,7 +45,7 @@ bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
|
||||||
|
|
||||||
bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const
|
bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const
|
||||||
{
|
{
|
||||||
return (this == pDir) || (mpParent && pDir && (mpParent == pDir || mpParent->IsDescendantOf(pDir)));
|
return (this == pDir) || (mpParent != nullptr && pDir != nullptr && (mpParent == pDir || mpParent->IsDescendantOf(pDir)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::IsSafeToDelete() const
|
bool CVirtualDirectory::IsSafeToDelete() const
|
||||||
|
@ -72,8 +74,8 @@ TString CVirtualDirectory::FullPath() const
|
||||||
{
|
{
|
||||||
if (IsRoot())
|
if (IsRoot())
|
||||||
return "";
|
return "";
|
||||||
else
|
|
||||||
return (mpParent ? mpParent->FullPath() + mName : static_cast<TString::BaseClass>(mName)) + '/';
|
return (mpParent != nullptr ? mpParent->FullPath() + mName : static_cast<TString::BaseClass>(mName)) + '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CVirtualDirectory::AbsolutePath() const
|
TString CVirtualDirectory::AbsolutePath() const
|
||||||
|
@ -83,40 +85,35 @@ TString CVirtualDirectory::AbsolutePath() const
|
||||||
|
|
||||||
CVirtualDirectory* CVirtualDirectory::GetRoot()
|
CVirtualDirectory* CVirtualDirectory::GetRoot()
|
||||||
{
|
{
|
||||||
return (mpParent ? mpParent->GetRoot() : this);
|
return mpParent != nullptr ? mpParent->GetRoot() : this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName, bool AllowCreate)
|
CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName, bool AllowCreate)
|
||||||
{
|
{
|
||||||
uint32 SlashIdx = rkName.IndexOf("\\/");
|
const uint32 SlashIdx = rkName.IndexOf("\\/");
|
||||||
TString DirName = (SlashIdx == -1 ? static_cast<TString::BaseClass>(rkName) : rkName.SubString(0, SlashIdx));
|
const TString DirName = (SlashIdx == UINT32_MAX ? static_cast<TString::BaseClass>(rkName) : rkName.SubString(0, SlashIdx));
|
||||||
|
|
||||||
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++)
|
for (auto* child : mSubdirectories)
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pChild = mSubdirectories[iSub];
|
if (child->Name().CaseInsensitiveCompare(DirName))
|
||||||
|
|
||||||
if (pChild->Name().CaseInsensitiveCompare(DirName))
|
|
||||||
{
|
{
|
||||||
if (SlashIdx == -1)
|
if (SlashIdx == UINT32_MAX)
|
||||||
return pChild;
|
return child;
|
||||||
|
|
||||||
else
|
const TString Remaining = rkName.SubString(SlashIdx + 1, rkName.Size() - SlashIdx);
|
||||||
{
|
|
||||||
TString Remaining = rkName.SubString(SlashIdx + 1, rkName.Size() - SlashIdx);
|
|
||||||
|
|
||||||
if (Remaining.IsEmpty())
|
if (Remaining.IsEmpty())
|
||||||
return pChild;
|
return child;
|
||||||
else
|
|
||||||
return pChild->FindChildDirectory(Remaining, AllowCreate);
|
return child->FindChildDirectory(Remaining, AllowCreate);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AllowCreate)
|
if (AllowCreate)
|
||||||
{
|
{
|
||||||
if ( AddChild(rkName, nullptr) )
|
if (AddChild(rkName, nullptr))
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pOut = FindChildDirectory(rkName, false);
|
CVirtualDirectory* pOut = FindChildDirectory(rkName, false);
|
||||||
ASSERT(pOut != nullptr);
|
ASSERT(pOut != nullptr);
|
||||||
return pOut;
|
return pOut;
|
||||||
}
|
}
|
||||||
|
@ -127,19 +124,19 @@ CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TString& rkName,
|
||||||
|
|
||||||
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath)
|
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath)
|
||||||
{
|
{
|
||||||
TString Dir = rkPath.GetFileDirectory();
|
const TString Dir = rkPath.GetFileDirectory();
|
||||||
TString Name = rkPath.GetFileName();
|
const TString Name = rkPath.GetFileName();
|
||||||
|
|
||||||
if (!Dir.IsEmpty())
|
if (!Dir.IsEmpty())
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pDir = FindChildDirectory(Dir, false);
|
CVirtualDirectory* pDir = FindChildDirectory(Dir, false);
|
||||||
if (pDir) return pDir->FindChildResource(Name);
|
if (pDir != nullptr)
|
||||||
|
return pDir->FindChildResource(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!Name.IsEmpty())
|
else if (!Name.IsEmpty())
|
||||||
{
|
{
|
||||||
TString Ext = Name.GetFileExtension();
|
const TString Ext = Name.GetFileExtension();
|
||||||
EResourceType Type = CResTypeInfo::TypeForCookedExtension(mpStore->Game(), Ext)->Type();
|
const EResourceType Type = CResTypeInfo::TypeForCookedExtension(mpStore->Game(), Ext)->Type();
|
||||||
return FindChildResource(Name.GetFileName(false), Type);
|
return FindChildResource(Name.GetFileName(false), Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,47 +145,48 @@ CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkPath)
|
||||||
|
|
||||||
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkName, EResourceType Type)
|
CResourceEntry* CVirtualDirectory::FindChildResource(const TString& rkName, EResourceType Type)
|
||||||
{
|
{
|
||||||
for (uint32 iRes = 0; iRes < mResources.size(); iRes++)
|
const auto it = std::find_if(mResources.begin(), mResources.end(), [&](const auto* resource) {
|
||||||
{
|
return rkName.CaseInsensitiveCompare(resource->Name()) && resource->ResourceType() == Type;
|
||||||
if (rkName.CaseInsensitiveCompare(mResources[iRes]->Name()) && mResources[iRes]->ResourceType() == Type)
|
});
|
||||||
return mResources[iRes];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
if (it == mResources.cend())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
|
bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
if (rkPath.IsEmpty())
|
if (rkPath.IsEmpty())
|
||||||
{
|
{
|
||||||
if (pEntry)
|
if (pEntry != nullptr)
|
||||||
{
|
{
|
||||||
mResources.push_back(pEntry);
|
mResources.push_back(pEntry);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (IsValidDirectoryPath(rkPath))
|
if (IsValidDirectoryPath(rkPath))
|
||||||
{
|
{
|
||||||
uint32 SlashIdx = rkPath.IndexOf("\\/");
|
const uint32 SlashIdx = rkPath.IndexOf("\\/");
|
||||||
TString DirName = (SlashIdx == -1 ? static_cast<TString::BaseClass>(rkPath) : rkPath.SubString(0, SlashIdx));
|
const TString DirName = (SlashIdx == UINT32_MAX ? static_cast<TString::BaseClass>(rkPath) : rkPath.SubString(0, SlashIdx));
|
||||||
TString Remaining = (SlashIdx == -1 ? "" : rkPath.SubString(SlashIdx + 1, rkPath.Size() - SlashIdx));
|
const TString Remaining = (SlashIdx == UINT32_MAX ? "" : rkPath.SubString(SlashIdx + 1, rkPath.Size() - SlashIdx));
|
||||||
|
|
||||||
// Check if this subdirectory already exists
|
// Check if this subdirectory already exists
|
||||||
CVirtualDirectory *pSubdir = nullptr;
|
CVirtualDirectory* pSubdir = nullptr;
|
||||||
|
|
||||||
for (uint32 iSub = 0; iSub < mSubdirectories.size(); iSub++)
|
for (auto* subdirectory : mSubdirectories)
|
||||||
{
|
{
|
||||||
if (mSubdirectories[iSub]->Name() == DirName)
|
if (subdirectory->Name() == DirName)
|
||||||
{
|
{
|
||||||
pSubdir = mSubdirectories[iSub];
|
pSubdir = subdirectory;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pSubdir)
|
if (pSubdir == nullptr)
|
||||||
{
|
{
|
||||||
// Create new subdirectory
|
// Create new subdirectory
|
||||||
pSubdir = new CVirtualDirectory(this, DirName, mpStore);
|
pSubdir = new CVirtualDirectory(this, DirName, mpStore);
|
||||||
|
@ -206,9 +204,9 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
|
||||||
// We also know none of the remaining directories already exist because this is a new, empty directory.
|
// We also know none of the remaining directories already exist because this is a new, empty directory.
|
||||||
TStringList Components = Remaining.Split("/\\");
|
TStringList Components = Remaining.Split("/\\");
|
||||||
|
|
||||||
for (auto Iter = Components.begin(); Iter != Components.end(); Iter++)
|
for (const auto& component : Components)
|
||||||
{
|
{
|
||||||
pSubdir = new CVirtualDirectory(pSubdir, *Iter, mpStore);
|
pSubdir = new CVirtualDirectory(pSubdir, component, mpStore);
|
||||||
|
|
||||||
if (!pSubdir->CreateFilesystemDirectory())
|
if (!pSubdir->CreateFilesystemDirectory())
|
||||||
{
|
{
|
||||||
|
@ -219,29 +217,30 @@ bool CVirtualDirectory::AddChild(const TString &rkPath, CResourceEntry *pEntry)
|
||||||
pSubdir->Parent()->mSubdirectories.push_back(pSubdir);
|
pSubdir->Parent()->mSubdirectories.push_back(pSubdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pEntry)
|
if (pEntry != nullptr)
|
||||||
pSubdir->mResources.push_back(pEntry);
|
pSubdir->mResources.push_back(pEntry);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have another valid child to add, return whether that operation completed successfully
|
// If we have another valid child to add, return whether that operation completed successfully
|
||||||
else if (!Remaining.IsEmpty() || pEntry)
|
if (!Remaining.IsEmpty() || pEntry != nullptr)
|
||||||
return pSubdir->AddChild(Remaining, pEntry);
|
return pSubdir->AddChild(Remaining, pEntry);
|
||||||
|
|
||||||
// Otherwise, we're done, so just return true
|
// Otherwise, we're done, so just return true
|
||||||
else
|
return true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir)
|
bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir)
|
||||||
{
|
{
|
||||||
if (pDir->Parent() != this) return false;
|
if (pDir->Parent() != this)
|
||||||
if (FindChildDirectory(pDir->Name(), false) != nullptr) return false;
|
return false;
|
||||||
|
|
||||||
|
if (FindChildDirectory(pDir->Name(), false) != nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
mSubdirectories.push_back(pDir);
|
mSubdirectories.push_back(pDir);
|
||||||
SortSubdirectories();
|
SortSubdirectories();
|
||||||
|
@ -251,36 +250,32 @@ bool CVirtualDirectory::AddChild(CVirtualDirectory *pDir)
|
||||||
|
|
||||||
bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir)
|
bool CVirtualDirectory::RemoveChildDirectory(CVirtualDirectory *pSubdir)
|
||||||
{
|
{
|
||||||
for (auto It = mSubdirectories.begin(); It != mSubdirectories.end(); It++)
|
const auto it = std::find_if(mSubdirectories.cbegin(), mSubdirectories.cend(),
|
||||||
{
|
[pSubdir](const auto* dir) { return dir == pSubdir; });
|
||||||
if (*It == pSubdir)
|
|
||||||
{
|
|
||||||
mSubdirectories.erase(It);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if (it == mSubdirectories.cend())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mSubdirectories.erase(it);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::RemoveChildResource(CResourceEntry *pEntry)
|
bool CVirtualDirectory::RemoveChildResource(CResourceEntry *pEntry)
|
||||||
{
|
{
|
||||||
for (auto It = mResources.begin(); It != mResources.end(); It++)
|
const auto it = std::find_if(mResources.cbegin(), mResources.cend(),
|
||||||
{
|
[pEntry](const auto* resource) { return resource == pEntry; });
|
||||||
if (*It == pEntry)
|
|
||||||
{
|
|
||||||
mResources.erase(It);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if (it == mResources.cend())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mResources.erase(it);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVirtualDirectory::SortSubdirectories()
|
void CVirtualDirectory::SortSubdirectories()
|
||||||
{
|
{
|
||||||
std::sort(mSubdirectories.begin(), mSubdirectories.end(), [](CVirtualDirectory *pLeft, CVirtualDirectory *pRight) -> bool {
|
std::sort(mSubdirectories.begin(), mSubdirectories.end(), [](const auto* pLeft, const auto* pRight) {
|
||||||
return (pLeft->Name().ToUpper() < pRight->Name().ToUpper());
|
return pLeft->Name().ToUpper() < pRight->Name().ToUpper();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,10 +285,10 @@ bool CVirtualDirectory::Rename(const TString& rkNewName)
|
||||||
|
|
||||||
if (!IsRoot())
|
if (!IsRoot())
|
||||||
{
|
{
|
||||||
if (!mpParent->FindChildDirectory(rkNewName, false))
|
if (mpParent->FindChildDirectory(rkNewName, false) == nullptr)
|
||||||
{
|
{
|
||||||
TString AbsPath = AbsolutePath();
|
const TString AbsPath = AbsolutePath();
|
||||||
TString NewPath = mpParent->AbsolutePath() + rkNewName + "/";
|
const TString NewPath = mpParent->AbsolutePath() + rkNewName + "/";
|
||||||
|
|
||||||
if (FileUtil::MoveDirectory(AbsPath, NewPath))
|
if (FileUtil::MoveDirectory(AbsPath, NewPath))
|
||||||
{
|
{
|
||||||
|
@ -317,7 +312,7 @@ bool CVirtualDirectory::Delete()
|
||||||
{
|
{
|
||||||
if (FileUtil::DeleteDirectory(AbsolutePath(), true))
|
if (FileUtil::DeleteDirectory(AbsolutePath(), true))
|
||||||
{
|
{
|
||||||
if (!mpParent || mpParent->RemoveChildDirectory(this))
|
if (mpParent == nullptr || mpParent->RemoveChildDirectory(this))
|
||||||
{
|
{
|
||||||
mpStore->SetCacheDirty();
|
mpStore->SetCacheDirty();
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -331,7 +326,7 @@ bool CVirtualDirectory::Delete()
|
||||||
|
|
||||||
void CVirtualDirectory::DeleteEmptySubdirectories()
|
void CVirtualDirectory::DeleteEmptySubdirectories()
|
||||||
{
|
{
|
||||||
for (uint32 SubdirIdx = 0; SubdirIdx < mSubdirectories.size(); SubdirIdx++)
|
for (size_t SubdirIdx = 0; SubdirIdx < mSubdirectories.size(); SubdirIdx++)
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pDir = mSubdirectories[SubdirIdx];
|
CVirtualDirectory *pDir = mSubdirectories[SubdirIdx];
|
||||||
|
|
||||||
|
@ -341,17 +336,19 @@ void CVirtualDirectory::DeleteEmptySubdirectories()
|
||||||
SubdirIdx--;
|
SubdirIdx--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
pDir->DeleteEmptySubdirectories();
|
pDir->DeleteEmptySubdirectories();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::CreateFilesystemDirectory()
|
bool CVirtualDirectory::CreateFilesystemDirectory()
|
||||||
{
|
{
|
||||||
TString AbsPath = AbsolutePath();
|
const TString AbsPath = AbsolutePath();
|
||||||
|
|
||||||
if (!FileUtil::Exists(AbsPath))
|
if (!FileUtil::Exists(AbsPath))
|
||||||
{
|
{
|
||||||
bool CreateSuccess = FileUtil::MakeDirectory(AbsPath);
|
const bool CreateSuccess = FileUtil::MakeDirectory(AbsPath);
|
||||||
|
|
||||||
if (!CreateSuccess)
|
if (!CreateSuccess)
|
||||||
errorf("FAILED to create filesystem directory: %s", *AbsPath);
|
errorf("FAILED to create filesystem directory: %s", *AbsPath);
|
||||||
|
@ -365,22 +362,23 @@ bool CVirtualDirectory::CreateFilesystemDirectory()
|
||||||
bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
|
bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
|
||||||
{
|
{
|
||||||
ASSERT(!pParent->IsDescendantOf(this));
|
ASSERT(!pParent->IsDescendantOf(this));
|
||||||
if (mpParent == pParent) return true;
|
if (mpParent == pParent)
|
||||||
|
return true;
|
||||||
|
|
||||||
debugf("MOVING DIRECTORY: %s -> %s", *FullPath(), *(pParent->FullPath() + mName + '/'));
|
debugf("MOVING DIRECTORY: %s -> %s", *FullPath(), *(pParent->FullPath() + mName + '/'));
|
||||||
|
|
||||||
// Check for a conflict
|
// Check for a conflict
|
||||||
CVirtualDirectory *pConflictDir = pParent->FindChildDirectory(mName, false);
|
CVirtualDirectory *pConflictDir = pParent->FindChildDirectory(mName, false);
|
||||||
|
|
||||||
if (pConflictDir)
|
if (pConflictDir != nullptr)
|
||||||
{
|
{
|
||||||
errorf("DIRECTORY MOVE FAILED: Conflicting directory exists at the destination path!");
|
errorf("DIRECTORY MOVE FAILED: Conflicting directory exists at the destination path!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move filesystem contents to new path
|
// Move filesystem contents to new path
|
||||||
TString AbsOldPath = mpStore->ResourcesDir() + FullPath();
|
const TString AbsOldPath = mpStore->ResourcesDir() + FullPath();
|
||||||
TString AbsNewPath = mpStore->ResourcesDir() + pParent->FullPath() + mName + '/';
|
const TString AbsNewPath = mpStore->ResourcesDir() + pParent->FullPath() + mName + '/';
|
||||||
|
|
||||||
if (mpParent->RemoveChildDirectory(this) && FileUtil::MoveDirectory(AbsOldPath, AbsNewPath))
|
if (mpParent->RemoveChildDirectory(this) && FileUtil::MoveDirectory(AbsOldPath, AbsNewPath))
|
||||||
{
|
{
|
||||||
|
@ -400,9 +398,9 @@ bool CVirtualDirectory::SetParent(CVirtualDirectory *pParent)
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
bool CVirtualDirectory::IsValidDirectoryName(const TString& rkName)
|
bool CVirtualDirectory::IsValidDirectoryName(const TString& rkName)
|
||||||
{
|
{
|
||||||
return ( rkName != "." &&
|
return rkName != "." &&
|
||||||
rkName != ".." &&
|
rkName != ".." &&
|
||||||
FileUtil::IsValidName(rkName, true) );
|
FileUtil::IsValidName(rkName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::IsValidDirectoryPath(TString Path)
|
bool CVirtualDirectory::IsValidDirectoryPath(TString Path)
|
||||||
|
@ -415,13 +413,6 @@ bool CVirtualDirectory::IsValidDirectoryPath(TString Path)
|
||||||
if (Path.EndsWith('/') || Path.EndsWith('\\'))
|
if (Path.EndsWith('/') || Path.EndsWith('\\'))
|
||||||
Path = Path.ChopBack(1);
|
Path = Path.ChopBack(1);
|
||||||
|
|
||||||
TStringList Parts = Path.Split("/\\", true);
|
const TStringList Parts = Path.Split("/\\", true);
|
||||||
|
return std::all_of(Parts.cbegin(), Parts.cend(), IsValidDirectoryPath);
|
||||||
for (auto Iter = Parts.begin(); Iter != Parts.end(); Iter++)
|
|
||||||
{
|
|
||||||
if (!IsValidDirectoryName(*Iter))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,14 @@ class CResourceStore;
|
||||||
|
|
||||||
class CVirtualDirectory
|
class CVirtualDirectory
|
||||||
{
|
{
|
||||||
CVirtualDirectory *mpParent;
|
CVirtualDirectory *mpParent = nullptr;
|
||||||
CResourceStore *mpStore;
|
CResourceStore *mpStore;
|
||||||
TString mName;
|
TString mName;
|
||||||
std::vector<CVirtualDirectory*> mSubdirectories;
|
std::vector<CVirtualDirectory*> mSubdirectories;
|
||||||
std::vector<CResourceEntry*> mResources;
|
std::vector<CResourceEntry*> mResources;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CVirtualDirectory(CResourceStore *pStore);
|
explicit CVirtualDirectory(CResourceStore *pStore);
|
||||||
CVirtualDirectory(const TString& rkName, CResourceStore *pStore);
|
CVirtualDirectory(const TString& rkName, CResourceStore *pStore);
|
||||||
CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore);
|
CVirtualDirectory(CVirtualDirectory *pParent, const TString& rkName, CResourceStore *pStore);
|
||||||
~CVirtualDirectory();
|
~CVirtualDirectory();
|
||||||
|
@ -48,14 +48,16 @@ public:
|
||||||
static bool IsValidDirectoryPath(TString Path);
|
static bool IsValidDirectoryPath(TString Path);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CVirtualDirectory* Parent() const { return mpParent; }
|
CVirtualDirectory* Parent() const { return mpParent; }
|
||||||
inline bool IsRoot() const { return !mpParent; }
|
bool IsRoot() const { return !mpParent; }
|
||||||
inline TString Name() const { return mName; }
|
TString Name() const { return mName; }
|
||||||
|
|
||||||
inline uint32 NumSubdirectories() const { return mSubdirectories.size(); }
|
size_t NumSubdirectories() const { return mSubdirectories.size(); }
|
||||||
inline CVirtualDirectory* SubdirectoryByIndex(uint32 Index) { return mSubdirectories[Index]; }
|
CVirtualDirectory* SubdirectoryByIndex(size_t Index) { return mSubdirectories[Index]; }
|
||||||
inline uint32 NumResources() const { return mResources.size(); }
|
const CVirtualDirectory* SubdirectoryByIndex(size_t Index) const { return mSubdirectories[Index]; }
|
||||||
inline CResourceEntry* ResourceByIndex(uint32 Index) { return mResources[Index]; }
|
size_t NumResources() const { return mResources.size(); }
|
||||||
|
CResourceEntry* ResourceByIndex(size_t Index) { return mResources[Index]; }
|
||||||
|
const CResourceEntry* ResourceByIndex(size_t Index) const { return mResources[Index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CVIRTUALDIRECTORY
|
#endif // CVIRTUALDIRECTORY
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
#include "DependencyListBuilders.h"
|
#include "DependencyListBuilders.h"
|
||||||
|
|
||||||
// ************ CCharacterUsageMap ************
|
// ************ CCharacterUsageMap ************
|
||||||
bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, uint32 CharacterIndex) const
|
bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, size_t CharacterIndex) const
|
||||||
{
|
{
|
||||||
if (mpStore->Game() >= EGame::CorruptionProto) return true;
|
if (mpStore->Game() >= EGame::CorruptionProto)
|
||||||
auto Find = mUsageMap.find(rkID);
|
return true;
|
||||||
if (Find == mUsageMap.end()) return false;
|
|
||||||
|
const auto Find = mUsageMap.find(rkID);
|
||||||
|
if (Find == mUsageMap.cend())
|
||||||
|
return false;
|
||||||
|
|
||||||
const std::vector<bool>& rkUsageList = Find->second;
|
const std::vector<bool>& rkUsageList = Find->second;
|
||||||
if (CharacterIndex >= rkUsageList.size()) return false;
|
if (CharacterIndex >= rkUsageList.size())
|
||||||
else return rkUsageList[CharacterIndex];
|
return false;
|
||||||
|
|
||||||
|
return rkUsageList[CharacterIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const
|
bool CCharacterUsageMap::IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const
|
||||||
{
|
{
|
||||||
auto Find = mUsageMap.find(rkID);
|
const auto Find = mUsageMap.find(rkID);
|
||||||
if (Find == mUsageMap.end()) return false;
|
if (Find == mUsageMap.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
const std::vector<bool>& rkUsageList = Find->second;
|
const std::vector<bool>& rkUsageList = Find->second;
|
||||||
|
|
||||||
for (uint32 iChar = 0; iChar < rkUsageList.size(); iChar++)
|
for (uint32 iChar = 0; iChar < rkUsageList.size(); iChar++)
|
||||||
|
@ -37,7 +44,7 @@ void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntr
|
||||||
{
|
{
|
||||||
ASSERT(pEntry->ResourceType() == EResourceType::Area);
|
ASSERT(pEntry->ResourceType() == EResourceType::Area);
|
||||||
|
|
||||||
for (uint32 iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
for (size_t iArea = 0; iArea < pWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
if (pWorld->AreaResourceID(iArea) == pEntry->ID())
|
if (pWorld->AreaResourceID(iArea) == pEntry->ID())
|
||||||
{
|
{
|
||||||
|
@ -47,17 +54,19 @@ void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, uint32 AreaIndex)
|
void CCharacterUsageMap::FindUsagesForArea(CWorld *pWorld, size_t AreaIndex)
|
||||||
{
|
{
|
||||||
// We only need to search forward from this area to other areas that both use the same character(s) + have duplicates enabled
|
// We only need to search forward from this area to other areas that both use the same character(s) + have duplicates enabled
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
for (uint32 iArea = AreaIndex; iArea < pWorld->NumAreas(); iArea++)
|
for (size_t iArea = AreaIndex; iArea < pWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
if (!mIsInitialArea && mStillLookingIDs.empty()) break;
|
if (!mIsInitialArea && mStillLookingIDs.empty())
|
||||||
|
break;
|
||||||
|
|
||||||
mCurrentAreaAllowsDupes = pWorld->DoesAreaAllowPakDuplicates(iArea);
|
mCurrentAreaAllowsDupes = pWorld->DoesAreaAllowPakDuplicates(iArea);
|
||||||
|
|
||||||
CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
const CAssetID AreaID = pWorld->AreaResourceID(iArea);
|
||||||
CResourceEntry *pEntry = mpStore->FindEntry(AreaID);
|
CResourceEntry *pEntry = mpStore->FindEntry(AreaID);
|
||||||
ASSERT(pEntry && pEntry->ResourceType() == EResourceType::Area);
|
ASSERT(pEntry && pEntry->ResourceType() == EResourceType::Area);
|
||||||
|
|
||||||
|
@ -75,11 +84,11 @@ void CCharacterUsageMap::FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 L
|
||||||
ASSERT(pTree->Type() == EDependencyNodeType::Area);
|
ASSERT(pTree->Type() == EDependencyNodeType::Area);
|
||||||
|
|
||||||
// Only examine dependencies of the particular layer specified by the caller
|
// Only examine dependencies of the particular layer specified by the caller
|
||||||
bool IsLastLayer = (mLayerIndex == pTree->NumScriptLayers() - 1);
|
const bool IsLastLayer = mLayerIndex == pTree->NumScriptLayers() - 1;
|
||||||
uint32 StartIdx = pTree->ScriptLayerOffset(mLayerIndex);
|
const size_t StartIdx = pTree->ScriptLayerOffset(mLayerIndex);
|
||||||
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(mLayerIndex + 1));
|
const size_t EndIdx = IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(mLayerIndex + 1);
|
||||||
|
|
||||||
for (uint32 iInst = StartIdx; iInst < EndIdx; iInst++)
|
for (size_t iInst = StartIdx; iInst < EndIdx; iInst++)
|
||||||
ParseDependencyNode(pTree->ChildByIndex(iInst));
|
ParseDependencyNode(pTree->ChildByIndex(iInst));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +96,7 @@ void CCharacterUsageMap::Clear()
|
||||||
{
|
{
|
||||||
mUsageMap.clear();
|
mUsageMap.clear();
|
||||||
mStillLookingIDs.clear();
|
mStillLookingIDs.clear();
|
||||||
mLayerIndex = -1;
|
mLayerIndex = UINT32_MAX;
|
||||||
mIsInitialArea = true;
|
mIsInitialArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,17 +104,15 @@ void CCharacterUsageMap::Clear()
|
||||||
|
|
||||||
void CCharacterUsageMap::DebugPrintContents()
|
void CCharacterUsageMap::DebugPrintContents()
|
||||||
{
|
{
|
||||||
for (auto Iter = mUsageMap.begin(); Iter != mUsageMap.end(); Iter++)
|
for (const auto& [ID, usedList] : mUsageMap)
|
||||||
{
|
{
|
||||||
CAssetID ID = Iter->first;
|
const auto* pSet = mpStore->LoadResource<CAnimSet>(ID);
|
||||||
std::vector<bool>& rUsedList = Iter->second;
|
|
||||||
CAnimSet *pSet = mpStore->LoadResource<CAnimSet>(ID);
|
|
||||||
|
|
||||||
for (uint32 iChar = 0; iChar < pSet->NumCharacters(); iChar++)
|
for (size_t iChar = 0; iChar < pSet->NumCharacters(); iChar++)
|
||||||
{
|
{
|
||||||
bool Used = (rUsedList.size() > iChar && rUsedList[iChar]);
|
const bool Used = usedList.size() > iChar && usedList[iChar];
|
||||||
TString CharName = pSet->Character(iChar)->Name;
|
const TString CharName = pSet->Character(iChar)->Name;
|
||||||
debugf("%s : Char %d : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED"));
|
debugf("%s : Char %zu : %s : %s", *ID.ToString(), iChar, *CharName, (Used ? "USED" : "UNUSED"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,59 +120,59 @@ void CCharacterUsageMap::DebugPrintContents()
|
||||||
// ************ PROTECTED ************
|
// ************ PROTECTED ************
|
||||||
void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
|
void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode)
|
||||||
{
|
{
|
||||||
if (!pNode) return;
|
if (!pNode)
|
||||||
EDependencyNodeType Type = pNode->Type();
|
return;
|
||||||
|
|
||||||
|
const EDependencyNodeType Type = pNode->Type();
|
||||||
|
|
||||||
if (Type == EDependencyNodeType::CharacterProperty)
|
if (Type == EDependencyNodeType::CharacterProperty)
|
||||||
{
|
{
|
||||||
CCharPropertyDependency *pDep = static_cast<CCharPropertyDependency*>(pNode);
|
auto *pDep = static_cast<CCharPropertyDependency*>(pNode);
|
||||||
CAssetID ResID = pDep->ID();
|
const CAssetID ResID = pDep->ID();
|
||||||
auto Find = mUsageMap.find(ResID);
|
const auto Find = mUsageMap.find(ResID);
|
||||||
|
|
||||||
if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.end())
|
if (!mIsInitialArea && mStillLookingIDs.find(ResID) == mStillLookingIDs.cend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Find != mUsageMap.end())
|
if (Find != mUsageMap.cend())
|
||||||
{
|
{
|
||||||
if (!mIsInitialArea && mCurrentAreaAllowsDupes)
|
if (!mIsInitialArea && mCurrentAreaAllowsDupes)
|
||||||
{
|
{
|
||||||
mStillLookingIDs.erase( mStillLookingIDs.find(ResID) );
|
mStillLookingIDs.erase(mStillLookingIDs.find(ResID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!mIsInitialArea) return;
|
if (!mIsInitialArea)
|
||||||
mUsageMap[ResID] = std::vector<bool>();
|
return;
|
||||||
|
|
||||||
|
mUsageMap.insert_or_assign(ResID, std::vector<bool>());
|
||||||
mStillLookingIDs.insert(ResID);
|
mStillLookingIDs.insert(ResID);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<bool>& rUsageList = mUsageMap[ResID];
|
std::vector<bool>& rUsageList = mUsageMap[ResID];
|
||||||
uint32 UsedChar = pDep->UsedChar();
|
const uint32 UsedChar = pDep->UsedChar();
|
||||||
|
|
||||||
if (rUsageList.size() <= UsedChar)
|
if (rUsageList.size() <= UsedChar)
|
||||||
rUsageList.resize(UsedChar + 1, false);
|
rUsageList.resize(UsedChar + 1, false);
|
||||||
|
|
||||||
rUsageList[UsedChar] = true;
|
rUsageList[UsedChar] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse dependencies of the referenced resource if it's a type that can reference animsets
|
// Parse dependencies of the referenced resource if it's a type that can reference animsets
|
||||||
else if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty)
|
else if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty)
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
auto* pDep = static_cast<CResourceDependency*>(pNode);
|
||||||
CResourceEntry *pEntry = mpStore->FindEntry(pDep->ID());
|
CResourceEntry* pEntry = mpStore->FindEntry(pDep->ID());
|
||||||
|
|
||||||
if (pEntry && pEntry->ResourceType() == EResourceType::Scan)
|
if (pEntry != nullptr && pEntry->ResourceType() == EResourceType::Scan)
|
||||||
{
|
{
|
||||||
ParseDependencyNode(pEntry->Dependencies());
|
ParseDependencyNode(pEntry->Dependencies());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Look for sub-dependencies of the current node
|
||||||
// Look for sub-dependencies of the current node
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||||
ParseDependencyNode(pNode->ChildByIndex(iChild));
|
ParseDependencyNode(pNode->ChildByIndex(iChild));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,11 +184,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
|
||||||
FindUniversalAreaAssets();
|
FindUniversalAreaAssets();
|
||||||
|
|
||||||
// Iterate over all resources and parse their dependencies
|
// Iterate over all resources and parse their dependencies
|
||||||
for (uint32 iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++)
|
for (size_t iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = mpkPackage->NamedResourceByIndex(iRes);
|
const SNamedResource& rkRes = mpkPackage->NamedResourceByIndex(iRes);
|
||||||
CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID);
|
CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID);
|
||||||
if (!pEntry) continue;
|
if (!pEntry)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG")
|
if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG")
|
||||||
{
|
{
|
||||||
|
@ -189,16 +197,17 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsUniversalAreaAsset = (mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.end());
|
mIsUniversalAreaAsset = mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.cend();
|
||||||
|
|
||||||
if (rkRes.Type == "MLVL")
|
if (rkRes.Type == "MLVL")
|
||||||
{
|
{
|
||||||
mpWorld = (CWorld*) pEntry->Load();
|
mpWorld = static_cast<CWorld*>(pEntry->Load());
|
||||||
ASSERT(mpWorld);
|
ASSERT(mpWorld);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
mCharacterUsageMap.FindUsagesForAsset(pEntry);
|
mCharacterUsageMap.FindUsagesForAsset(pEntry);
|
||||||
|
}
|
||||||
|
|
||||||
AddDependency(nullptr, rkRes.ID, rOut);
|
AddDependency(nullptr, rkRes.ID, rOut);
|
||||||
mpWorld = nullptr;
|
mpWorld = nullptr;
|
||||||
|
@ -207,9 +216,12 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st
|
||||||
|
|
||||||
void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut)
|
void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list<CAssetID>& rOut)
|
||||||
{
|
{
|
||||||
if (pCurEntry && pCurEntry->ResourceType() == EResourceType::DependencyGroup) return;
|
if (pCurEntry && pCurEntry->ResourceType() == EResourceType::DependencyGroup)
|
||||||
|
return;
|
||||||
|
|
||||||
CResourceEntry *pEntry = mpStore->FindEntry(rkID);
|
CResourceEntry *pEntry = mpStore->FindEntry(rkID);
|
||||||
if (!pEntry) return;
|
if (!pEntry)
|
||||||
|
return;
|
||||||
|
|
||||||
EResourceType ResType = pEntry->ResourceType();
|
EResourceType ResType = pEntry->ResourceType();
|
||||||
|
|
||||||
|
@ -219,13 +231,16 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||||
(ResType != EResourceType::World || !pCurEntry) &&
|
(ResType != EResourceType::World || !pCurEntry) &&
|
||||||
(ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World);
|
(ResType != EResourceType::Area || !pCurEntry || pCurEntry->ResourceType() == EResourceType::World);
|
||||||
|
|
||||||
if (!IsValid) return;
|
if (!IsValid)
|
||||||
|
|
||||||
if ( ( mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) ||
|
|
||||||
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ||
|
|
||||||
(!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end() ) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if ((mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) ||
|
||||||
|
(!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ||
|
||||||
|
(!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Entry is valid, parse its sub-dependencies
|
// Entry is valid, parse its sub-dependencies
|
||||||
mPackageUsedAssets.insert(rkID);
|
mPackageUsedAssets.insert(rkID);
|
||||||
mAreaUsedAssets.insert(rkID);
|
mAreaUsedAssets.insert(rkID);
|
||||||
|
@ -241,7 +256,7 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||||
|
|
||||||
if (mEnableDuplicates)
|
if (mEnableDuplicates)
|
||||||
{
|
{
|
||||||
for (uint32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
|
for (size_t iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
|
||||||
{
|
{
|
||||||
if (mpWorld->AreaResourceID(iArea) == rkID)
|
if (mpWorld->AreaResourceID(iArea) == rkID)
|
||||||
{
|
{
|
||||||
|
@ -251,10 +266,11 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animset - keep track of the current animset ID
|
// Animset - keep track of the current animset ID
|
||||||
else if (ResType == EResourceType::AnimSet)
|
else if (ResType == EResourceType::AnimSet)
|
||||||
|
{
|
||||||
mCurrentAnimSetID = rkID;
|
mCurrentAnimSetID = rkID;
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluate dependencies of this entry
|
// Evaluate dependencies of this entry
|
||||||
CDependencyTree *pTree = pEntry->Dependencies();
|
CDependencyTree *pTree = pEntry->Dependencies();
|
||||||
|
@ -264,7 +280,6 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||||
// Revert current animset ID
|
// Revert current animset ID
|
||||||
if (ResType == EResourceType::AnimSet)
|
if (ResType == EResourceType::AnimSet)
|
||||||
mCurrentAnimSetID = CAssetID::InvalidID(mGame);
|
mCurrentAnimSetID = CAssetID::InvalidID(mGame);
|
||||||
|
|
||||||
// Revert duplicate flag
|
// Revert duplicate flag
|
||||||
else if (ResType == EResourceType::Area)
|
else if (ResType == EResourceType::Area)
|
||||||
mCurrentAreaHasDuplicates = false;
|
mCurrentAreaHasDuplicates = false;
|
||||||
|
@ -272,54 +287,54 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||||
|
|
||||||
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
|
void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut)
|
||||||
{
|
{
|
||||||
if (!pNode) return;
|
if (!pNode)
|
||||||
EDependencyNodeType Type = pNode->Type();
|
return;
|
||||||
|
|
||||||
|
const EDependencyNodeType Type = pNode->Type();
|
||||||
bool ParseChildren = false;
|
bool ParseChildren = false;
|
||||||
|
|
||||||
// Straight resource dependencies should just be added to the tree directly
|
// Straight resource dependencies should just be added to the tree directly
|
||||||
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
const auto *pDep = static_cast<CResourceDependency*>(pNode);
|
||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
AddDependency(pCurEntry, pDep->ID(), rOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anim events should be added if either they apply to characters, or their character index is used
|
// Anim events should be added if either they apply to characters, or their character index is used
|
||||||
else if (Type == EDependencyNodeType::AnimEvent)
|
else if (Type == EDependencyNodeType::AnimEvent)
|
||||||
{
|
{
|
||||||
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
|
const auto *pDep = static_cast<CAnimEventDependency*>(pNode);
|
||||||
uint32 CharIndex = pDep->CharIndex();
|
const uint32 CharIndex = pDep->CharIndex();
|
||||||
|
|
||||||
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
||||||
AddDependency(pCurEntry, pDep->ID(), rOut);
|
AddDependency(pCurEntry, pDep->ID(), rOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set characters should only be added if their character index is used
|
// Set characters should only be added if their character index is used
|
||||||
else if (Type == EDependencyNodeType::SetCharacter)
|
else if (Type == EDependencyNodeType::SetCharacter)
|
||||||
{
|
{
|
||||||
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
const auto *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || mIsPlayerActor;
|
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || mIsPlayerActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set animations should only be added if they're being used by at least one used character
|
// Set animations should only be added if they're being used by at least one used character
|
||||||
else if (Type == EDependencyNodeType::SetAnimation)
|
else if (Type == EDependencyNodeType::SetAnimation)
|
||||||
{
|
{
|
||||||
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
auto *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
||||||
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
|
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ParseChildren = true;
|
ParseChildren = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Analyze this node's children
|
// Analyze this node's children
|
||||||
if (ParseChildren)
|
if (ParseChildren)
|
||||||
{
|
{
|
||||||
if (Type == EDependencyNodeType::ScriptInstance)
|
if (Type == EDependencyNodeType::ScriptInstance)
|
||||||
{
|
{
|
||||||
uint32 ObjType = static_cast<CScriptInstanceDependency*>(pNode)->ObjectType();
|
const uint32 ObjType = static_cast<CScriptInstanceDependency*>(pNode)->ObjectType();
|
||||||
mIsPlayerActor = (ObjType == 0x4C || ObjType == FOURCC('PLAC'));
|
mIsPlayerActor = (ObjType == 0x4C || ObjType == FOURCC('PLAC'));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||||
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
|
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
|
||||||
|
|
||||||
if (Type == EDependencyNodeType::ScriptInstance)
|
if (Type == EDependencyNodeType::ScriptInstance)
|
||||||
|
@ -335,7 +350,7 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
|
||||||
if (pPackage)
|
if (pPackage)
|
||||||
{
|
{
|
||||||
// Iterate over all the package contents, keep track of all universal area assets
|
// Iterate over all the package contents, keep track of all universal area assets
|
||||||
for (uint32 ResIdx = 0; ResIdx < pPackage->NumNamedResources(); ResIdx++)
|
for (size_t ResIdx = 0; ResIdx < pPackage->NumNamedResources(); ResIdx++)
|
||||||
{
|
{
|
||||||
const SNamedResource& rkRes = pPackage->NamedResourceByIndex(ResIdx);
|
const SNamedResource& rkRes = pPackage->NamedResourceByIndex(ResIdx);
|
||||||
|
|
||||||
|
@ -351,22 +366,22 @@ void CPackageDependencyListBuilder::FindUniversalAreaAssets()
|
||||||
if (pUniverseWorld)
|
if (pUniverseWorld)
|
||||||
{
|
{
|
||||||
// Area IDs
|
// Area IDs
|
||||||
for (uint32 AreaIdx = 0; AreaIdx < pUniverseWorld->NumAreas(); AreaIdx++)
|
for (size_t AreaIdx = 0; AreaIdx < pUniverseWorld->NumAreas(); AreaIdx++)
|
||||||
{
|
{
|
||||||
CAssetID AreaID = pUniverseWorld->AreaResourceID(AreaIdx);
|
const CAssetID AreaID = pUniverseWorld->AreaResourceID(AreaIdx);
|
||||||
|
|
||||||
if (AreaID.IsValid())
|
if (AreaID.IsValid())
|
||||||
mUniversalAreaAssets.insert(AreaID);
|
mUniversalAreaAssets.insert(AreaID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map IDs
|
// Map IDs
|
||||||
CDependencyGroup *pMapWorld = (CDependencyGroup*) pUniverseWorld->MapWorld();
|
auto *pMapWorld = static_cast<CDependencyGroup*>(pUniverseWorld->MapWorld());
|
||||||
|
|
||||||
if (pMapWorld)
|
if (pMapWorld)
|
||||||
{
|
{
|
||||||
for (uint32 DepIdx = 0; DepIdx < pMapWorld->NumDependencies(); DepIdx++)
|
for (size_t DepIdx = 0; DepIdx < pMapWorld->NumDependencies(); DepIdx++)
|
||||||
{
|
{
|
||||||
CAssetID DepID = pMapWorld->DependencyByIndex(DepIdx);
|
const CAssetID DepID = pMapWorld->DependencyByIndex(DepIdx);
|
||||||
|
|
||||||
if (DepID.IsValid())
|
if (DepID.IsValid())
|
||||||
mUniversalAreaAssets.insert(DepID);
|
mUniversalAreaAssets.insert(DepID);
|
||||||
|
@ -385,53 +400,55 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||||
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
|
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
|
||||||
|
|
||||||
// Fill area base used assets set (don't actually add to list yet)
|
// Fill area base used assets set (don't actually add to list yet)
|
||||||
uint32 BaseEndIndex = (pTree->NumScriptLayers() > 0 ? pTree->ScriptLayerOffset(0) : pTree->NumChildren());
|
const size_t BaseEndIndex = pTree->NumScriptLayers() > 0 ? pTree->ScriptLayerOffset(0) : pTree->NumChildren();
|
||||||
|
|
||||||
for (uint32 iDep = 0; iDep < BaseEndIndex; iDep++)
|
for (size_t iDep = 0; iDep < BaseEndIndex; iDep++)
|
||||||
{
|
{
|
||||||
CResourceDependency *pRes = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
const auto* pRes = static_cast<const CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||||
ASSERT(pRes->Type() == EDependencyNodeType::Resource);
|
ASSERT(pRes->Type() == EDependencyNodeType::Resource);
|
||||||
mBaseUsedAssets.insert(pRes->ID());
|
mBaseUsedAssets.insert(pRes->ID());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get dependencies of each layer
|
// Get dependencies of each layer
|
||||||
for (uint32 iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
|
for (size_t iLyr = 0; iLyr < pTree->NumScriptLayers(); iLyr++)
|
||||||
{
|
{
|
||||||
mLayerUsedAssets.clear();
|
mLayerUsedAssets.clear();
|
||||||
mCharacterUsageMap.FindUsagesForLayer(mpAreaEntry, iLyr);
|
mCharacterUsageMap.FindUsagesForLayer(mpAreaEntry, iLyr);
|
||||||
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
||||||
|
|
||||||
bool IsLastLayer = (iLyr == pTree->NumScriptLayers() - 1);
|
const bool IsLastLayer = iLyr == pTree->NumScriptLayers() - 1;
|
||||||
uint32 StartIdx = pTree->ScriptLayerOffset(iLyr);
|
const size_t StartIdx = pTree->ScriptLayerOffset(iLyr);
|
||||||
uint32 EndIdx = (IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(iLyr + 1));
|
const size_t EndIdx = IsLastLayer ? pTree->NumChildren() : pTree->ScriptLayerOffset(iLyr + 1);
|
||||||
|
|
||||||
for (uint32 iChild = StartIdx; iChild < EndIdx; iChild++)
|
for (size_t iChild = StartIdx; iChild < EndIdx; iChild++)
|
||||||
{
|
{
|
||||||
IDependencyNode *pNode = pTree->ChildByIndex(iChild);
|
const IDependencyNode *pNode = pTree->ChildByIndex(iChild);
|
||||||
|
|
||||||
if (pNode->Type() == EDependencyNodeType::ScriptInstance)
|
if (pNode->Type() == EDependencyNodeType::ScriptInstance)
|
||||||
{
|
{
|
||||||
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
|
const auto* pInst = static_cast<const CScriptInstanceDependency*>(pNode);
|
||||||
mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC'));
|
mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC'));
|
||||||
|
|
||||||
for (uint32 iDep = 0; iDep < pInst->NumChildren(); iDep++)
|
for (size_t iDep = 0; iDep < pInst->NumChildren(); iDep++)
|
||||||
{
|
{
|
||||||
CPropertyDependency *pDep = static_cast<CPropertyDependency*>(pInst->ChildByIndex(iDep));
|
const auto* pDep = static_cast<const CPropertyDependency*>(pInst->ChildByIndex(iDep));
|
||||||
|
|
||||||
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
|
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
|
||||||
if (mGame == EGame::Corruption && mIsPlayerActor)
|
if (mGame == EGame::Corruption && mIsPlayerActor)
|
||||||
{
|
{
|
||||||
TString PropID = pDep->PropertyID();
|
TString PropID = pDep->PropertyID();
|
||||||
|
|
||||||
if ( PropID == "0x846397A8" || PropID == "0x685A4C01" ||
|
if (PropID == "0x846397A8" || PropID == "0x685A4C01" ||
|
||||||
PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
|
PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
|
||||||
PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
|
PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
|
||||||
PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
|
PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
|
||||||
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
|
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
|
||||||
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
|
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
|
||||||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
|
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
|
||||||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE" )
|
PropID == "0xA8778E57" || PropID == "0x1CB10DBE")
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
||||||
|
@ -439,7 +456,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||||
}
|
}
|
||||||
else if (pNode->Type() == EDependencyNodeType::Resource)
|
else if (pNode->Type() == EDependencyNodeType::Resource)
|
||||||
{
|
{
|
||||||
CResourceDependency *pResDep = static_cast<CResourceDependency*>(pNode);
|
const auto* pResDep = static_cast<const CResourceDependency*>(pNode);
|
||||||
AddDependency(pResDep->ID(), rAssetsOut, pAudioGroupsOut);
|
AddDependency(pResDep->ID(), rAssetsOut, pAudioGroupsOut);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -454,9 +471,9 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||||
mLayerUsedAssets.clear();
|
mLayerUsedAssets.clear();
|
||||||
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
rLayerOffsetsOut.push_back(rAssetsOut.size());
|
||||||
|
|
||||||
for (uint32 iDep = 0; iDep < BaseEndIndex; iDep++)
|
for (size_t iDep = 0; iDep < BaseEndIndex; iDep++)
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
const auto* pDep = static_cast<const CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||||
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,9 +481,10 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||||
void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = mpStore->FindEntry(rkID);
|
CResourceEntry *pEntry = mpStore->FindEntry(rkID);
|
||||||
if (!pEntry) return;
|
if (!pEntry)
|
||||||
|
return;
|
||||||
|
|
||||||
EResourceType ResType = pEntry->ResourceType();
|
const EResourceType ResType = pEntry->ResourceType();
|
||||||
|
|
||||||
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
||||||
if (mGame <= EGame::Prime && ResType == EResourceType::AudioGroup)
|
if (mGame <= EGame::Prime && ResType == EResourceType::AudioGroup)
|
||||||
|
@ -515,47 +533,47 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
||||||
|
|
||||||
void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
||||||
{
|
{
|
||||||
if (!pNode) return;
|
if (!pNode)
|
||||||
EDependencyNodeType Type = pNode->Type();
|
return;
|
||||||
|
|
||||||
|
const EDependencyNodeType Type = pNode->Type();
|
||||||
bool ParseChildren = false;
|
bool ParseChildren = false;
|
||||||
|
|
||||||
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
||||||
{
|
{
|
||||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pNode);
|
const auto* pDep = static_cast<const CResourceDependency*>(pNode);
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::AnimEvent)
|
else if (Type == EDependencyNodeType::AnimEvent)
|
||||||
{
|
{
|
||||||
CAnimEventDependency *pDep = static_cast<CAnimEventDependency*>(pNode);
|
const auto* pDep = static_cast<const CAnimEventDependency*>(pNode);
|
||||||
uint32 CharIndex = pDep->CharIndex();
|
const uint32 CharIndex = pDep->CharIndex();
|
||||||
|
|
||||||
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
||||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::SetCharacter)
|
else if (Type == EDependencyNodeType::SetCharacter)
|
||||||
{
|
{
|
||||||
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
|
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
|
||||||
const uint32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5);
|
const uint32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5);
|
||||||
|
|
||||||
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
const auto *pChar = static_cast<const CSetCharacterDependency*>(pNode);
|
||||||
uint32 SetIndex = pChar->CharSetIndex();
|
const uint32 SetIndex = pChar->CharSetIndex();
|
||||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
|
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::SetAnimation)
|
else if (Type == EDependencyNodeType::SetAnimation)
|
||||||
{
|
{
|
||||||
CSetAnimationDependency *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
auto *pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
||||||
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
|
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim) || (mIsPlayerActor && pAnim->IsUsedByAnyCharacter());
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ParseChildren = true;
|
ParseChildren = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (ParseChildren)
|
if (ParseChildren)
|
||||||
{
|
{
|
||||||
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||||
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut, pAudioGroupsOut);
|
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut, pAudioGroupsOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,11 +588,12 @@ void CAssetDependencyListBuilder::BuildDependencyList(std::vector<CAssetID>& Out
|
||||||
void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector<CAssetID>& Out)
|
void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector<CAssetID>& Out)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = mpResourceEntry->ResourceStore()->FindEntry(kID);
|
CResourceEntry *pEntry = mpResourceEntry->ResourceStore()->FindEntry(kID);
|
||||||
if (!pEntry) return;
|
if (!pEntry)
|
||||||
|
return;
|
||||||
|
|
||||||
EResourceType ResType = pEntry->ResourceType();
|
const EResourceType ResType = pEntry->ResourceType();
|
||||||
|
|
||||||
if (mUsedAssets.find(kID) != mUsedAssets.end())
|
if (mUsedAssets.find(kID) != mUsedAssets.cend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Dependency is valid! Evaluate the node tree
|
// Dependency is valid! Evaluate the node tree
|
||||||
|
@ -598,43 +617,43 @@ void CAssetDependencyListBuilder::AddDependency(const CAssetID& kID, std::vector
|
||||||
|
|
||||||
void CAssetDependencyListBuilder::EvaluateDependencyNode(CResourceEntry* pCurEntry, IDependencyNode* pNode, std::vector<CAssetID>& Out)
|
void CAssetDependencyListBuilder::EvaluateDependencyNode(CResourceEntry* pCurEntry, IDependencyNode* pNode, std::vector<CAssetID>& Out)
|
||||||
{
|
{
|
||||||
if (!pNode) return;
|
if (!pNode)
|
||||||
EDependencyNodeType Type = pNode->Type();
|
return;
|
||||||
|
|
||||||
|
const EDependencyNodeType Type = pNode->Type();
|
||||||
bool ParseChildren = false;
|
bool ParseChildren = false;
|
||||||
|
|
||||||
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
if (Type == EDependencyNodeType::Resource || Type == EDependencyNodeType::ScriptProperty || Type == EDependencyNodeType::CharacterProperty)
|
||||||
{
|
{
|
||||||
CResourceDependency* pDep = static_cast<CResourceDependency*>(pNode);
|
const auto* pDep = static_cast<CResourceDependency*>(pNode);
|
||||||
AddDependency(pDep->ID(), Out);
|
AddDependency(pDep->ID(), Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::AnimEvent)
|
else if (Type == EDependencyNodeType::AnimEvent)
|
||||||
{
|
{
|
||||||
CAnimEventDependency* pDep = static_cast<CAnimEventDependency*>(pNode);
|
const auto* pDep = static_cast<CAnimEventDependency*>(pNode);
|
||||||
uint32 CharIndex = pDep->CharIndex();
|
const uint32 CharIndex = pDep->CharIndex();
|
||||||
|
|
||||||
if (CharIndex == -1 || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
if (CharIndex == UINT32_MAX || mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, CharIndex))
|
||||||
AddDependency(pDep->ID(), Out);
|
AddDependency(pDep->ID(), Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::SetCharacter)
|
else if (Type == EDependencyNodeType::SetCharacter)
|
||||||
{
|
{
|
||||||
CSetCharacterDependency* pChar = static_cast<CSetCharacterDependency*>(pNode);
|
const auto* pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex());
|
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Type == EDependencyNodeType::SetAnimation)
|
else if (Type == EDependencyNodeType::SetAnimation)
|
||||||
{
|
{
|
||||||
CSetAnimationDependency* pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
auto* pAnim = static_cast<CSetAnimationDependency*>(pNode);
|
||||||
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim);
|
ParseChildren = mCharacterUsageMap.IsAnimationUsed(mCurrentAnimSetID, pAnim);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ParseChildren = true;
|
ParseChildren = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (ParseChildren)
|
if (ParseChildren)
|
||||||
{
|
{
|
||||||
for (uint32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
for (size_t iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||||
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), Out);
|
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), Out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,21 @@ class CCharacterUsageMap
|
||||||
{
|
{
|
||||||
std::map<CAssetID, std::vector<bool>> mUsageMap;
|
std::map<CAssetID, std::vector<bool>> mUsageMap;
|
||||||
std::set<CAssetID> mStillLookingIDs;
|
std::set<CAssetID> mStillLookingIDs;
|
||||||
CResourceStore *mpStore;
|
CResourceStore *mpStore = nullptr;
|
||||||
uint32 mLayerIndex;
|
uint32 mLayerIndex = UINT32_MAX;
|
||||||
bool mIsInitialArea;
|
bool mIsInitialArea = true;
|
||||||
bool mCurrentAreaAllowsDupes;
|
bool mCurrentAreaAllowsDupes = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCharacterUsageMap(CResourceStore *pStore)
|
explicit CCharacterUsageMap(CResourceStore *pStore)
|
||||||
: mpStore(pStore), mLayerIndex(-1), mIsInitialArea(true), mCurrentAreaAllowsDupes(false)
|
: mpStore(pStore)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool IsCharacterUsed(const CAssetID& rkID, uint32 CharacterIndex) const;
|
bool IsCharacterUsed(const CAssetID& rkID, size_t CharacterIndex) const;
|
||||||
bool IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const;
|
bool IsAnimationUsed(const CAssetID& rkID, CSetAnimationDependency *pAnim) const;
|
||||||
void FindUsagesForAsset(CResourceEntry *pEntry);
|
void FindUsagesForAsset(CResourceEntry *pEntry);
|
||||||
void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry);
|
void FindUsagesForArea(CWorld *pWorld, CResourceEntry *pEntry);
|
||||||
void FindUsagesForArea(CWorld *pWorld, uint32 AreaIndex);
|
void FindUsagesForArea(CWorld *pWorld, size_t AreaIndex);
|
||||||
void FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 LayerIndex);
|
void FindUsagesForLayer(CResourceEntry *pAreaEntry, uint32 LayerIndex);
|
||||||
void Clear();
|
void Clear();
|
||||||
void DebugPrintContents();
|
void DebugPrintContents();
|
||||||
|
@ -47,19 +47,17 @@ class CPackageDependencyListBuilder
|
||||||
std::set<CAssetID> mPackageUsedAssets;
|
std::set<CAssetID> mPackageUsedAssets;
|
||||||
std::set<CAssetID> mAreaUsedAssets;
|
std::set<CAssetID> mAreaUsedAssets;
|
||||||
std::set<CAssetID> mUniversalAreaAssets;
|
std::set<CAssetID> mUniversalAreaAssets;
|
||||||
bool mEnableDuplicates;
|
bool mEnableDuplicates = false;
|
||||||
bool mCurrentAreaHasDuplicates;
|
bool mCurrentAreaHasDuplicates = false;
|
||||||
bool mIsUniversalAreaAsset;
|
bool mIsUniversalAreaAsset = false;
|
||||||
bool mIsPlayerActor;
|
bool mIsPlayerActor = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPackageDependencyListBuilder(const CPackage *pkPackage)
|
explicit CPackageDependencyListBuilder(const CPackage *pkPackage)
|
||||||
: mpkPackage(pkPackage)
|
: mpkPackage(pkPackage)
|
||||||
, mGame(pkPackage->Project()->Game())
|
|
||||||
, mpStore(pkPackage->Project()->ResourceStore())
|
, mpStore(pkPackage->Project()->ResourceStore())
|
||||||
|
, mGame(pkPackage->Project()->Game())
|
||||||
, mCharacterUsageMap(pkPackage->Project()->ResourceStore())
|
, mCharacterUsageMap(pkPackage->Project()->ResourceStore())
|
||||||
, mCurrentAreaHasDuplicates(false)
|
|
||||||
, mIsPlayerActor(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,10 +77,10 @@ class CAreaDependencyListBuilder
|
||||||
CCharacterUsageMap mCharacterUsageMap;
|
CCharacterUsageMap mCharacterUsageMap;
|
||||||
std::set<CAssetID> mBaseUsedAssets;
|
std::set<CAssetID> mBaseUsedAssets;
|
||||||
std::set<CAssetID> mLayerUsedAssets;
|
std::set<CAssetID> mLayerUsedAssets;
|
||||||
bool mIsPlayerActor;
|
bool mIsPlayerActor = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAreaDependencyListBuilder(CResourceEntry *pAreaEntry)
|
explicit CAreaDependencyListBuilder(CResourceEntry *pAreaEntry)
|
||||||
: mpAreaEntry(pAreaEntry)
|
: mpAreaEntry(pAreaEntry)
|
||||||
, mpStore(pAreaEntry->ResourceStore())
|
, mpStore(pAreaEntry->ResourceStore())
|
||||||
, mGame(pAreaEntry->Game())
|
, mGame(pAreaEntry->Game())
|
||||||
|
@ -106,7 +104,7 @@ class CAssetDependencyListBuilder
|
||||||
CAssetID mCurrentAnimSetID;
|
CAssetID mCurrentAnimSetID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAssetDependencyListBuilder(CResourceEntry* pEntry)
|
explicit CAssetDependencyListBuilder(CResourceEntry* pEntry)
|
||||||
: mpResourceEntry(pEntry)
|
: mpResourceEntry(pEntry)
|
||||||
, mCharacterUsageMap(pEntry->ResourceStore())
|
, mCharacterUsageMap(pEntry->ResourceStore())
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -7,14 +7,12 @@
|
||||||
class IProgressNotifier
|
class IProgressNotifier
|
||||||
{
|
{
|
||||||
TString mTaskName;
|
TString mTaskName;
|
||||||
int mTaskIndex;
|
int mTaskIndex = 0;
|
||||||
int mTaskCount;
|
int mTaskCount = 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IProgressNotifier()
|
IProgressNotifier() = default;
|
||||||
: mTaskIndex(0)
|
virtual ~IProgressNotifier() = default;
|
||||||
, mTaskCount(1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void SetNumTasks(int NumTasks)
|
void SetNumTasks(int NumTasks)
|
||||||
{
|
{
|
||||||
|
@ -25,7 +23,7 @@ public:
|
||||||
|
|
||||||
void SetTask(int TaskIndex, TString TaskName)
|
void SetTask(int TaskIndex, TString TaskName)
|
||||||
{
|
{
|
||||||
mTaskName = TaskName;
|
mTaskName = std::move(TaskName);
|
||||||
mTaskIndex = TaskIndex;
|
mTaskIndex = TaskIndex;
|
||||||
mTaskCount = Math::Max(mTaskCount, TaskIndex + 1);
|
mTaskCount = Math::Max(mTaskCount, TaskIndex + 1);
|
||||||
}
|
}
|
||||||
|
@ -67,9 +65,9 @@ protected:
|
||||||
class CNullProgressNotifier : public IProgressNotifier
|
class CNullProgressNotifier : public IProgressNotifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool ShouldCancel() const { return false; }
|
bool ShouldCancel() const override{ return false; }
|
||||||
protected:
|
protected:
|
||||||
void UpdateProgress(const TString&, const TString&, float) {}
|
void UpdateProgress(const TString&, const TString&, float) override {}
|
||||||
};
|
};
|
||||||
extern CNullProgressNotifier *gpNullProgress;
|
extern CNullProgressNotifier *gpNullProgress;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
class IUIRelay
|
class IUIRelay
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IUIRelay() = default;
|
||||||
virtual void ShowMessageBox(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
|
virtual void ShowMessageBox(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
|
||||||
virtual void ShowMessageBoxAsync(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
|
virtual void ShowMessageBoxAsync(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
|
||||||
virtual bool AskYesNoQuestion(const TString& rkInfoBoxTitle, const TString& rkQuestion) = 0;
|
virtual bool AskYesNoQuestion(const TString& rkInfoBoxTitle, const TString& rkQuestion) = 0;
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
#include "CDynamicVertexBuffer.h"
|
#include "CDynamicVertexBuffer.h"
|
||||||
#include "CVertexArrayManager.h"
|
#include "CVertexArrayManager.h"
|
||||||
|
|
||||||
static const uint32 gskAttribSize[] = {
|
#include <array>
|
||||||
|
|
||||||
|
constexpr std::array<uint32, 12> gskAttribSize{
|
||||||
0xC, 0xC, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8
|
0xC, 0xC, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
CDynamicVertexBuffer::CDynamicVertexBuffer()
|
CDynamicVertexBuffer::CDynamicVertexBuffer() = default;
|
||||||
: mAttribFlags(EVertexAttribute::None)
|
|
||||||
, mBufferedFlags(EVertexAttribute::None)
|
|
||||||
, mNumVertices(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CDynamicVertexBuffer::~CDynamicVertexBuffer()
|
CDynamicVertexBuffer::~CDynamicVertexBuffer()
|
||||||
{
|
{
|
||||||
|
@ -44,7 +41,7 @@ void CDynamicVertexBuffer::SetActiveAttribs(FVertexDescription AttribFlags)
|
||||||
|
|
||||||
void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkData)
|
void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkData)
|
||||||
{
|
{
|
||||||
uint32 Index;
|
size_t Index;
|
||||||
|
|
||||||
switch (Attrib)
|
switch (Attrib)
|
||||||
{
|
{
|
||||||
|
@ -69,9 +66,9 @@ void CDynamicVertexBuffer::BufferAttrib(EVertexAttribute Attrib, const void *pkD
|
||||||
|
|
||||||
void CDynamicVertexBuffer::ClearBuffers()
|
void CDynamicVertexBuffer::ClearBuffers()
|
||||||
{
|
{
|
||||||
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++)
|
for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
|
||||||
{
|
{
|
||||||
int Bit = 1 << iAttrib;
|
const int Bit = 1 << iAttrib;
|
||||||
|
|
||||||
if (mBufferedFlags & Bit)
|
if (mBufferedFlags & Bit)
|
||||||
glDeleteBuffers(1, &mAttribBuffers[iAttrib]);
|
glDeleteBuffers(1, &mAttribBuffers[iAttrib]);
|
||||||
|
@ -86,9 +83,9 @@ GLuint CDynamicVertexBuffer::CreateVAO()
|
||||||
glGenVertexArrays(1, &VertexArray);
|
glGenVertexArrays(1, &VertexArray);
|
||||||
glBindVertexArray(VertexArray);
|
glBindVertexArray(VertexArray);
|
||||||
|
|
||||||
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++)
|
for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
|
||||||
{
|
{
|
||||||
bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
|
const bool HasAttrib = (3 << (iAttrib * 2)) != 0;
|
||||||
|
|
||||||
if (HasAttrib)
|
if (HasAttrib)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +93,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
|
||||||
GLuint NumComponents;
|
GLuint NumComponents;
|
||||||
GLenum DataType;
|
GLenum DataType;
|
||||||
|
|
||||||
if ((iAttrib == 2) || (iAttrib == 3))
|
if (iAttrib == 2 || iAttrib == 3)
|
||||||
{
|
{
|
||||||
NumComponents = 4;
|
NumComponents = 4;
|
||||||
DataType = GL_UNSIGNED_BYTE;
|
DataType = GL_UNSIGNED_BYTE;
|
||||||
|
@ -107,7 +104,7 @@ GLuint CDynamicVertexBuffer::CreateVAO()
|
||||||
DataType = GL_FLOAT;
|
DataType = GL_FLOAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, (void*) 0);
|
glVertexAttribPointer(iAttrib, NumComponents, DataType, GL_FALSE, 0, nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,17 +116,18 @@ GLuint CDynamicVertexBuffer::CreateVAO()
|
||||||
// ************ PRIVATE ************
|
// ************ PRIVATE ************
|
||||||
void CDynamicVertexBuffer::InitBuffers()
|
void CDynamicVertexBuffer::InitBuffers()
|
||||||
{
|
{
|
||||||
if (mBufferedFlags) ClearBuffers();
|
if (mBufferedFlags)
|
||||||
|
ClearBuffers();
|
||||||
|
|
||||||
for (uint32 iAttrib = 0; iAttrib < 12; iAttrib++)
|
for (uint32 iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
|
||||||
{
|
{
|
||||||
bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
|
const bool HasAttrib = ((3 << (iAttrib * 2)) != 0);
|
||||||
|
|
||||||
if (HasAttrib)
|
if (HasAttrib)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mAttribBuffers[iAttrib]);
|
glGenBuffers(1, &mAttribBuffers[iAttrib]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, gskAttribSize[iAttrib] * mNumVertices, NULL, GL_DYNAMIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, gskAttribSize[iAttrib] * mNumVertices, nullptr, GL_DYNAMIC_DRAW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mBufferedFlags = mAttribFlags;
|
mBufferedFlags = mAttribFlags;
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
#include "Core/Resource/Model/EVertexAttribute.h"
|
#include "Core/Resource/Model/EVertexAttribute.h"
|
||||||
#include <Common/BasicTypes.h>
|
#include <Common/BasicTypes.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <array>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
class CDynamicVertexBuffer
|
class CDynamicVertexBuffer
|
||||||
{
|
{
|
||||||
FVertexDescription mAttribFlags;
|
FVertexDescription mAttribFlags{EVertexAttribute::None};
|
||||||
FVertexDescription mBufferedFlags;
|
FVertexDescription mBufferedFlags{EVertexAttribute::None};
|
||||||
uint32 mNumVertices;
|
uint32 mNumVertices = 0;
|
||||||
GLuint mAttribBuffers[12];
|
std::array<GLuint, 12> mAttribBuffers{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDynamicVertexBuffer();
|
CDynamicVertexBuffer();
|
||||||
|
|
|
@ -1,23 +1,9 @@
|
||||||
#include "CFramebuffer.h"
|
#include "CFramebuffer.h"
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
|
|
||||||
CFramebuffer::CFramebuffer()
|
CFramebuffer::CFramebuffer() = default;
|
||||||
: mpRenderbuffer(nullptr)
|
|
||||||
, mpTexture(nullptr)
|
|
||||||
, mWidth(0)
|
|
||||||
, mHeight(0)
|
|
||||||
, mEnableMultisampling(false)
|
|
||||||
, mInitialized(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CFramebuffer::CFramebuffer(uint32 Width, uint32 Height)
|
CFramebuffer::CFramebuffer(uint32 Width, uint32 Height)
|
||||||
: mpRenderbuffer(nullptr)
|
|
||||||
, mpTexture(nullptr)
|
|
||||||
, mWidth(0)
|
|
||||||
, mHeight(0)
|
|
||||||
, mEnableMultisampling(false)
|
|
||||||
, mInitialized(false)
|
|
||||||
{
|
{
|
||||||
Resize(Width, Height);
|
Resize(Width, Height);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@
|
||||||
|
|
||||||
class CFramebuffer
|
class CFramebuffer
|
||||||
{
|
{
|
||||||
GLuint mFramebuffer;
|
GLuint mFramebuffer = 0;
|
||||||
CRenderbuffer *mpRenderbuffer;
|
CRenderbuffer *mpRenderbuffer = nullptr;
|
||||||
CTexture *mpTexture;
|
CTexture *mpTexture = nullptr;
|
||||||
uint32 mWidth, mHeight;
|
uint32 mWidth = 0;
|
||||||
bool mEnableMultisampling;
|
uint32 mHeight = 0;
|
||||||
bool mInitialized;
|
bool mEnableMultisampling = false;
|
||||||
GLenum mStatus;
|
bool mInitialized = false;
|
||||||
|
GLenum mStatus{};
|
||||||
|
|
||||||
static GLint smDefaultFramebuffer;
|
static GLint smDefaultFramebuffer;
|
||||||
static bool smStaticsInitialized;
|
static bool smStaticsInitialized;
|
||||||
|
@ -28,7 +29,7 @@ public:
|
||||||
void SetMultisamplingEnabled(bool Enable);
|
void SetMultisamplingEnabled(bool Enable);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CTexture* Texture() const { return mpTexture; }
|
CTexture* Texture() const { return mpTexture; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static void BindDefaultFramebuffer(GLenum Target = GL_FRAMEBUFFER);
|
static void BindDefaultFramebuffer(GLenum Target = GL_FRAMEBUFFER);
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
#include "CIndexBuffer.h"
|
#include "CIndexBuffer.h"
|
||||||
|
|
||||||
CIndexBuffer::CIndexBuffer()
|
CIndexBuffer::CIndexBuffer() = default;
|
||||||
: mBuffered(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CIndexBuffer::CIndexBuffer(GLenum Type)
|
CIndexBuffer::CIndexBuffer(GLenum type)
|
||||||
: mPrimitiveType(Type)
|
: mPrimitiveType(type)
|
||||||
, mBuffered(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,21 +13,21 @@ CIndexBuffer::~CIndexBuffer()
|
||||||
glDeleteBuffers(1, &mIndexBuffer);
|
glDeleteBuffers(1, &mIndexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::AddIndex(uint16 Index)
|
void CIndexBuffer::AddIndex(uint16 index)
|
||||||
{
|
{
|
||||||
mIndices.push_back(Index);
|
mIndices.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::AddIndices(uint16 *pIndices, uint Count)
|
void CIndexBuffer::AddIndices(const uint16 *indices, size_t count)
|
||||||
{
|
{
|
||||||
Reserve(Count);
|
Reserve(count);
|
||||||
for (uint iIdx = 0; iIdx < Count; iIdx++)
|
for (size_t i = 0; i < count; i++)
|
||||||
mIndices.push_back(*pIndices++);
|
mIndices.push_back(*indices++);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::Reserve(uint Size)
|
void CIndexBuffer::Reserve(size_t size)
|
||||||
{
|
{
|
||||||
mIndices.reserve(mIndices.size() + Size);
|
mIndices.reserve(mIndices.size() + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::Clear()
|
void CIndexBuffer::Clear()
|
||||||
|
@ -57,7 +53,9 @@ void CIndexBuffer::Buffer()
|
||||||
|
|
||||||
void CIndexBuffer::Bind()
|
void CIndexBuffer::Bind()
|
||||||
{
|
{
|
||||||
if (!mBuffered) Buffer();
|
if (!mBuffered)
|
||||||
|
Buffer();
|
||||||
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,88 +66,88 @@ void CIndexBuffer::Unbind()
|
||||||
void CIndexBuffer::DrawElements()
|
void CIndexBuffer::DrawElements()
|
||||||
{
|
{
|
||||||
Bind();
|
Bind();
|
||||||
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, (void*) 0);
|
glDrawElements(mPrimitiveType, mIndices.size(), GL_UNSIGNED_SHORT, nullptr);
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::DrawElements(uint Offset, uint Size)
|
void CIndexBuffer::DrawElements(uint offset, uint size)
|
||||||
{
|
{
|
||||||
Bind();
|
Bind();
|
||||||
glDrawElements(mPrimitiveType, Size, GL_UNSIGNED_SHORT, (char*)0 + (Offset * 2));
|
glDrawElements(mPrimitiveType, size, GL_UNSIGNED_SHORT, (char*)0 + (offset * 2));
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CIndexBuffer::IsBuffered()
|
bool CIndexBuffer::IsBuffered() const
|
||||||
{
|
{
|
||||||
return mBuffered;
|
return mBuffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint CIndexBuffer::GetSize()
|
uint CIndexBuffer::GetSize() const
|
||||||
{
|
{
|
||||||
return mIndices.size();
|
return mIndices.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum CIndexBuffer::GetPrimitiveType()
|
GLenum CIndexBuffer::GetPrimitiveType() const
|
||||||
{
|
{
|
||||||
return mPrimitiveType;
|
return mPrimitiveType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::SetPrimitiveType(GLenum Type)
|
void CIndexBuffer::SetPrimitiveType(GLenum type)
|
||||||
{
|
{
|
||||||
mPrimitiveType = Type;
|
mPrimitiveType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::TrianglesToStrips(uint16 *pIndices, uint Count)
|
void CIndexBuffer::TrianglesToStrips(uint16 *indices, size_t count)
|
||||||
{
|
{
|
||||||
Reserve(Count + (Count / 3));
|
Reserve(count + (count / 3));
|
||||||
|
|
||||||
for (uint iIdx = 0; iIdx < Count; iIdx += 3)
|
for (size_t i = 0; i < count; i += 3)
|
||||||
{
|
{
|
||||||
mIndices.push_back(*pIndices++);
|
mIndices.push_back(*indices++);
|
||||||
mIndices.push_back(*pIndices++);
|
mIndices.push_back(*indices++);
|
||||||
mIndices.push_back(*pIndices++);
|
mIndices.push_back(*indices++);
|
||||||
mIndices.push_back(0xFFFF);
|
mIndices.push_back(0xFFFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::FansToStrips(uint16 *pIndices, uint Count)
|
void CIndexBuffer::FansToStrips(uint16 *indices, size_t count)
|
||||||
{
|
{
|
||||||
Reserve(Count);
|
Reserve(count);
|
||||||
uint16 FirstIndex = *pIndices;
|
const uint16 firstIndex = *indices;
|
||||||
|
|
||||||
for (uint iIdx = 2; iIdx < Count; iIdx += 3)
|
for (size_t i = 2; i < count; i += 3)
|
||||||
{
|
{
|
||||||
mIndices.push_back(pIndices[iIdx - 1]);
|
mIndices.push_back(indices[i - 1]);
|
||||||
mIndices.push_back(pIndices[iIdx]);
|
mIndices.push_back(indices[i]);
|
||||||
mIndices.push_back(FirstIndex);
|
mIndices.push_back(firstIndex);
|
||||||
if (iIdx + 1 < Count)
|
if (i + 1 < count)
|
||||||
mIndices.push_back(pIndices[iIdx + 1]);
|
mIndices.push_back(indices[i + 1]);
|
||||||
if (iIdx + 2 < Count)
|
if (i + 2 < count)
|
||||||
mIndices.push_back(pIndices[iIdx + 2]);
|
mIndices.push_back(indices[i + 2]);
|
||||||
mIndices.push_back(0xFFFF);
|
mIndices.push_back(0xFFFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIndexBuffer::QuadsToStrips(uint16 *pIndices, uint Count)
|
void CIndexBuffer::QuadsToStrips(uint16 *indices, size_t count)
|
||||||
{
|
{
|
||||||
Reserve((uint) (Count * 1.25));
|
Reserve(static_cast<size_t>(count * 1.25));
|
||||||
|
|
||||||
uint iIdx = 3;
|
size_t i = 3;
|
||||||
for (; iIdx < Count; iIdx += 4)
|
for (; i < count; i += 4)
|
||||||
{
|
{
|
||||||
mIndices.push_back(pIndices[iIdx - 2]);
|
mIndices.push_back(indices[i - 2]);
|
||||||
mIndices.push_back(pIndices[iIdx - 1]);
|
mIndices.push_back(indices[i - 1]);
|
||||||
mIndices.push_back(pIndices[iIdx - 3]);
|
mIndices.push_back(indices[i - 3]);
|
||||||
mIndices.push_back(pIndices[iIdx]);
|
mIndices.push_back(indices[i]);
|
||||||
mIndices.push_back(0xFFFF);
|
mIndices.push_back(0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's three indices present that indicates a single triangle
|
// if there's three indices present that indicates a single triangle
|
||||||
if (iIdx == Count)
|
if (i == count)
|
||||||
{
|
{
|
||||||
mIndices.push_back(pIndices[iIdx - 3]);
|
mIndices.push_back(indices[i - 3]);
|
||||||
mIndices.push_back(pIndices[iIdx - 2]);
|
mIndices.push_back(indices[i - 2]);
|
||||||
mIndices.push_back(pIndices[iIdx - 1]);
|
mIndices.push_back(indices[i - 1]);
|
||||||
mIndices.push_back(0xFFFF);
|
mIndices.push_back(0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,33 +7,33 @@
|
||||||
|
|
||||||
class CIndexBuffer
|
class CIndexBuffer
|
||||||
{
|
{
|
||||||
GLuint mIndexBuffer;
|
GLuint mIndexBuffer = 0;
|
||||||
std::vector<uint16> mIndices;
|
std::vector<uint16> mIndices;
|
||||||
GLenum mPrimitiveType;
|
GLenum mPrimitiveType{};
|
||||||
bool mBuffered;
|
bool mBuffered = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CIndexBuffer();
|
CIndexBuffer();
|
||||||
CIndexBuffer(GLenum Type);
|
explicit CIndexBuffer(GLenum type);
|
||||||
~CIndexBuffer();
|
~CIndexBuffer();
|
||||||
void AddIndex(uint16 Index);
|
void AddIndex(uint16 index);
|
||||||
void AddIndices(uint16 *pIndices, uint Count);
|
void AddIndices(const uint16 *indices, size_t count);
|
||||||
void Reserve(uint Size);
|
void Reserve(size_t size);
|
||||||
void Clear();
|
void Clear();
|
||||||
void Buffer();
|
void Buffer();
|
||||||
void Bind();
|
void Bind();
|
||||||
void Unbind();
|
void Unbind();
|
||||||
void DrawElements();
|
void DrawElements();
|
||||||
void DrawElements(uint Offset, uint Size);
|
void DrawElements(uint offset, uint size);
|
||||||
bool IsBuffered();
|
bool IsBuffered() const;
|
||||||
|
|
||||||
uint GetSize();
|
uint GetSize() const;
|
||||||
GLenum GetPrimitiveType();
|
GLenum GetPrimitiveType() const;
|
||||||
void SetPrimitiveType(GLenum Type);
|
void SetPrimitiveType(GLenum type);
|
||||||
|
|
||||||
void TrianglesToStrips(uint16 *pIndices, uint Count);
|
void TrianglesToStrips(uint16 *indices, size_t count);
|
||||||
void FansToStrips(uint16 *pIndices, uint Count);
|
void FansToStrips(uint16 *indices, size_t count);
|
||||||
void QuadsToStrips(uint16 *pIndices, uint Count);
|
void QuadsToStrips(uint16 *indices, size_t count);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CINDEXBUFFER_H
|
#endif // CINDEXBUFFER_H
|
||||||
|
|
|
@ -6,25 +6,17 @@
|
||||||
|
|
||||||
class CRenderbuffer
|
class CRenderbuffer
|
||||||
{
|
{
|
||||||
GLuint mRenderbuffer;
|
GLuint mRenderbuffer = 0;
|
||||||
uint mWidth, mHeight;
|
uint mWidth = 0;
|
||||||
bool mEnableMultisampling;
|
uint mHeight = 0;
|
||||||
bool mInitialized;
|
bool mEnableMultisampling = false;
|
||||||
|
bool mInitialized = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRenderbuffer()
|
CRenderbuffer() = default;
|
||||||
: mWidth(0)
|
|
||||||
, mHeight(0)
|
|
||||||
, mEnableMultisampling(false)
|
|
||||||
, mInitialized(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CRenderbuffer(uint Width, uint Height)
|
CRenderbuffer(uint Width, uint Height)
|
||||||
: mWidth(Width)
|
: mWidth(Width)
|
||||||
, mHeight(Height)
|
, mHeight(Height)
|
||||||
, mEnableMultisampling(false)
|
|
||||||
, mInitialized(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +33,7 @@ public:
|
||||||
InitStorage();
|
InitStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Resize(uint Width, uint Height)
|
void Resize(uint Width, uint Height)
|
||||||
{
|
{
|
||||||
mWidth = Width;
|
mWidth = Width;
|
||||||
mHeight = Height;
|
mHeight = Height;
|
||||||
|
@ -50,23 +42,23 @@ public:
|
||||||
InitStorage();
|
InitStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Bind()
|
void Bind()
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized) Init();
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
|
glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Unbind()
|
void Unbind()
|
||||||
{
|
{
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline GLuint BufferID()
|
GLuint BufferID() const
|
||||||
{
|
{
|
||||||
return mRenderbuffer;
|
return mRenderbuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetMultisamplingEnabled(bool Enable)
|
void SetMultisamplingEnabled(bool Enable)
|
||||||
{
|
{
|
||||||
if (mEnableMultisampling != Enable)
|
if (mEnableMultisampling != Enable)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,28 +5,18 @@
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
bool gDebugDumpShaders = false;
|
static bool gDebugDumpShaders = false;
|
||||||
uint64 gFailedCompileCount = 0;
|
static uint64 gFailedCompileCount = 0;
|
||||||
uint64 gSuccessfulCompileCount = 0;
|
static uint64 gSuccessfulCompileCount = 0;
|
||||||
|
|
||||||
CShader* CShader::spCurrentShader = nullptr;
|
|
||||||
int CShader::smNumShaders = 0;
|
|
||||||
|
|
||||||
CShader::CShader()
|
CShader::CShader()
|
||||||
{
|
{
|
||||||
mVertexShaderExists = false;
|
|
||||||
mPixelShaderExists = false;
|
|
||||||
mProgramExists = false;
|
|
||||||
smNumShaders++;
|
smNumShaders++;
|
||||||
}
|
}
|
||||||
|
|
||||||
CShader::CShader(const char *pkVertexSource, const char *pkPixelSource)
|
CShader::CShader(const char *pkVertexSource, const char *pkPixelSource)
|
||||||
{
|
{
|
||||||
mVertexShaderExists = false;
|
|
||||||
mPixelShaderExists = false;
|
|
||||||
mProgramExists = false;
|
|
||||||
smNumShaders++;
|
smNumShaders++;
|
||||||
|
|
||||||
CompileVertexSource(pkVertexSource);
|
CompileVertexSource(pkVertexSource);
|
||||||
|
@ -36,18 +26,25 @@ CShader::CShader(const char *pkVertexSource, const char *pkPixelSource)
|
||||||
|
|
||||||
CShader::~CShader()
|
CShader::~CShader()
|
||||||
{
|
{
|
||||||
if (mVertexShaderExists) glDeleteShader(mVertexShader);
|
if (mVertexShaderExists)
|
||||||
if (mPixelShaderExists) glDeleteShader(mPixelShader);
|
glDeleteShader(mVertexShader);
|
||||||
if (mProgramExists) glDeleteProgram(mProgram);
|
|
||||||
|
if (mPixelShaderExists)
|
||||||
|
glDeleteShader(mPixelShader);
|
||||||
|
|
||||||
|
if (mProgramExists)
|
||||||
|
glDeleteProgram(mProgram);
|
||||||
|
|
||||||
|
if (spCurrentShader == this)
|
||||||
|
spCurrentShader = nullptr;
|
||||||
|
|
||||||
if (spCurrentShader == this) spCurrentShader = 0;
|
|
||||||
smNumShaders--;
|
smNumShaders--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CShader::CompileVertexSource(const char* pkSource)
|
bool CShader::CompileVertexSource(const char* pkSource)
|
||||||
{
|
{
|
||||||
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
|
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
glShaderSource(mVertexShader, 1, (const GLchar**) &pkSource, NULL);
|
glShaderSource(mVertexShader, 1, (const GLchar**) &pkSource, nullptr);
|
||||||
glCompileShader(mVertexShader);
|
glCompileShader(mVertexShader);
|
||||||
|
|
||||||
// Shader should be compiled - check for errors
|
// Shader should be compiled - check for errors
|
||||||
|
@ -82,7 +79,7 @@ bool CShader::CompileVertexSource(const char* pkSource)
|
||||||
bool CShader::CompilePixelSource(const char* pkSource)
|
bool CShader::CompilePixelSource(const char* pkSource)
|
||||||
{
|
{
|
||||||
mPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
|
mPixelShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
glShaderSource(mPixelShader, 1, (const GLchar**) &pkSource, NULL);
|
glShaderSource(mPixelShader, 1, (const GLchar**) &pkSource, nullptr);
|
||||||
glCompileShader(mPixelShader);
|
glCompileShader(mPixelShader);
|
||||||
|
|
||||||
// Shader should be compiled - check for errors
|
// Shader should be compiled - check for errors
|
||||||
|
@ -116,7 +113,8 @@ bool CShader::CompilePixelSource(const char* pkSource)
|
||||||
|
|
||||||
bool CShader::LinkShaders()
|
bool CShader::LinkShaders()
|
||||||
{
|
{
|
||||||
if ((!mVertexShaderExists) || (!mPixelShaderExists)) return false;
|
if (!mVertexShaderExists || !mPixelShaderExists)
|
||||||
|
return false;
|
||||||
|
|
||||||
mProgram = glCreateProgram();
|
mProgram = glCreateProgram();
|
||||||
glAttachShader(mProgram, mVertexShader);
|
glAttachShader(mProgram, mVertexShader);
|
||||||
|
@ -139,17 +137,12 @@ bool CShader::LinkShaders()
|
||||||
|
|
||||||
GLint LogLen;
|
GLint LogLen;
|
||||||
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &LogLen);
|
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &LogLen);
|
||||||
GLchar *pInfoLog = new GLchar[LogLen];
|
auto pInfoLog = std::unique_ptr<GLchar[]>(new GLchar[LogLen]);
|
||||||
glGetProgramInfoLog(mProgram, LogLen, NULL, pInfoLog);
|
glGetProgramInfoLog(mProgram, LogLen, nullptr, pInfoLog.get());
|
||||||
|
|
||||||
std::ofstream LinkOut;
|
|
||||||
LinkOut.open(*Out);
|
|
||||||
|
|
||||||
|
std::ofstream LinkOut(*Out);
|
||||||
if (LogLen > 0)
|
if (LogLen > 0)
|
||||||
LinkOut << pInfoLog;
|
LinkOut << pInfoLog.get();
|
||||||
|
|
||||||
LinkOut.close();
|
|
||||||
delete[] pInfoLog;
|
|
||||||
|
|
||||||
gFailedCompileCount++;
|
gFailedCompileCount++;
|
||||||
glDeleteProgram(mProgram);
|
glDeleteProgram(mProgram);
|
||||||
|
@ -167,22 +160,22 @@ bool CShader::LinkShaders()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CShader::IsValidProgram()
|
bool CShader::IsValidProgram() const
|
||||||
{
|
{
|
||||||
return mProgramExists;
|
return mProgramExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CShader::GetProgramID()
|
GLuint CShader::GetProgramID() const
|
||||||
{
|
{
|
||||||
return mProgram;
|
return mProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CShader::GetUniformLocation(const char* pkUniform)
|
GLuint CShader::GetUniformLocation(const char* pkUniform) const
|
||||||
{
|
{
|
||||||
return glGetUniformLocation(mProgram, pkUniform);
|
return glGetUniformLocation(mProgram, pkUniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CShader::GetUniformBlockIndex(const char* pkUniformBlock)
|
GLuint CShader::GetUniformBlockIndex(const char* pkUniformBlock) const
|
||||||
{
|
{
|
||||||
return glGetUniformBlockIndex(mProgram, pkUniformBlock);
|
return glGetUniformBlockIndex(mProgram, pkUniformBlock);
|
||||||
}
|
}
|
||||||
|
@ -220,7 +213,7 @@ void CShader::SetCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
CShader* CShader::FromResourceFile(const TString& rkShaderName)
|
std::unique_ptr<CShader> CShader::FromResourceFile(const TString& rkShaderName)
|
||||||
{
|
{
|
||||||
TString VertexShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".vs";
|
TString VertexShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".vs";
|
||||||
TString PixelShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".ps";
|
TString PixelShaderFilename = gDataDir + "resources/shaders/" + rkShaderName + ".ps";
|
||||||
|
@ -233,7 +226,7 @@ CShader* CShader::FromResourceFile(const TString& rkShaderName)
|
||||||
if (VertexShaderText.IsEmpty() || PixelShaderText.IsEmpty())
|
if (VertexShaderText.IsEmpty() || PixelShaderText.IsEmpty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
CShader *pShader = new CShader();
|
auto pShader = std::make_unique<CShader>();
|
||||||
pShader->CompileVertexSource(*VertexShaderText);
|
pShader->CompileVertexSource(*VertexShaderText);
|
||||||
pShader->CompilePixelSource(*PixelShaderText);
|
pShader->CompilePixelSource(*PixelShaderText);
|
||||||
pShader->LinkShaders();
|
pShader->LinkShaders();
|
||||||
|
@ -247,15 +240,15 @@ CShader* CShader::CurrentShader()
|
||||||
|
|
||||||
void CShader::KillCachedShader()
|
void CShader::KillCachedShader()
|
||||||
{
|
{
|
||||||
spCurrentShader = 0;
|
spCurrentShader = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ PRIVATE ************
|
// ************ PRIVATE ************
|
||||||
void CShader::CacheCommonUniforms()
|
void CShader::CacheCommonUniforms()
|
||||||
{
|
{
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
for (size_t iTex = 0; iTex < 8; iTex++)
|
||||||
{
|
{
|
||||||
TString TexUniform = "Texture" + TString::FromInt32(iTex);
|
const TString TexUniform = "Texture" + std::to_string(iTex);
|
||||||
mTextureUniforms[iTex] = glGetUniformLocation(mProgram, *TexUniform);
|
mTextureUniforms[iTex] = glGetUniformLocation(mProgram, *TexUniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,26 +257,20 @@ void CShader::CacheCommonUniforms()
|
||||||
|
|
||||||
void CShader::DumpShaderSource(GLuint Shader, const TString& rkOut)
|
void CShader::DumpShaderSource(GLuint Shader, const TString& rkOut)
|
||||||
{
|
{
|
||||||
GLint SourceLen;
|
GLint SourceLen = 0;
|
||||||
glGetShaderiv(Shader, GL_SHADER_SOURCE_LENGTH, &SourceLen);
|
glGetShaderiv(Shader, GL_SHADER_SOURCE_LENGTH, &SourceLen);
|
||||||
GLchar *Source = new GLchar[SourceLen];
|
auto Source = std::unique_ptr<GLchar[]>(new GLchar[SourceLen]);
|
||||||
glGetShaderSource(Shader, SourceLen, NULL, Source);
|
glGetShaderSource(Shader, SourceLen, nullptr, Source.get());
|
||||||
|
|
||||||
GLint LogLen;
|
GLint LogLen = 0;
|
||||||
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLen);
|
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLen);
|
||||||
GLchar *pInfoLog = new GLchar[LogLen];
|
auto pInfoLog = std::unique_ptr<GLchar[]>(new GLchar[LogLen]);
|
||||||
glGetShaderInfoLog(Shader, LogLen, NULL, pInfoLog);
|
glGetShaderInfoLog(Shader, LogLen, nullptr, pInfoLog.get());
|
||||||
|
|
||||||
std::ofstream ShaderOut;
|
std::ofstream ShaderOut(*rkOut);
|
||||||
ShaderOut.open(*rkOut);
|
|
||||||
|
|
||||||
if (SourceLen > 0)
|
if (SourceLen > 0)
|
||||||
ShaderOut << Source;
|
ShaderOut << Source.get();
|
||||||
if (LogLen > 0)
|
if (LogLen > 0)
|
||||||
ShaderOut << pInfoLog;
|
ShaderOut << pInfoLog.get();
|
||||||
|
|
||||||
ShaderOut.close();
|
|
||||||
|
|
||||||
delete[] Source;
|
|
||||||
delete[] pInfoLog;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,28 +3,30 @@
|
||||||
|
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class CShader
|
class CShader
|
||||||
{
|
{
|
||||||
bool mVertexShaderExists;
|
bool mVertexShaderExists = false;
|
||||||
bool mPixelShaderExists;
|
bool mPixelShaderExists = false;
|
||||||
bool mProgramExists;
|
bool mProgramExists = false;
|
||||||
GLuint mVertexShader;
|
GLuint mVertexShader = 0;
|
||||||
GLuint mPixelShader;
|
GLuint mPixelShader = 0;
|
||||||
GLuint mProgram;
|
GLuint mProgram = 0;
|
||||||
|
|
||||||
GLuint mMVPBlockIndex;
|
GLuint mMVPBlockIndex = 0;
|
||||||
GLuint mVertexBlockIndex;
|
GLuint mVertexBlockIndex = 0;
|
||||||
GLuint mPixelBlockIndex;
|
GLuint mPixelBlockIndex = 0;
|
||||||
GLuint mLightBlockIndex;
|
GLuint mLightBlockIndex = 0;
|
||||||
GLuint mBoneTransformBlockIndex;
|
GLuint mBoneTransformBlockIndex = 0;
|
||||||
|
|
||||||
// Cached uniform locations
|
// Cached uniform locations
|
||||||
GLint mTextureUniforms[8];
|
std::array<GLint, 8> mTextureUniforms{};
|
||||||
GLint mNumLightsUniform;
|
GLint mNumLightsUniform = 0;
|
||||||
|
|
||||||
static int smNumShaders;
|
static inline int smNumShaders = 0;
|
||||||
static CShader* spCurrentShader;
|
static inline CShader* spCurrentShader = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CShader();
|
CShader();
|
||||||
|
@ -33,21 +35,21 @@ public:
|
||||||
bool CompileVertexSource(const char* pkSource);
|
bool CompileVertexSource(const char* pkSource);
|
||||||
bool CompilePixelSource(const char* pkSource);
|
bool CompilePixelSource(const char* pkSource);
|
||||||
bool LinkShaders();
|
bool LinkShaders();
|
||||||
bool IsValidProgram();
|
bool IsValidProgram() const;
|
||||||
GLuint GetProgramID();
|
GLuint GetProgramID() const;
|
||||||
GLuint GetUniformLocation(const char* pkUniform);
|
GLuint GetUniformLocation(const char* pkUniform) const;
|
||||||
GLuint GetUniformBlockIndex(const char* pkUniformBlock);
|
GLuint GetUniformBlockIndex(const char* pkUniformBlock) const;
|
||||||
void UniformBlockBinding(GLuint BlockIndex, GLuint BlockBinding);
|
void UniformBlockBinding(GLuint BlockIndex, GLuint BlockBinding);
|
||||||
void SetTextureUniforms(uint32 NumTextures);
|
void SetTextureUniforms(uint32 NumTextures);
|
||||||
void SetNumLights(uint32 NumLights);
|
void SetNumLights(uint32 NumLights);
|
||||||
void SetCurrent();
|
void SetCurrent();
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static CShader* FromResourceFile(const TString& rkShaderName);
|
static std::unique_ptr<CShader> FromResourceFile(const TString& rkShaderName);
|
||||||
static CShader* CurrentShader();
|
static CShader* CurrentShader();
|
||||||
static void KillCachedShader();
|
static void KillCachedShader();
|
||||||
|
|
||||||
inline static int NumShaders() { return smNumShaders; }
|
static int NumShaders() { return smNumShaders; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CacheCommonUniforms();
|
void CacheCommonUniforms();
|
||||||
|
|
|
@ -1,149 +1,148 @@
|
||||||
#include "CShaderGenerator.h"
|
#include "CShaderGenerator.h"
|
||||||
#include <Common/Macros.h>
|
#include <Common/Macros.h>
|
||||||
#include <iostream>
|
#include <array>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
const TString gkCoordSrc[] = {
|
using namespace std::string_view_literals;
|
||||||
"ModelSpacePos.xyz",
|
|
||||||
"ModelSpaceNormal.xyz",
|
constexpr std::array gkCoordSrc{
|
||||||
"0.0, 0.0, 0.0",
|
"ModelSpacePos.xyz"sv,
|
||||||
"0.0, 0.0, 0.0",
|
"ModelSpaceNormal.xyz"sv,
|
||||||
"RawTex0.xy, 1.0",
|
"0.0, 0.0, 0.0"sv,
|
||||||
"RawTex1.xy, 1.0",
|
"0.0, 0.0, 0.0"sv,
|
||||||
"RawTex2.xy, 1.0",
|
"RawTex0.xy, 1.0"sv,
|
||||||
"RawTex3.xy, 1.0",
|
"RawTex1.xy, 1.0"sv,
|
||||||
"RawTex4.xy, 1.0",
|
"RawTex2.xy, 1.0"sv,
|
||||||
"RawTex5.xy, 1.0",
|
"RawTex3.xy, 1.0"sv,
|
||||||
"RawTex6.xy, 1.0",
|
"RawTex4.xy, 1.0"sv,
|
||||||
"RawTex7.xy, 1.0"
|
"RawTex5.xy, 1.0"sv,
|
||||||
|
"RawTex6.xy, 1.0"sv,
|
||||||
|
"RawTex7.xy, 1.0"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkRasSel[] = {
|
constexpr std::array gkRasSel{
|
||||||
"vec4(COLOR0A0.rgb, 1.0)",
|
"vec4(COLOR0A0.rgb, 1.0)"sv,
|
||||||
"vec4(COLOR1A1.rgb, 1.0)",
|
"vec4(COLOR1A1.rgb, 1.0)"sv,
|
||||||
"vec4(0.0, 0.0, 0.0, COLOR0A0.a)",
|
"vec4(0.0, 0.0, 0.0, COLOR0A0.a)"sv,
|
||||||
"vec4(0.0, 0.0, 0.0, COLOR1A1.a)",
|
"vec4(0.0, 0.0, 0.0, COLOR1A1.a)"sv,
|
||||||
"COLOR0A0",
|
"COLOR0A0"sv,
|
||||||
"COLOR1A1",
|
"COLOR1A1"sv,
|
||||||
"vec4(0.0, 0.0, 0.0, 0.0)"
|
"vec4(0.0, 0.0, 0.0, 0.0)"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkKonstColor[] = {
|
constexpr std::array gkKonstColor{
|
||||||
"1.0, 1.0, 1.0",
|
"1.0, 1.0, 1.0"sv,
|
||||||
"0.875, 0.875, 0.875",
|
"0.875, 0.875, 0.875"sv,
|
||||||
"0.75, 0.75, 0.75",
|
"0.75, 0.75, 0.75"sv,
|
||||||
"0.625, 0.625, 0.625",
|
"0.625, 0.625, 0.625"sv,
|
||||||
"0.5, 0.5, 0.5",
|
"0.5, 0.5, 0.5"sv,
|
||||||
"0.375, 0.375, 0.375",
|
"0.375, 0.375, 0.375"sv,
|
||||||
"0.25, 0.25, 0.25",
|
"0.25, 0.25, 0.25"sv,
|
||||||
"0.125, 0.125, 0.125",
|
"0.125, 0.125, 0.125"sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"KonstColors[0].rgb",
|
"KonstColors[0].rgb"sv,
|
||||||
"KonstColors[1].rgb",
|
"KonstColors[1].rgb"sv,
|
||||||
"KonstColors[2].rgb",
|
"KonstColors[2].rgb"sv,
|
||||||
"KonstColors[3].rgb",
|
"KonstColors[3].rgb"sv,
|
||||||
"KonstColors[0].rrr",
|
"KonstColors[0].rrr"sv,
|
||||||
"KonstColors[1].rrr",
|
"KonstColors[1].rrr"sv,
|
||||||
"KonstColors[2].rrr",
|
"KonstColors[2].rrr"sv,
|
||||||
"KonstColors[3].rrr",
|
"KonstColors[3].rrr"sv,
|
||||||
"KonstColors[0].ggg",
|
"KonstColors[0].ggg"sv,
|
||||||
"KonstColors[1].ggg",
|
"KonstColors[1].ggg"sv,
|
||||||
"KonstColors[2].ggg",
|
"KonstColors[2].ggg"sv,
|
||||||
"KonstColors[3].ggg",
|
"KonstColors[3].ggg"sv,
|
||||||
"KonstColors[0].bbb",
|
"KonstColors[0].bbb"sv,
|
||||||
"KonstColors[1].bbb",
|
"KonstColors[1].bbb"sv,
|
||||||
"KonstColors[2].bbb",
|
"KonstColors[2].bbb"sv,
|
||||||
"KonstColors[3].bbb",
|
"KonstColors[3].bbb"sv,
|
||||||
"KonstColors[0].aaa",
|
"KonstColors[0].aaa"sv,
|
||||||
"KonstColors[1].aaa",
|
"KonstColors[1].aaa"sv,
|
||||||
"KonstColors[2].aaa",
|
"KonstColors[2].aaa"sv,
|
||||||
"KonstColors[3].aaa"
|
"KonstColors[3].aaa"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkKonstAlpha[] = {
|
constexpr std::array gkKonstAlpha{
|
||||||
"1.0",
|
"1.0"sv,
|
||||||
"0.875",
|
"0.875"sv,
|
||||||
"0.75",
|
"0.75"sv,
|
||||||
"0.625",
|
"0.625"sv,
|
||||||
"0.5",
|
"0.5"sv,
|
||||||
"0.375",
|
"0.375"sv,
|
||||||
"0.25",
|
"0.25"sv,
|
||||||
"0.125",
|
"0.125"sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"",
|
""sv,
|
||||||
"KonstColors[0].r",
|
"KonstColors[0].r"sv,
|
||||||
"KonstColors[1].r",
|
"KonstColors[1].r"sv,
|
||||||
"KonstColors[2].r",
|
"KonstColors[2].r"sv,
|
||||||
"KonstColors[3].r",
|
"KonstColors[3].r"sv,
|
||||||
"KonstColors[0].g",
|
"KonstColors[0].g"sv,
|
||||||
"KonstColors[1].g",
|
"KonstColors[1].g"sv,
|
||||||
"KonstColors[2].g",
|
"KonstColors[2].g"sv,
|
||||||
"KonstColors[3].g",
|
"KonstColors[3].g"sv,
|
||||||
"KonstColors[0].b",
|
"KonstColors[0].b"sv,
|
||||||
"KonstColors[1].b",
|
"KonstColors[1].b"sv,
|
||||||
"KonstColors[2].b",
|
"KonstColors[2].b"sv,
|
||||||
"KonstColors[3].b",
|
"KonstColors[3].b"sv,
|
||||||
"KonstColors[0].a",
|
"KonstColors[0].a"sv,
|
||||||
"KonstColors[1].a",
|
"KonstColors[1].a"sv,
|
||||||
"KonstColors[2].a",
|
"KonstColors[2].a"sv,
|
||||||
"KonstColors[3].a"
|
"KonstColors[3].a"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkTevColor[] = {
|
constexpr std::array gkTevColor{
|
||||||
"Prev.rgb",
|
"Prev.rgb"sv,
|
||||||
"Prev.aaa",
|
"Prev.aaa"sv,
|
||||||
"C0.rgb",
|
"C0.rgb"sv,
|
||||||
"C0.aaa",
|
"C0.aaa"sv,
|
||||||
"C1.rgb",
|
"C1.rgb"sv,
|
||||||
"C1.aaa",
|
"C1.aaa"sv,
|
||||||
"C2.rgb",
|
"C2.rgb"sv,
|
||||||
"C2.aaa",
|
"C2.aaa"sv,
|
||||||
"Tex.rgb",
|
"Tex.rgb"sv,
|
||||||
"Tex.aaa",
|
"Tex.aaa"sv,
|
||||||
"Ras.rgb",
|
"Ras.rgb"sv,
|
||||||
"Ras.aaa",
|
"Ras.aaa"sv,
|
||||||
"1.0, 1.0, 1.0",
|
"1.0, 1.0, 1.0"sv,
|
||||||
"0.5, 0.5, 0.5",
|
"0.5, 0.5, 0.5"sv,
|
||||||
"Konst.rgb",
|
"Konst.rgb"sv,
|
||||||
"0.0, 0.0, 0.0"
|
"0.0, 0.0, 0.0"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkTevAlpha[] = {
|
constexpr std::array gkTevAlpha{
|
||||||
"Prev.a",
|
"Prev.a"sv,
|
||||||
"C0.a",
|
"C0.a"sv,
|
||||||
"C1.a",
|
"C1.a"sv,
|
||||||
"C2.a",
|
"C2.a"sv,
|
||||||
"Tex.a",
|
"Tex.a"sv,
|
||||||
"Ras.a",
|
"Ras.a"sv,
|
||||||
"Konst.a",
|
"Konst.a"sv,
|
||||||
"0.0"
|
"0.0"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TString gkTevRigid[] = {
|
constexpr std::array gkTevRigid{
|
||||||
"Prev",
|
"Prev"sv,
|
||||||
"C0",
|
"C0"sv,
|
||||||
"C1",
|
"C1"sv,
|
||||||
"C2"
|
"C2"sv,
|
||||||
};
|
};
|
||||||
|
|
||||||
CShaderGenerator::CShaderGenerator()
|
CShaderGenerator::CShaderGenerator() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CShaderGenerator::~CShaderGenerator()
|
CShaderGenerator::~CShaderGenerator() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
|
bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
|
||||||
{
|
{
|
||||||
|
@ -366,34 +365,34 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
|
||||||
return mpShader->CompileVertexSource(ShaderCode.str().c_str());
|
return mpShader->CompileVertexSource(ShaderCode.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static TString GetColorInputExpression(const CMaterialPass* pPass, ETevColorInput iInput)
|
static std::string GetColorInputExpression(const CMaterialPass* pPass, ETevColorInput iInput)
|
||||||
{
|
{
|
||||||
if (iInput == ETevColorInput::kTextureRGB)
|
if (iInput == ETevColorInput::kTextureRGB)
|
||||||
{
|
{
|
||||||
TString Ret("Tex.");
|
std::string Ret("Tex.");
|
||||||
for (uint32 i = 0; i < 3; ++i)
|
for (uint32 i = 0; i < 3; ++i)
|
||||||
Ret += pPass->TexSwapComp(i);
|
Ret += pPass->TexSwapComp(i);
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
else if (iInput == ETevColorInput::kTextureAAA)
|
else if (iInput == ETevColorInput::kTextureAAA)
|
||||||
{
|
{
|
||||||
TString Ret("Tex.");
|
std::string Ret("Tex.");
|
||||||
for (uint32 i = 0; i < 3; ++i)
|
for (uint32 i = 0; i < 3; ++i)
|
||||||
Ret += pPass->TexSwapComp(3);
|
Ret += pPass->TexSwapComp(3);
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
return gkTevColor[iInput];
|
return std::string(gkTevColor[iInput]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TString GetAlphaInputExpression(const CMaterialPass* pPass, ETevAlphaInput iInput)
|
static std::string GetAlphaInputExpression(const CMaterialPass* pPass, ETevAlphaInput iInput)
|
||||||
{
|
{
|
||||||
if (iInput == ETevAlphaInput::kTextureAlpha)
|
if (iInput == ETevAlphaInput::kTextureAlpha)
|
||||||
{
|
{
|
||||||
TString Ret("Tex.");
|
std::string Ret("Tex.");
|
||||||
Ret += pPass->TexSwapComp(3);
|
Ret += pPass->TexSwapComp(3);
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
return gkTevAlpha[iInput];
|
return std::string(gkTevAlpha[iInput]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)
|
bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
*/
|
*/
|
||||||
class CShaderGenerator
|
class CShaderGenerator
|
||||||
{
|
{
|
||||||
CShader *mpShader;
|
CShader *mpShader = nullptr;
|
||||||
|
|
||||||
CShaderGenerator();
|
CShaderGenerator();
|
||||||
~CShaderGenerator();
|
~CShaderGenerator();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
class CUniformBuffer
|
class CUniformBuffer
|
||||||
{
|
{
|
||||||
GLuint mUniformBuffer;
|
GLuint mUniformBuffer;
|
||||||
uint mBufferSize;
|
uint32 mBufferSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ public:
|
||||||
SetBufferSize(0);
|
SetBufferSize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUniformBuffer(uint Size)
|
explicit CUniformBuffer(uint32 Size)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &mUniformBuffer);
|
glGenBuffers(1, &mUniformBuffer);
|
||||||
SetBufferSize(Size);
|
SetBufferSize(Size);
|
||||||
|
@ -52,20 +52,20 @@ public:
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferRange(const void *pkData, uint Offset, uint Size)
|
void BufferRange(const void *pkData, uint32 Offset, uint32 Size)
|
||||||
{
|
{
|
||||||
Bind();
|
Bind();
|
||||||
glBufferSubData(GL_UNIFORM_BUFFER, Offset, Size, pkData);
|
glBufferSubData(GL_UNIFORM_BUFFER, Offset, Size, pkData);
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetBufferSize(uint Size)
|
void SetBufferSize(uint32 Size)
|
||||||
{
|
{
|
||||||
mBufferSize = Size;
|
mBufferSize = Size;
|
||||||
InitializeBuffer();
|
InitializeBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint GetBufferSize()
|
uint32 GetBufferSize() const
|
||||||
{
|
{
|
||||||
return mBufferSize;
|
return mBufferSize;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ private:
|
||||||
void InitializeBuffer()
|
void InitializeBuffer()
|
||||||
{
|
{
|
||||||
Bind();
|
Bind();
|
||||||
glBufferData(GL_UNIFORM_BUFFER, mBufferSize, 0, GL_DYNAMIC_DRAW);
|
glBufferData(GL_UNIFORM_BUFFER, mBufferSize, nullptr, GL_DYNAMIC_DRAW);
|
||||||
Unbind();
|
Unbind();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,8 +22,10 @@ CVertexArrayManager::~CVertexArrayManager()
|
||||||
sVAManagers.erase(sVAManagers.begin() + mVectorIndex);
|
sVAManagers.erase(sVAManagers.begin() + mVectorIndex);
|
||||||
|
|
||||||
if (sVAManagers.size() > mVectorIndex)
|
if (sVAManagers.size() > mVectorIndex)
|
||||||
|
{
|
||||||
for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++)
|
for (auto it = sVAManagers.begin() + mVectorIndex; it != sVAManagers.end(); it++)
|
||||||
(*it)->mVectorIndex--;
|
(*it)->mVectorIndex--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ PUBLIC ************
|
// ************ PUBLIC ************
|
||||||
|
@ -34,15 +36,16 @@ void CVertexArrayManager::SetCurrent()
|
||||||
|
|
||||||
void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
|
void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
auto it = mVBOMap.find(pVBO);
|
const auto it = mVBOMap.find(pVBO);
|
||||||
|
|
||||||
if (it != mVBOMap.end())
|
if (it != mVBOMap.cend())
|
||||||
|
{
|
||||||
glBindVertexArray(it->second);
|
glBindVertexArray(it->second);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GLuint VAO = pVBO->CreateVAO();
|
const GLuint VAO = pVBO->CreateVAO();
|
||||||
mVBOMap[pVBO] = VAO;
|
mVBOMap.insert_or_assign(pVBO, VAO);
|
||||||
glBindVertexArray(VAO);
|
glBindVertexArray(VAO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,40 +53,41 @@ void CVertexArrayManager::BindVAO(CVertexBuffer *pVBO)
|
||||||
void CVertexArrayManager::BindVAO(CDynamicVertexBuffer *pVBO)
|
void CVertexArrayManager::BindVAO(CDynamicVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
// Overload for CDynamicVertexBuffer
|
// Overload for CDynamicVertexBuffer
|
||||||
auto it = mDynamicVBOMap.find(pVBO);
|
const auto it = mDynamicVBOMap.find(pVBO);
|
||||||
|
|
||||||
if (it != mDynamicVBOMap.end())
|
if (it != mDynamicVBOMap.cend())
|
||||||
|
{
|
||||||
glBindVertexArray(it->second);
|
glBindVertexArray(it->second);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GLuint VAO = pVBO->CreateVAO();
|
const GLuint VAO = pVBO->CreateVAO();
|
||||||
mDynamicVBOMap[pVBO] = VAO;
|
mDynamicVBOMap.insert_or_assign(pVBO, VAO);
|
||||||
glBindVertexArray(VAO);
|
glBindVertexArray(VAO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVertexArrayManager::DeleteVAO(CVertexBuffer *pVBO)
|
void CVertexArrayManager::DeleteVAO(CVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
auto it = mVBOMap.find(pVBO);
|
const auto it = mVBOMap.find(pVBO);
|
||||||
|
|
||||||
if (it != mVBOMap.end())
|
if (it == mVBOMap.cend())
|
||||||
{
|
return;
|
||||||
glDeleteVertexArrays(1, &it->second);
|
|
||||||
mVBOMap.erase(it);
|
glDeleteVertexArrays(1, &it->second);
|
||||||
}
|
mVBOMap.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVertexArrayManager::DeleteVAO(CDynamicVertexBuffer *pVBO)
|
void CVertexArrayManager::DeleteVAO(CDynamicVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
// Overload for CDynamicVertexBuffer
|
// Overload for CDynamicVertexBuffer
|
||||||
auto it = mDynamicVBOMap.find(pVBO);
|
const auto it = mDynamicVBOMap.find(pVBO);
|
||||||
|
|
||||||
if (it != mDynamicVBOMap.end())
|
if (it == mDynamicVBOMap.cend())
|
||||||
{
|
return;
|
||||||
glDeleteVertexArrays(1, &it->second);
|
|
||||||
mDynamicVBOMap.erase(it);
|
glDeleteVertexArrays(1, &it->second);
|
||||||
}
|
mDynamicVBOMap.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
|
@ -94,12 +98,12 @@ CVertexArrayManager* CVertexArrayManager::Current()
|
||||||
|
|
||||||
void CVertexArrayManager::DeleteAllArraysForVBO(CVertexBuffer *pVBO)
|
void CVertexArrayManager::DeleteAllArraysForVBO(CVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
for (uint32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++)
|
for (auto* vam : sVAManagers)
|
||||||
sVAManagers[iVAM]->DeleteVAO(pVBO);
|
vam->DeleteVAO(pVBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVertexArrayManager::DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO)
|
void CVertexArrayManager::DeleteAllArraysForVBO(CDynamicVertexBuffer *pVBO)
|
||||||
{
|
{
|
||||||
for (uint32 iVAM = 0; iVAM < sVAManagers.size(); iVAM++)
|
for (auto* vam : sVAManagers)
|
||||||
sVAManagers[iVAM]->DeleteVAO(pVBO);
|
vam->DeleteVAO(pVBO);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class CVertexArrayManager
|
||||||
{
|
{
|
||||||
std::unordered_map<CVertexBuffer*, GLuint> mVBOMap;
|
std::unordered_map<CVertexBuffer*, GLuint> mVBOMap;
|
||||||
std::unordered_map<CDynamicVertexBuffer*, GLuint> mDynamicVBOMap;
|
std::unordered_map<CDynamicVertexBuffer*, GLuint> mDynamicVBOMap;
|
||||||
uint32 mVectorIndex;
|
uint32 mVectorIndex = 0;
|
||||||
|
|
||||||
static std::vector<CVertexArrayManager*> sVAManagers;
|
static std::vector<CVertexArrayManager*> sVAManagers;
|
||||||
static CVertexArrayManager *spCurrentManager;
|
static CVertexArrayManager *spCurrentManager;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
CVertexBuffer::CVertexBuffer()
|
CVertexBuffer::CVertexBuffer()
|
||||||
{
|
{
|
||||||
mBuffered = false;
|
|
||||||
SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal |
|
SetVertexDesc(EVertexAttribute::Position | EVertexAttribute::Normal |
|
||||||
EVertexAttribute::Tex0 | EVertexAttribute::Tex1 |
|
EVertexAttribute::Tex0 | EVertexAttribute::Tex1 |
|
||||||
EVertexAttribute::Tex2 | EVertexAttribute::Tex3 |
|
EVertexAttribute::Tex2 | EVertexAttribute::Tex3 |
|
||||||
|
@ -22,72 +21,103 @@ CVertexBuffer::~CVertexBuffer()
|
||||||
CVertexArrayManager::DeleteAllArraysForVBO(this);
|
CVertexArrayManager::DeleteAllArraysForVBO(this);
|
||||||
|
|
||||||
if (mBuffered)
|
if (mBuffered)
|
||||||
glDeleteBuffers(14, mAttribBuffers);
|
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 CVertexBuffer::AddVertex(const CVertex& rkVtx)
|
uint16 CVertexBuffer::AddVertex(const CVertex& rkVtx)
|
||||||
{
|
{
|
||||||
if (mPositions.size() == 0xFFFF) throw std::overflow_error("VBO contains too many vertices");
|
if (mPositions.size() == 0xFFFF)
|
||||||
|
throw std::overflow_error("VBO contains too many vertices");
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Position) mPositions.push_back(rkVtx.Position);
|
if ((mVtxDesc & EVertexAttribute::Position) != 0)
|
||||||
if (mVtxDesc & EVertexAttribute::Normal) mNormals.push_back(rkVtx.Normal);
|
mPositions.emplace_back(rkVtx.Position);
|
||||||
if (mVtxDesc & EVertexAttribute::Color0) mColors[0].push_back(rkVtx.Color[0]);
|
if ((mVtxDesc & EVertexAttribute::Normal) != 0)
|
||||||
if (mVtxDesc & EVertexAttribute::Color1) mColors[1].push_back(rkVtx.Color[1]);
|
mNormals.emplace_back(rkVtx.Normal);
|
||||||
|
if ((mVtxDesc & EVertexAttribute::Color0) != 0)
|
||||||
|
mColors[0].emplace_back(rkVtx.Color[0]);
|
||||||
|
if ((mVtxDesc & EVertexAttribute::Color1) != 0)
|
||||||
|
mColors[1].emplace_back(rkVtx.Color[1]);
|
||||||
|
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
|
||||||
if (mVtxDesc & (EVertexAttribute::Tex0 << iTex)) mTexCoords[iTex].push_back(rkVtx.Tex[iTex]);
|
|
||||||
|
|
||||||
for (uint32 iMtx = 0; iMtx < 8; iMtx++)
|
|
||||||
if (mVtxDesc & (EVertexAttribute::PosMtx << iMtx)) mTexCoords[iMtx].push_back(rkVtx.MatrixIndices[iMtx]);
|
|
||||||
|
|
||||||
if (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights) && mpSkin)
|
|
||||||
{
|
{
|
||||||
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
|
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
|
||||||
if (mVtxDesc & EVertexAttribute::BoneIndices) mBoneIndices.push_back(rkWeights.Indices);
|
mTexCoords[iTex].emplace_back(rkVtx.Tex[iTex]);
|
||||||
if (mVtxDesc & EVertexAttribute::BoneWeights) mBoneWeights.push_back(rkWeights.Weights);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (mPositions.size() - 1);
|
for (size_t iMtx = 0; iMtx < mTexCoords.size(); iMtx++)
|
||||||
|
{
|
||||||
|
if ((mVtxDesc & (EVertexAttribute::PosMtx << iMtx)) != 0)
|
||||||
|
mTexCoords[iMtx].emplace_back(rkVtx.MatrixIndices[iMtx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights) && mpSkin != nullptr)
|
||||||
|
{
|
||||||
|
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
|
||||||
|
if ((mVtxDesc & EVertexAttribute::BoneIndices) != 0)
|
||||||
|
mBoneIndices.emplace_back(rkWeights.Indices);
|
||||||
|
if ((mVtxDesc & EVertexAttribute::BoneWeights) != 0)
|
||||||
|
mBoneWeights.emplace_back(rkWeights.Weights);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mPositions.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start)
|
uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start)
|
||||||
{
|
{
|
||||||
if (Start < mPositions.size())
|
if (Start < mPositions.size())
|
||||||
{
|
{
|
||||||
for (uint16 iVert = Start; iVert < mPositions.size(); iVert++)
|
for (size_t iVert = Start; iVert < mPositions.size(); iVert++)
|
||||||
{
|
{
|
||||||
// I use a bool because "continue" doesn't work properly within the iTex loop
|
// I use a bool because "continue" doesn't work properly within the iTex loop
|
||||||
bool Unique = false;
|
bool Unique = false;
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Position)
|
if ((mVtxDesc & EVertexAttribute::Position) != 0)
|
||||||
if (rkVtx.Position != mPositions[iVert]) Unique = true;
|
{
|
||||||
|
if (rkVtx.Position != mPositions[iVert])
|
||||||
|
Unique = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Unique && (mVtxDesc & EVertexAttribute::Normal))
|
if (!Unique && (mVtxDesc & EVertexAttribute::Normal) != 0)
|
||||||
if (rkVtx.Normal != mNormals[iVert]) Unique = true;
|
{
|
||||||
|
if (rkVtx.Normal != mNormals[iVert])
|
||||||
|
Unique = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Unique && (mVtxDesc & EVertexAttribute::Color0))
|
if (!Unique && (mVtxDesc & EVertexAttribute::Color0) != 0)
|
||||||
if (rkVtx.Color[0] != mColors[0][iVert]) Unique = true;
|
{
|
||||||
|
if (rkVtx.Color[0] != mColors[0][iVert])
|
||||||
|
Unique = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Unique && (mVtxDesc & EVertexAttribute::Color1))
|
if (!Unique && (mVtxDesc & EVertexAttribute::Color1) != 0)
|
||||||
if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true;
|
{
|
||||||
|
if (rkVtx.Color[1] != mColors[1][iVert])
|
||||||
|
Unique = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Unique)
|
if (!Unique)
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
{
|
||||||
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)))
|
for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
|
||||||
|
{
|
||||||
|
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
|
||||||
|
{
|
||||||
if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert])
|
if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert])
|
||||||
{
|
{
|
||||||
Unique = true;
|
Unique = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!Unique && mpSkin && (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights)))
|
if (!Unique && mpSkin != nullptr && (mVtxDesc.HasAnyFlags(EVertexAttribute::BoneIndices | EVertexAttribute::BoneWeights)))
|
||||||
{
|
{
|
||||||
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
|
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
|
||||||
|
|
||||||
for (uint32 iWgt = 0; iWgt < 4; iWgt++)
|
for (uint32 iWgt = 0; iWgt < 4; iWgt++)
|
||||||
{
|
{
|
||||||
if ( ((mVtxDesc & EVertexAttribute::BoneIndices) && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
|
if (((mVtxDesc & EVertexAttribute::BoneIndices) != 0 && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
|
||||||
((mVtxDesc & EVertexAttribute::BoneWeights) && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])) )
|
((mVtxDesc & EVertexAttribute::BoneWeights) != 0 && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])))
|
||||||
{
|
{
|
||||||
Unique = true;
|
Unique = true;
|
||||||
break;
|
break;
|
||||||
|
@ -95,44 +125,47 @@ uint16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, uint16 Start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Unique) return iVert;
|
if (!Unique)
|
||||||
|
return static_cast<uint16>(iVert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AddVertex(rkVtx);
|
return AddVertex(rkVtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVertexBuffer::Reserve(uint16 Size)
|
void CVertexBuffer::Reserve(size_t Size)
|
||||||
{
|
{
|
||||||
uint32 ReserveSize = mPositions.size() + Size;
|
const size_t ReserveSize = mPositions.size() + Size;
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Position)
|
if ((mVtxDesc & EVertexAttribute::Position) != 0)
|
||||||
mPositions.reserve(ReserveSize);
|
mPositions.reserve(ReserveSize);
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Normal)
|
if ((mVtxDesc & EVertexAttribute::Normal) != 0)
|
||||||
mNormals.reserve(ReserveSize);
|
mNormals.reserve(ReserveSize);
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Color0)
|
if ((mVtxDesc & EVertexAttribute::Color0) != 0)
|
||||||
mColors[0].reserve(ReserveSize);
|
mColors[0].reserve(ReserveSize);
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::Color1)
|
if ((mVtxDesc & EVertexAttribute::Color1) != 0)
|
||||||
mColors[1].reserve(ReserveSize);
|
mColors[1].reserve(ReserveSize);
|
||||||
|
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
for (size_t iTex = 0; iTex < mTexCoords.size(); iTex++)
|
||||||
if (mVtxDesc & (EVertexAttribute::Tex0 << iTex))
|
{
|
||||||
|
if ((mVtxDesc & (EVertexAttribute::Tex0 << iTex)) != 0)
|
||||||
mTexCoords[iTex].reserve(ReserveSize);
|
mTexCoords[iTex].reserve(ReserveSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::BoneIndices)
|
if ((mVtxDesc & EVertexAttribute::BoneIndices) != 0)
|
||||||
mBoneIndices.reserve(ReserveSize);
|
mBoneIndices.reserve(ReserveSize);
|
||||||
|
|
||||||
if (mVtxDesc & EVertexAttribute::BoneWeights)
|
if ((mVtxDesc & EVertexAttribute::BoneWeights) != 0)
|
||||||
mBoneWeights.reserve(ReserveSize);
|
mBoneWeights.reserve(ReserveSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVertexBuffer::Clear()
|
void CVertexBuffer::Clear()
|
||||||
{
|
{
|
||||||
if (mBuffered)
|
if (mBuffered)
|
||||||
glDeleteBuffers(14, mAttribBuffers);
|
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
|
||||||
|
|
||||||
mBuffered = false;
|
mBuffered = false;
|
||||||
mPositions.clear();
|
mPositions.clear();
|
||||||
|
@ -140,8 +173,8 @@ void CVertexBuffer::Clear()
|
||||||
mColors[0].clear();
|
mColors[0].clear();
|
||||||
mColors[1].clear();
|
mColors[1].clear();
|
||||||
|
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
for (auto& coord : mTexCoords)
|
||||||
mTexCoords[iTex].clear();
|
coord.clear();
|
||||||
|
|
||||||
mBoneIndices.clear();
|
mBoneIndices.clear();
|
||||||
mBoneWeights.clear();
|
mBoneWeights.clear();
|
||||||
|
@ -152,49 +185,46 @@ void CVertexBuffer::Buffer()
|
||||||
// Make sure we don't end up with two buffers for the same data...
|
// Make sure we don't end up with two buffers for the same data...
|
||||||
if (mBuffered)
|
if (mBuffered)
|
||||||
{
|
{
|
||||||
glDeleteBuffers(14, mAttribBuffers);
|
glDeleteBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
|
||||||
mBuffered = false;
|
mBuffered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate buffers
|
// Generate buffers
|
||||||
glGenBuffers(14, mAttribBuffers);
|
glGenBuffers(static_cast<GLsizei>(mAttribBuffers.size()), mAttribBuffers.data());
|
||||||
|
|
||||||
for (uint32 iAttrib = 0; iAttrib < 14; iAttrib++)
|
for (size_t iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
|
||||||
{
|
{
|
||||||
int Attrib = (EVertexAttribute::Position << iAttrib);
|
const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
|
||||||
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
|
const bool HasAttrib = (mVtxDesc & Attrib) != 0;
|
||||||
if (!HasAttrib) continue;
|
if (!HasAttrib)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (iAttrib < 2)
|
if (iAttrib < 2)
|
||||||
{
|
{
|
||||||
std::vector<CVector3f> *pBuffer = (iAttrib == 0) ? &mPositions : &mNormals;
|
const std::vector<CVector3f>& pBuffer = iAttrib == 0 ? mPositions : mNormals;
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, pBuffer->size() * sizeof(CVector3f), pBuffer->data(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, pBuffer.size() * sizeof(CVector3f), pBuffer.data(), GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib < 4)
|
else if (iAttrib < 4)
|
||||||
{
|
{
|
||||||
uint8 Index = (uint8) (iAttrib - 2);
|
const auto Index = static_cast<uint8>(iAttrib - 2);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib < 12)
|
else if (iAttrib < 12)
|
||||||
{
|
{
|
||||||
uint8 Index = (uint8) (iAttrib - 4);
|
const auto Index = static_cast<uint8>(iAttrib - 4);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib == 12)
|
else if (iAttrib == 12)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib == 13)
|
else if (iAttrib == 13)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
|
@ -207,7 +237,9 @@ void CVertexBuffer::Buffer()
|
||||||
|
|
||||||
void CVertexBuffer::Bind()
|
void CVertexBuffer::Bind()
|
||||||
{
|
{
|
||||||
if (!mBuffered) Buffer();
|
if (!mBuffered)
|
||||||
|
Buffer();
|
||||||
|
|
||||||
CVertexArrayManager::Current()->BindVAO(this);
|
CVertexArrayManager::Current()->BindVAO(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,12 +248,12 @@ void CVertexBuffer::Unbind()
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVertexBuffer::IsBuffered()
|
bool CVertexBuffer::IsBuffered() const
|
||||||
{
|
{
|
||||||
return mBuffered;
|
return mBuffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
FVertexDescription CVertexBuffer::VertexDesc()
|
FVertexDescription CVertexBuffer::VertexDesc() const
|
||||||
{
|
{
|
||||||
return mVtxDesc;
|
return mVtxDesc;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +270,7 @@ void CVertexBuffer::SetSkin(CSkin *pSkin)
|
||||||
mpSkin = pSkin;
|
mpSkin = pSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 CVertexBuffer::Size()
|
size_t CVertexBuffer::Size() const
|
||||||
{
|
{
|
||||||
return mPositions.size();
|
return mPositions.size();
|
||||||
}
|
}
|
||||||
|
@ -249,44 +281,40 @@ GLuint CVertexBuffer::CreateVAO()
|
||||||
glGenVertexArrays(1, &VertexArray);
|
glGenVertexArrays(1, &VertexArray);
|
||||||
glBindVertexArray(VertexArray);
|
glBindVertexArray(VertexArray);
|
||||||
|
|
||||||
for (uint32 iAttrib = 0; iAttrib < 14; iAttrib++)
|
for (size_t iAttrib = 0; iAttrib < mAttribBuffers.size(); iAttrib++)
|
||||||
{
|
{
|
||||||
int Attrib = (EVertexAttribute::Position << iAttrib);
|
const auto Attrib = static_cast<int>(EVertexAttribute::Position << iAttrib);
|
||||||
bool HasAttrib = ((mVtxDesc & Attrib) != 0);
|
const bool HasAttrib = (mVtxDesc & Attrib) != 0;
|
||||||
if (!HasAttrib) continue;
|
if (!HasAttrib) continue;
|
||||||
|
|
||||||
if (iAttrib < 2)
|
if (iAttrib < 2)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), (void*) 0);
|
glVertexAttribPointer(iAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(CVector3f), nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib < 4)
|
else if (iAttrib < 4)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), (void*) 0);
|
glVertexAttribPointer(iAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(CColor), nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib < 12)
|
else if (iAttrib < 12)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0);
|
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib == 12)
|
else if (iAttrib == 12)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glVertexAttribIPointer(iAttrib, 1, GL_UNSIGNED_INT, sizeof(TBoneIndices), (void*) 0);
|
glVertexAttribIPointer(iAttrib, 1, GL_UNSIGNED_INT, sizeof(TBoneIndices), nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (iAttrib == 13)
|
else if (iAttrib == 13)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||||
glVertexAttribPointer(iAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(TBoneWeights), (void*) 0);
|
glVertexAttribPointer(iAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(TBoneWeights), nullptr);
|
||||||
glEnableVertexAttribArray(iAttrib);
|
glEnableVertexAttribArray(iAttrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,38 +5,39 @@
|
||||||
#include "Core/Resource/Animation/CSkin.h"
|
#include "Core/Resource/Animation/CSkin.h"
|
||||||
#include "Core/Resource/Model/CVertex.h"
|
#include "Core/Resource/Model/CVertex.h"
|
||||||
#include "Core/Resource/Model/EVertexAttribute.h"
|
#include "Core/Resource/Model/EVertexAttribute.h"
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
class CVertexBuffer
|
class CVertexBuffer
|
||||||
{
|
{
|
||||||
FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
|
FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
|
||||||
GLuint mAttribBuffers[14]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
|
std::array<GLuint, 14> mAttribBuffers{}; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
|
||||||
TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models;
|
TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models;
|
||||||
std::vector<CVector3f> mPositions; // Vector of vertex positions
|
std::vector<CVector3f> mPositions; // Vector of vertex positions
|
||||||
std::vector<CVector3f> mNormals; // Vector of vertex normals
|
std::vector<CVector3f> mNormals; // Vector of vertex normals
|
||||||
std::vector<CColor> mColors[2]; // Vectors of vertex colors
|
std::array<std::vector<CColor>, 2> mColors; // Vectors of vertex colors
|
||||||
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates
|
std::array<std::vector<CVector2f>, 8> mTexCoords; // Vectors of texture coordinates
|
||||||
std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices
|
std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices
|
||||||
std::vector<TBoneWeights> mBoneWeights; // Vectors of bone weights
|
std::vector<TBoneWeights> mBoneWeights; // Vectors of bone weights
|
||||||
bool mBuffered; // Bool value that indicates whether the attributes have been buffered.
|
bool mBuffered = false; // Bool value that indicates whether the attributes have been buffered.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CVertexBuffer();
|
CVertexBuffer();
|
||||||
CVertexBuffer(FVertexDescription Desc);
|
explicit CVertexBuffer(FVertexDescription Desc);
|
||||||
~CVertexBuffer();
|
~CVertexBuffer();
|
||||||
uint16 AddVertex(const CVertex& rkVtx);
|
uint16 AddVertex(const CVertex& rkVtx);
|
||||||
uint16 AddIfUnique(const CVertex& rkVtx, uint16 Start);
|
uint16 AddIfUnique(const CVertex& rkVtx, uint16 Start);
|
||||||
void Reserve(uint16 Size);
|
void Reserve(size_t Size);
|
||||||
void Clear();
|
void Clear();
|
||||||
void Buffer();
|
void Buffer();
|
||||||
void Bind();
|
void Bind();
|
||||||
void Unbind();
|
void Unbind();
|
||||||
bool IsBuffered();
|
bool IsBuffered() const;
|
||||||
FVertexDescription VertexDesc();
|
FVertexDescription VertexDesc() const;
|
||||||
void SetVertexDesc(FVertexDescription Desc);
|
void SetVertexDesc(FVertexDescription Desc);
|
||||||
void SetSkin(CSkin *pSkin);
|
void SetSkin(CSkin *pSkin);
|
||||||
uint32 Size();
|
size_t Size() const;
|
||||||
GLuint CreateVAO();
|
GLuint CreateVAO();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "GLCommon.h"
|
#include "GLCommon.h"
|
||||||
#include <Common/Macros.h>
|
#include <Common/Macros.h>
|
||||||
|
|
||||||
GLenum gBlendFactor[] =
|
const std::array<GLenum, 8> gBlendFactor
|
||||||
{
|
{
|
||||||
GL_ZERO, // GX_BL_ZERO
|
GL_ZERO, // GX_BL_ZERO
|
||||||
GL_ONE, // GX_BL_ONE
|
GL_ONE, // GX_BL_ONE
|
||||||
|
@ -14,7 +14,7 @@ GLenum gBlendFactor[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
GLenum gZMode[] =
|
const std::array<GLenum, 7> gZMode
|
||||||
{
|
{
|
||||||
GL_NEVER, // GX_NEVER
|
GL_NEVER, // GX_NEVER
|
||||||
GL_LESS, // GX_LESS
|
GL_LESS, // GX_LESS
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <Common/BasicTypes.h>
|
#include <Common/BasicTypes.h>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
enum class EBlendFactor
|
enum class EBlendFactor
|
||||||
{
|
{
|
||||||
|
@ -29,8 +30,8 @@ enum class EPrimitiveType
|
||||||
Points = 0xB8
|
Points = 0xB8
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GLenum gBlendFactor[];
|
extern const std::array<GLenum, 8> gBlendFactor;
|
||||||
extern GLenum gZMode[];
|
extern const std::array<GLenum, 7> gZMode;
|
||||||
GLenum GXPrimToGLPrim(EPrimitiveType Type);
|
GLenum GXPrimToGLPrim(EPrimitiveType Type);
|
||||||
|
|
||||||
#endif // GLCOMMON_H
|
#endif // GLCOMMON_H
|
||||||
|
|
|
@ -11,16 +11,16 @@ class CBoneTransformData
|
||||||
std::vector<CTransform4f> mBoneMatrices;
|
std::vector<CTransform4f> mBoneMatrices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CBoneTransformData() { }
|
CBoneTransformData() = default;
|
||||||
CBoneTransformData(CSkeleton *pSkel) { ResizeToSkeleton(pSkel); }
|
explicit CBoneTransformData(CSkeleton *pSkel) { ResizeToSkeleton(pSkel); }
|
||||||
inline void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); }
|
void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); }
|
||||||
inline CTransform4f& BoneMatrix(uint32 BoneID) { return mBoneMatrices[BoneID]; }
|
CTransform4f& BoneMatrix(size_t BoneID) { return mBoneMatrices[BoneID]; }
|
||||||
inline const CTransform4f& BoneMatrix(uint32 BoneID) const { return mBoneMatrices[BoneID]; }
|
const CTransform4f& BoneMatrix(size_t BoneID) const { return mBoneMatrices[BoneID]; }
|
||||||
inline const void* Data() const { return mBoneMatrices.data(); }
|
const void* Data() const { return mBoneMatrices.data(); }
|
||||||
inline uint32 DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); }
|
size_t DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); }
|
||||||
inline uint32 NumTrackedBones() const { return mBoneMatrices.size(); }
|
size_t NumTrackedBones() const { return mBoneMatrices.size(); }
|
||||||
inline CTransform4f& operator[](uint32 BoneIndex) { return BoneMatrix(BoneIndex); }
|
CTransform4f& operator[](size_t BoneIndex) { return BoneMatrix(BoneIndex); }
|
||||||
inline const CTransform4f& operator[](uint32 BoneIndex) const { return BoneMatrix(BoneIndex); }
|
const CTransform4f& operator[](size_t BoneIndex) const { return BoneMatrix(BoneIndex); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CBONETRANSFORMDATA
|
#endif // CBONETRANSFORMDATA
|
||||||
|
|
|
@ -4,17 +4,7 @@
|
||||||
#include <Common/Math/MathUtil.h>
|
#include <Common/Math/MathUtil.h>
|
||||||
|
|
||||||
CCamera::CCamera()
|
CCamera::CCamera()
|
||||||
: mMode(ECameraMoveMode::Free)
|
: mYaw(-Math::skHalfPi)
|
||||||
, mPosition(0)
|
|
||||||
, mAspectRatio(1.7777777f)
|
|
||||||
, mYaw(-Math::skHalfPi)
|
|
||||||
, mPitch(0.f)
|
|
||||||
, mMoveSpeed(1.f)
|
|
||||||
, mLookSpeed(1.f)
|
|
||||||
, mTransformDirty(true)
|
|
||||||
, mViewDirty(true)
|
|
||||||
, mProjectionDirty(true)
|
|
||||||
, mFrustumPlanesDirty(true)
|
|
||||||
{
|
{
|
||||||
ResetOrbit();
|
ResetOrbit();
|
||||||
}
|
}
|
||||||
|
@ -22,12 +12,8 @@ CCamera::CCamera()
|
||||||
// todo: make it actually look at the target!
|
// todo: make it actually look at the target!
|
||||||
// don't actually use this constructor, it's unfinished and won't work properly
|
// don't actually use this constructor, it's unfinished and won't work properly
|
||||||
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
|
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
|
||||||
: mMode(ECameraMoveMode::Free)
|
: mPosition(Position)
|
||||||
, mMoveSpeed(1.f)
|
|
||||||
, mLookSpeed(1.f)
|
|
||||||
, mPosition(Position)
|
|
||||||
, mYaw(-Math::skHalfPi)
|
, mYaw(-Math::skHalfPi)
|
||||||
, mPitch(0.f)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,28 +26,28 @@ enum class ECameraMoveMode
|
||||||
* const function). */
|
* const function). */
|
||||||
class CCamera
|
class CCamera
|
||||||
{
|
{
|
||||||
ECameraMoveMode mMode;
|
ECameraMoveMode mMode{ECameraMoveMode::Free};
|
||||||
mutable CVector3f mPosition;
|
mutable CVector3f mPosition;
|
||||||
mutable CVector3f mDirection;
|
mutable CVector3f mDirection;
|
||||||
mutable CVector3f mRightVector;
|
mutable CVector3f mRightVector;
|
||||||
mutable CVector3f mUpVector;
|
mutable CVector3f mUpVector;
|
||||||
float mAspectRatio;
|
float mAspectRatio = 1.7777777f;
|
||||||
|
|
||||||
float mYaw;
|
float mYaw;
|
||||||
float mPitch;
|
float mPitch = 0.0f;
|
||||||
CVector3f mOrbitTarget;
|
CVector3f mOrbitTarget;
|
||||||
mutable float mOrbitDistance;
|
mutable float mOrbitDistance = 0.0f;
|
||||||
float mMoveSpeed;
|
float mMoveSpeed = 1.0f;
|
||||||
float mLookSpeed;
|
float mLookSpeed = 1.0f;
|
||||||
|
|
||||||
mutable CMatrix4f mViewMatrix;
|
mutable CMatrix4f mViewMatrix;
|
||||||
mutable CMatrix4f mProjectionMatrix;
|
mutable CMatrix4f mProjectionMatrix;
|
||||||
mutable CFrustumPlanes mFrustumPlanes;
|
mutable CFrustumPlanes mFrustumPlanes;
|
||||||
|
|
||||||
mutable bool mTransformDirty;
|
mutable bool mTransformDirty = true;
|
||||||
mutable bool mViewDirty;
|
mutable bool mViewDirty = true;
|
||||||
mutable bool mProjectionDirty;
|
mutable bool mProjectionDirty = true;
|
||||||
mutable bool mFrustumPlanesDirty;
|
mutable bool mFrustumPlanesDirty = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCamera();
|
CCamera();
|
||||||
|
@ -70,25 +70,25 @@ public:
|
||||||
void SetOrbitDistance(float Distance);
|
void SetOrbitDistance(float Distance);
|
||||||
|
|
||||||
// Inline Accessors
|
// Inline Accessors
|
||||||
inline CVector3f Position() const { UpdateTransform(); return mPosition; }
|
CVector3f Position() const { UpdateTransform(); return mPosition; }
|
||||||
inline CVector3f Direction() const { UpdateTransform(); return mDirection; }
|
CVector3f Direction() const { UpdateTransform(); return mDirection; }
|
||||||
inline CVector3f UpVector() const { UpdateTransform(); return mUpVector; }
|
CVector3f UpVector() const { UpdateTransform(); return mUpVector; }
|
||||||
inline CVector3f RightVector() const { UpdateTransform(); return mRightVector; }
|
CVector3f RightVector() const { UpdateTransform(); return mRightVector; }
|
||||||
inline float Yaw() const { return mYaw; }
|
float Yaw() const { return mYaw; }
|
||||||
inline float Pitch() const { return mPitch; }
|
float Pitch() const { return mPitch; }
|
||||||
inline float FieldOfView() const { return 55.f; }
|
float FieldOfView() const { return 55.f; }
|
||||||
inline ECameraMoveMode MoveMode() const { return mMode; }
|
ECameraMoveMode MoveMode() const { return mMode; }
|
||||||
inline const CMatrix4f& ViewMatrix() const { UpdateView(); return mViewMatrix; }
|
const CMatrix4f& ViewMatrix() const { UpdateView(); return mViewMatrix; }
|
||||||
inline const CMatrix4f& ProjectionMatrix() const { UpdateProjection(); return mProjectionMatrix; }
|
const CMatrix4f& ProjectionMatrix() const { UpdateProjection(); return mProjectionMatrix; }
|
||||||
inline const CFrustumPlanes& FrustumPlanes() const { UpdateFrustum(); return mFrustumPlanes; }
|
const CFrustumPlanes& FrustumPlanes() const { UpdateFrustum(); return mFrustumPlanes; }
|
||||||
|
|
||||||
inline void SetYaw(float Yaw) { mYaw = Yaw; mTransformDirty = true; }
|
void SetYaw(float Yaw) { mYaw = Yaw; mTransformDirty = true; }
|
||||||
inline void SetPitch(float Pitch) { mPitch = Pitch; ValidatePitch(); mTransformDirty = true; }
|
void SetPitch(float Pitch) { mPitch = Pitch; ValidatePitch(); mTransformDirty = true; }
|
||||||
inline void SetMoveSpeed(float MoveSpeed) { mMoveSpeed = MoveSpeed; }
|
void SetMoveSpeed(float MoveSpeed) { mMoveSpeed = MoveSpeed; }
|
||||||
inline void SetLookSpeed(float LookSpeed) { mLookSpeed = LookSpeed; }
|
void SetLookSpeed(float LookSpeed) { mLookSpeed = LookSpeed; }
|
||||||
inline void SetAspectRatio(float AspectRatio) { mAspectRatio = AspectRatio; mProjectionDirty = true; mFrustumPlanesDirty = true; }
|
void SetAspectRatio(float AspectRatio) { mAspectRatio = AspectRatio; mProjectionDirty = true; mFrustumPlanesDirty = true; }
|
||||||
|
|
||||||
inline void ResetOrbit() { SetOrbit(CVector3f::skZero, 5.f); }
|
void ResetOrbit() { SetOrbit(CVector3f::Zero(), 5.f); }
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -3,42 +3,6 @@
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "Core/GameProject/CResourceStore.h"
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
#include <Common/Math/CTransform4f.h>
|
#include <Common/Math/CTransform4f.h>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
// ************ MEMBER INITIALIZATION ************
|
|
||||||
std::optional<CVertexBuffer> CDrawUtil::mGridVertices;
|
|
||||||
CIndexBuffer CDrawUtil::mGridIndices;
|
|
||||||
|
|
||||||
std::optional<CDynamicVertexBuffer> CDrawUtil::mSquareVertices;
|
|
||||||
CIndexBuffer CDrawUtil::mSquareIndices;
|
|
||||||
|
|
||||||
std::optional<CDynamicVertexBuffer> CDrawUtil::mLineVertices;
|
|
||||||
CIndexBuffer CDrawUtil::mLineIndices;
|
|
||||||
|
|
||||||
TResPtr<CModel> CDrawUtil::mpCubeModel;
|
|
||||||
|
|
||||||
std::optional<CVertexBuffer> CDrawUtil::mWireCubeVertices;
|
|
||||||
CIndexBuffer CDrawUtil::mWireCubeIndices;
|
|
||||||
|
|
||||||
TResPtr<CModel> CDrawUtil::mpSphereModel;
|
|
||||||
TResPtr<CModel> CDrawUtil::mpDoubleSidedSphereModel;
|
|
||||||
|
|
||||||
TResPtr<CModel> CDrawUtil::mpWireSphereModel;
|
|
||||||
|
|
||||||
CShader *CDrawUtil::mpColorShader;
|
|
||||||
CShader *CDrawUtil::mpColorShaderLighting;
|
|
||||||
CShader *CDrawUtil::mpBillboardShader;
|
|
||||||
CShader *CDrawUtil::mpLightBillboardShader;
|
|
||||||
CShader *CDrawUtil::mpTextureShader;
|
|
||||||
CShader *CDrawUtil::mpCollisionShader;
|
|
||||||
CShader *CDrawUtil::mpTextShader;
|
|
||||||
|
|
||||||
TResPtr<CTexture> CDrawUtil::mpCheckerTexture;
|
|
||||||
|
|
||||||
TResPtr<CTexture> CDrawUtil::mpLightTextures[4];
|
|
||||||
TResPtr<CTexture> CDrawUtil::mpLightMasks[4];
|
|
||||||
|
|
||||||
bool CDrawUtil::mDrawUtilInitialized = false;
|
|
||||||
|
|
||||||
// ************ PUBLIC ************
|
// ************ PUBLIC ************
|
||||||
void CDrawUtil::DrawGrid(CColor LineColor, CColor BoldLineColor)
|
void CDrawUtil::DrawGrid(CColor LineColor, CColor BoldLineColor)
|
||||||
|
@ -99,13 +63,13 @@ void CDrawUtil::DrawSquare(const float *pTexCoords)
|
||||||
|
|
||||||
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB)
|
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB)
|
||||||
{
|
{
|
||||||
DrawLine(PointA, PointB, CColor::skWhite);
|
DrawLine(PointA, PointB, CColor::White());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB)
|
void CDrawUtil::DrawLine(const CVector2f& PointA, const CVector2f& PointB)
|
||||||
{
|
{
|
||||||
// Overload for 2D lines
|
// Overload for 2D lines
|
||||||
DrawLine(CVector3f(PointA.X, PointA.Y, 0.f), CVector3f(PointB.X, PointB.Y, 0.f), CColor::skWhite);
|
DrawLine(CVector3f(PointA.X, PointA.Y, 0.f), CVector3f(PointB.X, PointB.Y, 0.f), CColor::White());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor)
|
void CDrawUtil::DrawLine(const CVector3f& PointA, const CVector3f& PointB, const CColor& LineColor)
|
||||||
|
@ -317,7 +281,7 @@ void CDrawUtil::UseColorShaderLighting(const CColor& kColor)
|
||||||
|
|
||||||
void CDrawUtil::UseTextureShader()
|
void CDrawUtil::UseTextureShader()
|
||||||
{
|
{
|
||||||
UseTextureShader(CColor::skWhite);
|
UseTextureShader(CColor::White());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawUtil::UseTextureShader(const CColor& TintColor)
|
void CDrawUtil::UseTextureShader(const CColor& TintColor)
|
||||||
|
@ -354,7 +318,7 @@ void CDrawUtil::UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColo
|
||||||
CShader* CDrawUtil::GetTextShader()
|
CShader* CDrawUtil::GetTextShader()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
return mpTextShader;
|
return mpTextShader.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
|
void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
|
||||||
|
@ -366,13 +330,13 @@ void CDrawUtil::LoadCheckerboardTexture(uint32 GLTextureUnit)
|
||||||
CTexture* CDrawUtil::GetLightTexture(ELightType Type)
|
CTexture* CDrawUtil::GetLightTexture(ELightType Type)
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
return mpLightTextures[(int) Type];
|
return mpLightTextures[static_cast<size_t>(Type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
CTexture* CDrawUtil::GetLightMask(ELightType Type)
|
CTexture* CDrawUtil::GetLightMask(ELightType Type)
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
return mpLightMasks[(int) Type];
|
return mpLightMasks[static_cast<size_t>(Type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
CModel* CDrawUtil::GetCubeModel()
|
CModel* CDrawUtil::GetCubeModel()
|
||||||
|
@ -410,16 +374,18 @@ void CDrawUtil::InitGrid()
|
||||||
|
|
||||||
const int kGridSize = 501; // must be odd
|
const int kGridSize = 501; // must be odd
|
||||||
const float kGridSpacing = 1.f;
|
const float kGridSpacing = 1.f;
|
||||||
int MinIdx = (kGridSize - 1) / -2;
|
const int MinIdx = (kGridSize - 1) / -2;
|
||||||
int MaxIdx = (kGridSize - 1) / 2;
|
const int MaxIdx = (kGridSize - 1) / 2;
|
||||||
|
|
||||||
mGridVertices.emplace();
|
mGridVertices.emplace();
|
||||||
mGridVertices->SetVertexDesc(EVertexAttribute::Position);
|
mGridVertices->SetVertexDesc(EVertexAttribute::Position);
|
||||||
mGridVertices->Reserve(kGridSize * 4);
|
mGridVertices->Reserve(static_cast<size_t>(kGridSize * 4));
|
||||||
|
|
||||||
for (int32 i = MinIdx; i <= MaxIdx; i++)
|
for (int32 i = MinIdx; i <= MaxIdx; i++)
|
||||||
{
|
{
|
||||||
if (i == 0) continue;
|
if (i == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
mGridVertices->AddVertex(CVector3f(MinIdx * kGridSpacing, i * kGridSpacing, 0.0f));
|
mGridVertices->AddVertex(CVector3f(MinIdx * kGridSpacing, i * kGridSpacing, 0.0f));
|
||||||
mGridVertices->AddVertex(CVector3f(MaxIdx * kGridSpacing, i * kGridSpacing, 0.0f));
|
mGridVertices->AddVertex(CVector3f(MaxIdx * kGridSpacing, i * kGridSpacing, 0.0f));
|
||||||
mGridVertices->AddVertex(CVector3f(i * kGridSpacing, MinIdx * kGridSpacing, 0.0f));
|
mGridVertices->AddVertex(CVector3f(i * kGridSpacing, MinIdx * kGridSpacing, 0.0f));
|
||||||
|
@ -431,9 +397,10 @@ void CDrawUtil::InitGrid()
|
||||||
mGridVertices->AddVertex(CVector3f(0, MinIdx * kGridSpacing, 0.0f));
|
mGridVertices->AddVertex(CVector3f(0, MinIdx * kGridSpacing, 0.0f));
|
||||||
mGridVertices->AddVertex(CVector3f(0, MaxIdx * kGridSpacing, 0.0f));
|
mGridVertices->AddVertex(CVector3f(0, MaxIdx * kGridSpacing, 0.0f));
|
||||||
|
|
||||||
int NumIndices = kGridSize * 4;
|
const auto NumIndices = static_cast<size_t>(kGridSize * 4);
|
||||||
mGridIndices.Reserve(NumIndices);
|
mGridIndices.Reserve(NumIndices);
|
||||||
for (uint16 i = 0; i < NumIndices; i++) mGridIndices.AddIndex(i);
|
for (uint16 i = 0; i < NumIndices; i++)
|
||||||
|
mGridIndices.AddIndex(i);
|
||||||
mGridIndices.SetPrimitiveType(GL_LINES);
|
mGridIndices.SetPrimitiveType(GL_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,37 +417,37 @@ void CDrawUtil::InitSquare()
|
||||||
EVertexAttribute::Tex4 |
|
EVertexAttribute::Tex4 |
|
||||||
EVertexAttribute::Tex5 |
|
EVertexAttribute::Tex5 |
|
||||||
EVertexAttribute::Tex6 |
|
EVertexAttribute::Tex6 |
|
||||||
EVertexAttribute::Tex7 );
|
EVertexAttribute::Tex7);
|
||||||
mSquareVertices->SetVertexCount(4);
|
mSquareVertices->SetVertexCount(4);
|
||||||
|
|
||||||
CVector3f SquareVertices[] = {
|
static constexpr std::array SquareVertices{
|
||||||
CVector3f(-1.f, 1.f, 0.f),
|
CVector3f(-1.f, 1.f, 0.f),
|
||||||
CVector3f( 1.f, 1.f, 0.f),
|
CVector3f( 1.f, 1.f, 0.f),
|
||||||
CVector3f( 1.f, -1.f, 0.f),
|
CVector3f( 1.f, -1.f, 0.f),
|
||||||
CVector3f(-1.f, -1.f, 0.f)
|
CVector3f(-1.f, -1.f, 0.f)
|
||||||
};
|
};
|
||||||
|
|
||||||
CVector3f SquareNormals[] = {
|
static constexpr std::array SquareNormals{
|
||||||
CVector3f(0.f, 0.f, 1.f),
|
CVector3f(0.f, 0.f, 1.f),
|
||||||
CVector3f(0.f, 0.f, 1.f),
|
CVector3f(0.f, 0.f, 1.f),
|
||||||
CVector3f(0.f, 0.f, 1.f),
|
CVector3f(0.f, 0.f, 1.f),
|
||||||
CVector3f(0.f, 0.f, 1.f)
|
CVector3f(0.f, 0.f, 1.f)
|
||||||
};
|
};
|
||||||
|
|
||||||
CVector2f SquareTexCoords[] = {
|
static constexpr std::array SquareTexCoords{
|
||||||
CVector2f(0.f, 1.f),
|
CVector2f(0.f, 1.f),
|
||||||
CVector2f(1.f, 1.f),
|
CVector2f(1.f, 1.f),
|
||||||
CVector2f(1.f, 0.f),
|
CVector2f(1.f, 0.f),
|
||||||
CVector2f(0.f, 0.f)
|
CVector2f(0.f, 0.f)
|
||||||
};
|
};
|
||||||
|
|
||||||
mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices);
|
mSquareVertices->BufferAttrib(EVertexAttribute::Position, SquareVertices.data());
|
||||||
mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals);
|
mSquareVertices->BufferAttrib(EVertexAttribute::Normal, SquareNormals.data());
|
||||||
|
|
||||||
for (uint32 iTex = 0; iTex < 8; iTex++)
|
for (uint32 iTex = 0; iTex < 8; iTex++)
|
||||||
{
|
{
|
||||||
EVertexAttribute Attrib = (EVertexAttribute) (EVertexAttribute::Tex0 << iTex);
|
const auto Attrib = static_cast<EVertexAttribute>(EVertexAttribute::Tex0 << iTex);
|
||||||
mSquareVertices->BufferAttrib(Attrib, SquareTexCoords);
|
mSquareVertices->BufferAttrib(Attrib, SquareTexCoords.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
mSquareIndices.Reserve(4);
|
mSquareIndices.Reserve(4);
|
||||||
|
@ -525,7 +492,7 @@ void CDrawUtil::InitWireCube()
|
||||||
mWireCubeVertices->AddVertex(CVector3f( 0.5f, 0.5f, 0.5f));
|
mWireCubeVertices->AddVertex(CVector3f( 0.5f, 0.5f, 0.5f));
|
||||||
mWireCubeVertices->AddVertex(CVector3f(-0.5f, 0.5f, 0.5f));
|
mWireCubeVertices->AddVertex(CVector3f(-0.5f, 0.5f, 0.5f));
|
||||||
|
|
||||||
uint16 Indices[] = {
|
static constexpr std::array<uint16, 24> Indices{
|
||||||
0, 1,
|
0, 1,
|
||||||
1, 2,
|
1, 2,
|
||||||
2, 3,
|
2, 3,
|
||||||
|
@ -539,7 +506,7 @@ void CDrawUtil::InitWireCube()
|
||||||
2, 6,
|
2, 6,
|
||||||
3, 5
|
3, 5
|
||||||
};
|
};
|
||||||
mWireCubeIndices.AddIndices(Indices, sizeof(Indices) / sizeof(uint16));
|
mWireCubeIndices.AddIndices(Indices.data(), Indices.size());
|
||||||
mWireCubeIndices.SetPrimitiveType(GL_LINES);
|
mWireCubeIndices.SetPrimitiveType(GL_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,18 +553,18 @@ void CDrawUtil::InitTextures()
|
||||||
|
|
||||||
void CDrawUtil::Shutdown()
|
void CDrawUtil::Shutdown()
|
||||||
{
|
{
|
||||||
if (mDrawUtilInitialized)
|
if (!mDrawUtilInitialized)
|
||||||
{
|
return;
|
||||||
debugf("Shutting down");
|
|
||||||
mGridVertices = std::nullopt;
|
debugf("Shutting down");
|
||||||
mSquareVertices = std::nullopt;
|
mGridVertices.reset();
|
||||||
mLineVertices = std::nullopt;
|
mSquareVertices.reset();
|
||||||
mWireCubeVertices = std::nullopt;
|
mLineVertices.reset();
|
||||||
delete mpColorShader;
|
mWireCubeVertices.reset();
|
||||||
delete mpColorShaderLighting;
|
mpColorShader.reset();
|
||||||
delete mpTextureShader;
|
mpColorShaderLighting.reset();
|
||||||
delete mpCollisionShader;
|
mpTextureShader.reset();
|
||||||
delete mpTextShader;
|
mpCollisionShader.reset();
|
||||||
mDrawUtilInitialized = false;
|
mpTextShader.reset();
|
||||||
}
|
mDrawUtilInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "Core/Resource/Model/CModel.h"
|
#include "Core/Resource/Model/CModel.h"
|
||||||
#include "Core/Resource/CLight.h"
|
#include "Core/Resource/CLight.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,48 +20,48 @@
|
||||||
class CDrawUtil
|
class CDrawUtil
|
||||||
{
|
{
|
||||||
// 7x7 Grid
|
// 7x7 Grid
|
||||||
static std::optional<CVertexBuffer> mGridVertices;
|
static inline std::optional<CVertexBuffer> mGridVertices;
|
||||||
static CIndexBuffer mGridIndices;
|
static inline CIndexBuffer mGridIndices;
|
||||||
|
|
||||||
// Square
|
// Square
|
||||||
static std::optional<CDynamicVertexBuffer> mSquareVertices;
|
static inline std::optional<CDynamicVertexBuffer> mSquareVertices;
|
||||||
static CIndexBuffer mSquareIndices;
|
static inline CIndexBuffer mSquareIndices;
|
||||||
|
|
||||||
// Line
|
// Line
|
||||||
static std::optional<CDynamicVertexBuffer> mLineVertices;
|
static inline std::optional<CDynamicVertexBuffer> mLineVertices;
|
||||||
static CIndexBuffer mLineIndices;
|
static inline CIndexBuffer mLineIndices;
|
||||||
|
|
||||||
// Cube
|
// Cube
|
||||||
static TResPtr<CModel> mpCubeModel;
|
static inline TResPtr<CModel> mpCubeModel;
|
||||||
|
|
||||||
// Wire Cube
|
// Wire Cube
|
||||||
static std::optional<CVertexBuffer> mWireCubeVertices;
|
static inline std::optional<CVertexBuffer> mWireCubeVertices;
|
||||||
static CIndexBuffer mWireCubeIndices;
|
static inline CIndexBuffer mWireCubeIndices;
|
||||||
|
|
||||||
// Sphere
|
// Sphere
|
||||||
static TResPtr<CModel> mpSphereModel;
|
static inline TResPtr<CModel> mpSphereModel;
|
||||||
static TResPtr<CModel> mpDoubleSidedSphereModel;
|
static inline TResPtr<CModel> mpDoubleSidedSphereModel;
|
||||||
|
|
||||||
// Wire Sphere
|
// Wire Sphere
|
||||||
static TResPtr<CModel> mpWireSphereModel;
|
static inline TResPtr<CModel> mpWireSphereModel;
|
||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
static CShader *mpColorShader;
|
static inline std::unique_ptr<CShader> mpColorShader;
|
||||||
static CShader *mpColorShaderLighting;
|
static inline std::unique_ptr<CShader> mpColorShaderLighting;
|
||||||
static CShader *mpBillboardShader;
|
static inline std::unique_ptr<CShader> mpBillboardShader;
|
||||||
static CShader *mpLightBillboardShader;
|
static inline std::unique_ptr<CShader> mpLightBillboardShader;
|
||||||
static CShader *mpTextureShader;
|
static inline std::unique_ptr<CShader> mpTextureShader;
|
||||||
static CShader *mpCollisionShader;
|
static inline std::unique_ptr<CShader> mpCollisionShader;
|
||||||
static CShader *mpTextShader;
|
static inline std::unique_ptr<CShader> mpTextShader;
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
static TResPtr<CTexture> mpCheckerTexture;
|
static inline TResPtr<CTexture> mpCheckerTexture;
|
||||||
|
|
||||||
static TResPtr<CTexture> mpLightTextures[4];
|
static inline std::array<TResPtr<CTexture>, 4> mpLightTextures;
|
||||||
static TResPtr<CTexture> mpLightMasks[4];
|
static inline std::array<TResPtr<CTexture>, 4> mpLightMasks;
|
||||||
|
|
||||||
// Have all the above members been initialized?
|
// Have all the above members been initialized?
|
||||||
static bool mDrawUtilInitialized;
|
static inline bool mDrawUtilInitialized = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void DrawGrid(CColor LineColor, CColor BoldLineColor);
|
static void DrawGrid(CColor LineColor, CColor BoldLineColor);
|
||||||
|
@ -85,17 +86,17 @@ public:
|
||||||
static void DrawSphere(bool DoubleSided = false);
|
static void DrawSphere(bool DoubleSided = false);
|
||||||
static void DrawSphere(const CColor& Color);
|
static void DrawSphere(const CColor& Color);
|
||||||
|
|
||||||
static void DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color = CColor::skWhite);
|
static void DrawWireSphere(const CVector3f& Position, float Radius, const CColor& Color = CColor::White());
|
||||||
|
|
||||||
static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
|
static void DrawBillboard(CTexture* pTexture, const CVector3f& Position, const CVector2f& Scale = CVector2f::One(), const CColor& Tint = CColor::White());
|
||||||
|
|
||||||
static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::skOne, const CColor& Tint = CColor::skWhite);
|
static void DrawLightBillboard(ELightType Type, const CColor& LightColor, const CVector3f& Position, const CVector2f& Scale = CVector2f::One(), const CColor& Tint = CColor::White());
|
||||||
|
|
||||||
static void UseColorShader(const CColor& Color);
|
static void UseColorShader(const CColor& Color);
|
||||||
static void UseColorShaderLighting(const CColor& Color);
|
static void UseColorShaderLighting(const CColor& Color);
|
||||||
static void UseTextureShader();
|
static void UseTextureShader();
|
||||||
static void UseTextureShader(const CColor& TintColor);
|
static void UseTextureShader(const CColor& TintColor);
|
||||||
static void UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColor& TintColor = CColor::skWhite);
|
static void UseCollisionShader(bool IsFloor, bool IsUnstandable, const CColor& TintColor = CColor::White());
|
||||||
|
|
||||||
static CShader* GetTextShader();
|
static CShader* GetTextShader();
|
||||||
static void LoadCheckerboardTexture(uint32 GLTextureUnit);
|
static void LoadCheckerboardTexture(uint32 GLTextureUnit);
|
||||||
|
|
|
@ -22,14 +22,13 @@ CGraphics::SLightBlock CGraphics::sLightBlock;
|
||||||
|
|
||||||
CGraphics::ELightingMode CGraphics::sLightMode;
|
CGraphics::ELightingMode CGraphics::sLightMode;
|
||||||
uint32 CGraphics::sNumLights;
|
uint32 CGraphics::sNumLights;
|
||||||
const CColor CGraphics::skDefaultAmbientColor = CColor(0.5f, 0.5f, 0.5f, 0.0f);
|
CColor CGraphics::sAreaAmbientColor = CColor::TransparentBlack();
|
||||||
CColor CGraphics::sAreaAmbientColor = CColor::skTransparentBlack;
|
|
||||||
float CGraphics::sWorldLightMultiplier;
|
float CGraphics::sWorldLightMultiplier;
|
||||||
CLight CGraphics::sDefaultDirectionalLights[3] = {
|
std::array<CLight, 3> CGraphics::sDefaultDirectionalLights{{
|
||||||
CLight::BuildDirectional(CVector3f(0), CVector3f (0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
CLight::BuildDirectional(CVector3f(0), CVector3f(0.f, -0.866025f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
||||||
CLight::BuildDirectional(CVector3f(0), CVector3f(-0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
CLight::BuildDirectional(CVector3f(0), CVector3f(-0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
||||||
CLight::BuildDirectional(CVector3f(0), CVector3f( 0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f))
|
CLight::BuildDirectional(CVector3f(0), CVector3f(0.75f, 0.433013f, -0.5f), CColor(0.3f, 0.3f, 0.3f, 0.3f)),
|
||||||
};
|
}};
|
||||||
|
|
||||||
// ************ FUNCTIONS ************
|
// ************ FUNCTIONS ************
|
||||||
void CGraphics::Initialize()
|
void CGraphics::Initialize()
|
||||||
|
@ -170,8 +169,8 @@ void CGraphics::SetDefaultLighting()
|
||||||
sNumLights = 0;
|
sNumLights = 0;
|
||||||
UpdateLightBlock();
|
UpdateLightBlock();
|
||||||
|
|
||||||
sVertexBlock.COLOR0_Amb = CColor::skGray;
|
sVertexBlock.COLOR0_Amb = CColor::Gray();
|
||||||
sVertexBlock.COLOR0_Mat = CColor::skWhite;
|
sVertexBlock.COLOR0_Mat = CColor::White();
|
||||||
UpdateVertexBlock();
|
UpdateVertexBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +181,7 @@ void CGraphics::SetupAmbientColor()
|
||||||
else if (sLightMode == ELightingMode::Basic)
|
else if (sLightMode == ELightingMode::Basic)
|
||||||
sVertexBlock.COLOR0_Amb = skDefaultAmbientColor;
|
sVertexBlock.COLOR0_Amb = skDefaultAmbientColor;
|
||||||
else
|
else
|
||||||
sVertexBlock.COLOR0_Amb = CColor::skTransparentWhite;
|
sVertexBlock.COLOR0_Amb = CColor::TransparentWhite();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGraphics::SetIdentityMVP()
|
void CGraphics::SetIdentityMVP()
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <Common/Math/CMatrix4f.h>
|
#include <Common/Math/CMatrix4f.h>
|
||||||
#include <Common/Math/CVector3f.h>
|
#include <Common/Math/CVector3f.h>
|
||||||
#include <Common/Math/CVector4f.h>
|
#include <Common/Math/CVector4f.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* todo: this entire thing needs to be further abstracted, other classes shouldn't
|
* todo: this entire thing needs to be further abstracted, other classes shouldn't
|
||||||
|
@ -43,8 +44,8 @@ public:
|
||||||
// SVertexBlock
|
// SVertexBlock
|
||||||
struct SVertexBlock
|
struct SVertexBlock
|
||||||
{
|
{
|
||||||
CMatrix4f TexMatrices[10];
|
std::array<CMatrix4f, 10> TexMatrices;
|
||||||
CMatrix4f PostMatrices[20];
|
std::array<CMatrix4f, 20> PostMatrices;
|
||||||
CColor COLOR0_Amb;
|
CColor COLOR0_Amb;
|
||||||
CColor COLOR0_Mat;
|
CColor COLOR0_Mat;
|
||||||
CColor COLOR1_Amb;
|
CColor COLOR1_Amb;
|
||||||
|
@ -55,15 +56,15 @@ public:
|
||||||
// SPixelBlock
|
// SPixelBlock
|
||||||
struct SPixelBlock
|
struct SPixelBlock
|
||||||
{
|
{
|
||||||
CColor Konst[4];
|
std::array<CColor, 4> Konst;
|
||||||
CColor TevColor[4];
|
std::array<CColor, 4> TevColor;
|
||||||
CColor TintColor;
|
CColor TintColor;
|
||||||
float LightmapMultiplier;
|
float LightmapMultiplier;
|
||||||
float Padding[3];
|
std::array<float, 3> Padding;
|
||||||
|
|
||||||
void SetAllTevColors(const CColor& color)
|
void SetAllTevColors(const CColor& color)
|
||||||
{
|
{
|
||||||
std::fill(std::begin(TevColor), std::end(TevColor), color);
|
TevColor.fill(color);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static SPixelBlock sPixelBlock;
|
static SPixelBlock sPixelBlock;
|
||||||
|
@ -79,7 +80,7 @@ public:
|
||||||
CVector4f DistAtten;
|
CVector4f DistAtten;
|
||||||
CVector4f AngleAtten;
|
CVector4f AngleAtten;
|
||||||
};
|
};
|
||||||
SGXLight Lights[8];
|
std::array<SGXLight, 8> Lights;
|
||||||
};
|
};
|
||||||
static SLightBlock sLightBlock;
|
static SLightBlock sLightBlock;
|
||||||
|
|
||||||
|
@ -87,10 +88,10 @@ public:
|
||||||
enum class ELightingMode { None, Basic, World };
|
enum class ELightingMode { None, Basic, World };
|
||||||
static ELightingMode sLightMode;
|
static ELightingMode sLightMode;
|
||||||
static uint32 sNumLights;
|
static uint32 sNumLights;
|
||||||
static const CColor skDefaultAmbientColor;
|
static constexpr CColor skDefaultAmbientColor{0.5f, 0.5f, 0.5f, 0.0f};
|
||||||
static CColor sAreaAmbientColor;
|
static CColor sAreaAmbientColor;
|
||||||
static float sWorldLightMultiplier;
|
static float sWorldLightMultiplier;
|
||||||
static CLight sDefaultDirectionalLights[3];
|
static std::array<CLight, 3> sDefaultDirectionalLights;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
|
|
|
@ -18,52 +18,55 @@ void CRenderBucket::CSubBucket::Add(const SRenderablePtr& rkPtr)
|
||||||
void CRenderBucket::CSubBucket::Sort(const CCamera* pkCamera, bool DebugVisualization)
|
void CRenderBucket::CSubBucket::Sort(const CCamera* pkCamera, bool DebugVisualization)
|
||||||
{
|
{
|
||||||
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize,
|
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize,
|
||||||
[&, pkCamera](const SRenderablePtr& rkLeft, const SRenderablePtr& rkRight) -> bool
|
[&, pkCamera](const auto& rkLeft, const auto& rkRight) {
|
||||||
|
const CVector3f CamPos = pkCamera->Position();
|
||||||
|
const CVector3f CamDir = pkCamera->Direction();
|
||||||
|
|
||||||
|
const CVector3f DistL = rkLeft.AABox.ClosestPointAlongVector(CamDir) - CamPos;
|
||||||
|
const CVector3f DistR = rkRight.AABox.ClosestPointAlongVector(CamDir) - CamPos;
|
||||||
|
const float DotL = DistL.Dot(CamDir);
|
||||||
|
const float DotR = DistR.Dot(CamDir);
|
||||||
|
return DotL > DotR;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!DebugVisualization)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t iPtr = 0; iPtr < mSize; iPtr++)
|
||||||
{
|
{
|
||||||
CVector3f CamPos = pkCamera->Position();
|
const SRenderablePtr *pPtr = &mRenderables[iPtr];
|
||||||
CVector3f CamDir = pkCamera->Direction();
|
const CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
|
||||||
|
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::White());
|
||||||
|
|
||||||
CVector3f DistL = rkLeft.AABox.ClosestPointAlongVector(CamDir) - CamPos;
|
const CVector3f Dist = Point - pkCamera->Position();
|
||||||
CVector3f DistR = rkRight.AABox.ClosestPointAlongVector(CamDir) - CamPos;
|
float Dot = Dist.Dot(pkCamera->Direction());
|
||||||
float DotL = DistL.Dot(CamDir);
|
if (Dot < 0.f)
|
||||||
float DotR = DistR.Dot(CamDir);
|
Dot = -Dot;
|
||||||
return (DotL > DotR);
|
Dot = std::min(Dot, 50.f);
|
||||||
});
|
const float Intensity = 1.f - (Dot / 50.f);
|
||||||
|
const CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
|
||||||
|
|
||||||
if (DebugVisualization)
|
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Point);
|
||||||
{
|
CGraphics::UpdateMVPBlock();
|
||||||
for (uint32 iPtr = 0; iPtr < mSize; iPtr++)
|
CDrawUtil::DrawCube(CubeColor);
|
||||||
{
|
|
||||||
SRenderablePtr *pPtr = &mRenderables[iPtr];
|
|
||||||
CVector3f Point = pPtr->AABox.ClosestPointAlongVector(pkCamera->Direction());
|
|
||||||
CDrawUtil::DrawWireCube(pPtr->AABox, CColor::skWhite);
|
|
||||||
|
|
||||||
CVector3f Dist = Point - pkCamera->Position();
|
|
||||||
float Dot = Dist.Dot(pkCamera->Direction());
|
|
||||||
if (Dot < 0.f) Dot = -Dot;
|
|
||||||
if (Dot > 50.f) Dot = 50.f;
|
|
||||||
float Intensity = 1.f - (Dot / 50.f);
|
|
||||||
CColor CubeColor(Intensity, Intensity, Intensity, 1.f);
|
|
||||||
|
|
||||||
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Point);
|
|
||||||
CGraphics::UpdateMVPBlock();
|
|
||||||
CDrawUtil::DrawCube(CubeColor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderBucket::CSubBucket::Clear()
|
void CRenderBucket::CSubBucket::Clear()
|
||||||
{
|
{
|
||||||
mEstSize = mSize;
|
mEstSize = mSize;
|
||||||
if (mRenderables.size() > mSize) mRenderables.resize(mSize);
|
|
||||||
|
if (mRenderables.size() > mSize)
|
||||||
|
mRenderables.resize(mSize);
|
||||||
|
|
||||||
mSize = 0;
|
mSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderBucket::CSubBucket::Draw(const SViewInfo& rkViewInfo)
|
void CRenderBucket::CSubBucket::Draw(const SViewInfo& rkViewInfo)
|
||||||
{
|
{
|
||||||
FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions();
|
const FRenderOptions Options = rkViewInfo.pRenderer->RenderOptions();
|
||||||
|
|
||||||
for (uint32 iPtr = 0; iPtr < mSize; iPtr++)
|
for (size_t iPtr = 0; iPtr < mSize; iPtr++)
|
||||||
{
|
{
|
||||||
const SRenderablePtr& rkPtr = mRenderables[iPtr];
|
const SRenderablePtr& rkPtr = mRenderables[iPtr];
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,16 @@
|
||||||
|
|
||||||
class CRenderBucket
|
class CRenderBucket
|
||||||
{
|
{
|
||||||
bool mEnableDepthSortDebugVisualization;
|
bool mEnableDepthSortDebugVisualization = false;
|
||||||
|
|
||||||
class CSubBucket
|
class CSubBucket
|
||||||
{
|
{
|
||||||
std::vector<SRenderablePtr> mRenderables;
|
std::vector<SRenderablePtr> mRenderables;
|
||||||
uint32 mEstSize;
|
uint32 mEstSize = 0;
|
||||||
uint32 mSize;
|
uint32 mSize = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSubBucket()
|
CSubBucket() = default;
|
||||||
: mEstSize(0)
|
|
||||||
, mSize(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void Add(const SRenderablePtr &rkPtr);
|
void Add(const SRenderablePtr &rkPtr);
|
||||||
void Sort(const CCamera *pkCamera, bool DebugVisualization);
|
void Sort(const CCamera *pkCamera, bool DebugVisualization);
|
||||||
|
@ -36,9 +33,7 @@ class CRenderBucket
|
||||||
CSubBucket mTransparentSubBucket;
|
CSubBucket mTransparentSubBucket;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRenderBucket()
|
CRenderBucket() = default;
|
||||||
: mEnableDepthSortDebugVisualization(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void Add(const SRenderablePtr& rkPtr, bool Transparent);
|
void Add(const SRenderablePtr& rkPtr, bool Transparent);
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
|
@ -6,22 +6,11 @@
|
||||||
#include "Core/Resource/Factory/CTextureDecoder.h"
|
#include "Core/Resource/Factory/CTextureDecoder.h"
|
||||||
#include <Common/Math/CTransform4f.h>
|
#include <Common/Math/CTransform4f.h>
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
// ************ STATIC MEMBER INITIALIZATION ************
|
// ************ STATIC MEMBER INITIALIZATION ************
|
||||||
uint32 CRenderer::sNumRenderers = 0;
|
uint32 CRenderer::sNumRenderers = 0;
|
||||||
|
|
||||||
// ************ INITIALIZATION ************
|
// ************ INITIALIZATION ************
|
||||||
CRenderer::CRenderer()
|
CRenderer::CRenderer()
|
||||||
: mOptions(ERenderOption::EnableUVScroll | ERenderOption::EnableBackfaceCull)
|
|
||||||
, mBloomMode(EBloomMode::NoBloom)
|
|
||||||
, mDrawGrid(true)
|
|
||||||
, mInitialized(false)
|
|
||||||
, mContextIndex(-1)
|
|
||||||
{
|
{
|
||||||
sNumRenderers++;
|
sNumRenderers++;
|
||||||
}
|
}
|
||||||
|
@ -104,10 +93,10 @@ void CRenderer::SetViewportSize(uint32 Width, uint32 Height)
|
||||||
{
|
{
|
||||||
mViewportWidth = Width;
|
mViewportWidth = Width;
|
||||||
mViewportHeight = Height;
|
mViewportHeight = Height;
|
||||||
mBloomHScale = ((float) Width / 640);
|
mBloomHScale = static_cast<float>(Width) / 640.0f;
|
||||||
mBloomVScale = ((float) Height / 528);
|
mBloomVScale = static_cast<float>(Height) / 528.0f;
|
||||||
mBloomWidth = (uint32) (320 * mBloomHScale);
|
mBloomWidth = static_cast<uint32>(320.0f * mBloomHScale);
|
||||||
mBloomHeight = (uint32) (224 * mBloomVScale);
|
mBloomHeight = static_cast<uint32>(224.0f * mBloomVScale);
|
||||||
mBloomHScale = 1.f / mBloomHScale;
|
mBloomHScale = 1.f / mBloomHScale;
|
||||||
mBloomVScale = 1.f / mBloomVScale;
|
mBloomVScale = 1.f / mBloomVScale;
|
||||||
}
|
}
|
||||||
|
@ -115,12 +104,16 @@ void CRenderer::SetViewportSize(uint32 Width, uint32 Height)
|
||||||
// ************ RENDER ************
|
// ************ RENDER ************
|
||||||
void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
|
void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized)
|
||||||
|
Init();
|
||||||
|
|
||||||
mSceneFramebuffer.Bind();
|
mSceneFramebuffer.Bind();
|
||||||
|
|
||||||
// Set backface culling
|
// Set backface culling
|
||||||
if (mOptions & ERenderOption::EnableBackfaceCull) glEnable(GL_CULL_FACE);
|
if ((mOptions & ERenderOption::EnableBackfaceCull) != 0)
|
||||||
else glDisable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
else
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
// Render scene to texture
|
// Render scene to texture
|
||||||
glDepthRange(0.f, 1.f);
|
glDepthRange(0.f, 1.f);
|
||||||
|
@ -146,26 +139,41 @@ void CRenderer::RenderBuckets(const SViewInfo& rkViewInfo)
|
||||||
void CRenderer::RenderBloom()
|
void CRenderer::RenderBloom()
|
||||||
{
|
{
|
||||||
// Check to ensure bloom is enabled. Also don't render bloom in unlit mode.
|
// Check to ensure bloom is enabled. Also don't render bloom in unlit mode.
|
||||||
if (mBloomMode == EBloomMode::NoBloom || CGraphics::sLightMode != CGraphics::ELightingMode::World) return;
|
if (mBloomMode == EBloomMode::NoBloom || CGraphics::sLightMode != CGraphics::ELightingMode::World)
|
||||||
|
return;
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
static const float skHOffset[6] = { -0.008595f, -0.005470f, -0.002345f,
|
static constexpr std::array skHOffset{
|
||||||
0.002345f, 0.005470f, 0.008595f };
|
-0.008595f,
|
||||||
|
-0.005470f,
|
||||||
|
-0.002345f,
|
||||||
|
0.002345f,
|
||||||
|
0.005470f,
|
||||||
|
0.008595f,
|
||||||
|
};
|
||||||
|
|
||||||
static const float skVOffset[6] = { -0.012275f, -0.007815f, -0.003350f,
|
static constexpr std::array skVOffset{
|
||||||
0.003350f, 0.007815f, 0.012275f };
|
-0.012275f,
|
||||||
|
-0.007815f,
|
||||||
|
-0.003350f,
|
||||||
|
0.003350f,
|
||||||
|
0.007815f,
|
||||||
|
0.012275f,
|
||||||
|
};
|
||||||
|
|
||||||
static const CColor skTintColors[6] = { CColor::Integral(17, 17, 17),
|
static constexpr std::array skTintColors{
|
||||||
CColor::Integral(53, 53, 53),
|
CColor::Integral(17, 17, 17),
|
||||||
CColor::Integral(89, 89, 89),
|
CColor::Integral(53, 53, 53),
|
||||||
CColor::Integral(89, 89, 89),
|
CColor::Integral(89, 89, 89),
|
||||||
CColor::Integral(53, 53, 53),
|
CColor::Integral(89, 89, 89),
|
||||||
CColor::Integral(17, 17, 17) };
|
CColor::Integral(53, 53, 53),
|
||||||
|
CColor::Integral(17, 17, 17),
|
||||||
|
};
|
||||||
|
|
||||||
uint32 BloomWidth = (mBloomMode == EBloomMode::Bloom ? mBloomWidth : mViewportWidth);
|
const uint32 BloomWidth = (mBloomMode == EBloomMode::Bloom ? mBloomWidth : mViewportWidth);
|
||||||
uint32 BloomHeight = (mBloomMode == EBloomMode::Bloom ? mBloomHeight : mViewportHeight);
|
const uint32 BloomHeight = (mBloomMode == EBloomMode::Bloom ? mBloomHeight : mViewportHeight);
|
||||||
float BloomHScale = (mBloomMode == EBloomMode::Bloom ? mBloomHScale : 0);
|
const float BloomHScale = (mBloomMode == EBloomMode::Bloom ? mBloomHScale : 0);
|
||||||
float BloomVScale = (mBloomMode == EBloomMode::Bloom ? mBloomVScale : 0);
|
const float BloomVScale = (mBloomMode == EBloomMode::Bloom ? mBloomVScale : 0);
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glViewport(0, 0, BloomWidth, BloomHeight);
|
glViewport(0, 0, BloomWidth, BloomHeight);
|
||||||
|
@ -195,15 +203,15 @@ void CRenderer::RenderBloom()
|
||||||
mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight);
|
mBloomFramebuffers[1].Resize(BloomWidth, BloomHeight);
|
||||||
mBloomFramebuffers[1].Bind();
|
mBloomFramebuffers[1].Bind();
|
||||||
|
|
||||||
CDrawUtil::UseTextureShader(CColor::skGray);
|
CDrawUtil::UseTextureShader(CColor::Gray());
|
||||||
glBlendFunc(GL_ONE, GL_ZERO);
|
glBlendFunc(GL_ONE, GL_ZERO);
|
||||||
mBloomFramebuffers[0].Texture()->Bind(0);
|
mBloomFramebuffers[0].Texture()->Bind(0);
|
||||||
CDrawUtil::DrawSquare();
|
CDrawUtil::DrawSquare();
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < 6; iPass++)
|
for (size_t iPass = 0; iPass < skTintColors.size(); iPass++)
|
||||||
{
|
{
|
||||||
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
||||||
CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f);
|
const CVector3f Translate(skHOffset[iPass] * BloomHScale, 0.f, 0.f);
|
||||||
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
||||||
CGraphics::UpdateMVPBlock();
|
CGraphics::UpdateMVPBlock();
|
||||||
glBlendFunc(GL_ONE, GL_ONE);
|
glBlendFunc(GL_ONE, GL_ONE);
|
||||||
|
@ -215,15 +223,15 @@ void CRenderer::RenderBloom()
|
||||||
mBloomFramebuffers[2].Bind();
|
mBloomFramebuffers[2].Bind();
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
CDrawUtil::UseTextureShader(CColor::skGray);
|
CDrawUtil::UseTextureShader(CColor::Gray());
|
||||||
glBlendFunc(GL_ONE, GL_ZERO);
|
glBlendFunc(GL_ONE, GL_ZERO);
|
||||||
mBloomFramebuffers[1].Texture()->Bind(0);
|
mBloomFramebuffers[1].Texture()->Bind(0);
|
||||||
CDrawUtil::DrawSquare();
|
CDrawUtil::DrawSquare();
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < 6; iPass++)
|
for (size_t iPass = 0; iPass < skTintColors.size(); iPass++)
|
||||||
{
|
{
|
||||||
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
CDrawUtil::UseTextureShader(skTintColors[iPass]);
|
||||||
CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f);
|
const CVector3f Translate(0.f, skVOffset[iPass] * BloomVScale, 0.f);
|
||||||
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(Translate);
|
||||||
CGraphics::UpdateMVPBlock();
|
CGraphics::UpdateMVPBlock();
|
||||||
glBlendFunc(GL_ONE, GL_ONE);
|
glBlendFunc(GL_ONE, GL_ONE);
|
||||||
|
@ -247,7 +255,7 @@ void CRenderer::RenderBloom()
|
||||||
{
|
{
|
||||||
// Bloom maps are in the framebuffer alpha channel.
|
// Bloom maps are in the framebuffer alpha channel.
|
||||||
// White * dst alpha = bloom map colors
|
// White * dst alpha = bloom map colors
|
||||||
CDrawUtil::UseColorShader(CColor::skWhite);
|
CDrawUtil::UseColorShader(CColor::White());
|
||||||
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
|
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
|
||||||
CDrawUtil::DrawSquare();
|
CDrawUtil::DrawSquare();
|
||||||
}
|
}
|
||||||
|
@ -263,16 +271,19 @@ void CRenderer::RenderBloom()
|
||||||
|
|
||||||
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& rkViewInfo)
|
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& rkViewInfo)
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized)
|
||||||
if (!pSkyboxModel) return;
|
Init();
|
||||||
|
|
||||||
|
if (pSkyboxModel == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
||||||
CGraphics::sVertexBlock.COLOR0_Amb = CColor::skTransparentWhite;
|
CGraphics::sVertexBlock.COLOR0_Amb = CColor::TransparentWhite();
|
||||||
CGraphics::sVertexBlock.COLOR0_Mat = CColor::skTransparentWhite;
|
CGraphics::sVertexBlock.COLOR0_Mat = CColor::TransparentWhite();
|
||||||
CGraphics::sPixelBlock.SetAllTevColors(CColor::skWhite);
|
CGraphics::sPixelBlock.SetAllTevColors(CColor::White());
|
||||||
CGraphics::sPixelBlock.TintColor = CColor::skWhite;
|
CGraphics::sPixelBlock.TintColor = CColor::White();
|
||||||
CGraphics::sNumLights = 0;
|
CGraphics::sNumLights = 0;
|
||||||
CGraphics::UpdateVertexBlock();
|
CGraphics::UpdateVertexBlock();
|
||||||
CGraphics::UpdatePixelBlock();
|
CGraphics::UpdatePixelBlock();
|
||||||
|
@ -316,7 +327,8 @@ void CRenderer::AddMesh(IRenderable *pRenderable, int ComponentIndex, const CAAB
|
||||||
|
|
||||||
void CRenderer::BeginFrame()
|
void CRenderer::BeginFrame()
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized)
|
||||||
|
Init();
|
||||||
|
|
||||||
CGraphics::SetActiveContext(mContextIndex);
|
CGraphics::SetActiveContext(mContextIndex);
|
||||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer);
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer);
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <Common/Math/CAABox.h>
|
#include <Common/Math/CAABox.h>
|
||||||
#include <Common/Math/CMatrix4f.h>
|
#include <Common/Math/CMatrix4f.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
enum class EBloomMode
|
enum class EBloomMode
|
||||||
{
|
{
|
||||||
NoBloom,
|
NoBloom,
|
||||||
|
@ -48,20 +50,23 @@ enum class EBloomMode
|
||||||
*/
|
*/
|
||||||
class CRenderer
|
class CRenderer
|
||||||
{
|
{
|
||||||
FRenderOptions mOptions;
|
FRenderOptions mOptions{ERenderOption::EnableUVScroll | ERenderOption::EnableBackfaceCull};
|
||||||
EBloomMode mBloomMode;
|
EBloomMode mBloomMode{EBloomMode::NoBloom};
|
||||||
bool mDrawGrid;
|
bool mDrawGrid = true;
|
||||||
CColor mClearColor;
|
CColor mClearColor;
|
||||||
uint32 mContextIndex;
|
uint32 mContextIndex = UINT32_MAX;
|
||||||
bool mInitialized;
|
bool mInitialized = false;
|
||||||
uint32 mViewportWidth, mViewportHeight;
|
uint32 mViewportWidth = 0;
|
||||||
uint32 mBloomWidth, mBloomHeight;
|
uint32 mViewportHeight = 0;
|
||||||
float mBloomHScale, mBloomVScale;
|
uint32 mBloomWidth = 0;
|
||||||
|
uint32 mBloomHeight = 0;
|
||||||
|
float mBloomHScale = 0.0f;
|
||||||
|
float mBloomVScale = 0.0f;
|
||||||
|
|
||||||
CFramebuffer mSceneFramebuffer;
|
CFramebuffer mSceneFramebuffer;
|
||||||
CFramebuffer mPostProcessFramebuffer;
|
CFramebuffer mPostProcessFramebuffer;
|
||||||
CFramebuffer mBloomFramebuffers[3];
|
std::array<CFramebuffer, 3> mBloomFramebuffers;
|
||||||
GLint mDefaultFramebuffer;
|
GLint mDefaultFramebuffer = 0;
|
||||||
|
|
||||||
CRenderBucket mBackgroundBucket;
|
CRenderBucket mBackgroundBucket;
|
||||||
CRenderBucket mMidgroundBucket;
|
CRenderBucket mMidgroundBucket;
|
||||||
|
|
|
@ -11,8 +11,8 @@ class CRenderer;
|
||||||
class IRenderable
|
class IRenderable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IRenderable() {}
|
IRenderable() = default;
|
||||||
virtual ~IRenderable() {}
|
virtual ~IRenderable() = default;
|
||||||
virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo) = 0;
|
virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo) = 0;
|
||||||
virtual void Draw(FRenderOptions /*Options*/, int /*ComponentIndex*/, ERenderCommand /*Command*/, const SViewInfo& /*rkViewInfo*/) {}
|
virtual void Draw(FRenderOptions /*Options*/, int /*ComponentIndex*/, ERenderCommand /*Command*/, const SViewInfo& /*rkViewInfo*/) {}
|
||||||
virtual void DrawSelection() {}
|
virtual void DrawSelection() {}
|
||||||
|
|
|
@ -9,28 +9,19 @@
|
||||||
|
|
||||||
struct SCollisionRenderSettings
|
struct SCollisionRenderSettings
|
||||||
{
|
{
|
||||||
uint64 HighlightMask;
|
uint64 HighlightMask = 0;
|
||||||
uint64 HideMask;
|
uint64 HideMask = 0;
|
||||||
int BoundingHierarchyRenderDepth;
|
int BoundingHierarchyRenderDepth = 0;
|
||||||
|
|
||||||
CCollisionMaterial HideMaterial;
|
CCollisionMaterial HideMaterial;
|
||||||
bool DrawWireframe;
|
bool DrawWireframe = true;
|
||||||
bool DrawBackfaces;
|
bool DrawBackfaces = false;
|
||||||
bool DrawAreaCollisionBounds;
|
bool DrawAreaCollisionBounds = true;
|
||||||
bool DrawBoundingHierarchy;
|
bool DrawBoundingHierarchy = false;
|
||||||
bool TintWithSurfaceColor;
|
bool TintWithSurfaceColor = true;
|
||||||
bool TintUnwalkableTris;
|
bool TintUnwalkableTris = true;
|
||||||
|
|
||||||
SCollisionRenderSettings()
|
SCollisionRenderSettings() = default;
|
||||||
: HighlightMask(0)
|
|
||||||
, HideMask(0)
|
|
||||||
, BoundingHierarchyRenderDepth(0)
|
|
||||||
, DrawWireframe(true)
|
|
||||||
, DrawBackfaces(false)
|
|
||||||
, DrawAreaCollisionBounds(true)
|
|
||||||
, DrawBoundingHierarchy(false)
|
|
||||||
, TintWithSurfaceColor(true)
|
|
||||||
, TintUnwalkableTris(true) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SViewInfo
|
struct SViewInfo
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define CANIMEVENTDATA
|
#define CANIMEVENTDATA
|
||||||
|
|
||||||
#include "Core/Resource/CResource.h"
|
#include "Core/Resource/CResource.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CAnimEventData : public CResource
|
class CAnimEventData : public CResource
|
||||||
{
|
{
|
||||||
|
@ -16,38 +18,36 @@ class CAnimEventData : public CResource
|
||||||
std::vector<SEvent> mEvents;
|
std::vector<SEvent> mEvents;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimEventData(CResourceEntry *pEntry = 0)
|
explicit CAnimEventData(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
AddDependenciesToTree(pTree);
|
AddDependenciesToTree(pTree.get());
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddDependenciesToTree(CDependencyTree *pTree) const
|
void AddDependenciesToTree(CDependencyTree *pTree) const
|
||||||
{
|
{
|
||||||
for (uint32 iEvt = 0; iEvt < mEvents.size(); iEvt++)
|
for (const SEvent& event : mEvents)
|
||||||
{
|
{
|
||||||
const SEvent& rkEvent = mEvents[iEvt];
|
CAssetID ID = event.mAssetRef;
|
||||||
CAssetID ID = rkEvent.mAssetRef;
|
|
||||||
|
|
||||||
if (ID.IsValid() && !pTree->HasDependency(ID))
|
if (ID.IsValid() && !pTree->HasDependency(ID))
|
||||||
{
|
{
|
||||||
CAnimEventDependency *pDep = new CAnimEventDependency(ID, rkEvent.mCharacterIndex);
|
pTree->AddChild(std::make_unique<CAnimEventDependency>(ID, event.mCharacterIndex));
|
||||||
pTree->AddChild(pDep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 NumEvents() const { return mEvents.size(); }
|
size_t NumEvents() const { return mEvents.size(); }
|
||||||
inline uint32 EventCharacterIndex(uint32 EventIdx) const { return mEvents[EventIdx].mCharacterIndex; }
|
uint32 EventCharacterIndex(size_t EventIdx) const { return mEvents[EventIdx].mCharacterIndex; }
|
||||||
inline CAssetID EventAssetRef(uint32 EventIdx) const { return mEvents[EventIdx].mAssetRef; }
|
CAssetID EventAssetRef(size_t EventIdx) const { return mEvents[EventIdx].mAssetRef; }
|
||||||
|
|
||||||
inline void AddEvent(uint32 CharIdx, CAssetID AssetID) { mEvents.push_back( SEvent { CharIdx, AssetID } ); }
|
void AddEvent(uint32 CharIdx, CAssetID AssetID) { mEvents.push_back(SEvent{CharIdx, AssetID}); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CANIMEVENTDATA
|
#endif // CANIMEVENTDATA
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "Core/Resource/Model/CModel.h"
|
#include "Core/Resource/Model/CModel.h"
|
||||||
#include <Common/BasicTypes.h>
|
#include <Common/BasicTypes.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Animation structures
|
// Animation structures
|
||||||
|
@ -27,7 +29,7 @@ struct SAdditiveAnim
|
||||||
struct SAnimation
|
struct SAnimation
|
||||||
{
|
{
|
||||||
TString Name;
|
TString Name;
|
||||||
IMetaAnimation *pMetaAnim;
|
std::unique_ptr<IMetaAnimation> pMetaAnim;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct STransition
|
struct STransition
|
||||||
|
@ -35,13 +37,13 @@ struct STransition
|
||||||
uint32 Unknown;
|
uint32 Unknown;
|
||||||
uint32 AnimIdA;
|
uint32 AnimIdA;
|
||||||
uint32 AnimIdB;
|
uint32 AnimIdB;
|
||||||
IMetaTransition *pMetaTrans;
|
std::unique_ptr<IMetaTransition> pMetaTrans;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHalfTransition
|
struct SHalfTransition
|
||||||
{
|
{
|
||||||
uint32 AnimID;
|
uint32 AnimID;
|
||||||
IMetaTransition *pMetaTrans;
|
std::unique_ptr<IMetaTransition> pMetaTrans;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Character structures
|
// Character structures
|
||||||
|
@ -94,50 +96,37 @@ class CAnimSet : public CResource
|
||||||
std::vector<CAnimPrimitive> mAnimPrimitives;
|
std::vector<CAnimPrimitive> mAnimPrimitives;
|
||||||
std::vector<SAnimation> mAnimations;
|
std::vector<SAnimation> mAnimations;
|
||||||
std::vector<STransition> mTransitions;
|
std::vector<STransition> mTransitions;
|
||||||
IMetaTransition *mpDefaultTransition;
|
std::unique_ptr<IMetaTransition> mpDefaultTransition;
|
||||||
std::vector<SAdditiveAnim> mAdditiveAnims;
|
std::vector<SAdditiveAnim> mAdditiveAnims;
|
||||||
float mDefaultAdditiveFadeIn;
|
float mDefaultAdditiveFadeIn = 0.0f;
|
||||||
float mDefaultAdditiveFadeOut;
|
float mDefaultAdditiveFadeOut = 0.0f;
|
||||||
std::vector<SHalfTransition> mHalfTransitions;
|
std::vector<SHalfTransition> mHalfTransitions;
|
||||||
std::vector<CAnimEventData*> mAnimEvents; // note: these are for MP2, where event data isn't a standalone resource; these are owned by the animset
|
std::vector<std::unique_ptr<CAnimEventData>> mAnimEvents; // note: these are for MP2, where event data isn't a standalone resource; these are owned by the animset
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimSet(CResourceEntry *pEntry = 0)
|
explicit CAnimSet(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mpDefaultTransition(nullptr)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~CAnimSet()
|
~CAnimSet() override
|
||||||
{
|
{
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
|
||||||
delete mAnimations[iAnim].pMetaAnim;
|
|
||||||
|
|
||||||
for (uint32 iTrans = 0; iTrans < mTransitions.size(); iTrans++)
|
|
||||||
delete mTransitions[iTrans].pMetaTrans;
|
|
||||||
|
|
||||||
for (uint32 iHalf = 0; iHalf < mHalfTransitions.size(); iHalf++)
|
|
||||||
delete mHalfTransitions[iHalf].pMetaTrans;
|
|
||||||
|
|
||||||
delete mpDefaultTransition;
|
|
||||||
|
|
||||||
// For MP2, anim events need to be cleaned up manually
|
// For MP2, anim events need to be cleaned up manually
|
||||||
for (uint32 iEvent = 0; iEvent < mAnimEvents.size(); iEvent++)
|
for ([[maybe_unused]] const auto& event : mAnimEvents)
|
||||||
{
|
{
|
||||||
ASSERT(mAnimEvents[iEvent] && !mAnimEvents[iEvent]->Entry());
|
ASSERT(event != nullptr && !event->Entry());
|
||||||
delete mAnimEvents[iEvent];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
|
|
||||||
// Character dependencies
|
// Character dependencies
|
||||||
for (uint32 iChar = 0; iChar < mCharacters.size(); iChar++)
|
for (const auto& character : mCharacters)
|
||||||
{
|
{
|
||||||
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree( mCharacters[iChar] );
|
auto pCharTree = CSetCharacterDependency::BuildTree(character);
|
||||||
ASSERT(pCharTree);
|
ASSERT(pCharTree);
|
||||||
pTree->AddChild(pCharTree);
|
pTree->AddChild(std::move(pCharTree));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animation dependencies
|
// Animation dependencies
|
||||||
|
@ -145,58 +134,52 @@ public:
|
||||||
{
|
{
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||||
{
|
{
|
||||||
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
|
auto pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
|
||||||
ASSERT(pAnimTree);
|
ASSERT(pAnimTree);
|
||||||
pTree->AddChild(pAnimTree);
|
pTree->AddChild(std::move(pAnimTree));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (Game() <= EGame::Corruption)
|
else if (Game() <= EGame::Corruption)
|
||||||
{
|
{
|
||||||
const SSetCharacter& rkChar = mCharacters[0];
|
const SSetCharacter& rkChar = mCharacters[0];
|
||||||
std::set<CAnimPrimitive> PrimitiveSet;
|
std::set<CAnimPrimitive> PrimitiveSet;
|
||||||
|
|
||||||
// Animations
|
// Animations
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
for (const auto& anim : mAnimations)
|
||||||
{
|
{
|
||||||
const SAnimation& rkAnim = mAnimations[iAnim];
|
anim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
|
||||||
rkAnim.pMetaAnim->GetUniquePrimitives(PrimitiveSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSourceAnimData *pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID);
|
if (auto* pAnimData = gpResourceStore->LoadResource<CSourceAnimData>(rkChar.AnimDataID))
|
||||||
if (pAnimData)
|
pAnimData->AddTransitionDependencies(pTree.get());
|
||||||
pAnimData->AddTransitionDependencies(pTree);
|
|
||||||
|
|
||||||
for (auto Iter = PrimitiveSet.begin(); Iter != PrimitiveSet.end(); Iter++)
|
for (const auto& prim : PrimitiveSet)
|
||||||
{
|
{
|
||||||
const CAnimPrimitive& rkPrim = *Iter;
|
pTree->AddDependency(prim.Animation());
|
||||||
pTree->AddDependency(rkPrim.Animation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event sounds
|
// Event sounds
|
||||||
for (uint32 iSound = 0; iSound < rkChar.SoundEffects.size(); iSound++)
|
for (const auto& effect : rkChar.SoundEffects)
|
||||||
{
|
{
|
||||||
pTree->AddDependency(rkChar.SoundEffects[iSound]);
|
pTree->AddDependency(effect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const SSetCharacter& rkChar = mCharacters[0];
|
const SSetCharacter& rkChar = mCharacters[0];
|
||||||
|
|
||||||
for (uint32 iDep = 0; iDep < rkChar.DKDependencies.size(); iDep++)
|
for (const auto& dep : rkChar.DKDependencies)
|
||||||
pTree->AddDependency(rkChar.DKDependencies[iDep]);
|
pTree->AddDependency(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAnimation* FindAnimationAsset(uint32 AnimID) const
|
CAnimation* FindAnimationAsset(size_t AnimID) const
|
||||||
{
|
{
|
||||||
if (AnimID >= 0 && AnimID < mAnimPrimitives.size())
|
if (AnimID < mAnimPrimitives.size())
|
||||||
{
|
{
|
||||||
CAnimPrimitive Prim = mAnimPrimitives[AnimID];
|
return mAnimPrimitives[AnimID].Animation();
|
||||||
return Prim.Animation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -204,39 +187,37 @@ public:
|
||||||
|
|
||||||
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||||
{
|
{
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimPrimitives.size(); iAnim++)
|
rPrimSet.insert(mAnimPrimitives.cbegin(), mAnimPrimitives.cend());
|
||||||
rPrimSet.insert(mAnimPrimitives[iAnim]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline uint32 NumCharacters() const { return mCharacters.size(); }
|
size_t NumCharacters() const { return mCharacters.size(); }
|
||||||
inline uint32 NumAnimations() const { return mAnimations.size(); }
|
size_t NumAnimations() const { return mAnimations.size(); }
|
||||||
|
|
||||||
inline const SSetCharacter* Character(uint32 Index) const
|
const SSetCharacter* Character(size_t Index) const
|
||||||
{
|
{
|
||||||
ASSERT(Index >= 0 && Index < NumCharacters());
|
ASSERT(Index < NumCharacters());
|
||||||
return &mCharacters[Index];
|
return &mCharacters[Index];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const SAnimation* Animation(uint32 Index) const
|
const SAnimation* Animation(size_t Index) const
|
||||||
{
|
{
|
||||||
ASSERT(Index >= 0 && Index < NumAnimations());
|
ASSERT(Index < NumAnimations());
|
||||||
return &mAnimations[Index];
|
return &mAnimations[Index];
|
||||||
}
|
}
|
||||||
|
|
||||||
CAnimEventData* AnimationEventData(uint32 Index) const
|
CAnimEventData* AnimationEventData(size_t Index) const
|
||||||
{
|
{
|
||||||
ASSERT(Index >= 0 && Index < NumAnimations());
|
ASSERT(Index < NumAnimations());
|
||||||
|
|
||||||
if (Game() <= EGame::Prime)
|
if (Game() <= EGame::Prime)
|
||||||
{
|
{
|
||||||
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
|
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
|
||||||
return rkPrim.Animation() ? rkPrim.Animation()->EventData() : nullptr;
|
return rkPrim.Animation() != nullptr ? rkPrim.Animation()->EventData() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (Index < mAnimEvents.size() ? mAnimEvents[Index] : nullptr);
|
return (Index < mAnimEvents.size() ? mAnimEvents[Index].get() : nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,21 +6,12 @@
|
||||||
|
|
||||||
CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/)
|
CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mDuration(0.f)
|
|
||||||
, mTickInterval(0.0333333f)
|
|
||||||
, mNumKeys(0)
|
|
||||||
{
|
{
|
||||||
for (uint32 iBone = 0; iBone < 100; iBone++)
|
|
||||||
{
|
|
||||||
mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
|
|
||||||
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
|
|
||||||
mBoneInfo[iBone].ScaleChannelIdx = 0xFF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* CAnimation::BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> CAnimation::BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
pTree->AddDependency(mpEventData);
|
pTree->AddDependency(mpEventData);
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Core/Resource/Animation/CAnimEventData.h"
|
#include "Core/Resource/Animation/CAnimEventData.h"
|
||||||
#include <Common/Math/CQuaternion.h>
|
#include <Common/Math/CQuaternion.h>
|
||||||
#include <Common/Math/CVector3f.h>
|
#include <Common/Math/CVector3f.h>
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class CAnimation : public CResource
|
class CAnimation : public CResource
|
||||||
|
@ -13,13 +14,13 @@ class CAnimation : public CResource
|
||||||
DECLARE_RESOURCE_TYPE(Animation)
|
DECLARE_RESOURCE_TYPE(Animation)
|
||||||
friend class CAnimationLoader;
|
friend class CAnimationLoader;
|
||||||
|
|
||||||
typedef std::vector<CVector3f> TScaleChannel;
|
using TScaleChannel = std::vector<CVector3f>;
|
||||||
typedef std::vector<CQuaternion> TRotationChannel;
|
using TRotationChannel = std::vector<CQuaternion>;
|
||||||
typedef std::vector<CVector3f> TTranslationChannel;
|
using TTranslationChannel = std::vector<CVector3f>;
|
||||||
|
|
||||||
float mDuration;
|
float mDuration = 0.0f;
|
||||||
float mTickInterval;
|
float mTickInterval = 0.0333333f;
|
||||||
uint32 mNumKeys;
|
uint32 mNumKeys = 0;
|
||||||
|
|
||||||
std::vector<TScaleChannel> mScaleChannels;
|
std::vector<TScaleChannel> mScaleChannels;
|
||||||
std::vector<TRotationChannel> mRotationChannels;
|
std::vector<TRotationChannel> mRotationChannels;
|
||||||
|
@ -27,24 +28,24 @@ class CAnimation : public CResource
|
||||||
|
|
||||||
struct SBoneChannelInfo
|
struct SBoneChannelInfo
|
||||||
{
|
{
|
||||||
uint8 ScaleChannelIdx;
|
uint8 ScaleChannelIdx = 0xFF;
|
||||||
uint8 RotationChannelIdx;
|
uint8 RotationChannelIdx = 0xFF;
|
||||||
uint8 TranslationChannelIdx;
|
uint8 TranslationChannelIdx = 0xFF;
|
||||||
};
|
};
|
||||||
SBoneChannelInfo mBoneInfo[100];
|
std::array<SBoneChannelInfo, 100> mBoneInfo;
|
||||||
|
|
||||||
TResPtr<CAnimEventData> mpEventData;
|
TResPtr<CAnimEventData> mpEventData;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimation(CResourceEntry *pEntry = 0);
|
explicit CAnimation(CResourceEntry *pEntry = nullptr);
|
||||||
CDependencyTree* BuildDependencyTree() const;
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
|
||||||
void EvaluateTransform(float Time, uint32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const;
|
void EvaluateTransform(float Time, uint32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const;
|
||||||
bool HasTranslation(uint32 BoneID) const;
|
bool HasTranslation(uint32 BoneID) const;
|
||||||
|
|
||||||
inline float Duration() const { return mDuration; }
|
float Duration() const { return mDuration; }
|
||||||
inline uint32 NumKeys() const { return mNumKeys; }
|
uint32 NumKeys() const { return mNumKeys; }
|
||||||
inline float TickInterval() const { return mTickInterval; }
|
float TickInterval() const { return mTickInterval; }
|
||||||
inline CAnimEventData* EventData() const { return mpEventData; }
|
CAnimEventData* EventData() const { return mpEventData; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CANIMATION_H
|
#endif // CANIMATION_H
|
||||||
|
|
|
@ -2,33 +2,16 @@
|
||||||
#include "CAnimSet.h"
|
#include "CAnimSet.h"
|
||||||
#include "Core/GameProject/CResourceStore.h"
|
#include "Core/GameProject/CResourceStore.h"
|
||||||
#include <Common/Log.h>
|
#include <Common/Log.h>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
CAnimationParameters::CAnimationParameters()
|
CAnimationParameters::CAnimationParameters() = default;
|
||||||
: mGame(EGame::Prime)
|
|
||||||
, mCharIndex(0)
|
|
||||||
, mAnimIndex(0)
|
|
||||||
, mUnknown2(0)
|
|
||||||
, mUnknown3(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CAnimationParameters::CAnimationParameters(EGame Game)
|
CAnimationParameters::CAnimationParameters(EGame Game)
|
||||||
: mGame(Game)
|
: mGame(Game), mCharacterID(CAssetID::InvalidID(Game))
|
||||||
, mCharacterID( CAssetID::InvalidID(Game) )
|
|
||||||
, mCharIndex(0)
|
|
||||||
, mAnimIndex(0)
|
|
||||||
, mUnknown2(0)
|
|
||||||
, mUnknown3(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
|
CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
|
||||||
: mGame(Game)
|
: mGame(Game)
|
||||||
, mCharIndex(0)
|
|
||||||
, mAnimIndex(0)
|
|
||||||
, mUnknown2(0)
|
|
||||||
, mUnknown3(0)
|
|
||||||
{
|
{
|
||||||
if (Game <= EGame::Echoes)
|
if (Game <= EGame::Echoes)
|
||||||
{
|
{
|
||||||
|
@ -156,36 +139,36 @@ void CAnimationParameters::Serialize(IArchive& rArc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(int32 NodeIndex /*= -1*/)
|
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(int32 NodeIndex) const
|
||||||
{
|
{
|
||||||
CAnimSet *pSet = AnimSet();
|
const CAnimSet *pSet = AnimSet();
|
||||||
|
|
||||||
if (pSet && (pSet->Type() == EResourceType::AnimSet || pSet->Type() == EResourceType::Character))
|
if (pSet != nullptr && (pSet->Type() == EResourceType::AnimSet || pSet->Type() == EResourceType::Character))
|
||||||
{
|
{
|
||||||
if (NodeIndex == -1)
|
if (NodeIndex == -1)
|
||||||
NodeIndex = mCharIndex;
|
NodeIndex = mCharIndex;
|
||||||
|
|
||||||
if (mCharIndex != -1 && pSet->NumCharacters() > (uint32) NodeIndex)
|
if (mCharIndex != UINT32_MAX && pSet->NumCharacters() > static_cast<uint32>(NodeIndex))
|
||||||
return pSet->Character(NodeIndex);
|
return pSet->Character(NodeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CModel* CAnimationParameters::GetCurrentModel(int32 NodeIndex /*= -1*/)
|
CModel* CAnimationParameters::GetCurrentModel(int32 NodeIndex)
|
||||||
{
|
{
|
||||||
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
|
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
|
||||||
return pkChar ? pkChar->pModel : nullptr;
|
return pkChar != nullptr ? pkChar->pModel : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TString CAnimationParameters::GetCurrentCharacterName(int32 NodeIndex /*= -1*/)
|
TString CAnimationParameters::GetCurrentCharacterName(int32 NodeIndex) const
|
||||||
{
|
{
|
||||||
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
|
const SSetCharacter *pkChar = GetCurrentSetCharacter(NodeIndex);
|
||||||
return pkChar ? pkChar->Name : "";
|
return pkChar != nullptr ? pkChar->Name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ ACCESSORS ************
|
// ************ ACCESSORS ************
|
||||||
uint32 CAnimationParameters::Unknown(uint32 Index)
|
uint32 CAnimationParameters::Unknown(uint32 Index) const
|
||||||
{
|
{
|
||||||
// mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot
|
// mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot
|
||||||
// of UI stuff that depends on these functions atm for accessing and editing parameters.
|
// of UI stuff that depends on these functions atm for accessing and editing parameters.
|
||||||
|
@ -225,8 +208,14 @@ void CAnimationParameters::SetUnknown(uint32 Index, uint32 Value)
|
||||||
{
|
{
|
||||||
switch (Index)
|
switch (Index)
|
||||||
{
|
{
|
||||||
case 0: mAnimIndex = Value;
|
case 0:
|
||||||
case 1: mUnknown2 = Value;
|
mAnimIndex = Value;
|
||||||
case 2: mUnknown3 = Value;
|
break;
|
||||||
|
case 1:
|
||||||
|
mUnknown2 = Value;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mUnknown3 = Value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,35 +8,39 @@ class CModel;
|
||||||
|
|
||||||
class CAnimationParameters
|
class CAnimationParameters
|
||||||
{
|
{
|
||||||
EGame mGame;
|
EGame mGame = EGame::Prime;
|
||||||
CAssetID mCharacterID;
|
CAssetID mCharacterID;
|
||||||
|
|
||||||
uint32 mCharIndex;
|
uint32 mCharIndex = 0;
|
||||||
uint32 mAnimIndex;
|
uint32 mAnimIndex = 0;
|
||||||
uint32 mUnknown2;
|
uint32 mUnknown2 = 0;
|
||||||
uint32 mUnknown3;
|
uint32 mUnknown3 = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimationParameters();
|
CAnimationParameters();
|
||||||
CAnimationParameters(EGame Game);
|
explicit CAnimationParameters(EGame Game);
|
||||||
CAnimationParameters(IInputStream& rSCLY, EGame Game);
|
explicit CAnimationParameters(IInputStream& rSCLY, EGame Game);
|
||||||
|
|
||||||
|
CAnimationParameters(const CAnimationParameters&) = default;
|
||||||
|
CAnimationParameters& operator=(const CAnimationParameters&) = default;
|
||||||
|
|
||||||
void Write(IOutputStream& rSCLY);
|
void Write(IOutputStream& rSCLY);
|
||||||
void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc);
|
||||||
|
|
||||||
const SSetCharacter* GetCurrentSetCharacter(int32 NodeIndex = -1);
|
const SSetCharacter* GetCurrentSetCharacter(int32 NodeIndex = -1) const;
|
||||||
CModel* GetCurrentModel(int32 NodeIndex = -1);
|
CModel* GetCurrentModel(int32 NodeIndex = -1);
|
||||||
TString GetCurrentCharacterName(int32 NodeIndex = -1);
|
TString GetCurrentCharacterName(int32 NodeIndex = -1) const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline EGame Version() const { return mGame; }
|
EGame Version() const { return mGame; }
|
||||||
inline CAssetID ID() const { return mCharacterID; }
|
CAssetID ID() const { return mCharacterID; }
|
||||||
inline CAnimSet* AnimSet() const { return (CAnimSet*) gpResourceStore->LoadResource(mCharacterID); }
|
CAnimSet* AnimSet() const { return (CAnimSet*) gpResourceStore->LoadResource(mCharacterID); }
|
||||||
inline uint32 CharacterIndex() const { return mCharIndex; }
|
uint32 CharacterIndex() const { return mCharIndex; }
|
||||||
inline uint32 AnimIndex() const { return mAnimIndex; }
|
uint32 AnimIndex() const { return mAnimIndex; }
|
||||||
inline void SetCharIndex(uint32 Index) { mCharIndex = Index; }
|
void SetCharIndex(uint32 Index) { mCharIndex = Index; }
|
||||||
inline void SetAnimIndex(uint32 Index) { mAnimIndex = Index; }
|
void SetAnimIndex(uint32 Index) { mAnimIndex = Index; }
|
||||||
|
|
||||||
inline void SetGame(EGame Game)
|
void SetGame(EGame Game)
|
||||||
{
|
{
|
||||||
mGame = Game;
|
mGame = Game;
|
||||||
|
|
||||||
|
@ -50,30 +54,22 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Unknown(uint32 Index);
|
uint32 Unknown(uint32 Index) const;
|
||||||
void SetResource(const CAssetID& rkID);
|
void SetResource(const CAssetID& rkID);
|
||||||
void SetUnknown(uint32 Index, uint32 Value);
|
void SetUnknown(uint32 Index, uint32 Value);
|
||||||
|
|
||||||
// Operators
|
bool operator==(const CAnimationParameters& other) const
|
||||||
inline CAnimationParameters& operator=(const CAnimationParameters& rkOther)
|
|
||||||
{
|
{
|
||||||
mGame = rkOther.mGame;
|
return mGame == other.mGame &&
|
||||||
mCharacterID = rkOther.mCharacterID;
|
mCharacterID == other.mCharacterID &&
|
||||||
mCharIndex = rkOther.mCharIndex;
|
mCharIndex == other.mCharIndex &&
|
||||||
mAnimIndex = rkOther.mAnimIndex;
|
mAnimIndex == other.mAnimIndex &&
|
||||||
mUnknown2 = rkOther.mUnknown2;
|
mUnknown2 == other.mUnknown2 &&
|
||||||
mUnknown3 = rkOther.mUnknown3;
|
mUnknown3 == other.mUnknown3;
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
bool operator!=(const CAnimationParameters& other) const
|
||||||
inline bool operator==(const CAnimationParameters& rkOther) const
|
|
||||||
{
|
{
|
||||||
return ( (mGame == rkOther.mGame) &&
|
return !operator==(other);
|
||||||
(mCharacterID == rkOther.mCharacterID) &&
|
|
||||||
(mCharIndex == rkOther.mCharIndex) &&
|
|
||||||
(mAnimIndex == rkOther.mAnimIndex) &&
|
|
||||||
(mUnknown2 == rkOther.mUnknown2) &&
|
|
||||||
(mUnknown3 == rkOther.mUnknown3) );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
#include <Common/Macros.h>
|
#include <Common/Macros.h>
|
||||||
#include <Common/Math/MathUtil.h>
|
#include <Common/Math/MathUtil.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
|
|
||||||
// ************ CBone ************
|
// ************ CBone ************
|
||||||
CBone::CBone(CSkeleton *pSkel)
|
CBone::CBone(CSkeleton *pSkel)
|
||||||
: mpSkeleton(pSkel)
|
: mpSkeleton(pSkel)
|
||||||
, mSelected(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo&
|
||||||
pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
|
pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
|
||||||
|
|
||||||
if (AnchorRoot && IsRoot())
|
if (AnchorRoot && IsRoot())
|
||||||
TransformInfo.Position = CVector3f::skZero;
|
TransformInfo.Position = CVector3f::Zero();
|
||||||
|
|
||||||
// Apply parent transform
|
// Apply parent transform
|
||||||
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position));
|
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position));
|
||||||
|
@ -39,8 +39,8 @@ void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo&
|
||||||
rTransform *= mInvBind;
|
rTransform *= mInvBind;
|
||||||
|
|
||||||
// Calculate children
|
// Calculate children
|
||||||
for (uint32 iChild = 0; iChild < mChildren.size(); iChild++)
|
for (auto* child : mChildren)
|
||||||
mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
|
child->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
|
CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
|
||||||
|
@ -58,57 +58,51 @@ bool CBone::IsRoot() const
|
||||||
// In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the
|
// In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the
|
||||||
// actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton),
|
// actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton),
|
||||||
// so we need to account for both
|
// so we need to account for both
|
||||||
return (mpParent == nullptr || mpParent->Parent() == nullptr);
|
return mpParent == nullptr || mpParent->Parent() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CSkeleton ************
|
// ************ CSkeleton ************
|
||||||
const float CSkeleton::skSphereRadius = 0.025f;
|
|
||||||
|
|
||||||
CSkeleton::CSkeleton(CResourceEntry *pEntry /*= 0*/)
|
CSkeleton::CSkeleton(CResourceEntry *pEntry)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mpRootBone(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CSkeleton::~CSkeleton()
|
CSkeleton::~CSkeleton() = default;
|
||||||
{
|
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
|
||||||
delete mBones[iBone];
|
|
||||||
}
|
|
||||||
|
|
||||||
CBone* CSkeleton::BoneByID(uint32 BoneID) const
|
CBone* CSkeleton::BoneByID(uint32 BoneID) const
|
||||||
{
|
{
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
const auto iter = std::find_if(mBones.begin(), mBones.end(),
|
||||||
{
|
[BoneID](const auto& bone) { return bone->ID() == BoneID; });
|
||||||
if (mBones[iBone]->ID() == BoneID)
|
|
||||||
return mBones[iBone];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
if (iter == mBones.cend())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return iter->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBone* CSkeleton::BoneByName(const TString& rkBoneName) const
|
CBone* CSkeleton::BoneByName(std::string_view name) const
|
||||||
{
|
{
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
const auto iter = std::find_if(mBones.begin(), mBones.end(),
|
||||||
{
|
[&name](const auto& bone) { return bone->Name() == name; });
|
||||||
if (mBones[iBone]->Name() == rkBoneName)
|
|
||||||
return mBones[iBone];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
if (iter == mBones.cend())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return iter->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 CSkeleton::MaxBoneID() const
|
uint32 CSkeleton::MaxBoneID() const
|
||||||
{
|
{
|
||||||
uint32 ID = 0;
|
const auto iter = std::max_element(mBones.cbegin(), mBones.cend(),
|
||||||
|
[](const auto& a, const auto& b) { return a->ID() < b->ID(); });
|
||||||
|
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
if (iter == mBones.cend())
|
||||||
{
|
{
|
||||||
if (mBones[iBone]->ID() > ID)
|
return 0;
|
||||||
ID = mBones[iBone]->ID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ID;
|
return (*iter)->ID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
|
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
|
||||||
|
@ -123,55 +117,52 @@ void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkDat
|
||||||
glLineWidth(1.f);
|
glLineWidth(1.f);
|
||||||
|
|
||||||
// Draw all child links first to minimize model matrix swaps.
|
// Draw all child links first to minimize model matrix swaps.
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
for (const auto& pBone : mBones)
|
||||||
{
|
{
|
||||||
CBone *pBone = mBones[iBone];
|
const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
|
||||||
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
|
|
||||||
|
|
||||||
// Draw the bone's local XYZ axes for selected bones
|
// Draw the bone's local XYZ axes for selected bones
|
||||||
if (pBone->IsSelected())
|
if (pBone->IsSelected())
|
||||||
{
|
{
|
||||||
CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
|
const CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
|
||||||
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::skRed);
|
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::Red());
|
||||||
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::skGreen);
|
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::Green());
|
||||||
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::skBlue);
|
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::Blue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw child links
|
// Draw child links
|
||||||
for (uint32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
|
for (size_t iChild = 0; iChild < pBone->NumChildren(); iChild++)
|
||||||
{
|
{
|
||||||
CBone *pChild = pBone->ChildByIndex(iChild);
|
const CBone *pChild = pBone->ChildByIndex(iChild);
|
||||||
CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
|
const CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
|
||||||
CDrawUtil::DrawLine(BonePos, ChildPos);
|
CDrawUtil::DrawLine(BonePos, ChildPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bone spheres
|
// Draw bone spheres
|
||||||
CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix;
|
const CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix;
|
||||||
|
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
for (const auto& pBone : mBones)
|
||||||
{
|
{
|
||||||
CBone *pBone = mBones[iBone];
|
const CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
|
||||||
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
|
|
||||||
|
|
||||||
CTransform4f Transform;
|
CTransform4f Transform;
|
||||||
Transform.Scale(skSphereRadius);
|
Transform.Scale(skSphereRadius);
|
||||||
Transform.Translate(BonePos);
|
Transform.Translate(BonePos);
|
||||||
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
|
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
|
||||||
CGraphics::UpdateMVPBlock();
|
CGraphics::UpdateMVPBlock();
|
||||||
CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::skRed : CColor::skWhite);
|
CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::Red() : CColor::White());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<int32,float> CSkeleton::RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData)
|
std::pair<int32,float> CSkeleton::RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData) const
|
||||||
{
|
{
|
||||||
std::pair<int32,float> Out(-1, FLT_MAX);
|
std::pair<int32,float> Out(-1, FLT_MAX);
|
||||||
|
|
||||||
for (uint32 iBone = 0; iBone < mBones.size(); iBone++)
|
for (const auto& pBone : mBones)
|
||||||
{
|
{
|
||||||
CBone *pBone = mBones[iBone];
|
const CVector3f BonePos = pBone->TransformedPosition(rkData);
|
||||||
CVector3f BonePos = pBone->TransformedPosition(rkData);
|
const std::pair<bool, float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
|
||||||
std::pair<bool,float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
|
|
||||||
|
|
||||||
if (Intersect.first && Intersect.second < Out.second)
|
if (Intersect.first && Intersect.second < Out.second)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,18 +8,17 @@
|
||||||
#include <Common/TString.h>
|
#include <Common/TString.h>
|
||||||
#include <Common/Math/CRay.h>
|
#include <Common/Math/CRay.h>
|
||||||
#include <Common/Math/CVector3f.h>
|
#include <Common/Math/CVector3f.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
class CBoneTransformData;
|
class CBoneTransformData;
|
||||||
class CBone;
|
class CBone;
|
||||||
|
|
||||||
struct SBoneTransformInfo
|
struct SBoneTransformInfo
|
||||||
{
|
{
|
||||||
CVector3f Position;
|
CVector3f Position{CVector3f::Zero()};
|
||||||
CQuaternion Rotation;
|
CQuaternion Rotation{CQuaternion::Identity()};
|
||||||
CVector3f Scale;
|
CVector3f Scale{CVector3f::One()};
|
||||||
|
|
||||||
SBoneTransformInfo()
|
|
||||||
: Position(CVector3f::skZero), Rotation(CQuaternion::skIdentity), Scale(CVector3f::skOne) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CSkeleton : public CResource
|
class CSkeleton : public CResource
|
||||||
|
@ -27,24 +26,24 @@ class CSkeleton : public CResource
|
||||||
DECLARE_RESOURCE_TYPE(Skeleton)
|
DECLARE_RESOURCE_TYPE(Skeleton)
|
||||||
friend class CSkeletonLoader;
|
friend class CSkeletonLoader;
|
||||||
|
|
||||||
CBone *mpRootBone;
|
CBone *mpRootBone = nullptr;
|
||||||
std::vector<CBone*> mBones;
|
std::vector<std::unique_ptr<CBone>> mBones;
|
||||||
|
|
||||||
static const float skSphereRadius;
|
static constexpr float skSphereRadius = 0.025f;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSkeleton(CResourceEntry *pEntry = 0);
|
explicit CSkeleton(CResourceEntry *pEntry = nullptr);
|
||||||
~CSkeleton();
|
~CSkeleton() override;
|
||||||
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
|
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
|
||||||
CBone* BoneByID(uint32 BoneID) const;
|
CBone* BoneByID(uint32 BoneID) const;
|
||||||
CBone* BoneByName(const TString& rkBoneName) const;
|
CBone* BoneByName(std::string_view name) const;
|
||||||
uint32 MaxBoneID() const;
|
uint32 MaxBoneID() const;
|
||||||
|
|
||||||
void Draw(FRenderOptions Options, const CBoneTransformData *pkData);
|
void Draw(FRenderOptions Options, const CBoneTransformData *pkData);
|
||||||
std::pair<int32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
|
std::pair<int32, float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData) const;
|
||||||
|
|
||||||
inline uint32 NumBones() const { return mBones.size(); }
|
size_t NumBones() const { return mBones.size(); }
|
||||||
inline CBone* RootBone() const { return mpRootBone; }
|
CBone* RootBone() const { return mpRootBone; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CBone
|
class CBone
|
||||||
|
@ -52,38 +51,38 @@ class CBone
|
||||||
friend class CSkeletonLoader;
|
friend class CSkeletonLoader;
|
||||||
|
|
||||||
CSkeleton *mpSkeleton;
|
CSkeleton *mpSkeleton;
|
||||||
CBone *mpParent;
|
CBone *mpParent = nullptr;
|
||||||
std::vector<CBone*> mChildren;
|
std::vector<CBone*> mChildren;
|
||||||
uint32 mID;
|
uint32 mID = 0;
|
||||||
CVector3f mPosition;
|
CVector3f mPosition;
|
||||||
CVector3f mLocalPosition;
|
CVector3f mLocalPosition;
|
||||||
CQuaternion mRotation;
|
CQuaternion mRotation;
|
||||||
CQuaternion mLocalRotation;
|
CQuaternion mLocalRotation;
|
||||||
TString mName;
|
TString mName;
|
||||||
CTransform4f mInvBind;
|
CTransform4f mInvBind;
|
||||||
bool mSelected;
|
bool mSelected = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CBone(CSkeleton *pSkel);
|
explicit CBone(CSkeleton *pSkel);
|
||||||
void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
|
void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
|
||||||
CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
|
CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
|
||||||
CQuaternion TransformedRotation(const CBoneTransformData& rkData) const;
|
CQuaternion TransformedRotation(const CBoneTransformData& rkData) const;
|
||||||
bool IsRoot() const;
|
bool IsRoot() const;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CSkeleton* Skeleton() const { return mpSkeleton; }
|
CSkeleton* Skeleton() const { return mpSkeleton; }
|
||||||
inline CBone* Parent() const { return mpParent; }
|
CBone* Parent() const { return mpParent; }
|
||||||
inline uint32 NumChildren() const { return mChildren.size(); }
|
size_t NumChildren() const { return mChildren.size(); }
|
||||||
inline CBone* ChildByIndex(uint32 Index) const { return mChildren[Index]; }
|
CBone* ChildByIndex(size_t Index) const { return mChildren[Index]; }
|
||||||
inline uint32 ID() const { return mID; }
|
uint32 ID() const { return mID; }
|
||||||
inline CVector3f Position() const { return mPosition; }
|
CVector3f Position() const { return mPosition; }
|
||||||
inline CVector3f LocalPosition() const { return mLocalPosition; }
|
CVector3f LocalPosition() const { return mLocalPosition; }
|
||||||
inline CQuaternion Rotation() const { return mRotation; }
|
CQuaternion Rotation() const { return mRotation; }
|
||||||
inline CQuaternion LocalRotation() const { return mLocalRotation; }
|
CQuaternion LocalRotation() const { return mLocalRotation; }
|
||||||
inline TString Name() const { return mName; }
|
TString Name() const { return mName; }
|
||||||
inline bool IsSelected() const { return mSelected; }
|
bool IsSelected() const { return mSelected; }
|
||||||
|
|
||||||
inline void SetSelected(bool Selected) { mSelected = Selected; }
|
void SetSelected(bool Selected) { mSelected = Selected; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CSKELETON_H
|
#endif // CSKELETON_H
|
||||||
|
|
|
@ -23,24 +23,24 @@ class CSkin : public CResource
|
||||||
std::vector<SVertGroup> mVertGroups;
|
std::vector<SVertGroup> mVertGroups;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSkin(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
explicit CSkin(CResourceEntry *pEntry = nullptr) : CResource(pEntry) {}
|
||||||
|
|
||||||
const SVertexWeights& WeightsForVertex(uint32 VertIdx)
|
const SVertexWeights& WeightsForVertex(uint32 VertIdx)
|
||||||
{
|
{
|
||||||
// Null weights bind everything to the root bone in case there is no matching vertex group
|
// Null weights bind everything to the root bone in case there is no matching vertex group
|
||||||
static const SVertexWeights skNullWeights = {
|
static constexpr SVertexWeights skNullWeights{
|
||||||
{ 3, 0, 0, 0 },
|
{3, 0, 0, 0},
|
||||||
{ 1.f, 0.f, 0.f, 0.f }
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32 Index = 0;
|
uint32 Index = 0;
|
||||||
|
|
||||||
for (uint32 iGrp = 0; iGrp < mVertGroups.size(); iGrp++)
|
for (const auto& group : mVertGroups)
|
||||||
{
|
{
|
||||||
if (VertIdx < Index + mVertGroups[iGrp].NumVertices)
|
if (VertIdx < Index + group.NumVertices)
|
||||||
return mVertGroups[iGrp].Weights;
|
return group.Weights;
|
||||||
|
|
||||||
Index += mVertGroups[iGrp].NumVertices;
|
Index += group.NumVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
return skNullWeights;
|
return skNullWeights;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "Core/Resource/CResource.h"
|
#include "Core/Resource/CResource.h"
|
||||||
#include "IMetaTransition.h"
|
#include "IMetaTransition.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class CSourceAnimData : public CResource
|
class CSourceAnimData : public CResource
|
||||||
{
|
{
|
||||||
DECLARE_RESOURCE_TYPE(SourceAnimData)
|
DECLARE_RESOURCE_TYPE(SourceAnimData)
|
||||||
|
@ -13,52 +15,42 @@ class CSourceAnimData : public CResource
|
||||||
{
|
{
|
||||||
CAssetID AnimA;
|
CAssetID AnimA;
|
||||||
CAssetID AnimB;
|
CAssetID AnimB;
|
||||||
IMetaTransition *pTransition;
|
std::unique_ptr<IMetaTransition> pTransition;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHalfTransition
|
struct SHalfTransition
|
||||||
{
|
{
|
||||||
CAssetID Anim;
|
CAssetID Anim;
|
||||||
IMetaTransition *pTransition;
|
std::unique_ptr<IMetaTransition> pTransition;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<STransition> mTransitions;
|
std::vector<STransition> mTransitions;
|
||||||
std::vector<SHalfTransition> mHalfTransitions;
|
std::vector<SHalfTransition> mHalfTransitions;
|
||||||
IMetaTransition *mpDefaultTransition;
|
std::unique_ptr<IMetaTransition> mpDefaultTransition;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSourceAnimData(CResourceEntry *pEntry = 0)
|
explicit CSourceAnimData(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mpDefaultTransition(nullptr)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~CSourceAnimData()
|
~CSourceAnimData() override = default;
|
||||||
{
|
|
||||||
for (uint32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++)
|
|
||||||
delete mTransitions[TransIdx].pTransition;
|
|
||||||
|
|
||||||
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
delete mHalfTransitions[HalfIdx].pTransition;
|
|
||||||
|
|
||||||
delete mpDefaultTransition;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
|
||||||
{
|
{
|
||||||
// SAND normally has dependencies from meta-transitions and events
|
// SAND normally has dependencies from meta-transitions and events
|
||||||
// However, all of these can be character-specific. To simplify things, all SAND
|
// However, all of these can be character-specific. To simplify things, all SAND
|
||||||
// dependencies are being added to the CHAR dependency tree instead. Therefore the
|
// dependencies are being added to the CHAR dependency tree instead. Therefore the
|
||||||
// SAND dependency tree is left empty.
|
// SAND dependency tree is left empty.
|
||||||
return new CDependencyTree();
|
return std::make_unique<CDependencyTree>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||||
{
|
{
|
||||||
for (uint32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++)
|
for (const auto& transition : mTransitions)
|
||||||
mTransitions[TransIdx].pTransition->GetUniquePrimitives(rPrimSet);
|
transition.pTransition->GetUniquePrimitives(rPrimSet);
|
||||||
|
|
||||||
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
|
for (const auto& halfTrans : mHalfTransitions)
|
||||||
mHalfTransitions[HalfIdx].pTransition->GetUniquePrimitives(rPrimSet);
|
halfTrans.pTransition->GetUniquePrimitives(rPrimSet);
|
||||||
|
|
||||||
if (mpDefaultTransition)
|
if (mpDefaultTransition)
|
||||||
mpDefaultTransition->GetUniquePrimitives(rPrimSet);
|
mpDefaultTransition->GetUniquePrimitives(rPrimSet);
|
||||||
|
@ -74,33 +66,31 @@ public:
|
||||||
// Find all relevant primitives
|
// Find all relevant primitives
|
||||||
std::set<CAnimPrimitive> PrimSet;
|
std::set<CAnimPrimitive> PrimSet;
|
||||||
|
|
||||||
if (UsedTransitions.find(mpDefaultTransition) == UsedTransitions.end())
|
if (UsedTransitions.find(mpDefaultTransition.get()) == UsedTransitions.cend())
|
||||||
{
|
{
|
||||||
mpDefaultTransition->GetUniquePrimitives(PrimSet);
|
mpDefaultTransition->GetUniquePrimitives(PrimSet);
|
||||||
UsedTransitions.insert(mpDefaultTransition);
|
UsedTransitions.insert(mpDefaultTransition.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 TransitionIdx = 0; TransitionIdx < mTransitions.size(); TransitionIdx++)
|
for (const STransition& transition : mTransitions)
|
||||||
{
|
{
|
||||||
const STransition& rkTransition = mTransitions[TransitionIdx];
|
IMetaTransition *pTransition = transition.pTransition.get();
|
||||||
IMetaTransition *pTransition = rkTransition.pTransition;
|
|
||||||
|
|
||||||
if ( pTree->HasDependency(rkTransition.AnimA) &&
|
if (pTree->HasDependency(transition.AnimA) &&
|
||||||
pTree->HasDependency(rkTransition.AnimB) &&
|
pTree->HasDependency(transition.AnimB) &&
|
||||||
UsedTransitions.find(pTransition) == UsedTransitions.end() )
|
UsedTransitions.find(pTransition) == UsedTransitions.cend())
|
||||||
{
|
{
|
||||||
pTransition->GetUniquePrimitives(PrimSet);
|
pTransition->GetUniquePrimitives(PrimSet);
|
||||||
UsedTransitions.insert(pTransition);
|
UsedTransitions.insert(pTransition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
|
for (const SHalfTransition& halfTrans : mHalfTransitions)
|
||||||
{
|
{
|
||||||
const SHalfTransition& rkHalfTrans = mHalfTransitions[HalfIdx];
|
IMetaTransition *pTransition = halfTrans.pTransition.get();
|
||||||
IMetaTransition *pTransition = rkHalfTrans.pTransition;
|
|
||||||
|
|
||||||
if ( pTree->HasDependency(rkHalfTrans.Anim) &&
|
if (pTree->HasDependency(halfTrans.Anim) &&
|
||||||
UsedTransitions.find(pTransition) == UsedTransitions.end() )
|
UsedTransitions.find(pTransition) == UsedTransitions.cend())
|
||||||
{
|
{
|
||||||
pTransition->GetUniquePrimitives(PrimSet);
|
pTransition->GetUniquePrimitives(PrimSet);
|
||||||
UsedTransitions.insert(pTransition);
|
UsedTransitions.insert(pTransition);
|
||||||
|
@ -112,8 +102,8 @@ public:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Add all transition primitives to the tree
|
// Add all transition primitives to the tree
|
||||||
for (auto Iter = PrimSet.begin(); Iter != PrimSet.end(); Iter++)
|
for (const auto& primitive : PrimSet)
|
||||||
pTree->AddDependency(Iter->Animation());
|
pTree->AddDependency(primitive.Animation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,27 +3,27 @@
|
||||||
// ************ CMetaAnimFactory ************
|
// ************ CMetaAnimFactory ************
|
||||||
CMetaAnimFactory gMetaAnimFactory;
|
CMetaAnimFactory gMetaAnimFactory;
|
||||||
|
|
||||||
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game)
|
std::unique_ptr<IMetaAnimation> CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
|
||||||
{
|
{
|
||||||
EMetaAnimType Type = (EMetaAnimType) rInput.ReadLong();
|
const auto Type = static_cast<EMetaAnimType>(rInput.ReadLong());
|
||||||
|
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
case EMetaAnimType::Play:
|
case EMetaAnimType::Play:
|
||||||
return new CMetaAnimPlay(rInput, Game);
|
return std::make_unique<CMetaAnimPlay>(rInput, Game);
|
||||||
|
|
||||||
case EMetaAnimType::Blend:
|
case EMetaAnimType::Blend:
|
||||||
case EMetaAnimType::PhaseBlend:
|
case EMetaAnimType::PhaseBlend:
|
||||||
return new CMetaAnimBlend(Type, rInput, Game);
|
return std::make_unique<CMetaAnimBlend>(Type, rInput, Game);
|
||||||
|
|
||||||
case EMetaAnimType::Random:
|
case EMetaAnimType::Random:
|
||||||
return new CMetaAnimRandom(rInput, Game);
|
return std::make_unique<CMetaAnimRandom>(rInput, Game);
|
||||||
|
|
||||||
case EMetaAnimType::Sequence:
|
case EMetaAnimType::Sequence:
|
||||||
return new CMetaAnimSequence(rInput, Game);
|
return std::make_unique<CMetaAnimSequence>(rInput, Game);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorf("Unrecognized meta-animation type: %d", Type);
|
errorf("Unrecognized meta-animation type: %d", static_cast<int>(Type));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,7 @@ CMetaAnimBlend::CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame G
|
||||||
mUnknownB = rInput.ReadBool();
|
mUnknownB = rInput.ReadBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
CMetaAnimBlend::~CMetaAnimBlend()
|
CMetaAnimBlend::~CMetaAnimBlend() = default;
|
||||||
{
|
|
||||||
delete mpMetaAnimA;
|
|
||||||
delete mpMetaAnimB;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMetaAnimType CMetaAnimBlend::Type() const
|
EMetaAnimType CMetaAnimBlend::Type() const
|
||||||
{
|
{
|
||||||
|
@ -84,7 +80,7 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) con
|
||||||
// ************ CMetaAnimRandom ************
|
// ************ CMetaAnimRandom ************
|
||||||
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
|
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
|
||||||
{
|
{
|
||||||
uint32 NumPairs = rInput.ReadLong();
|
const uint32 NumPairs = rInput.ReadLong();
|
||||||
mProbabilityPairs.reserve(NumPairs);
|
mProbabilityPairs.reserve(NumPairs);
|
||||||
|
|
||||||
for (uint32 iAnim = 0; iAnim < NumPairs; iAnim++)
|
for (uint32 iAnim = 0; iAnim < NumPairs; iAnim++)
|
||||||
|
@ -92,15 +88,11 @@ CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
|
||||||
SAnimProbabilityPair Pair;
|
SAnimProbabilityPair Pair;
|
||||||
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
||||||
Pair.Probability = rInput.ReadLong();
|
Pair.Probability = rInput.ReadLong();
|
||||||
mProbabilityPairs.push_back(Pair);
|
mProbabilityPairs.push_back(std::move(Pair));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CMetaAnimRandom::~CMetaAnimRandom()
|
CMetaAnimRandom::~CMetaAnimRandom() = default;
|
||||||
{
|
|
||||||
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
|
||||||
delete mProbabilityPairs[iPair].pAnim;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMetaAnimType CMetaAnimRandom::Type() const
|
EMetaAnimType CMetaAnimRandom::Type() const
|
||||||
{
|
{
|
||||||
|
@ -109,28 +101,23 @@ EMetaAnimType CMetaAnimRandom::Type() const
|
||||||
|
|
||||||
void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||||
{
|
{
|
||||||
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
for (const auto& pair : mProbabilityPairs)
|
||||||
mProbabilityPairs[iPair].pAnim->GetUniquePrimitives(rPrimSet);
|
pair.pAnim->GetUniquePrimitives(rPrimSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CMetaAnimSequence ************
|
// ************ CMetaAnimSequence ************
|
||||||
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
|
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
|
||||||
{
|
{
|
||||||
uint32 NumAnims = rInput.ReadLong();
|
const uint32 NumAnims = rInput.ReadLong();
|
||||||
mAnimations.reserve(NumAnims);
|
mAnimations.reserve(NumAnims);
|
||||||
|
|
||||||
for (uint32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
for (uint32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||||
{
|
{
|
||||||
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
mAnimations.push_back(gMetaAnimFactory.LoadFromStream(rInput, Game));
|
||||||
mAnimations.push_back(pAnim);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CMetaAnimSequence::~CMetaAnimSequence()
|
CMetaAnimSequence::~CMetaAnimSequence() = default;
|
||||||
{
|
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
|
||||||
delete mAnimations[iAnim];
|
|
||||||
}
|
|
||||||
|
|
||||||
EMetaAnimType CMetaAnimSequence::Type() const
|
EMetaAnimType CMetaAnimSequence::Type() const
|
||||||
{
|
{
|
||||||
|
@ -139,6 +126,6 @@ EMetaAnimType CMetaAnimSequence::Type() const
|
||||||
|
|
||||||
void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||||
{
|
{
|
||||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
for (const auto& anim : mAnimations)
|
||||||
mAnimations[iAnim]->GetUniquePrimitives(rPrimSet);
|
anim->GetUniquePrimitives(rPrimSet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ enum class EMetaAnimType
|
||||||
class CMetaAnimFactory
|
class CMetaAnimFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
|
std::unique_ptr<class IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game) const;
|
||||||
};
|
};
|
||||||
extern CMetaAnimFactory gMetaAnimFactory;
|
extern CMetaAnimFactory gMetaAnimFactory;
|
||||||
|
|
||||||
|
@ -26,11 +26,11 @@ extern CMetaAnimFactory gMetaAnimFactory;
|
||||||
class CAnimPrimitive
|
class CAnimPrimitive
|
||||||
{
|
{
|
||||||
TResPtr<CAnimation> mpAnim;
|
TResPtr<CAnimation> mpAnim;
|
||||||
uint32 mID;
|
uint32 mID = 0;
|
||||||
TString mName;
|
TString mName;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAnimPrimitive() : mID(0) {}
|
CAnimPrimitive() = default;
|
||||||
|
|
||||||
CAnimPrimitive(const CAssetID& rkAnimAssetID, uint32 CharAnimID, const TString& rkAnimName)
|
CAnimPrimitive(const CAssetID& rkAnimAssetID, uint32 CharAnimID, const TString& rkAnimName)
|
||||||
: mID(CharAnimID), mName(rkAnimName)
|
: mID(CharAnimID), mName(rkAnimName)
|
||||||
|
@ -45,8 +45,9 @@ public:
|
||||||
mName = rInput.ReadString();
|
mName = rInput.ReadString();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const CAnimPrimitive& rkRight) const { return mID == rkRight.mID; }
|
bool operator==(const CAnimPrimitive& other) const { return mID == other.mID; }
|
||||||
inline bool operator< (const CAnimPrimitive& rkRight) const { return mID < rkRight.mID; }
|
bool operator!=(const CAnimPrimitive& other) const { return !operator==(other); }
|
||||||
|
bool operator< (const CAnimPrimitive& other) const { return mID < other.mID; }
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
CAnimation* Animation() const { return mpAnim; }
|
CAnimation* Animation() const { return mpAnim; }
|
||||||
|
@ -58,13 +59,13 @@ public:
|
||||||
class IMetaAnimation
|
class IMetaAnimation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IMetaAnimation() {}
|
IMetaAnimation() = default;
|
||||||
virtual ~IMetaAnimation() {}
|
virtual ~IMetaAnimation() = default;
|
||||||
virtual EMetaAnimType Type() const = 0;
|
virtual EMetaAnimType Type() const = 0;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
|
static std::unique_ptr<IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game);
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaAnimPlay - plays an animation
|
// CMetaAnimPlay - plays an animation
|
||||||
|
@ -78,13 +79,13 @@ protected:
|
||||||
public:
|
public:
|
||||||
CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, uint32 UnkB);
|
CMetaAnimPlay(const CAnimPrimitive& rkPrimitive, float UnkA, uint32 UnkB);
|
||||||
CMetaAnimPlay(IInputStream& rInput, EGame Game);
|
CMetaAnimPlay(IInputStream& rInput, EGame Game);
|
||||||
virtual EMetaAnimType Type() const;
|
EMetaAnimType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline CAnimPrimitive Primitive() const { return mPrimitive; }
|
CAnimPrimitive Primitive() const { return mPrimitive; }
|
||||||
inline float UnknownA() const { return mUnknownA; }
|
float UnknownA() const { return mUnknownA; }
|
||||||
inline uint32 UnknownB() const { return mUnknownB; }
|
uint32 UnknownB() const { return mUnknownB; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaAnimBlend - blend between two animations
|
// CMetaAnimBlend - blend between two animations
|
||||||
|
@ -92,28 +93,28 @@ class CMetaAnimBlend : public IMetaAnimation
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
EMetaAnimType mType;
|
EMetaAnimType mType;
|
||||||
IMetaAnimation *mpMetaAnimA;
|
std::unique_ptr<IMetaAnimation> mpMetaAnimA;
|
||||||
IMetaAnimation *mpMetaAnimB;
|
std::unique_ptr<IMetaAnimation> mpMetaAnimB;
|
||||||
float mUnknownA;
|
float mUnknownA;
|
||||||
bool mUnknownB;
|
bool mUnknownB;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame Game);
|
CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame Game);
|
||||||
~CMetaAnimBlend();
|
~CMetaAnimBlend() override;
|
||||||
virtual EMetaAnimType Type() const;
|
EMetaAnimType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA; }
|
IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA.get(); }
|
||||||
inline IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB; }
|
IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB.get(); }
|
||||||
inline float UnknownA() const { return mUnknownA; }
|
float UnknownA() const { return mUnknownA; }
|
||||||
inline bool UnknownB() const { return mUnknownB; }
|
bool UnknownB() const { return mUnknownB; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
|
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
|
||||||
struct SAnimProbabilityPair
|
struct SAnimProbabilityPair
|
||||||
{
|
{
|
||||||
IMetaAnimation *pAnim;
|
std::unique_ptr<IMetaAnimation> pAnim;
|
||||||
uint32 Probability;
|
uint32 Probability;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,22 +126,22 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetaAnimRandom(IInputStream& rInput, EGame Game);
|
CMetaAnimRandom(IInputStream& rInput, EGame Game);
|
||||||
~CMetaAnimRandom();
|
~CMetaAnimRandom() override;
|
||||||
virtual EMetaAnimType Type() const;
|
EMetaAnimType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaAnim - play a series of animations in sequence
|
// CMetaAnim - play a series of animations in sequence
|
||||||
class CMetaAnimSequence : public IMetaAnimation
|
class CMetaAnimSequence : public IMetaAnimation
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<IMetaAnimation*> mAnimations;
|
std::vector<std::unique_ptr<IMetaAnimation>> mAnimations;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetaAnimSequence(IInputStream& rInput, EGame Game);
|
CMetaAnimSequence(IInputStream& rInput, EGame Game);
|
||||||
~CMetaAnimSequence();
|
~CMetaAnimSequence() override;
|
||||||
virtual EMetaAnimType Type() const;
|
EMetaAnimType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMETAANIMATION
|
#endif // IMETAANIMATION
|
||||||
|
|
|
@ -4,41 +4,38 @@
|
||||||
// ************ CMetaTransFactory ************
|
// ************ CMetaTransFactory ************
|
||||||
CMetaTransFactory gMetaTransFactory;
|
CMetaTransFactory gMetaTransFactory;
|
||||||
|
|
||||||
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game)
|
std::unique_ptr<IMetaTransition> CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
|
||||||
{
|
{
|
||||||
EMetaTransType Type = (EMetaTransType) rInput.ReadLong();
|
const auto Type = static_cast<EMetaTransType>(rInput.ReadLong());
|
||||||
|
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
case EMetaTransType::MetaAnim:
|
case EMetaTransType::MetaAnim:
|
||||||
return new CMetaTransMetaAnim(rInput, Game);
|
return std::make_unique<CMetaTransMetaAnim>(rInput, Game);
|
||||||
|
|
||||||
case EMetaTransType::Trans:
|
case EMetaTransType::Trans:
|
||||||
case EMetaTransType::PhaseTrans:
|
case EMetaTransType::PhaseTrans:
|
||||||
return new CMetaTransTrans(Type, rInput, Game);
|
return std::make_unique<CMetaTransTrans>(Type, rInput, Game);
|
||||||
|
|
||||||
case EMetaTransType::Snap:
|
case EMetaTransType::Snap:
|
||||||
return new CMetaTransSnap(rInput, Game);
|
return std::make_unique<CMetaTransSnap>(rInput, Game);
|
||||||
|
|
||||||
case EMetaTransType::Type4:
|
case EMetaTransType::Type4:
|
||||||
return new CMetaTransType4(rInput, Game);
|
return std::make_unique<CMetaTransType4>(rInput, Game);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorf("Unrecognized meta-transition type: %d", Type);
|
errorf("Unrecognized meta-transition type: %d", static_cast<int>(Type));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CMetaTransMetaAnim ************
|
// ************ CMetaTransMetaAnim ************
|
||||||
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
|
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
|
||||||
|
: mpAnim{gMetaAnimFactory.LoadFromStream(rInput, Game)}
|
||||||
{
|
{
|
||||||
mpAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CMetaTransMetaAnim::~CMetaTransMetaAnim()
|
CMetaTransMetaAnim::~CMetaTransMetaAnim() = default;
|
||||||
{
|
|
||||||
delete mpAnim;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMetaTransType CMetaTransMetaAnim::Type() const
|
EMetaTransType CMetaTransMetaAnim::Type() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,13 @@
|
||||||
#define IMETATRANSITION_H
|
#define IMETATRANSITION_H
|
||||||
|
|
||||||
#include "IMetaAnimation.h"
|
#include "IMetaAnimation.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class IInputStream;
|
||||||
class IMetaAnimation;
|
class IMetaAnimation;
|
||||||
class IMetaTransition;
|
class IMetaTransition;
|
||||||
|
enum class EGame;
|
||||||
|
|
||||||
enum class EMetaTransType
|
enum class EMetaTransType
|
||||||
{
|
{
|
||||||
|
@ -19,7 +23,7 @@ enum class EMetaTransType
|
||||||
class CMetaTransFactory
|
class CMetaTransFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class IMetaTransition* LoadFromStream(IInputStream& rInput, EGame Game);
|
std::unique_ptr<IMetaTransition> LoadFromStream(IInputStream& rInput, EGame Game) const;
|
||||||
};
|
};
|
||||||
extern CMetaTransFactory gMetaTransFactory;
|
extern CMetaTransFactory gMetaTransFactory;
|
||||||
|
|
||||||
|
@ -27,8 +31,8 @@ extern CMetaTransFactory gMetaTransFactory;
|
||||||
class IMetaTransition
|
class IMetaTransition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IMetaTransition() {}
|
IMetaTransition() = default;
|
||||||
virtual ~IMetaTransition() {}
|
virtual ~IMetaTransition() = default;
|
||||||
virtual EMetaTransType Type() const = 0;
|
virtual EMetaTransType Type() const = 0;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
||||||
};
|
};
|
||||||
|
@ -36,29 +40,29 @@ public:
|
||||||
// CMetaTransMetaAnim
|
// CMetaTransMetaAnim
|
||||||
class CMetaTransMetaAnim : public IMetaTransition
|
class CMetaTransMetaAnim : public IMetaTransition
|
||||||
{
|
{
|
||||||
IMetaAnimation *mpAnim;
|
std::unique_ptr<IMetaAnimation> mpAnim;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
|
CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
|
||||||
~CMetaTransMetaAnim();
|
~CMetaTransMetaAnim() override;
|
||||||
virtual EMetaTransType Type() const;
|
EMetaTransType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaTransTrans
|
// CMetaTransTrans
|
||||||
class CMetaTransTrans : public IMetaTransition
|
class CMetaTransTrans : public IMetaTransition
|
||||||
{
|
{
|
||||||
EMetaTransType mType;
|
EMetaTransType mType;
|
||||||
float mUnknownA;
|
float mUnknownA = 0.0f;
|
||||||
uint32 mUnknownB;
|
uint32 mUnknownB = 0;
|
||||||
bool mUnknownC;
|
bool mUnknownC = false;
|
||||||
bool mUnknownD;
|
bool mUnknownD = false;
|
||||||
uint32 mUnknownE;
|
uint32 mUnknownE = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMetaTransTrans(EMetaTransType Type, IInputStream& rInput, EGame Game);
|
CMetaTransTrans(EMetaTransType Type, IInputStream& rInput, EGame Game);
|
||||||
virtual EMetaTransType Type() const;
|
EMetaTransType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaTransSnap
|
// CMetaTransSnap
|
||||||
|
@ -66,8 +70,8 @@ class CMetaTransSnap : public IMetaTransition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMetaTransSnap(IInputStream& rInput, EGame Game);
|
CMetaTransSnap(IInputStream& rInput, EGame Game);
|
||||||
virtual EMetaTransType Type() const;
|
EMetaTransType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// CMetaTransType4
|
// CMetaTransType4
|
||||||
|
@ -75,8 +79,8 @@ class CMetaTransType4 : public IMetaTransition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMetaTransType4(IInputStream& rInput, EGame Game);
|
CMetaTransType4(IInputStream& rInput, EGame Game);
|
||||||
virtual EMetaTransType Type() const;
|
EMetaTransType Type() const override;
|
||||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMETATRANSITION_H
|
#endif // IMETATRANSITION_H
|
||||||
|
|
|
@ -2,37 +2,26 @@
|
||||||
#include "Core/Resource/Script/CScriptLayer.h"
|
#include "Core/Resource/Script/CScriptLayer.h"
|
||||||
#include "Core/Render/CRenderer.h"
|
#include "Core/Render/CRenderer.h"
|
||||||
|
|
||||||
CGameArea::CGameArea(CResourceEntry *pEntry /*= 0*/)
|
CGameArea::CGameArea(CResourceEntry *pEntry)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mWorldIndex(-1)
|
|
||||||
, mVertexCount(0)
|
|
||||||
, mTriangleCount(0)
|
|
||||||
, mTerrainMerged(false)
|
|
||||||
, mOriginalWorldMeshCount(0)
|
|
||||||
, mUsesCompression(false)
|
|
||||||
, mpMaterialSet(nullptr)
|
|
||||||
, mpCollision(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CGameArea::~CGameArea()
|
CGameArea::~CGameArea()
|
||||||
{
|
{
|
||||||
ClearTerrain();
|
ClearTerrain();
|
||||||
|
|
||||||
for (uint32 iSCLY = 0; iSCLY < mScriptLayers.size(); iSCLY++)
|
|
||||||
delete mScriptLayers[iSCLY];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* CGameArea::BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> CGameArea::BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
// Base dependencies
|
// Base dependencies
|
||||||
CAreaDependencyTree *pTree = new CAreaDependencyTree();
|
auto pTree = std::make_unique<CAreaDependencyTree>();
|
||||||
|
|
||||||
std::set<CAssetID> MatTextures;
|
std::set<CAssetID> MatTextures;
|
||||||
mpMaterialSet->GetUsedTextureIDs(MatTextures);
|
mpMaterialSet->GetUsedTextureIDs(MatTextures);
|
||||||
|
|
||||||
for (auto Iter = MatTextures.begin(); Iter != MatTextures.end(); Iter++)
|
for (const auto& id : MatTextures)
|
||||||
pTree->AddDependency(*Iter);
|
pTree->AddDependency(id);
|
||||||
|
|
||||||
pTree->AddDependency(mPathID);
|
pTree->AddDependency(mPathID);
|
||||||
|
|
||||||
|
@ -43,8 +32,8 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra deps
|
// Extra deps
|
||||||
for (uint32 iDep = 0; iDep < mExtraAreaDeps.size(); iDep++)
|
for (const auto& dep : mExtraAreaDeps)
|
||||||
pTree->AddDependency(mExtraAreaDeps[iDep]);
|
pTree->AddDependency(dep);
|
||||||
|
|
||||||
// Layer dependencies
|
// Layer dependencies
|
||||||
std::vector<CAssetID> DummyDeps;
|
std::vector<CAssetID> DummyDeps;
|
||||||
|
@ -52,18 +41,19 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
|
||||||
for (uint32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
|
for (uint32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
|
||||||
{
|
{
|
||||||
const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps);
|
const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps);
|
||||||
pTree->AddScriptLayer(mScriptLayers[iLayer], rkExtras);
|
pTree->AddScriptLayer(mScriptLayers[iLayer].get(), rkExtras);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameArea::AddWorldModel(CModel *pModel)
|
void CGameArea::AddWorldModel(std::unique_ptr<CModel>&& pModel)
|
||||||
{
|
{
|
||||||
mWorldModels.push_back(pModel);
|
|
||||||
mVertexCount += pModel->GetVertexCount();
|
mVertexCount += pModel->GetVertexCount();
|
||||||
mTriangleCount += pModel->GetTriangleCount();
|
mTriangleCount += pModel->GetTriangleCount();
|
||||||
mAABox.ExpandBounds(pModel->AABox());
|
mAABox.ExpandBounds(pModel->AABox());
|
||||||
|
|
||||||
|
mWorldModels.push_back(std::move(pModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameArea::MergeTerrain()
|
void CGameArea::MergeTerrain()
|
||||||
|
@ -71,18 +61,17 @@ void CGameArea::MergeTerrain()
|
||||||
if (mTerrainMerged) return;
|
if (mTerrainMerged) return;
|
||||||
|
|
||||||
// Nothing really complicated here - iterate through every terrain submesh, add each to a static model
|
// Nothing really complicated here - iterate through every terrain submesh, add each to a static model
|
||||||
for (uint32 iMdl = 0; iMdl < mWorldModels.size(); iMdl++)
|
for (auto& pMdl : mWorldModels)
|
||||||
{
|
{
|
||||||
CModel *pMdl = mWorldModels[iMdl];
|
const size_t SubmeshCount = pMdl->GetSurfaceCount();
|
||||||
uint32 SubmeshCount = pMdl->GetSurfaceCount();
|
|
||||||
|
|
||||||
for (uint32 iSurf = 0; iSurf < SubmeshCount; iSurf++)
|
for (size_t iSurf = 0; iSurf < SubmeshCount; iSurf++)
|
||||||
{
|
{
|
||||||
SSurface *pSurf = pMdl->GetSurface(iSurf);
|
SSurface *pSurf = pMdl->GetSurface(iSurf);
|
||||||
CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID, false);
|
CMaterial *pMat = mpMaterialSet->MaterialByIndex(pSurf->MaterialID, false);
|
||||||
|
|
||||||
bool NewMat = true;
|
bool NewMat = true;
|
||||||
for (std::vector<CStaticModel*>::iterator it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); it++)
|
for (auto it = mStaticWorldModels.begin(); it != mStaticWorldModels.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->GetMaterial() == pMat)
|
if ((*it)->GetMaterial() == pMat)
|
||||||
{
|
{
|
||||||
|
@ -91,10 +80,10 @@ void CGameArea::MergeTerrain()
|
||||||
// (particularly with multi-layered transparent meshes)
|
// (particularly with multi-layered transparent meshes)
|
||||||
// so we need to at least try to maintain it.
|
// so we need to at least try to maintain it.
|
||||||
// This is maybe not the most efficient way to do this, but it works.
|
// This is maybe not the most efficient way to do this, but it works.
|
||||||
CStaticModel *pStatic = *it;
|
auto pStatic = std::move(*it);
|
||||||
pStatic->AddSurface(pSurf);
|
pStatic->AddSurface(pSurf);
|
||||||
mStaticWorldModels.erase(it);
|
mStaticWorldModels.erase(it);
|
||||||
mStaticWorldModels.push_back(pStatic);
|
mStaticWorldModels.push_back(std::move(pStatic));
|
||||||
NewMat = false;
|
NewMat = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -102,9 +91,9 @@ void CGameArea::MergeTerrain()
|
||||||
|
|
||||||
if (NewMat)
|
if (NewMat)
|
||||||
{
|
{
|
||||||
CStaticModel *pStatic = new CStaticModel(pMat);
|
auto pStatic = std::make_unique<CStaticModel>(pMat);
|
||||||
pStatic->AddSurface(pSurf);
|
pStatic->AddSurface(pSurf);
|
||||||
mStaticWorldModels.push_back(pStatic);
|
mStaticWorldModels.push_back(std::move(pStatic));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,44 +101,41 @@ void CGameArea::MergeTerrain()
|
||||||
|
|
||||||
void CGameArea::ClearTerrain()
|
void CGameArea::ClearTerrain()
|
||||||
{
|
{
|
||||||
for (uint32 iModel = 0; iModel < mWorldModels.size(); iModel++)
|
|
||||||
delete mWorldModels[iModel];
|
|
||||||
mWorldModels.clear();
|
mWorldModels.clear();
|
||||||
|
|
||||||
for (uint32 iStatic = 0; iStatic < mStaticWorldModels.size(); iStatic++)
|
|
||||||
delete mStaticWorldModels[iStatic];
|
|
||||||
mStaticWorldModels.clear();
|
mStaticWorldModels.clear();
|
||||||
|
|
||||||
if (mpMaterialSet) delete mpMaterialSet;
|
if (mpMaterialSet)
|
||||||
|
delete mpMaterialSet;
|
||||||
|
|
||||||
mVertexCount = 0;
|
mVertexCount = 0;
|
||||||
mTriangleCount = 0;
|
mTriangleCount = 0;
|
||||||
mTerrainMerged = false;
|
mTerrainMerged = false;
|
||||||
mAABox = CAABox::skInfinite;
|
mAABox = CAABox::Infinite();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameArea::ClearScriptLayers()
|
void CGameArea::ClearScriptLayers()
|
||||||
{
|
{
|
||||||
for (auto it = mScriptLayers.begin(); it != mScriptLayers.end(); it++)
|
|
||||||
delete *it;
|
|
||||||
mScriptLayers.clear();
|
mScriptLayers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 CGameArea::TotalInstanceCount() const
|
size_t CGameArea::TotalInstanceCount() const
|
||||||
{
|
{
|
||||||
uint32 Num = 0;
|
size_t Num = 0;
|
||||||
|
|
||||||
for (uint32 iLyr = 0; iLyr < mScriptLayers.size(); iLyr++)
|
for (const auto& layer : mScriptLayers)
|
||||||
Num += mScriptLayers[iLyr]->NumInstances();
|
Num += layer->NumInstances();
|
||||||
|
|
||||||
return Num;
|
return Num;
|
||||||
}
|
}
|
||||||
|
|
||||||
CScriptObject* CGameArea::InstanceByID(uint32 InstanceID)
|
CScriptObject* CGameArea::InstanceByID(uint32 InstanceID)
|
||||||
{
|
{
|
||||||
auto it = mObjectMap.find(InstanceID);
|
const auto it = mObjectMap.find(InstanceID);
|
||||||
if (it != mObjectMap.end()) return it->second;
|
|
||||||
else return nullptr;
|
if (it != mObjectMap.cend())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 CGameArea::FindUnusedInstanceID() const
|
uint32 CGameArea::FindUnusedInstanceID() const
|
||||||
|
@ -178,30 +164,30 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
|
||||||
uint32 SuggestedLayerIndex /*= -1*/ )
|
uint32 SuggestedLayerIndex /*= -1*/ )
|
||||||
{
|
{
|
||||||
// Verify we can fit another instance in this area.
|
// Verify we can fit another instance in this area.
|
||||||
uint32 NumInstances = TotalInstanceCount();
|
const size_t NumInstances = TotalInstanceCount();
|
||||||
|
|
||||||
if (NumInstances >= 0xFFFF)
|
if (NumInstances >= 0xFFFF)
|
||||||
{
|
{
|
||||||
errorf("Unable to spawn a new script instance; too many instances in area (%d)", NumInstances);
|
errorf("Unable to spawn a new script instance; too many instances in area (%zu)", NumInstances);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the suggested instance ID is valid
|
// Check whether the suggested instance ID is valid
|
||||||
uint32 InstanceID = SuggestedID;
|
uint32 InstanceID = SuggestedID;
|
||||||
|
|
||||||
if (InstanceID != -1)
|
if (InstanceID != UINT32_MAX)
|
||||||
{
|
{
|
||||||
if (mObjectMap.find(InstanceID) == mObjectMap.end())
|
if (mObjectMap.find(InstanceID) == mObjectMap.cend())
|
||||||
InstanceID = -1;
|
InstanceID = UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not valid (or if there's no suggested ID) then determine a new instance ID
|
// If not valid (or if there's no suggested ID) then determine a new instance ID
|
||||||
if (InstanceID == -1)
|
if (InstanceID == UINT32_MAX)
|
||||||
{
|
{
|
||||||
// Determine layer index
|
// Determine layer index
|
||||||
uint32 LayerIndex = pLayer->AreaIndex();
|
const uint32 LayerIndex = pLayer->AreaIndex();
|
||||||
|
|
||||||
if (LayerIndex == -1)
|
if (LayerIndex == UINT32_MAX)
|
||||||
{
|
{
|
||||||
errorf("Unable to spawn a new script instance; invalid script layer passed in");
|
errorf("Unable to spawn a new script instance; invalid script layer passed in");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -212,13 +198,14 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn instance
|
// Spawn instance
|
||||||
CScriptObject *pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate);
|
auto* pInstance = new CScriptObject(InstanceID, this, pLayer, pTemplate);
|
||||||
pInstance->EvaluateProperties();
|
pInstance->EvaluateProperties();
|
||||||
pInstance->SetPosition(rkPosition);
|
pInstance->SetPosition(rkPosition);
|
||||||
pInstance->SetRotation(rkRotation.ToEuler());
|
pInstance->SetRotation(rkRotation.ToEuler());
|
||||||
pInstance->SetScale(rkScale);
|
pInstance->SetScale(rkScale);
|
||||||
pInstance->SetName(pTemplate->Name());
|
pInstance->SetName(pTemplate->Name());
|
||||||
if (pTemplate->Game() < EGame::EchoesDemo) pInstance->SetActive(true);
|
if (pTemplate->Game() < EGame::EchoesDemo)
|
||||||
|
pInstance->SetActive(true);
|
||||||
pLayer->AddInstance(pInstance, SuggestedLayerIndex);
|
pLayer->AddInstance(pInstance, SuggestedLayerIndex);
|
||||||
mObjectMap[InstanceID] = pInstance;
|
mObjectMap[InstanceID] = pInstance;
|
||||||
return pInstance;
|
return pInstance;
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
#include <Common/Math/CQuaternion.h>
|
#include <Common/Math/CQuaternion.h>
|
||||||
#include <Common/Math/CTransform4f.h>
|
#include <Common/Math/CTransform4f.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CScriptLayer;
|
class CScriptLayer;
|
||||||
class CScriptObject;
|
class CScriptObject;
|
||||||
|
@ -24,17 +26,17 @@ class CGameArea : public CResource
|
||||||
friend class CAreaLoader;
|
friend class CAreaLoader;
|
||||||
friend class CAreaCooker;
|
friend class CAreaCooker;
|
||||||
|
|
||||||
uint32 mWorldIndex;
|
uint32 mWorldIndex = UINT32_MAX;
|
||||||
uint32 mVertexCount;
|
uint32 mVertexCount = 0;
|
||||||
uint32 mTriangleCount;
|
uint32 mTriangleCount = 0;
|
||||||
bool mTerrainMerged;
|
bool mTerrainMerged = false;
|
||||||
CTransform4f mTransform;
|
CTransform4f mTransform;
|
||||||
CAABox mAABox;
|
CAABox mAABox;
|
||||||
|
|
||||||
// Data saved from the original file to help on recook
|
// Data saved from the original file to help on recook
|
||||||
std::vector<std::vector<uint8>> mSectionDataBuffers;
|
std::vector<std::vector<uint8>> mSectionDataBuffers;
|
||||||
uint32 mOriginalWorldMeshCount;
|
uint32 mOriginalWorldMeshCount = 0;
|
||||||
bool mUsesCompression;
|
bool mUsesCompression = false;
|
||||||
|
|
||||||
struct SSectionNumber
|
struct SSectionNumber
|
||||||
{
|
{
|
||||||
|
@ -44,11 +46,11 @@ class CGameArea : public CResource
|
||||||
std::vector<SSectionNumber> mSectionNumbers;
|
std::vector<SSectionNumber> mSectionNumbers;
|
||||||
|
|
||||||
// Geometry
|
// Geometry
|
||||||
CMaterialSet *mpMaterialSet;
|
CMaterialSet *mpMaterialSet = nullptr;
|
||||||
std::vector<CModel*> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
|
std::vector<std::unique_ptr<CModel>> mWorldModels; // TerrainModels is the original version of each model; this is currently mainly used in the POI map editor
|
||||||
std::vector<CStaticModel*> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor
|
std::vector<std::unique_ptr<CStaticModel>> mStaticWorldModels; // StaticTerrainModels is the merged terrain for faster rendering in the world editor
|
||||||
// Script
|
// Script
|
||||||
std::vector<CScriptLayer*> mScriptLayers;
|
std::vector<std::unique_ptr<CScriptLayer>> mScriptLayers;
|
||||||
std::unordered_map<uint32, CScriptObject*> mObjectMap;
|
std::unordered_map<uint32, CScriptObject*> mObjectMap;
|
||||||
// Collision
|
// Collision
|
||||||
std::unique_ptr<CCollisionMeshGroup> mpCollision;
|
std::unique_ptr<CCollisionMeshGroup> mpCollision;
|
||||||
|
@ -65,46 +67,47 @@ class CGameArea : public CResource
|
||||||
std::vector< std::vector<CAssetID> > mExtraLayerDeps;
|
std::vector< std::vector<CAssetID> > mExtraLayerDeps;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CGameArea(CResourceEntry *pEntry = 0);
|
explicit CGameArea(CResourceEntry *pEntry = nullptr);
|
||||||
~CGameArea();
|
~CGameArea() override;
|
||||||
CDependencyTree* BuildDependencyTree() const;
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
|
||||||
|
|
||||||
void AddWorldModel(CModel *pModel);
|
void AddWorldModel(std::unique_ptr<CModel>&& pModel);
|
||||||
void MergeTerrain();
|
void MergeTerrain();
|
||||||
void ClearTerrain();
|
void ClearTerrain();
|
||||||
void ClearScriptLayers();
|
void ClearScriptLayers();
|
||||||
uint32 TotalInstanceCount() const;
|
size_t TotalInstanceCount() const;
|
||||||
CScriptObject* InstanceByID(uint32 InstanceID);
|
CScriptObject* InstanceByID(uint32 InstanceID);
|
||||||
uint32 FindUnusedInstanceID() const;
|
uint32 FindUnusedInstanceID() const;
|
||||||
CScriptObject* SpawnInstance(CScriptTemplate *pTemplate, CScriptLayer *pLayer,
|
CScriptObject* SpawnInstance(CScriptTemplate* pTemplate, CScriptLayer* pLayer,
|
||||||
const CVector3f& rkPosition = CVector3f::skZero,
|
const CVector3f& rkPosition = CVector3f::Zero(),
|
||||||
const CQuaternion& rkRotation = CQuaternion::skIdentity,
|
const CQuaternion& rkRotation = CQuaternion::Identity(),
|
||||||
const CVector3f& rkScale = CVector3f::skOne,
|
const CVector3f& rkScale = CVector3f::One(),
|
||||||
uint32 SuggestedID = -1, uint32 SuggestedLayerIndex = -1);
|
uint32 SuggestedID = UINT32_MAX,
|
||||||
|
uint32 SuggestedLayerIndex = UINT32_MAX);
|
||||||
void AddInstanceToArea(CScriptObject *pInstance);
|
void AddInstanceToArea(CScriptObject *pInstance);
|
||||||
void DeleteInstance(CScriptObject *pInstance);
|
void DeleteInstance(CScriptObject *pInstance);
|
||||||
void ClearExtraDependencies();
|
void ClearExtraDependencies();
|
||||||
|
|
||||||
// Inline Accessors
|
// Accessors
|
||||||
inline uint32 WorldIndex() const { return mWorldIndex; }
|
uint32 WorldIndex() const { return mWorldIndex; }
|
||||||
inline CTransform4f Transform() const { return mTransform; }
|
CTransform4f Transform() const { return mTransform; }
|
||||||
inline CMaterialSet* Materials() const { return mpMaterialSet; }
|
CMaterialSet* Materials() const { return mpMaterialSet; }
|
||||||
inline uint32 NumWorldModels() const { return mWorldModels.size(); }
|
size_t NumWorldModels() const { return mWorldModels.size(); }
|
||||||
inline uint32 NumStaticModels() const { return mStaticWorldModels.size(); }
|
size_t NumStaticModels() const { return mStaticWorldModels.size(); }
|
||||||
inline CModel* TerrainModel(uint32 iMdl) const { return mWorldModels[iMdl]; }
|
CModel* TerrainModel(size_t iMdl) const { return mWorldModels[iMdl].get(); }
|
||||||
inline CStaticModel* StaticModel(uint32 iMdl) const { return mStaticWorldModels[iMdl]; }
|
CStaticModel* StaticModel(size_t iMdl) const { return mStaticWorldModels[iMdl].get(); }
|
||||||
inline CCollisionMeshGroup* Collision() const { return mpCollision.get(); }
|
CCollisionMeshGroup* Collision() const { return mpCollision.get(); }
|
||||||
inline uint32 NumScriptLayers() const { return mScriptLayers.size(); }
|
size_t NumScriptLayers() const { return mScriptLayers.size(); }
|
||||||
inline CScriptLayer* ScriptLayer(uint32 Index) const { return mScriptLayers[Index]; }
|
CScriptLayer* ScriptLayer(size_t Index) const { return mScriptLayers[Index].get(); }
|
||||||
inline uint32 NumLightLayers() const { return mLightLayers.size(); }
|
size_t NumLightLayers() const { return mLightLayers.size(); }
|
||||||
inline uint32 NumLights(uint32 LayerIndex) const { return (LayerIndex < mLightLayers.size() ? mLightLayers[LayerIndex].size() : 0); }
|
size_t NumLights(size_t LayerIndex) const { return (LayerIndex < mLightLayers.size() ? mLightLayers[LayerIndex].size() : 0); }
|
||||||
inline CLight* Light(uint32 LayerIndex, uint32 LightIndex) { return &mLightLayers[LayerIndex][LightIndex]; }
|
CLight* Light(size_t LayerIndex, size_t LightIndex) { return &mLightLayers[LayerIndex][LightIndex]; }
|
||||||
inline CAssetID PathID() const { return mPathID; }
|
CAssetID PathID() const { return mPathID; }
|
||||||
inline CPoiToWorld* PoiToWorldMap() const { return mpPoiToWorldMap; }
|
CPoiToWorld* PoiToWorldMap() const { return mpPoiToWorldMap; }
|
||||||
inline CAssetID PortalAreaID() const { return mPortalAreaID; }
|
CAssetID PortalAreaID() const { return mPortalAreaID; }
|
||||||
inline CAABox AABox() const { return mAABox; }
|
CAABox AABox() const { return mAABox; }
|
||||||
|
|
||||||
inline void SetWorldIndex(uint32 NewWorldIndex) { mWorldIndex = NewWorldIndex; }
|
void SetWorldIndex(uint32 NewWorldIndex) { mWorldIndex = NewWorldIndex; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CGAMEAREA_H
|
#endif // CGAMEAREA_H
|
||||||
|
|
|
@ -10,20 +10,19 @@ class CAudioGroup : public CResource
|
||||||
friend class CAudioGroupLoader;
|
friend class CAudioGroupLoader;
|
||||||
|
|
||||||
TString mGroupName;
|
TString mGroupName;
|
||||||
uint32 mGroupID;
|
uint32 mGroupID = UINT32_MAX;
|
||||||
std::vector<uint16> mDefineIDs;
|
std::vector<uint16> mDefineIDs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAudioGroup(CResourceEntry *pEntry = 0)
|
explicit CAudioGroup(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
, mGroupID(-1)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString GroupName() const { return mGroupName; }
|
TString GroupName() const { return mGroupName; }
|
||||||
inline uint32 GroupID() const { return mGroupID; }
|
uint32 GroupID() const { return mGroupID; }
|
||||||
inline uint32 NumSoundDefineIDs() const { return mDefineIDs.size(); }
|
size_t NumSoundDefineIDs() const { return mDefineIDs.size(); }
|
||||||
inline uint16 SoundDefineIDByIndex(uint32 Index) const { return mDefineIDs[Index]; }
|
uint16 SoundDefineIDByIndex(size_t Index) const { return mDefineIDs[Index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CAUDIOGROUP
|
#endif // CAUDIOGROUP
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CAUDIOLOOKUPTABLE
|
#define CAUDIOLOOKUPTABLE
|
||||||
|
|
||||||
#include "CResource.h"
|
#include "CResource.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CAudioLookupTable : public CResource
|
class CAudioLookupTable : public CResource
|
||||||
{
|
{
|
||||||
|
@ -10,13 +11,15 @@ class CAudioLookupTable : public CResource
|
||||||
std::vector<uint16> mDefineIDs;
|
std::vector<uint16> mDefineIDs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAudioLookupTable(CResourceEntry *pEntry = 0)
|
explicit CAudioLookupTable(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline uint16 FindSoundDefineID(uint32 SoundID)
|
uint16 FindSoundDefineID(size_t SoundID) const
|
||||||
{
|
{
|
||||||
if (SoundID >= mDefineIDs.size()) return -1;
|
if (SoundID >= mDefineIDs.size())
|
||||||
|
return UINT16_MAX;
|
||||||
|
|
||||||
return mDefineIDs[SoundID];
|
return mDefineIDs[SoundID];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,24 +12,24 @@ class CAudioMacro : public CResource
|
||||||
std::vector<CAssetID> mSamples;
|
std::vector<CAssetID> mSamples;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CAudioMacro(CResourceEntry *pEntry = 0)
|
explicit CAudioMacro(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual CDependencyTree* BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
|
|
||||||
for (uint32 iSamp = 0; iSamp < mSamples.size(); iSamp++)
|
for (const auto& sample : mSamples)
|
||||||
pTree->AddDependency(mSamples[iSamp]);
|
pTree->AddDependency(sample);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString MacroName() const { return mMacroName; }
|
TString MacroName() const { return mMacroName; }
|
||||||
inline uint32 NumSamples() const { return mSamples.size(); }
|
size_t NumSamples() const { return mSamples.size(); }
|
||||||
inline CAssetID SampleByIndex(uint32 Index) const { return mSamples[Index]; }
|
CAssetID SampleByIndex(size_t Index) const { return mSamples[Index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CAUDIOMACRO_H
|
#endif // CAUDIOMACRO_H
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CDEPENDENCYGROUP
|
#define CDEPENDENCYGROUP
|
||||||
|
|
||||||
#include "CResource.h"
|
#include "CResource.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
class CDependencyGroup : public CResource
|
class CDependencyGroup : public CResource
|
||||||
{
|
{
|
||||||
|
@ -9,53 +10,47 @@ class CDependencyGroup : public CResource
|
||||||
std::vector<CAssetID> mDependencies;
|
std::vector<CAssetID> mDependencies;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDependencyGroup(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
explicit CDependencyGroup(CResourceEntry *pEntry = nullptr) : CResource(pEntry) {}
|
||||||
|
|
||||||
inline void Clear() { mDependencies.clear(); }
|
void Clear() { mDependencies.clear(); }
|
||||||
inline uint32 NumDependencies() const { return mDependencies.size(); }
|
uint32 NumDependencies() const { return mDependencies.size(); }
|
||||||
inline CAssetID DependencyByIndex(uint32 Index) const { return mDependencies[Index]; }
|
CAssetID DependencyByIndex(size_t Index) const { return mDependencies[Index]; }
|
||||||
|
|
||||||
inline void AddDependency(const CAssetID& rkID)
|
void AddDependency(const CAssetID& rkID)
|
||||||
{
|
{
|
||||||
if (!HasDependency(rkID))
|
if (!HasDependency(rkID))
|
||||||
mDependencies.push_back(rkID);
|
mDependencies.push_back(rkID);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AddDependency(CResource *pRes)
|
void AddDependency(const CResource* pRes)
|
||||||
{
|
{
|
||||||
if ( pRes && !HasDependency(pRes->ID()) )
|
if (pRes != nullptr && !HasDependency(pRes->ID()))
|
||||||
mDependencies.push_back(pRes->ID());
|
mDependencies.push_back(pRes->ID());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveDependency(const CAssetID& rkID)
|
void RemoveDependency(const CAssetID& rkID)
|
||||||
{
|
{
|
||||||
for (auto Iter = mDependencies.begin(); Iter != mDependencies.end(); Iter++)
|
const auto it = std::find_if(mDependencies.cbegin(), mDependencies.cend(),
|
||||||
{
|
[&rkID](const auto& entry) { return entry == rkID; });
|
||||||
if (*Iter == rkID)
|
|
||||||
{
|
if (it == mDependencies.cend())
|
||||||
mDependencies.erase(Iter);
|
return;
|
||||||
return;
|
|
||||||
}
|
mDependencies.erase(it);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasDependency(const CAssetID &rkID) const
|
bool HasDependency(const CAssetID& rkID) const
|
||||||
{
|
{
|
||||||
for (uint32 iDep = 0; iDep < mDependencies.size(); iDep++)
|
return std::any_of(mDependencies.cbegin(), mDependencies.cend(),
|
||||||
{
|
[&rkID](const auto& entry) { return entry == rkID; });
|
||||||
if (mDependencies[iDep] == rkID)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
|
|
||||||
for (auto DepIt = mDependencies.begin(); DepIt != mDependencies.end(); DepIt++)
|
for (const auto& dep : mDependencies)
|
||||||
pTree->AddDependency(*DepIt);
|
pTree->AddDependency(dep);
|
||||||
|
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,25 @@
|
||||||
#include "Core/Render/CRenderer.h"
|
#include "Core/Render/CRenderer.h"
|
||||||
|
|
||||||
std::optional<CDynamicVertexBuffer> CFont::smGlyphVertices;
|
std::optional<CDynamicVertexBuffer> CFont::smGlyphVertices;
|
||||||
CIndexBuffer CFont::smGlyphIndices;
|
CIndexBuffer CFont::smGlyphIndices;
|
||||||
bool CFont::smBuffersInitialized = false;
|
bool CFont::smBuffersInitialized = false;
|
||||||
|
|
||||||
CFont::CFont(CResourceEntry *pEntry /*= 0*/) : CResource(pEntry)
|
CFont::CFont(CResourceEntry *pEntry) : CResource(pEntry)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CFont::~CFont()
|
CFont::~CFont() = default;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float PtsToFloat(int32 Pt)
|
static constexpr float PtsToFloat(int32 Pt)
|
||||||
{
|
{
|
||||||
// This is a bit of an arbitrary number but it works
|
// This is a bit of an arbitrary number but it works
|
||||||
// 1 / (1280 / 1.333333f / 2)
|
// 1 / (1280 / 1.333333f / 2)
|
||||||
return 0.00208333f * Pt;
|
return 0.00208333f * Pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDependencyTree* CFont::BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> CFont::BuildDependencyTree() const
|
||||||
{
|
{
|
||||||
CDependencyTree *pOut = new CDependencyTree();
|
auto pOut = std::make_unique<CDependencyTree>();
|
||||||
pOut->AddDependency(mpFontTexture);
|
pOut->AddDependency(mpFontTexture);
|
||||||
return pOut;
|
return pOut;
|
||||||
}
|
}
|
||||||
|
@ -33,32 +31,35 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
|
||||||
CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, uint32 FontSize)
|
CVector2f /*Position*/, CColor FillColor, CColor StrokeColor, uint32 FontSize)
|
||||||
{
|
{
|
||||||
// WIP
|
// WIP
|
||||||
if (!smBuffersInitialized) InitBuffers();
|
if (!smBuffersInitialized)
|
||||||
|
InitBuffers();
|
||||||
|
|
||||||
// Shader setup
|
// Shader setup
|
||||||
CShader *pTextShader = CDrawUtil::GetTextShader();
|
CShader *pTextShader = CDrawUtil::GetTextShader();
|
||||||
pTextShader->SetCurrent();
|
pTextShader->SetCurrent();
|
||||||
|
|
||||||
GLuint ModelMtxLoc = pTextShader->GetUniformLocation("ModelMtx");
|
const GLuint ModelMtxLoc = pTextShader->GetUniformLocation("ModelMtx");
|
||||||
GLuint ColorLoc = pTextShader->GetUniformLocation("FontColor");
|
const GLuint ColorLoc = pTextShader->GetUniformLocation("FontColor");
|
||||||
GLuint LayerLoc = pTextShader->GetUniformLocation("RGBALayer");
|
const GLuint LayerLoc = pTextShader->GetUniformLocation("RGBALayer");
|
||||||
mpFontTexture->Bind(0);
|
mpFontTexture->Bind(0);
|
||||||
smGlyphVertices->Bind();
|
smGlyphVertices->Bind();
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
// Initialize some more stuff before we start the character loop
|
// Initialize some more stuff before we start the character loop
|
||||||
CVector2f PrintHead(-1.f, 1.f);
|
CVector2f PrintHead(-1.f, 1.f);
|
||||||
CTransform4f PtScale = CTransform4f::ScaleMatrix(PtsToFloat(1));
|
const CTransform4f PtScale = CTransform4f::ScaleMatrix(PtsToFloat(1));
|
||||||
SGlyph *pPrevGlyph = nullptr;
|
SGlyph *pPrevGlyph = nullptr;
|
||||||
|
|
||||||
float Scale;
|
float Scale;
|
||||||
if (FontSize == CFONT_DEFAULT_SIZE) Scale = 1.f;
|
if (FontSize == CFONT_DEFAULT_SIZE)
|
||||||
else Scale = (float) FontSize / (mDefaultSize != 0 ? mDefaultSize : 18);
|
Scale = 1.f;
|
||||||
|
else
|
||||||
|
Scale = static_cast<float>(FontSize) / (mDefaultSize != 0 ? mDefaultSize : 18);
|
||||||
|
|
||||||
for (uint32 iChar = 0; iChar < rkString.Length(); iChar++)
|
for (uint32 iChar = 0; iChar < rkString.Length(); iChar++)
|
||||||
{
|
{
|
||||||
// Get character, check for newline
|
// Get character, check for newline
|
||||||
char Char = rkString[iChar];
|
const char Char = rkString[iChar];
|
||||||
|
|
||||||
if (Char == '\n')
|
if (Char == '\n')
|
||||||
{
|
{
|
||||||
|
@ -70,7 +71,8 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
|
||||||
|
|
||||||
// Get glyph
|
// Get glyph
|
||||||
auto iGlyph = mGlyphs.find(Char);
|
auto iGlyph = mGlyphs.find(Char);
|
||||||
if (iGlyph == mGlyphs.end()) continue;
|
if (iGlyph == mGlyphs.end())
|
||||||
|
continue;
|
||||||
SGlyph *pGlyph = &iGlyph->second;
|
SGlyph *pGlyph = &iGlyph->second;
|
||||||
|
|
||||||
// Apply left padding and kerning
|
// Apply left padding and kerning
|
||||||
|
@ -78,7 +80,7 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
|
||||||
|
|
||||||
if (pPrevGlyph)
|
if (pPrevGlyph)
|
||||||
{
|
{
|
||||||
if (pPrevGlyph->KerningIndex != -1)
|
if (pPrevGlyph->KerningIndex != UINT32_MAX)
|
||||||
{
|
{
|
||||||
for (uint32 iKern = pPrevGlyph->KerningIndex; iKern < mKerningTable.size(); iKern++)
|
for (uint32 iKern = pPrevGlyph->KerningIndex; iKern < mKerningTable.size(); iKern++)
|
||||||
{
|
{
|
||||||
|
@ -101,22 +103,24 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
|
||||||
if (Char == ' ') continue;
|
if (Char == ' ') continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float XTrans = PrintHead.X;
|
const float XTrans = PrintHead.X;
|
||||||
float YTrans = PrintHead.Y + ((PtsToFloat(pGlyph->BaseOffset * 2) - PtsToFloat(mVerticalOffset * 2)) * Scale);
|
const float YTrans = PrintHead.Y + ((PtsToFloat(pGlyph->BaseOffset * 2) - PtsToFloat(mVerticalOffset * 2)) * Scale);
|
||||||
|
|
||||||
CTransform4f GlyphTransform = PtScale;
|
CTransform4f GlyphTransform = PtScale;
|
||||||
GlyphTransform.Scale(CVector3f((float) pGlyph->Width / 2, (float) pGlyph->Height, 1.f));
|
GlyphTransform.Scale(CVector3f(static_cast<float>(pGlyph->Width) / 2, static_cast<float>(pGlyph->Height), 1.f));
|
||||||
GlyphTransform.Scale(Scale);
|
GlyphTransform.Scale(Scale);
|
||||||
GlyphTransform.Translate(CVector3f(XTrans, YTrans, 0.f));
|
GlyphTransform.Translate(CVector3f(XTrans, YTrans, 0.f));
|
||||||
|
|
||||||
// Get glyph layer
|
// Get glyph layer
|
||||||
uint8 GlyphLayer = pGlyph->RGBAChannel;
|
uint8 GlyphLayer = pGlyph->RGBAChannel;
|
||||||
if (mTextureFormat == 3) GlyphLayer *= 2;
|
if (mTextureFormat == 3)
|
||||||
else if (mTextureFormat == 8) GlyphLayer = 3;
|
GlyphLayer *= 2;
|
||||||
|
else if (mTextureFormat == 8)
|
||||||
|
GlyphLayer = 3;
|
||||||
|
|
||||||
// Load shader uniforms, buffer texture
|
// Load shader uniforms, buffer texture
|
||||||
glUniformMatrix4fv(ModelMtxLoc, 1, GL_FALSE, (GLfloat*) &GlyphTransform);
|
glUniformMatrix4fv(ModelMtxLoc, 1, GL_FALSE, (GLfloat*) &GlyphTransform);
|
||||||
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, &pGlyph->TexCoords);
|
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, pGlyph->TexCoords.data());
|
||||||
|
|
||||||
// Draw fill
|
// Draw fill
|
||||||
glUniform1i(LayerLoc, GlyphLayer);
|
glUniform1i(LayerLoc, GlyphLayer);
|
||||||
|
@ -124,12 +128,15 @@ CVector2f CFont::RenderString(const TString& rkString, CRenderer* /*pRenderer*/,
|
||||||
smGlyphIndices.DrawElements();
|
smGlyphIndices.DrawElements();
|
||||||
|
|
||||||
// Draw stroke
|
// Draw stroke
|
||||||
if ((mTextureFormat == 1) || (mTextureFormat == 3) || (mTextureFormat == 8))
|
if (mTextureFormat == 1 || mTextureFormat == 3 || mTextureFormat == 8)
|
||||||
{
|
{
|
||||||
uint8 StrokeLayer;
|
uint8 StrokeLayer = 0;
|
||||||
if (mTextureFormat == 1) StrokeLayer = 1;
|
if (mTextureFormat == 1)
|
||||||
else if (mTextureFormat == 3) StrokeLayer = GlyphLayer + 1;
|
StrokeLayer = 1;
|
||||||
else if (mTextureFormat == 8) StrokeLayer = GlyphLayer - 2;
|
else if (mTextureFormat == 3)
|
||||||
|
StrokeLayer = GlyphLayer + 1;
|
||||||
|
else if (mTextureFormat == 8)
|
||||||
|
StrokeLayer = GlyphLayer - 2;
|
||||||
|
|
||||||
glUniform1i(LayerLoc, StrokeLayer);
|
glUniform1i(LayerLoc, StrokeLayer);
|
||||||
glUniform4fv(ColorLoc, 1, &StrokeColor.R);
|
glUniform4fv(ColorLoc, 1, &StrokeColor.R);
|
||||||
|
@ -152,21 +159,21 @@ void CFont::InitBuffers()
|
||||||
smGlyphVertices->SetActiveAttribs(EVertexAttribute::Position | EVertexAttribute::Tex0);
|
smGlyphVertices->SetActiveAttribs(EVertexAttribute::Position | EVertexAttribute::Tex0);
|
||||||
smGlyphVertices->SetVertexCount(4);
|
smGlyphVertices->SetVertexCount(4);
|
||||||
|
|
||||||
CVector3f Vertices[4] = {
|
static constexpr std::array Vertices{
|
||||||
CVector3f( 0.f, 0.f, 0.f),
|
CVector3f( 0.f, 0.f, 0.f),
|
||||||
CVector3f( 2.f, 0.f, 0.f),
|
CVector3f( 2.f, 0.f, 0.f),
|
||||||
CVector3f( 0.f, -2.f, 0.f),
|
CVector3f( 0.f, -2.f, 0.f),
|
||||||
CVector3f( 2.f, -2.f, 0.f)
|
CVector3f( 2.f, -2.f, 0.f)
|
||||||
};
|
};
|
||||||
smGlyphVertices->BufferAttrib(EVertexAttribute::Position, Vertices);
|
smGlyphVertices->BufferAttrib(EVertexAttribute::Position, Vertices.data());
|
||||||
|
|
||||||
CVector2f TexCoords[4] = {
|
static constexpr std::array TexCoords{
|
||||||
CVector2f(0.f, 0.f),
|
CVector2f(0.f, 0.f),
|
||||||
CVector2f(1.f, 0.f),
|
CVector2f(1.f, 0.f),
|
||||||
CVector2f(0.f, 1.f),
|
CVector2f(0.f, 1.f),
|
||||||
CVector2f(1.f, 1.f)
|
CVector2f(1.f, 1.f)
|
||||||
};
|
};
|
||||||
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, TexCoords);
|
smGlyphVertices->BufferAttrib(EVertexAttribute::Tex0, TexCoords.data());
|
||||||
|
|
||||||
smGlyphIndices.Reserve(4);
|
smGlyphIndices.Reserve(4);
|
||||||
smGlyphIndices.AddIndex(0);
|
smGlyphIndices.AddIndex(0);
|
||||||
|
|
|
@ -9,11 +9,13 @@
|
||||||
#include "Core/OpenGL/CIndexBuffer.h"
|
#include "Core/OpenGL/CIndexBuffer.h"
|
||||||
#include <Common/BasicTypes.h>
|
#include <Common/BasicTypes.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define CFONT_DEFAULT_SIZE -1
|
#define CFONT_DEFAULT_SIZE UINT32_MAX
|
||||||
|
|
||||||
class CRenderer;
|
class CRenderer;
|
||||||
|
|
||||||
|
@ -25,27 +27,27 @@ class CFont : public CResource
|
||||||
static CIndexBuffer smGlyphIndices; // This is the index buffer used to draw glyphs. It uses a triangle strip.
|
static CIndexBuffer smGlyphIndices; // This is the index buffer used to draw glyphs. It uses a triangle strip.
|
||||||
static bool smBuffersInitialized; // This bool indicates whether the vertex/index buffer have been initialized. Checked at the start of RenderString().
|
static bool smBuffersInitialized; // This bool indicates whether the vertex/index buffer have been initialized. Checked at the start of RenderString().
|
||||||
|
|
||||||
uint32 mUnknown; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes.
|
uint32 mUnknown = 0; // Value at offset 0x8. Not sure what this is. Including for experimentation purposes.
|
||||||
uint32 mLineHeight; // Height of each line, in points
|
uint32 mLineHeight = 0; // Height of each line, in points
|
||||||
uint32 mLineMargin; // Gap between lines, in points - this is added to the line height
|
uint32 mLineMargin = 0; // Gap between lines, in points - this is added to the line height
|
||||||
uint32 mVerticalOffset; // In points. This is used to reposition glyphs after the per-glyph vertical offset is applied
|
uint32 mVerticalOffset = 0; // In points. This is used to reposition glyphs after the per-glyph vertical offset is applied
|
||||||
uint32 mDefaultSize; // In points.
|
uint32 mDefaultSize = 0; // In points.
|
||||||
TString mFontName; // Self-explanatory
|
TString mFontName; // Self-explanatory
|
||||||
TResPtr<CTexture> mpFontTexture; // The texture used by this font
|
TResPtr<CTexture> mpFontTexture; // The texture used by this font
|
||||||
uint32 mTextureFormat; // Indicates which layers on the texture are for what - multiple glyph layers or fill/stroke
|
uint32 mTextureFormat = 0; // Indicates which layers on the texture are for what - multiple glyph layers or fill/stroke
|
||||||
|
|
||||||
struct SGlyph
|
struct SGlyph
|
||||||
{
|
{
|
||||||
uint16 Character; // The UTF-16 character that this glyph corresponds to
|
uint16 Character; // The UTF-16 character that this glyph corresponds to
|
||||||
CVector2f TexCoords[4]; // The format only lists the min/max X/Y values; tracking absolute coordinates in memory is faster
|
std::array<CVector2f, 4> TexCoords; // The format only lists the min/max X/Y values; tracking absolute coordinates in memory is faster
|
||||||
int32 LeftPadding; // The amount of padding applied left of this glyph, in points
|
int32 LeftPadding; // The amount of padding applied left of this glyph, in points
|
||||||
int32 RightPadding; // The amount of padding applied right of this glyph, in points
|
int32 RightPadding; // The amount of padding applied right of this glyph, in points
|
||||||
uint32 Width; // The width of the glyph, in points
|
uint32 Width; // The width of the glyph, in points
|
||||||
uint32 Height; // The height of the glyph, in points
|
uint32 Height; // The height of the glyph, in points
|
||||||
uint32 PrintAdvance; // How far the print head advances horizontally after printing this glyph, in points
|
uint32 PrintAdvance; // How far the print head advances horizontally after printing this glyph, in points
|
||||||
uint32 BaseOffset; // Vertical offset for this glyph, in points; the font-wide offset is added to this
|
uint32 BaseOffset; // Vertical offset for this glyph, in points; the font-wide offset is added to this
|
||||||
uint32 KerningIndex; // Index into the kerning table of the first kerning pair for this glyph. -1 if no pairs.
|
uint32 KerningIndex; // Index into the kerning table of the first kerning pair for this glyph. -1 if no pairs.
|
||||||
uint8 RGBAChannel; // Fonts can store multiple glyphs in the same space on different RGBA channels. This value corresponds to R, G, B, or A.
|
uint8 RGBAChannel; // Fonts can store multiple glyphs in the same space on different RGBA channels. This value corresponds to R, G, B, or A.
|
||||||
};
|
};
|
||||||
std::unordered_map<uint16, SGlyph> mGlyphs;
|
std::unordered_map<uint16, SGlyph> mGlyphs;
|
||||||
|
|
||||||
|
@ -53,23 +55,23 @@ class CFont : public CResource
|
||||||
{
|
{
|
||||||
uint16 CharacterA; // Left character
|
uint16 CharacterA; // Left character
|
||||||
uint16 CharacterB; // Right character
|
uint16 CharacterB; // Right character
|
||||||
int32 Adjust; // The horizontal offset to apply to CharacterB if this pair is encountered, in points
|
int32 Adjust; // The horizontal offset to apply to CharacterB if this pair is encountered, in points
|
||||||
};
|
};
|
||||||
std::vector<SKerningPair> mKerningTable; // The kerning table should be laid out in alphabetical order for the indices to work properly
|
std::vector<SKerningPair> mKerningTable; // The kerning table should be laid out in alphabetical order for the indices to work properly
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFont(CResourceEntry *pEntry = 0);
|
explicit CFont(CResourceEntry *pEntry = nullptr);
|
||||||
~CFont();
|
~CFont() override;
|
||||||
CDependencyTree* BuildDependencyTree() const;
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override;
|
||||||
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
|
CVector2f RenderString(const TString& rkString, CRenderer *pRenderer, float AspectRatio,
|
||||||
CVector2f Position = CVector2f(0,0),
|
CVector2f Position = CVector2f(0,0),
|
||||||
CColor FillColor = CColor::skWhite, CColor StrokeColor = CColor::skBlack,
|
CColor FillColor = CColor::White(), CColor StrokeColor = CColor::Black(),
|
||||||
uint32 FontSize = CFONT_DEFAULT_SIZE);
|
uint32 FontSize = CFONT_DEFAULT_SIZE);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString FontName() const { return mFontName; }
|
TString FontName() const { return mFontName; }
|
||||||
inline CTexture* Texture() const { return mpFontTexture; }
|
CTexture* Texture() const { return mpFontTexture; }
|
||||||
private:
|
private:
|
||||||
static void InitBuffers();
|
static void InitBuffers();
|
||||||
static void ShutdownBuffers();
|
static void ShutdownBuffers();
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
#include "CLight.h"
|
#include "CLight.h"
|
||||||
#include "Core/Render/CGraphics.h"
|
#include "Core/Render/CGraphics.h"
|
||||||
#include <Common/Common.h>
|
#include <Common/Common.h>
|
||||||
|
#include <cfloat>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <float.h>
|
|
||||||
|
|
||||||
#define CLIGHT_NO_RADIUS 0x40
|
constexpr uint32_t CLIGHT_NO_RADIUS = 0x40;
|
||||||
#define CLIGHT_NO_INTENSITY 0x80
|
constexpr uint32_t CLIGHT_NO_INTENSITY = 0x80;
|
||||||
|
|
||||||
CLight::CLight()
|
CLight::CLight()
|
||||||
: mPosition(skDefaultLightPos)
|
: mDirtyFlags(CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY)
|
||||||
, mDirection(skDefaultLightDir)
|
|
||||||
, mDistAttenCoefficients(0.f, 1.f, 0.f)
|
|
||||||
, mAngleAttenCoefficients(0.f, 1.f, 0.f)
|
|
||||||
, mCachedRadius(0.f)
|
|
||||||
, mCachedIntensity(0.f)
|
|
||||||
, mDirtyFlags(CLIGHT_NO_RADIUS | CLIGHT_NO_INTENSITY)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +70,7 @@ float CLight::CalculateIntensity() const
|
||||||
if (mType == ELightType::Custom)
|
if (mType == ELightType::Custom)
|
||||||
coef = mAngleAttenCoefficients.X;
|
coef = mAngleAttenCoefficients.X;
|
||||||
|
|
||||||
return coef * std::max(mColor.R, std::max(mColor.G, mColor.B));
|
return coef * std::max({mColor.R, mColor.G, mColor.B});
|
||||||
#if 0
|
#if 0
|
||||||
// Get the color component with the greatest numeric value
|
// Get the color component with the greatest numeric value
|
||||||
float Greatest = (mColor.G >= mColor.B) ? mColor.G : mColor.B;
|
float Greatest = (mColor.G >= mColor.B) ? mColor.G : mColor.B;
|
||||||
|
@ -88,13 +82,14 @@ float CLight::CalculateIntensity() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// As is this one... partly
|
// As is this one... partly
|
||||||
CVector3f CLight::CalculateSpotAngleAtten()
|
CVector3f CLight::CalculateSpotAngleAtten() const
|
||||||
{
|
{
|
||||||
if (mType != ELightType::Spot) return CVector3f(1.f, 0.f, 0.f);
|
if (mType != ELightType::Spot)
|
||||||
|
return CVector3f(1.f, 0.f, 0.f);
|
||||||
|
|
||||||
float RadianCutoff = mSpotCutoff * (3.1415927f / 180.f);
|
const float RadianCutoff = mSpotCutoff * (3.1415927f / 180.f);
|
||||||
float RadianCosine = cosf(RadianCutoff);
|
const float RadianCosine = cosf(RadianCutoff);
|
||||||
float InvCosine = 1.f - RadianCosine;
|
const float InvCosine = 1.f - RadianCosine;
|
||||||
|
|
||||||
return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine);
|
return CVector3f(0.f, -RadianCosine / InvCosine, 1.f / InvCosine);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +97,7 @@ CVector3f CLight::CalculateSpotAngleAtten()
|
||||||
// ************ ACCESSORS ************
|
// ************ ACCESSORS ************
|
||||||
float CLight::GetRadius() const
|
float CLight::GetRadius() const
|
||||||
{
|
{
|
||||||
if (mDirtyFlags & CLIGHT_NO_RADIUS)
|
if ((mDirtyFlags & CLIGHT_NO_RADIUS) != 0)
|
||||||
{
|
{
|
||||||
mCachedRadius = CalculateRadius();
|
mCachedRadius = CalculateRadius();
|
||||||
mDirtyFlags &= ~CLIGHT_NO_RADIUS;
|
mDirtyFlags &= ~CLIGHT_NO_RADIUS;
|
||||||
|
@ -113,7 +108,7 @@ float CLight::GetRadius() const
|
||||||
|
|
||||||
float CLight::GetIntensity() const
|
float CLight::GetIntensity() const
|
||||||
{
|
{
|
||||||
if (mDirtyFlags & CLIGHT_NO_INTENSITY)
|
if ((mDirtyFlags & CLIGHT_NO_INTENSITY) != 0)
|
||||||
{
|
{
|
||||||
mCachedIntensity = CalculateIntensity();
|
mCachedIntensity = CalculateIntensity();
|
||||||
mDirtyFlags &= ~CLIGHT_NO_INTENSITY;
|
mDirtyFlags &= ~CLIGHT_NO_INTENSITY;
|
||||||
|
@ -131,7 +126,7 @@ void CLight::SetColor(const CColor& rkColor)
|
||||||
void CLight::SetSpotCutoff(float Cutoff)
|
void CLight::SetSpotCutoff(float Cutoff)
|
||||||
{
|
{
|
||||||
mSpotCutoff = Cutoff * 0.5f;
|
mSpotCutoff = Cutoff * 0.5f;
|
||||||
CalculateSpotAngleAtten();
|
mAngleAttenCoefficients = CalculateSpotAngleAtten();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC)
|
void CLight::SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC)
|
||||||
|
@ -198,8 +193,9 @@ CStructProperty* CLight::GetProperties() const
|
||||||
// ************ OTHER ************
|
// ************ OTHER ************
|
||||||
void CLight::Load() const
|
void CLight::Load() const
|
||||||
{
|
{
|
||||||
uint8 Index = (uint8) CGraphics::sNumLights;
|
const auto Index = static_cast<uint8>(CGraphics::sNumLights);
|
||||||
if (Index >= 8) return;
|
if (Index >= CGraphics::sLightBlock.Lights.size())
|
||||||
|
return;
|
||||||
|
|
||||||
CGraphics::SLightBlock::SGXLight *pLight = &CGraphics::sLightBlock.Lights[Index];
|
CGraphics::SLightBlock::SGXLight *pLight = &CGraphics::sLightBlock.Lights[Index];
|
||||||
|
|
||||||
|
@ -288,7 +284,3 @@ CLight CLight::BuildCustom(const CVector3f& rkPosition, const CVector3f& rkDirec
|
||||||
pLight.mAngleAttenCoefficients.Z = AngleAttenC * AngleAttenC;
|
pLight.mAngleAttenCoefficients.Z = AngleAttenC * AngleAttenC;
|
||||||
return pLight;
|
return pLight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CONSTANTS ************
|
|
||||||
const CVector3f CLight::skDefaultLightPos(0.f, 0.f, 0.f);
|
|
||||||
const CVector3f CLight::skDefaultLightDir(0.f,-1.f, 0.f);
|
|
||||||
|
|
|
@ -19,17 +19,17 @@ enum class ELightType
|
||||||
|
|
||||||
class CLight
|
class CLight
|
||||||
{
|
{
|
||||||
ELightType mType;
|
ELightType mType{};
|
||||||
uint32 mLayerIndex;
|
uint32 mLayerIndex = 0;
|
||||||
CVector3f mPosition;
|
CVector3f mPosition{skDefaultLightPos};
|
||||||
CVector3f mDirection;
|
CVector3f mDirection{skDefaultLightDir};
|
||||||
CColor mColor;
|
CColor mColor;
|
||||||
float mSpotCutoff;
|
float mSpotCutoff = 0.0f;
|
||||||
CVector3f mDistAttenCoefficients;
|
CVector3f mDistAttenCoefficients{0.f, 1.f, 0.f};
|
||||||
CVector3f mAngleAttenCoefficients;
|
CVector3f mAngleAttenCoefficients{0.f, 1.f, 0.f};
|
||||||
|
|
||||||
mutable float mCachedRadius;
|
mutable float mCachedRadius = 0.0f;
|
||||||
mutable float mCachedIntensity;
|
mutable float mCachedIntensity = 0.0f;
|
||||||
mutable uint8 mDirtyFlags;
|
mutable uint8 mDirtyFlags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -39,21 +39,21 @@ private:
|
||||||
// Data Manipulation
|
// Data Manipulation
|
||||||
float CalculateRadius() const;
|
float CalculateRadius() const;
|
||||||
float CalculateIntensity() const;
|
float CalculateIntensity() const;
|
||||||
CVector3f CalculateSpotAngleAtten();
|
CVector3f CalculateSpotAngleAtten() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Accessors
|
// Accessors
|
||||||
inline ELightType Type() const { return mType; }
|
ELightType Type() const { return mType; }
|
||||||
inline uint32 LayerIndex() const { return mLayerIndex; }
|
uint32 LayerIndex() const { return mLayerIndex; }
|
||||||
inline CVector3f Position() const { return mPosition; }
|
CVector3f Position() const { return mPosition; }
|
||||||
inline CVector3f Direction() const { return mDirection; }
|
CVector3f Direction() const { return mDirection; }
|
||||||
inline CColor Color() const { return mColor; }
|
CColor Color() const { return mColor; }
|
||||||
inline CVector3f DistAttenuation() const { return mDistAttenCoefficients; }
|
CVector3f DistAttenuation() const { return mDistAttenCoefficients; }
|
||||||
inline CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; }
|
CVector3f AngleAttenuation() const { return mAngleAttenCoefficients; }
|
||||||
|
|
||||||
inline void SetLayer(uint32 Index) { mLayerIndex = Index; }
|
void SetLayer(uint32 Index) { mLayerIndex = Index; }
|
||||||
inline void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; }
|
void SetPosition(const CVector3f& rkPosition) { mPosition = rkPosition; }
|
||||||
inline void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; }
|
void SetDirection(const CVector3f& rkDirection) { mDirection = rkDirection; }
|
||||||
|
|
||||||
float GetRadius() const;
|
float GetRadius() const;
|
||||||
float GetIntensity() const;
|
float GetIntensity() const;
|
||||||
|
@ -77,8 +77,8 @@ public:
|
||||||
float AngleAttenA, float AngleAttenB, float AngleAttenC);
|
float AngleAttenA, float AngleAttenB, float AngleAttenC);
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
static const CVector3f skDefaultLightPos;
|
static constexpr CVector3f skDefaultLightPos{0.f, 0.f, 0.f};
|
||||||
static const CVector3f skDefaultLightDir;
|
static constexpr CVector3f skDefaultLightDir{0.f, -1.f, 0.f};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLIGHT_H
|
#endif // CLIGHT_H
|
||||||
|
|
|
@ -10,13 +10,13 @@ class CMapArea : public CResource
|
||||||
CAssetID mNameString;
|
CAssetID mNameString;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CMapArea(CResourceEntry *pEntry = 0)
|
explicit CMapArea(CResourceEntry *pEntry = nullptr)
|
||||||
: CResource(pEntry)
|
: CResource(pEntry)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CDependencyTree* BuildDependencyTree() const
|
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||||
{
|
{
|
||||||
CDependencyTree *pTree = new CDependencyTree();
|
auto pTree = std::make_unique<CDependencyTree>();
|
||||||
pTree->AddDependency(mNameString);
|
pTree->AddDependency(mNameString);
|
||||||
return pTree;
|
return pTree;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,45 +6,18 @@
|
||||||
#include "Core/OpenGL/CShaderGenerator.h"
|
#include "Core/OpenGL/CShaderGenerator.h"
|
||||||
#include <Common/Hash/CFNV1A.h>
|
#include <Common/Hash/CFNV1A.h>
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
uint64 CMaterial::sCurrentMaterial = 0;
|
uint64 CMaterial::sCurrentMaterial = 0;
|
||||||
CColor CMaterial::sCurrentTint = CColor::skWhite;
|
CColor CMaterial::sCurrentTint = CColor::White();
|
||||||
std::map<uint64, CMaterial::SMaterialShader> CMaterial::smShaderMap;
|
std::map<uint64, CMaterial::SMaterialShader> CMaterial::smShaderMap;
|
||||||
|
|
||||||
CMaterial::CMaterial()
|
CMaterial::CMaterial() = default;
|
||||||
: mpShader(nullptr)
|
|
||||||
, mShaderStatus(EShaderStatus::NoShader)
|
|
||||||
, mRecalcHash(true)
|
|
||||||
, mVersion(EGame::Invalid)
|
|
||||||
, mOptions(EMaterialOption::None)
|
|
||||||
, mVtxDesc(EVertexAttribute::None)
|
|
||||||
, mBlendSrcFac(GL_ONE)
|
|
||||||
, mBlendDstFac(GL_ZERO)
|
|
||||||
, mLightingEnabled(true)
|
|
||||||
, mEchoesUnknownA(0)
|
|
||||||
, mEchoesUnknownB(0)
|
|
||||||
, mpIndirectTexture(nullptr)
|
|
||||||
, mpNextDrawPassMaterial(nullptr)
|
|
||||||
, mpBloomMaterial(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc)
|
CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc)
|
||||||
: mpShader(nullptr)
|
: mVersion(Version)
|
||||||
, mShaderStatus(EShaderStatus::NoShader)
|
|
||||||
, mRecalcHash(true)
|
|
||||||
, mVersion(Version)
|
|
||||||
, mOptions(EMaterialOption::DepthWrite | EMaterialOption::ColorWrite)
|
, mOptions(EMaterialOption::DepthWrite | EMaterialOption::ColorWrite)
|
||||||
, mVtxDesc(VtxDesc)
|
, mVtxDesc(VtxDesc)
|
||||||
, mBlendSrcFac(GL_ONE)
|
|
||||||
, mBlendDstFac(GL_ZERO)
|
|
||||||
, mLightingEnabled(true)
|
|
||||||
, mEchoesUnknownA(0)
|
|
||||||
, mEchoesUnknownB(0)
|
|
||||||
, mpIndirectTexture(nullptr)
|
|
||||||
, mpNextDrawPassMaterial(nullptr)
|
|
||||||
, mpBloomMaterial(nullptr)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CMaterial::~CMaterial()
|
CMaterial::~CMaterial()
|
||||||
|
@ -59,10 +32,8 @@ std::unique_ptr<CMaterial> CMaterial::Clone()
|
||||||
pOut->mVersion = mVersion;
|
pOut->mVersion = mVersion;
|
||||||
pOut->mOptions = mOptions;
|
pOut->mOptions = mOptions;
|
||||||
pOut->mVtxDesc = mVtxDesc;
|
pOut->mVtxDesc = mVtxDesc;
|
||||||
for (uint32 iKonst = 0; iKonst < 4; iKonst++)
|
pOut->mKonstColors = mKonstColors;
|
||||||
pOut->mKonstColors[iKonst] = mKonstColors[iKonst];
|
pOut->mTevColors = mTevColors;
|
||||||
for (uint32 iTev = 0; iTev < 4; iTev++)
|
|
||||||
pOut->mTevColors[iTev] = mTevColors[iTev];
|
|
||||||
pOut->mBlendSrcFac = mBlendSrcFac;
|
pOut->mBlendSrcFac = mBlendSrcFac;
|
||||||
pOut->mBlendDstFac = mBlendDstFac;
|
pOut->mBlendDstFac = mBlendDstFac;
|
||||||
pOut->mLightingEnabled = mLightingEnabled;
|
pOut->mLightingEnabled = mLightingEnabled;
|
||||||
|
@ -126,25 +97,25 @@ void CMaterial::GenerateShader(bool AllowRegen /*= true*/)
|
||||||
|
|
||||||
void CMaterial::ClearShader()
|
void CMaterial::ClearShader()
|
||||||
{
|
{
|
||||||
if (mpShader)
|
if (mpShader == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto Find = smShaderMap.find(mParametersHash);
|
||||||
|
ASSERT(Find != smShaderMap.cend());
|
||||||
|
|
||||||
|
SMaterialShader& rShader = Find->second;
|
||||||
|
ASSERT(rShader.pShader == mpShader);
|
||||||
|
|
||||||
|
rShader.NumReferences--;
|
||||||
|
|
||||||
|
if (rShader.NumReferences == 0)
|
||||||
{
|
{
|
||||||
auto Find = smShaderMap.find(mParametersHash);
|
delete mpShader;
|
||||||
ASSERT(Find != smShaderMap.end());
|
smShaderMap.erase(Find);
|
||||||
|
|
||||||
SMaterialShader& rShader = Find->second;
|
|
||||||
ASSERT(rShader.pShader == mpShader);
|
|
||||||
|
|
||||||
rShader.NumReferences--;
|
|
||||||
|
|
||||||
if (rShader.NumReferences == 0)
|
|
||||||
{
|
|
||||||
delete mpShader;
|
|
||||||
smShaderMap.erase(Find);
|
|
||||||
}
|
|
||||||
|
|
||||||
mpShader = nullptr;
|
|
||||||
mShaderStatus = EShaderStatus::NoShader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mpShader = nullptr;
|
||||||
|
mShaderStatus = EShaderStatus::NoShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMaterial::SetCurrent(FRenderOptions Options)
|
bool CMaterial::SetCurrent(FRenderOptions Options)
|
||||||
|
@ -162,7 +133,7 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
|
||||||
// Set RGB blend equation - force to ZERO/ONE if alpha is disabled
|
// Set RGB blend equation - force to ZERO/ONE if alpha is disabled
|
||||||
GLenum srcRGB, dstRGB, srcAlpha, dstAlpha;
|
GLenum srcRGB, dstRGB, srcAlpha, dstAlpha;
|
||||||
|
|
||||||
if (Options & ERenderOption::NoAlpha) {
|
if ((Options & ERenderOption::NoAlpha) != 0) {
|
||||||
srcRGB = GL_ONE;
|
srcRGB = GL_ONE;
|
||||||
dstRGB = GL_ZERO;
|
dstRGB = GL_ZERO;
|
||||||
} else {
|
} else {
|
||||||
|
@ -170,7 +141,7 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
|
||||||
dstRGB = mBlendDstFac;
|
dstRGB = mBlendDstFac;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mOptions & EMaterialOption::ZeroDestAlpha) {
|
if ((mOptions & EMaterialOption::ZeroDestAlpha) != 0) {
|
||||||
srcAlpha = GL_ZERO;
|
srcAlpha = GL_ZERO;
|
||||||
dstAlpha = GL_ZERO;
|
dstAlpha = GL_ZERO;
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,43 +152,45 @@ bool CMaterial::SetCurrent(FRenderOptions Options)
|
||||||
glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||||
|
|
||||||
// Set konst inputs
|
// Set konst inputs
|
||||||
for (uint32 iKonst = 0; iKonst < 4; iKonst++)
|
CGraphics::sPixelBlock.Konst = mKonstColors;
|
||||||
CGraphics::sPixelBlock.Konst[iKonst] = mKonstColors[iKonst];
|
|
||||||
|
|
||||||
// Set TEV registers
|
// Set TEV registers
|
||||||
if (mVersion >= EGame::Corruption)
|
if (mVersion >= EGame::Corruption)
|
||||||
for (uint32 iTev = 0; iTev < 4; iTev++)
|
{
|
||||||
CGraphics::sPixelBlock.TevColor[iTev] = mTevColors[iTev];
|
CGraphics::sPixelBlock.TevColor = mTevColors;
|
||||||
|
}
|
||||||
|
|
||||||
// Set color channels
|
// Set color channels
|
||||||
// COLOR0_Amb,Mat is initialized by the node instead of by the material
|
// COLOR0_Amb,Mat is initialized by the node instead of by the material
|
||||||
|
|
||||||
// Set depth write - force on if alpha is disabled (lots of weird depth issues otherwise)
|
// Set depth write - force on if alpha is disabled (lots of weird depth issues otherwise)
|
||||||
if ((mOptions & EMaterialOption::DepthWrite) || (Options & ERenderOption::NoAlpha)) glDepthMask(GL_TRUE);
|
if ((mOptions & EMaterialOption::DepthWrite) != 0 || (Options & ERenderOption::NoAlpha) != 0)
|
||||||
else glDepthMask(GL_FALSE);
|
glDepthMask(GL_TRUE);
|
||||||
|
else
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
// Set color/alpha write
|
// Set color/alpha write
|
||||||
GLboolean bColorWrite = mOptions.HasFlag(EMaterialOption::ColorWrite);
|
const GLboolean bColorWrite = mOptions.HasFlag(EMaterialOption::ColorWrite);
|
||||||
GLboolean bAlphaWrite = mOptions.HasFlag(EMaterialOption::AlphaWrite);
|
const GLboolean bAlphaWrite = mOptions.HasFlag(EMaterialOption::AlphaWrite);
|
||||||
glColorMask(bColorWrite, bColorWrite, bColorWrite, bAlphaWrite);
|
glColorMask(bColorWrite, bColorWrite, bColorWrite, bAlphaWrite);
|
||||||
|
|
||||||
// Load uniforms
|
// Load uniforms
|
||||||
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++)
|
for (size_t iPass = 0; iPass < mPasses.size(); iPass++)
|
||||||
mPasses[iPass]->SetAnimCurrent(Options, iPass);
|
mPasses[iPass]->SetAnimCurrent(Options, iPass);
|
||||||
|
|
||||||
sCurrentMaterial = HashParameters();
|
sCurrentMaterial = HashParameters();
|
||||||
}
|
}
|
||||||
|
else // If the passes are otherwise the same, update UV anims that use the model matrix
|
||||||
// If the passes are otherwise the same, update UV anims that use the model matrix
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++)
|
for (size_t iPass = 0; iPass < mPasses.size(); iPass++)
|
||||||
{
|
{
|
||||||
EUVAnimMode mode = mPasses[iPass]->AnimMode();
|
const EUVAnimMode mode = mPasses[iPass]->AnimMode();
|
||||||
|
|
||||||
if ((mode == EUVAnimMode::InverseMV) || (mode == EUVAnimMode::InverseMVTranslated) ||
|
if (mode == EUVAnimMode::InverseMV || mode == EUVAnimMode::InverseMVTranslated ||
|
||||||
(mode == EUVAnimMode::ModelMatrix) || (mode == EUVAnimMode::SimpleMode))
|
mode == EUVAnimMode::ModelMatrix || mode == EUVAnimMode::SimpleMode)
|
||||||
|
{
|
||||||
mPasses[iPass]->SetAnimCurrent(Options, iPass);
|
mPasses[iPass]->SetAnimCurrent(Options, iPass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,23 +213,23 @@ uint64 CMaterial::HashParameters()
|
||||||
{
|
{
|
||||||
if (mRecalcHash)
|
if (mRecalcHash)
|
||||||
{
|
{
|
||||||
CFNV1A Hash(CFNV1A::k64Bit);
|
CFNV1A Hash(CFNV1A::EHashLength::k64Bit);
|
||||||
|
|
||||||
Hash.HashLong((int) mVersion);
|
Hash.HashLong(static_cast<int>(mVersion));
|
||||||
Hash.HashLong(mOptions);
|
Hash.HashLong(mOptions);
|
||||||
Hash.HashLong(mVtxDesc);
|
Hash.HashLong(mVtxDesc);
|
||||||
Hash.HashData(mKonstColors, sizeof(CColor) * 4);
|
Hash.HashData(mKonstColors.data(), sizeof(mKonstColors));
|
||||||
Hash.HashData(mTevColors, sizeof(CColor) * 4);
|
Hash.HashData(mTevColors.data(), sizeof(mTevColors));
|
||||||
Hash.HashLong(mBlendSrcFac);
|
Hash.HashLong(mBlendSrcFac);
|
||||||
Hash.HashLong(mBlendDstFac);
|
Hash.HashLong(mBlendDstFac);
|
||||||
Hash.HashByte(mLightingEnabled);
|
Hash.HashByte(mLightingEnabled);
|
||||||
Hash.HashLong(mEchoesUnknownA);
|
Hash.HashLong(mEchoesUnknownA);
|
||||||
Hash.HashLong(mEchoesUnknownB);
|
Hash.HashLong(mEchoesUnknownB);
|
||||||
|
|
||||||
for (uint32 iPass = 0; iPass < mPasses.size(); iPass++)
|
for (auto& pass : mPasses)
|
||||||
mPasses[iPass]->HashParameters(Hash);
|
pass->HashParameters(Hash);
|
||||||
|
|
||||||
uint64 NewHash = Hash.GetHash64();
|
const uint64 NewHash = Hash.GetHash64();
|
||||||
|
|
||||||
if (mParametersHash != NewHash)
|
if (mParametersHash != NewHash)
|
||||||
ClearShader();
|
ClearShader();
|
||||||
|
@ -274,15 +247,15 @@ void CMaterial::Update()
|
||||||
mShaderStatus = EShaderStatus::NoShader;
|
mShaderStatus = EShaderStatus::NoShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMaterial::SetNumPasses(uint32 NumPasses)
|
void CMaterial::SetNumPasses(size_t NumPasses)
|
||||||
{
|
{
|
||||||
uint32 OldCount = mPasses.size();
|
const size_t OldCount = mPasses.size();
|
||||||
mPasses.resize(NumPasses);
|
mPasses.resize(NumPasses);
|
||||||
|
|
||||||
if (NumPasses > OldCount)
|
if (NumPasses > OldCount)
|
||||||
{
|
{
|
||||||
for (uint32 iPass = OldCount; iPass < NumPasses; iPass++)
|
for (size_t i = OldCount; i < NumPasses; i++)
|
||||||
mPasses[iPass] = std::make_unique<CMaterialPass>(this);
|
mPasses[i] = std::make_unique<CMaterialPass>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRecalcHash = true;
|
mRecalcHash = true;
|
||||||
|
|
|
@ -74,23 +74,23 @@ private:
|
||||||
static CColor sCurrentTint; // The tint for the currently bound material
|
static CColor sCurrentTint; // The tint for the currently bound material
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
TString mName; // Name of the material
|
TString mName; // Name of the material
|
||||||
CShader *mpShader; // This material's generated shader. Created with GenerateShader().
|
CShader *mpShader = nullptr; // This material's generated shader. Created with GenerateShader().
|
||||||
EShaderStatus mShaderStatus; // A status variable so that PWE won't crash if a shader fails to compile.
|
EShaderStatus mShaderStatus{EShaderStatus::NoShader}; // A status variable so that PWE won't crash if a shader fails to compile.
|
||||||
uint64 mParametersHash; // A hash of all the parameters that can identify this TEV setup.
|
uint64 mParametersHash = 0; // A hash of all the parameters that can identify this TEV setup.
|
||||||
bool mRecalcHash; // Indicates the hash needs to be recalculated. Set true when parameters are changed.
|
bool mRecalcHash = true; // Indicates the hash needs to be recalculated. Set true when parameters are changed.
|
||||||
|
|
||||||
EGame mVersion;
|
EGame mVersion{EGame::Invalid};
|
||||||
FMaterialOptions mOptions; // See the EMaterialOption enum above
|
FMaterialOptions mOptions{EMaterialOption::None}; // See the EMaterialOption enum above
|
||||||
FVertexDescription mVtxDesc; // Descriptor of vertex attributes used by this material
|
FVertexDescription mVtxDesc{EVertexAttribute::None}; // Descriptor of vertex attributes used by this material
|
||||||
CColor mKonstColors[4]; // Konst color values for TEV
|
std::array<CColor, 4> mKonstColors; // Konst color values for TEV
|
||||||
CColor mTevColors[4]; // Initial TEV color register values (for MP3 materials only)
|
std::array<CColor, 4> mTevColors; // Initial TEV color register values (for MP3 materials only)
|
||||||
GLenum mBlendSrcFac; // Source blend factor
|
GLenum mBlendSrcFac{GL_ONE}; // Source blend factor
|
||||||
GLenum mBlendDstFac; // Dest blend factor
|
GLenum mBlendDstFac{GL_ZERO}; // Dest blend factor
|
||||||
bool mLightingEnabled; // Color channel control flags; indicate whether lighting is enabled
|
bool mLightingEnabled = true; // Color channel control flags; indicate whether lighting is enabled
|
||||||
uint32 mEchoesUnknownA; // First unknown value introduced in Echoes. Included for cooking.
|
uint32 mEchoesUnknownA = 0; // First unknown value introduced in Echoes. Included for cooking.
|
||||||
uint32 mEchoesUnknownB; // Second unknown value introduced in Echoes. Included for cooking.
|
uint32 mEchoesUnknownB = 0; // Second unknown value introduced in Echoes. Included for cooking.
|
||||||
TResPtr<CTexture> mpIndirectTexture; // Optional texture used for the indirect stage for reflections
|
TResPtr<CTexture> mpIndirectTexture; // Optional texture used for the indirect stage for reflections
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CMaterialPass>> mPasses;
|
std::vector<std::unique_ptr<CMaterialPass>> mPasses;
|
||||||
|
|
||||||
|
@ -123,37 +123,37 @@ public:
|
||||||
bool SetCurrent(FRenderOptions Options);
|
bool SetCurrent(FRenderOptions Options);
|
||||||
uint64 HashParameters();
|
uint64 HashParameters();
|
||||||
void Update();
|
void Update();
|
||||||
void SetNumPasses(uint32 NumPasses);
|
void SetNumPasses(size_t NumPasses);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline TString Name() const { return mName; }
|
TString Name() const { return mName; }
|
||||||
inline EGame Version() const { return mVersion; }
|
EGame Version() const { return mVersion; }
|
||||||
inline FMaterialOptions Options() const { return mOptions; }
|
FMaterialOptions Options() const { return mOptions; }
|
||||||
inline FVertexDescription VtxDesc() const { return mVtxDesc; }
|
FVertexDescription VtxDesc() const { return mVtxDesc; }
|
||||||
inline GLenum BlendSrcFac() const { return mBlendSrcFac; }
|
GLenum BlendSrcFac() const { return mBlendSrcFac; }
|
||||||
inline GLenum BlendDstFac() const { return mBlendDstFac; }
|
GLenum BlendDstFac() const { return mBlendDstFac; }
|
||||||
inline CColor Konst(uint32 KIndex) const { return mKonstColors[KIndex]; }
|
CColor Konst(size_t KIndex) const { return mKonstColors[KIndex]; }
|
||||||
inline CColor TevColor(ETevOutput Out) const { return mTevColors[int(Out)]; }
|
CColor TevColor(ETevOutput Out) const { return mTevColors[static_cast<size_t>(Out)]; }
|
||||||
inline CTexture* IndTexture() const { return mpIndirectTexture; }
|
CTexture* IndTexture() const { return mpIndirectTexture; }
|
||||||
inline bool IsLightingEnabled() const { return mLightingEnabled; }
|
bool IsLightingEnabled() const { return mLightingEnabled; }
|
||||||
inline uint32 EchoesUnknownA() const { return mEchoesUnknownA; }
|
uint32 EchoesUnknownA() const { return mEchoesUnknownA; }
|
||||||
inline uint32 EchoesUnknownB() const { return mEchoesUnknownB; }
|
uint32 EchoesUnknownB() const { return mEchoesUnknownB; }
|
||||||
inline uint32 PassCount() const { return mPasses.size(); }
|
uint32 PassCount() const { return mPasses.size(); }
|
||||||
inline CMaterialPass* Pass(uint32 PassIndex) const { return mPasses[PassIndex].get(); }
|
CMaterialPass* Pass(size_t PassIndex) const { return mPasses[PassIndex].get(); }
|
||||||
inline CMaterial* GetNextDrawPass() const { return mpNextDrawPassMaterial.get(); }
|
CMaterial* GetNextDrawPass() const { return mpNextDrawPassMaterial.get(); }
|
||||||
inline CMaterial* GetBloomVersion() const { return mpBloomMaterial.get(); }
|
CMaterial* GetBloomVersion() const { return mpBloomMaterial.get(); }
|
||||||
|
|
||||||
inline void SetName(const TString& rkName) { mName = rkName; }
|
void SetName(TString rkName) { mName = std::move(rkName); }
|
||||||
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
|
void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
|
||||||
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
|
void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
|
||||||
inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
|
void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
|
||||||
inline void SetKonst(const CColor& Konst, uint32 KIndex) { mKonstColors[KIndex] = Konst; Update(); }
|
void SetKonst(const CColor& Konst, size_t KIndex) { mKonstColors[KIndex] = Konst; Update(); }
|
||||||
inline void SetTevColor(const CColor& Color, ETevOutput Out) { mTevColors[int(Out)] = Color; }
|
void SetTevColor(const CColor& Color, ETevOutput Out) { mTevColors[static_cast<size_t>(Out)] = Color; }
|
||||||
inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
|
void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
|
||||||
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }
|
void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
inline static void KillCachedMaterial() { sCurrentMaterial = 0; }
|
static void KillCachedMaterial() { sCurrentMaterial = 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MATERIAL_H
|
#endif // MATERIAL_H
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue