Merge branch 'master' of ssh+git://git.axiodl.com:6431/AxioDL/urde

This commit is contained in:
Phillip Stephens 2020-04-15 00:57:37 -07:00
commit 8a974d6e5e
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
55 changed files with 1216 additions and 901 deletions

View File

@ -15,10 +15,11 @@
namespace DataSpec::DNAANCS { namespace DataSpec::DNAANCS {
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion> template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, const hecl::ProjectPath& outPath, bool ReadANCSToBlender(hecl::blender::Token& btok, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec, PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged, bool force) { std::function<void(const hecl::SystemChar*)> fileChanged, bool force) {
/* Extract character CMDL/CSKR first */ auto& conn = btok.getBlenderConnection();
/* Extract character CMDL/CSKR/CINF first */
std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo; std::vector<CharacterResInfo<typename PAKRouter::IDType>> chResInfo;
ancs.getCharacterResInfo(chResInfo); ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo) { for (const auto& info : chResInfo) {
@ -49,11 +50,19 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
conn.saveBlend(); conn.saveBlend();
} }
} }
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(info.cinf, &node, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
if (cinfPath.getPathType() == hecl::ProjectPath::Type::None) {
PAKEntryReadStream rs = cinfE->beginReadStream(*node);
ANCSDNA::CINFType::Extract(dataspec, rs, cinfPath, pakRouter, *cinfE, false, btok, fileChanged);
}
}
} }
/* Extract attachment CMDL/CSKRs first */ /* Extract attachment CMDL/CSKR/CINFs first */
auto attRange = pakRouter.lookupCharacterAttachmentRigs(entry.id); auto attRange = pakRouter.lookupCharacterAttachmentRigs(entry.id);
for (auto it = attRange.first; it != attRange.second; ++it) { for (auto it = attRange.first; it != attRange.second; ++it) {
auto cinfid = it->second.first.cinf;
auto cmdlid = it->second.first.cmdl; auto cmdlid = it->second.first.cmdl;
const nod::Node* node; const nod::Node* node;
@ -61,8 +70,9 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE); hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) { if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false); cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh)) if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh)) {
return false; return false;
}
std::string bestName = pakRouter.getBestEntryName(*cmdlE); std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName); hecl::SystemStringConv bestNameView(bestName);
@ -84,6 +94,15 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
conn.saveBlend(); conn.saveBlend();
} }
} }
if (cinfid.isValid()) {
if (const typename PAKRouter::EntryType* cinfE = pakRouter.lookupEntry(cinfid, &node, true, false)) {
hecl::ProjectPath cinfPath = pakRouter.getWorking(cinfE);
if (cinfPath.getPathType() == hecl::ProjectPath::Type::None) {
PAKEntryReadStream rs = cinfE->beginReadStream(*node);
ANCSDNA::CINFType::Extract(dataspec, rs, cinfPath, pakRouter, *cinfE, false, btok, fileChanged);
}
}
}
} }
std::string bestName = pakRouter.getBestEntryName(entry); std::string bestName = pakRouter.getBestEntryName(entry);
@ -253,17 +272,17 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
template bool template bool
ReadANCSToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::ANCS, DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, 2>( ReadANCSToBlender<PAKRouter<DNAMP1::PAKBridge>, DNAMP1::ANCS, DNAMP1::MaterialSet, DNACMDL::SurfaceHeader_1, 2>(
hecl::blender::Connection& conn, const DNAMP1::ANCS& ancs, const hecl::ProjectPath& outPath, hecl::blender::Token& btok, const DNAMP1::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP1::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry, PAKRouter<DNAMP1::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP1::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force); const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool template bool
ReadANCSToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::ANCS, DNAMP2::MaterialSet, DNACMDL::SurfaceHeader_2, 4>( ReadANCSToBlender<PAKRouter<DNAMP2::PAKBridge>, DNAMP2::ANCS, DNAMP2::MaterialSet, DNACMDL::SurfaceHeader_2, 4>(
hecl::blender::Connection& conn, const DNAMP2::ANCS& ancs, const hecl::ProjectPath& outPath, hecl::blender::Token& btok, const DNAMP2::ANCS& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP2::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry, PAKRouter<DNAMP2::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP2::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force); const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool template bool
ReadANCSToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::CHAR, DNAMP3::MaterialSet, DNACMDL::SurfaceHeader_3, 4>( ReadANCSToBlender<PAKRouter<DNAMP3::PAKBridge>, DNAMP3::CHAR, DNAMP3::MaterialSet, DNACMDL::SurfaceHeader_3, 4>(
hecl::blender::Connection& conn, const DNAMP3::CHAR& ancs, const hecl::ProjectPath& outPath, hecl::blender::Token& btok, const DNAMP3::CHAR& ancs, const hecl::ProjectPath& outPath,
PAKRouter<DNAMP3::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry, PAKRouter<DNAMP3::PAKBridge>& pakRouter, const typename PAKRouter<DNAMP3::PAKBridge>::EntryType& entry,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force); const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);

View File

@ -41,7 +41,7 @@ struct AnimationResInfo {
}; };
template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion> template <class PAKRouter, class ANCSDNA, class MaterialSet, class SurfaceHeader, atUint32 CMDLVersion>
bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, const hecl::ProjectPath& outPath, bool ReadANCSToBlender(hecl::blender::Token& btok, const ANCSDNA& ancs, const hecl::ProjectPath& outPath,
PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec, PAKRouter& pakRouter, const typename PAKRouter::EntryType& entry, const SpecBase& dataspec,
std::function<void(const hecl::SystemChar*)> fileChanged, bool force = false); std::function<void(const hecl::SystemChar*)> fileChanged, bool force = false);

View File

@ -975,9 +975,8 @@ bool ANCS::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl:
} }
if (force || blendType == hecl::ProjectPath::Type::None) { if (force || blendType == hecl::ProjectPath::Type::None) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, ANCS, MaterialSet, DNACMDL::SurfaceHeader_1, 2>( DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, ANCS, MaterialSet, DNACMDL::SurfaceHeader_1, 2>(
conn, ancs, blendPath, pakRouter, entry, dataSpec, fileChanged, force); btok, ancs, blendPath, pakRouter, entry, dataSpec, fileChanged, force);
} }
} }

View File

@ -215,9 +215,8 @@ struct ANCS : BigDNA {
} }
if (force || blendType == hecl::ProjectPath::Type::None) { if (force || blendType == hecl::ProjectPath::Type::None) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, ANCS, MaterialSet, DNACMDL::SurfaceHeader_2, 4>( DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, ANCS, MaterialSet, DNACMDL::SurfaceHeader_2, 4>(
conn, ancs, blendPath, pakRouter, entry, dataSpec, fileChanged, force); btok, ancs, blendPath, pakRouter, entry, dataSpec, fileChanged, force);
} }
} }

View File

@ -283,9 +283,8 @@ struct CHAR : BigDNA {
} }
if (force || blendType == hecl::ProjectPath::Type::None) { if (force || blendType == hecl::ProjectPath::Type::None) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, CHAR, MaterialSet, DNACMDL::SurfaceHeader_3, 4>( DNAANCS::ReadANCSToBlender<PAKRouter<PAKBridge>, CHAR, MaterialSet, DNACMDL::SurfaceHeader_3, 4>(
conn, aChar, blendPath, pakRouter, entry, dataSpec, fileChanged, force); btok, aChar, blendPath, pakRouter, entry, dataSpec, fileChanged, force);
} }
} }

View File

@ -22,15 +22,10 @@ namespace DataSpec::DNAMP3 {
logvisor::Module Log("urde::DNAMP3"); logvisor::Module Log("urde::DNAMP3");
static bool GetNoShare(std::string_view name) { static bool GetNoShare(std::string_view name) {
if (name == "UniverseArea.pak"sv)
return false;
std::string lowerName(name); std::string lowerName(name);
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower); std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
if (!lowerName.compare(0, 7, "metroid")) return !lowerName.starts_with("metroid"sv) && !lowerName.starts_with("frontend"sv) &&
return false; !lowerName.starts_with("rs5fe"sv) && !lowerName.starts_with("universearea"sv);
if (!lowerName.compare(0, 5, "rs5fe"))
return false;
return true;
} }
PAKBridge::PAKBridge(const nod::Node& node, bool doExtract) PAKBridge::PAKBridge(const nod::Node& node, bool doExtract)

View File

@ -29,7 +29,7 @@ void ViewManager::InitMP1(MP1::CMain& main) {
if (!m_noShaderWarmup) if (!m_noShaderWarmup)
main.WarmupShaders(); main.WarmupShaders();
m_testGameView.reset(new TestGameView(*this, m_viewResources, *m_rootView)); m_testGameView.reset(new TestGameView(*this, m_viewResources, *m_rootView, m_cvarManager));
m_rootView->accessContentViews().clear(); m_rootView->accessContentViews().clear();
m_rootView->accessContentViews().push_back(m_testGameView.get()); m_rootView->accessContentViews().push_back(m_testGameView.get());
@ -62,17 +62,11 @@ void ViewManager::TestGameView::think() {
if (m_debugText) { if (m_debugText) {
std::string overlayText; std::string overlayText;
const hecl::CVar* showFrameIdx = hecl::CVarManager::instance()->findCVar("debugOverlay.showFrameCounter");
const hecl::CVar* playerInfo = hecl::CVarManager::instance()->findCVar("debugOverlay.playerInfo");
const hecl::CVar* worldInfo = hecl::CVarManager::instance()->findCVar("debugOverlay.worldInfo");
const hecl::CVar* areaInfo = hecl::CVarManager::instance()->findCVar("debugOverlay.areaInfo");
const hecl::CVar* showInGameTime = hecl::CVarManager::instance()->findCVar("debugOverlay.showInGameTime");
const hecl::CVar* showResourceStats = hecl::CVarManager::instance()->findCVar("debugOverlay.showResourceStats");
if (g_StateManager) { if (g_StateManager) {
if (showFrameIdx && showFrameIdx->toBoolean()) if (m_cvarCommons.m_debugOverlayShowFrameCounter->toBoolean())
overlayText += fmt::format(FMT_STRING("Frame: {}\n"), g_StateManager->GetUpdateFrameIndex()); overlayText += fmt::format(FMT_STRING("Frame: {}\n"), g_StateManager->GetUpdateFrameIndex());
if (showInGameTime && showInGameTime->toBoolean()) { if (m_cvarCommons.m_debugOverlayShowInGameTime->toBoolean()) {
double igt = g_GameState->GetTotalPlayTime(); double igt = g_GameState->GetTotalPlayTime();
u32 ms = u64(igt * 1000) % 1000; u32 ms = u64(igt * 1000) % 1000;
auto pt = std::div(igt, 3600); auto pt = std::div(igt, 3600);
@ -80,7 +74,7 @@ void ViewManager::TestGameView::think() {
fmt::format(FMT_STRING("PlayTime: {:02d}:{:02d}:{:02d}.{:03d}\n"), pt.quot, pt.rem / 60, pt.rem % 60, ms); fmt::format(FMT_STRING("PlayTime: {:02d}:{:02d}:{:02d}.{:03d}\n"), pt.quot, pt.rem / 60, pt.rem % 60, ms);
} }
if (g_StateManager->Player() && playerInfo && playerInfo->toBoolean()) { if (g_StateManager->Player() && m_cvarCommons.m_debugOverlayPlayerInfo->toBoolean()) {
const CPlayer& pl = g_StateManager->GetPlayer(); const CPlayer& pl = g_StateManager->GetPlayer();
const zeus::CQuaternion plQ = zeus::CQuaternion(pl.GetTransform().getRotation().buildMatrix3f()); const zeus::CQuaternion plQ = zeus::CQuaternion(pl.GetTransform().getRotation().buildMatrix3f());
const zeus::CTransform camXf = g_StateManager->GetCameraManager()->GetCurrentCameraTransform(*g_StateManager); const zeus::CTransform camXf = g_StateManager->GetCameraManager()->GetCurrentCameraTransform(*g_StateManager);
@ -98,7 +92,7 @@ void ViewManager::TestGameView::think() {
camXf.origin.y(), camXf.origin.z(), zeus::radToDeg(camQ.roll()), camXf.origin.y(), camXf.origin.z(), zeus::radToDeg(camQ.roll()),
zeus::radToDeg(camQ.pitch()), zeus::radToDeg(camQ.yaw())); zeus::radToDeg(camQ.pitch()), zeus::radToDeg(camQ.yaw()));
} }
if (worldInfo && worldInfo->toBoolean()) { if (m_cvarCommons.m_debugOverlayWorldInfo->toBoolean()) {
TLockedToken<CStringTable> tbl = TLockedToken<CStringTable> tbl =
g_SimplePool->GetObj({FOURCC('STRG'), g_StateManager->GetWorld()->IGetStringTableAssetId()}); g_SimplePool->GetObj({FOURCC('STRG'), g_StateManager->GetWorld()->IGetStringTableAssetId()});
const urde::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId(); const urde::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
@ -107,7 +101,7 @@ void ViewManager::TestGameView::think() {
} }
const urde::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId(); const urde::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
if (areaInfo && areaInfo->toBoolean() && g_StateManager->GetWorld() && if (m_cvarCommons.m_debugOverlayAreaInfo->toBoolean() && g_StateManager->GetWorld() &&
g_StateManager->GetWorld()->DoesAreaExist(aId)) { g_StateManager->GetWorld()->DoesAreaExist(aId)) {
const auto& layerStates = g_GameState->CurrentWorldState().GetLayerState(); const auto& layerStates = g_GameState->CurrentWorldState().GetLayerState();
std::string layerBits; std::string layerBits;
@ -126,7 +120,7 @@ void ViewManager::TestGameView::think() {
} }
} }
if (showResourceStats && showResourceStats->toBoolean()) if (m_cvarCommons.m_debugOverlayShowResourceStats->toBoolean())
overlayText += fmt::format(FMT_STRING("Resource Objects: {}\n"), g_SimplePool->GetLiveObjects()); overlayText += fmt::format(FMT_STRING("Resource Objects: {}\n"), g_SimplePool->GetLiveObjects());
if (!overlayText.empty()) if (!overlayText.empty())

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "hecl/CVarManager.hpp" #include "hecl/CVarManager.hpp"
#include "hecl/CVarCommons.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp"
#include "amuse/BooBackend.hpp" #include "amuse/BooBackend.hpp"
#include "ProjectManager.hpp" #include "ProjectManager.hpp"
@ -57,9 +58,11 @@ class ViewManager final : public specter::IViewManager {
class TestGameView : public specter::View { class TestGameView : public specter::View {
ViewManager& m_vm; ViewManager& m_vm;
std::unique_ptr<specter::MultiLineTextView> m_debugText; std::unique_ptr<specter::MultiLineTextView> m_debugText;
hecl::CVarCommons m_cvarCommons;
public: public:
TestGameView(ViewManager& vm, specter::ViewResources& res, specter::View& parent) : View(res, parent), m_vm(vm) {} TestGameView(ViewManager& vm, specter::ViewResources& res, specter::View& parent, hecl::CVarManager& cvarMgr)
: View(res, parent), m_vm(vm), m_cvarCommons(cvarMgr) {}
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) override; void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) override;
void draw(boo::IGraphicsCommandQueue* gfxQ) override; void draw(boo::IGraphicsCommandQueue* gfxQ) override;
void think() override; void think() override;

View File

@ -89,7 +89,6 @@ struct Application : boo::IApplicationCallback {
void initialize(boo::IApplication* app) { void initialize(boo::IApplication* app) {
zeus::detectCPU(); zeus::detectCPU();
createGlobalCVars();
for (const boo::SystemString& arg : app->getArgs()) { for (const boo::SystemString& arg : app->getArgs()) {
if (arg.find(_SYS_STR("--verbosity=")) == 0 || arg.find(_SYS_STR("-v=")) == 0) { if (arg.find(_SYS_STR("--verbosity=")) == 0 || arg.find(_SYS_STR("-v=")) == 0) {
hecl::SystemUTF8Conv utf8Arg(arg.substr(arg.find_last_of('=') + 1)); hecl::SystemUTF8Conv utf8Arg(arg.substr(arg.find_last_of('=') + 1));
@ -113,27 +112,6 @@ struct Application : boo::IApplicationCallback {
uint32_t getAnisotropy() const { return m_cvarCommons.getAnisotropy(); } uint32_t getAnisotropy() const { return m_cvarCommons.getAnisotropy(); }
bool getDeepColor() const { return m_cvarCommons.getDeepColor(); } bool getDeepColor() const { return m_cvarCommons.getDeepColor(); }
void createGlobalCVars() {
m_cvarManager.findOrMakeCVar("debugOverlay.playerInfo"sv,
"Displays information about the player, such as location and orientation"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_cvarManager.findOrMakeCVar("debugOverlay.worldInfo"sv,
"Displays information about the current world, such as world asset ID, and areaId"sv,
false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_cvarManager.findOrMakeCVar(
"debugOverlay.areaInfo"sv,
"Displays information about the current area, such as asset ID, object/layer counts, and active layer bits"sv,
false, hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_cvarManager.findOrMakeCVar("debugOverlay.showFrameCounter"sv, "Displays the current frame index"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_cvarManager.findOrMakeCVar("debugOverlay.showInGameTime"sv, "Displays the current in game time"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_cvarManager.findOrMakeCVar("debugOverlay.showResourceStats"sv,
"Displays the current live resource object and token counts"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
}
}; };
} // namespace urde } // namespace urde

View File

@ -3,6 +3,8 @@
**Official Discord Channel:** https://discord.gg/AMBVFuf **Official Discord Channel:** https://discord.gg/AMBVFuf
![URDE screenshot](assets/urde-screen1.png)
### Download ### Download
Precompiled builds of the command-line extraction utility (`hecl`) with embedded dataspec libraries are available at https://releases.axiodl.com. This will give you intermediate dumps of original formats as *blender* and *yaml* representations. Precompiled builds of the command-line extraction utility (`hecl`) with embedded dataspec libraries are available at https://releases.axiodl.com. This will give you intermediate dumps of original formats as *blender* and *yaml* representations.

View File

@ -12,6 +12,8 @@ class CScannableObjectInfo {
public: public:
enum class EPanelType {}; enum class EPanelType {};
static constexpr size_t NumBuckets = 4;
struct SBucket { struct SBucket {
CAssetId x0_texture; CAssetId x0_texture;
float x4_appearanceRange = 0.f; float x4_appearanceRange = 0.f;
@ -29,14 +31,14 @@ private:
float x8_totalDownloadTime = 0.f; float x8_totalDownloadTime = 0.f;
u32 xc_category = 0; u32 xc_category = 0;
bool x10_important = false; bool x10_important = false;
rstl::reserved_vector<SBucket, 4> x14_buckets; rstl::reserved_vector<SBucket, NumBuckets> x14_buckets;
public: public:
CScannableObjectInfo(CInputStream&, CAssetId); CScannableObjectInfo(CInputStream&, CAssetId);
CAssetId GetScannableObjectId() const { return x0_scannableObjectId; } CAssetId GetScannableObjectId() const { return x0_scannableObjectId; }
CAssetId GetStringTableId() const { return x4_stringId; } CAssetId GetStringTableId() const { return x4_stringId; }
float GetTotalDownloadTime() const { return x8_totalDownloadTime; } float GetTotalDownloadTime() const { return x8_totalDownloadTime; }
const SBucket& GetBucket(s32 idx) const { return x14_buckets[idx]; } const SBucket& GetBucket(size_t idx) const { return x14_buckets[idx]; }
u32 GetCategory() const { return xc_category; } u32 GetCategory() const { return xc_category; }
bool IsImportant() const { return x10_important; } bool IsImportant() const { return x10_important; }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <array>
#include <vector> #include <vector>
#include "Runtime/CPlayerState.hpp" #include "Runtime/CPlayerState.hpp"
@ -120,13 +121,13 @@ private:
bool x219_missileShot = false; bool x219_missileShot = false;
bool x21a_fullyCharged = false; bool x21a_fullyCharged = false;
u8 x21b_ = 0; u8 x21b_ = 0;
u32 x21c_; u32 x21c_ = 0;
u32 x220_; u32 x220_ = 0;
u32 x228_; u32 x228_ = 0;
struct SScanReticuleRenderer { struct SScanReticuleRenderer {
std::optional<CLineRenderer> m_lineRenderers[2]; std::array<std::optional<CLineRenderer>, 2> m_lineRenderers;
std::optional<CLineRenderer> m_stripRenderers[2][4]; std::array<std::array<std::optional<CLineRenderer>, 4>, 2> m_stripRenderers;
SScanReticuleRenderer(); SScanReticuleRenderer();
}; };
SScanReticuleRenderer m_scanRetRenderer; SScanReticuleRenderer m_scanRetRenderer;

View File

@ -219,7 +219,7 @@ void CGuiTextSupport::AutoSetExtent() {
void CGuiTextSupport::Render() { void CGuiTextSupport::Render() {
CheckAndRebuildRenderBuffer(); CheckAndRebuildRenderBuffer();
if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
SCOPED_GRAPHICS_DEBUG_GROUP("CGuiTextSupport::Draw", zeus::skBlue); SCOPED_GRAPHICS_DEBUG_GROUP("CGuiTextSupport::Render", zeus::skBlue);
zeus::CTransform oldModel = CGraphics::g_GXModelMatrix; zeus::CTransform oldModel = CGraphics::g_GXModelMatrix;
CGraphics::SetModelMatrix(oldModel * zeus::CTransform::Scale(1.f, 1.f, -1.f)); CGraphics::SetModelMatrix(oldModel * zeus::CTransform::Scale(1.f, 1.f, -1.f));
buf->Render(x2c_geometryColor, x10_curTimeMod900); buf->Render(x2c_geometryColor, x10_curTimeMod900);

View File

@ -15,10 +15,11 @@ CHudBossEnergyInterface::CHudBossEnergyInterface(CGuiFrame& selHud) {
x18_energybart01_bossbar->SetCoordFunc(BossEnergyCoordFunc); x18_energybart01_bossbar->SetCoordFunc(BossEnergyCoordFunc);
x18_energybart01_bossbar->SetTesselation(0.2f); x18_energybart01_bossbar->SetTesselation(0.2f);
ITweakGuiColors::VisorEnergyBarColors barColors = g_tweakGuiColors->GetVisorEnergyBarColors(0);
x18_energybart01_bossbar->SetFilledColor(barColors.filled); const auto& [filled, empty, shadow] = g_tweakGuiColors->GetVisorEnergyBarColors(0);
x18_energybart01_bossbar->SetShadowColor(barColors.shadow); x18_energybart01_bossbar->SetFilledColor(filled);
x18_energybart01_bossbar->SetEmptyColor(barColors.empty); x18_energybart01_bossbar->SetShadowColor(shadow);
x18_energybart01_bossbar->SetEmptyColor(empty);
} }
void CHudBossEnergyInterface::Update(float dt) { void CHudBossEnergyInterface::Update(float dt) {

View File

@ -10,7 +10,7 @@ class CGuiTextPane;
class CGuiWidget; class CGuiWidget;
class CHudBossEnergyInterface { class CHudBossEnergyInterface {
float x0_alpha; float x0_alpha = 0.f;
float x4_fader = 0.f; float x4_fader = 0.f;
float x8_curEnergy = 0.f; float x8_curEnergy = 0.f;
float xc_maxEnergy = 0.f; float xc_maxEnergy = 0.f;

View File

@ -34,7 +34,7 @@ CHudDecoInterfaceCombat::CHudDecoInterfaceCombat(CGuiFrame& selHud) {
x78_basewidget_tickdeco0->SetColor(g_tweakGuiColors->GetTickDecoColor()); x78_basewidget_tickdeco0->SetColor(g_tweakGuiColors->GetTickDecoColor());
x38_basePosition = x7c_basewidget_frame->GetLocalPosition(); x38_basePosition = x7c_basewidget_frame->GetLocalPosition();
x44_baseRotation = x7c_basewidget_frame->GetLocalTransform().buildMatrix3f(); x44_baseRotation = x7c_basewidget_frame->GetLocalTransform().buildMatrix3f();
UpdateHudAlpha(); CHudDecoInterfaceCombat::UpdateHudAlpha();
} }
void CHudDecoInterfaceCombat::UpdateVisibility() { void CHudDecoInterfaceCombat::UpdateVisibility() {
@ -127,7 +127,7 @@ CHudDecoInterfaceScan::CHudDecoInterfaceScan(CGuiFrame& selHud) : x14_selHud(sel
x250_basewidget_rightside->SetLocalPosition(x250_basewidget_rightside->RotateO2P(x224_rightsidePosition - sidesPos)); x250_basewidget_rightside->SetLocalPosition(x250_basewidget_rightside->RotateO2P(x224_rightsidePosition - sidesPos));
x234_sidesPositioner = FLT_MAX; x234_sidesPositioner = FLT_MAX;
UpdateHudAlpha(); CHudDecoInterfaceScan::UpdateHudAlpha();
} }
void CHudDecoInterfaceScan::UpdateVisibility() { void CHudDecoInterfaceScan::UpdateVisibility() {
@ -377,7 +377,7 @@ CHudDecoInterfaceXRay::CHudDecoInterfaceXRay(CGuiFrame& selHud) {
if (CGuiWidget* w = selHud.FindWidget("model_threatslider")) if (CGuiWidget* w = selHud.FindWidget("model_threatslider"))
w->SetDepthWrite(true); w->SetDepthWrite(true);
UpdateHudAlpha(); CHudDecoInterfaceXRay::UpdateHudAlpha();
} }
void CHudDecoInterfaceXRay::UpdateVisibility() { void CHudDecoInterfaceXRay::UpdateVisibility() {
@ -482,7 +482,7 @@ CHudDecoInterfaceThermal::CHudDecoInterfaceThermal(CGuiFrame& selHud) {
} }
x14_pivotPosition = x78_basewidget_pivot->GetIdlePosition(); x14_pivotPosition = x78_basewidget_pivot->GetIdlePosition();
UpdateHudAlpha(); CHudDecoInterfaceThermal::UpdateHudAlpha();
} }
void CHudDecoInterfaceThermal::UpdateVisibility() { void CHudDecoInterfaceThermal::UpdateVisibility() {

View File

@ -45,19 +45,22 @@ void CHudRadarInterface::DoDrawRadarPaint(const zeus::CVector3f& translate, floa
void CHudRadarInterface::DrawRadarPaint(const zeus::CVector3f& enemyPos, float radius, float alpha, void CHudRadarInterface::DrawRadarPaint(const zeus::CVector3f& enemyPos, float radius, float alpha,
const SRadarPaintDrawParms& parms) { const SRadarPaintDrawParms& parms) {
zeus::CVector2f playerToEnemy = enemyPos.toVec2f() - parms.x0_playerPos.toVec2f(); const zeus::CVector2f playerToEnemy = enemyPos.toVec2f() - parms.x0_playerPos.toVec2f();
const float zDelta = std::fabs(enemyPos.z() - parms.x0_playerPos.z());
float zDelta = std::fabs(enemyPos.z() - parms.x0_playerPos.z()); if (playerToEnemy.magnitude() > parms.x78_xyRadius || zDelta > parms.x7c_zRadius) {
return;
if (playerToEnemy.magnitude() <= parms.x78_xyRadius && zDelta <= parms.x7c_zRadius) {
if (zDelta > parms.x80_ZCloseRadius)
alpha *= 1.f - (zDelta - parms.x80_ZCloseRadius) / (parms.x7c_zRadius - parms.x80_ZCloseRadius);
zeus::CVector2f scopeScaled = playerToEnemy * parms.x70_scopeScalar;
zeus::CColor color = g_tweakGuiColors->GetRadarEnemyPaintColor();
color.a() *= alpha;
color.a() *= parms.x74_alpha;
DoDrawRadarPaint(parms.xc_preTranslate * zeus::CVector3f(scopeScaled.x(), 0.f, scopeScaled.y()), radius, color);
} }
if (zDelta > parms.x80_ZCloseRadius) {
alpha *= 1.f - (zDelta - parms.x80_ZCloseRadius) / (parms.x7c_zRadius - parms.x80_ZCloseRadius);
}
const zeus::CVector2f scopeScaled = playerToEnemy * parms.x70_scopeScalar;
zeus::CColor color = g_tweakGuiColors->GetRadarEnemyPaintColor();
color.a() *= alpha;
color.a() *= parms.x74_alpha;
DoDrawRadarPaint(parms.xc_preTranslate * zeus::CVector3f(scopeScaled.x(), 0.f, scopeScaled.y()), radius, color);
} }
void CHudRadarInterface::SetIsVisibleGame(bool v) { void CHudRadarInterface::SetIsVisibleGame(bool v) {
@ -66,29 +69,33 @@ void CHudRadarInterface::SetIsVisibleGame(bool v) {
} }
void CHudRadarInterface::Update(float dt, const CStateManager& mgr) { void CHudRadarInterface::Update(float dt, const CStateManager& mgr) {
CPlayerState& playerState = *mgr.GetPlayerState(); const CPlayerState& playerState = *mgr.GetPlayerState();
float visorTransFactor = (playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Combat) const float visorTransFactor = (playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Combat)
? playerState.GetVisorTransitionFactor() ? playerState.GetVisorTransitionFactor()
: 0.f; : 0.f;
zeus::CColor color = g_tweakGuiColors->GetRadarStuffColor(); zeus::CColor color = g_tweakGuiColors->GetRadarStuffColor();
color.a() *= g_GameState->GameOptions().GetHUDAlpha() / 255.f * visorTransFactor; color.a() *= g_GameState->GameOptions().GetHUDAlpha() / 255.f * visorTransFactor;
x40_BaseWidget_RadarStuff->SetColor(color); x40_BaseWidget_RadarStuff->SetColor(color);
bool tweakVis = g_tweakGui->GetHudVisMode() >= ITweakGui::EHudVisMode::Three; const bool tweakVis = g_tweakGui->GetHudVisMode() >= ITweakGui::EHudVisMode::Three;
if (tweakVis != x3c_25_visibleDebug) {
x3c_25_visibleDebug = tweakVis; if (tweakVis == x3c_25_visibleDebug) {
x40_BaseWidget_RadarStuff->SetVisibility(x3c_25_visibleDebug && x3c_24_visibleGame, ETraversalMode::Children); return;
} }
x3c_25_visibleDebug = tweakVis;
x40_BaseWidget_RadarStuff->SetVisibility(x3c_25_visibleDebug && x3c_24_visibleGame, ETraversalMode::Children);
} }
void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) { void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
alpha *= g_GameState->GameOptions().GetHUDAlpha() / 255.f; alpha *= g_GameState->GameOptions().GetHUDAlpha() / 255.f;
if (g_tweakGui->GetHudVisMode() == ITweakGui::EHudVisMode::Zero || !x3c_24_visibleGame || !x0_txtrRadarPaint || if (g_tweakGui->GetHudVisMode() == ITweakGui::EHudVisMode::Zero || !x3c_24_visibleGame || !x0_txtrRadarPaint ||
!x0_txtrRadarPaint.IsLoaded()) !x0_txtrRadarPaint.IsLoaded()) {
return; return;
}
SRadarPaintDrawParms drawParms; SRadarPaintDrawParms drawParms;
CPlayer& player = mgr.GetPlayer(); const CPlayer& player = mgr.GetPlayer();
if (player.IsOverrideRadarRadius()) { if (player.IsOverrideRadarRadius()) {
drawParms.x78_xyRadius = player.GetRadarXYRadiusOverride(); drawParms.x78_xyRadius = player.GetRadarXYRadiusOverride();
drawParms.x7c_zRadius = player.GetRadarZRadiusOverride(); drawParms.x7c_zRadius = player.GetRadarZRadiusOverride();
@ -102,13 +109,13 @@ void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
drawParms.x6c_scopeRadius = g_tweakGui->GetRadarScopeCoordRadius(); drawParms.x6c_scopeRadius = g_tweakGui->GetRadarScopeCoordRadius();
drawParms.x70_scopeScalar = drawParms.x6c_scopeRadius / drawParms.x78_xyRadius; drawParms.x70_scopeScalar = drawParms.x6c_scopeRadius / drawParms.x78_xyRadius;
float camZ = const float camZ =
zeus::CEulerAngles(zeus::CQuaternion(mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().basis)).z(); zeus::CEulerAngles(zeus::CQuaternion(mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().basis)).z();
zeus::CRelAngle angleZ(camZ); zeus::CRelAngle angleZ(camZ);
angleZ.makeRel(); angleZ.makeRel();
drawParms.xc_preTranslate = zeus::CTransform::RotateY(angleZ); drawParms.xc_preTranslate = zeus::CTransform::RotateY(angleZ);
drawParms.x3c_postTranslate = x40_BaseWidget_RadarStuff->GetWorldTransform(); drawParms.x3c_postTranslate = x40_BaseWidget_RadarStuff->GetWorldTransform();
float enemyRadius = g_tweakGui->GetRadarEnemyPaintRadius(); const float enemyRadius = g_tweakGui->GetRadarEnemyPaintRadius();
m_paintInsts.clear(); m_paintInsts.clear();
x44_camera->Draw(CGuiWidgetDrawParms{0.f, zeus::CVector3f{}}); x44_camera->Draw(CGuiWidgetDrawParms{0.f, zeus::CVector3f{}});
@ -118,7 +125,7 @@ void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
playerColor.a() *= alpha; playerColor.a() *= alpha;
DoDrawRadarPaint(zeus::skZero3f, g_tweakGui->GetRadarPlayerPaintRadius(), playerColor); DoDrawRadarPaint(zeus::skZero3f, g_tweakGui->GetRadarPlayerPaintRadius(), playerColor);
zeus::CAABox radarBounds( const zeus::CAABox radarBounds(
player.GetTranslation().x() - drawParms.x78_xyRadius, player.GetTranslation().y() - drawParms.x78_xyRadius, player.GetTranslation().x() - drawParms.x78_xyRadius, player.GetTranslation().y() - drawParms.x78_xyRadius,
player.GetTranslation().z() - drawParms.x7c_zRadius, player.GetTranslation().x() + drawParms.x78_xyRadius, player.GetTranslation().z() - drawParms.x7c_zRadius, player.GetTranslation().x() + drawParms.x78_xyRadius,
player.GetTranslation().y() + drawParms.x78_xyRadius, player.GetTranslation().z() + drawParms.x7c_zRadius); player.GetTranslation().y() + drawParms.x78_xyRadius, player.GetTranslation().z() + drawParms.x7c_zRadius);
@ -132,15 +139,17 @@ void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
drawParms.x0_playerPos = mgr.GetPlayer().GetTranslation(); drawParms.x0_playerPos = mgr.GetPlayer().GetTranslation();
drawParms.x74_alpha = alpha; drawParms.x74_alpha = alpha;
for (TUniqueId id : nearList) { for (const TUniqueId id : nearList) {
if (TCastToConstPtr<CActor> act = mgr.GetObjectById(id)) { if (const TCastToConstPtr<CActor> act = mgr.GetObjectById(id)) {
if (!act->GetActive()) if (!act->GetActive()) {
continue; continue;
if (TCastToConstPtr<CWallCrawlerSwarm> swarm = act.GetPtr()) { }
float radius = enemyRadius * 0.5f; if (const TCastToConstPtr<CWallCrawlerSwarm> swarm = act.GetPtr()) {
const float radius = enemyRadius * 0.5f;
for (const CWallCrawlerSwarm::CBoid& boid : swarm->GetBoids()) { for (const CWallCrawlerSwarm::CBoid& boid : swarm->GetBoids()) {
if (!boid.GetActive()) if (!boid.GetActive()) {
continue; continue;
}
DrawRadarPaint(boid.GetTranslation(), radius, 0.5f, drawParms); DrawRadarPaint(boid.GetTranslation(), radius, 0.5f, drawParms);
} }
} else { } else {

View File

@ -71,9 +71,10 @@ void CScanDisplay::CDataDot::SetDestPosition(const zeus::CVector2f& pos) {
CScanDisplay::CScanDisplay(const CGuiFrame& selHud) : xa0_selHud(selHud) { CScanDisplay::CScanDisplay(const CGuiFrame& selHud) : xa0_selHud(selHud) {
x0_dataDot = g_SimplePool->GetObj("TXTR_DataDot"); x0_dataDot = g_SimplePool->GetObj("TXTR_DataDot");
for (int i = 0; i < 4; ++i) for (size_t i = 0; i < xbc_dataDots.capacity(); ++i) {
xbc_dataDots.emplace_back(x0_dataDot); xbc_dataDots.emplace_back(x0_dataDot);
x170_paneStates.resize(4); }
x170_paneStates.resize(x170_paneStates.capacity());
} }
void CScanDisplay::ProcessInput(const CFinalInput& input) { void CScanDisplay::ProcessInput(const CFinalInput& input) {
@ -139,26 +140,34 @@ void CScanDisplay::ProcessInput(const CFinalInput& input) {
xb8_dash->SetColor(zeus::CColor(0.53f, 0.84f, 1.f, dashAlpha)); xb8_dash->SetColor(zeus::CColor(0.53f, 0.84f, 1.f, dashAlpha));
} }
float CScanDisplay::GetDownloadStartTime(int idx) const { float CScanDisplay::GetDownloadStartTime(size_t idx) const {
if (!x14_scannableInfo) if (!x14_scannableInfo) {
return 0.f; return 0.f;
float nTime = x14_scannableInfo->GetBucket(idx).x4_appearanceRange;
float maxTime = 0.f;
for (int i = 0; i < 4; ++i) {
float iTime = x14_scannableInfo->GetBucket(i).x4_appearanceRange;
if (iTime < nTime)
maxTime = std::max(iTime, maxTime);
} }
const float nTime = x14_scannableInfo->GetBucket(idx).x4_appearanceRange;
float maxTime = 0.f;
for (size_t i = 0; i < CScannableObjectInfo::NumBuckets; ++i) {
const float iTime = x14_scannableInfo->GetBucket(i).x4_appearanceRange;
if (iTime < nTime) {
maxTime = std::max(iTime, maxTime);
}
}
return maxTime + g_tweakGui->GetScanAppearanceDuration(); return maxTime + g_tweakGui->GetScanAppearanceDuration();
} }
float CScanDisplay::GetDownloadFraction(int idx, float scanningTime) const { float CScanDisplay::GetDownloadFraction(size_t idx, float scanningTime) const {
if (!x14_scannableInfo) if (!x14_scannableInfo) {
return 0.f; return 0.f;
float appearTime = GetDownloadStartTime(idx); }
float appearRange = x14_scannableInfo->GetBucket(idx).x4_appearanceRange;
if (appearTime == appearRange) const float appearTime = GetDownloadStartTime(idx);
const float appearRange = x14_scannableInfo->GetBucket(idx).x4_appearanceRange;
if (appearTime == appearRange) {
return 1.f; return 1.f;
}
return zeus::clamp(0.f, (scanningTime - appearTime) / (appearRange - appearTime), 1.f); return zeus::clamp(0.f, (scanningTime - appearTime) / (appearRange - appearTime), 1.f);
} }
@ -182,26 +191,26 @@ void CScanDisplay::StartScan(TUniqueId id, const CScannableObjectInfo& scanInfo,
xa8_message->TextSupport().SetText(u""); xa8_message->TextSupport().SetText(u"");
xac_scrollMessage->TextSupport().SetText(u""); xac_scrollMessage->TextSupport().SetText(u"");
for (int i = 0; i < 20; ++i) { for (size_t i = 0; i < 20; ++i) {
CAuiImagePane* pane = auto* pane = static_cast<CAuiImagePane*>(xa0_selHud.FindWidget(MP1::CPauseScreenBase::GetImagePaneName(i)));
static_cast<CAuiImagePane*>(xa0_selHud.FindWidget(MP1::CPauseScreenBase::GetImagePaneName(i)));
zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor(); zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor();
color.a() = 0.f; color.a() = 0.f;
pane->SetColor(color); pane->SetColor(color);
pane->SetTextureID0({}, g_SimplePool); pane->SetTextureID0({}, g_SimplePool);
pane->SetAnimationParms(zeus::skZero2f, 0.f, 0.f); pane->SetAnimationParms(zeus::skZero2f, 0.f, 0.f);
int pos = -1; size_t pos = SIZE_MAX;
for (int j = 0; j < 4; ++j) { for (size_t j = 0; j < CScannableObjectInfo::NumBuckets; ++j) {
if (x14_scannableInfo->GetBucket(j).x8_imagePos == i) { if (x14_scannableInfo->GetBucket(j).x8_imagePos == i) {
pos = j; pos = j;
break; break;
} }
} }
if (pos >= 0) if (pos != SIZE_MAX) {
x170_paneStates[pos].second = pane; x170_paneStates[pos].second = pane;
}
} }
for (int i = 0; i < x170_paneStates.size(); ++i) { for (size_t i = 0; i < x170_paneStates.size(); ++i) {
std::pair<float, CAuiImagePane*>& state = x170_paneStates[i]; std::pair<float, CAuiImagePane*>& state = x170_paneStates[i];
if (state.second) { if (state.second) {
const CScannableObjectInfo::SBucket& bucket = x14_scannableInfo->GetBucket(i); const CScannableObjectInfo::SBucket& bucket = x14_scannableInfo->GetBucket(i);
@ -211,22 +220,25 @@ void CScanDisplay::StartScan(TUniqueId id, const CScannableObjectInfo& scanInfo,
} }
state.second->SetTextureID0(bucket.x0_texture, g_SimplePool); state.second->SetTextureID0(bucket.x0_texture, g_SimplePool);
state.second->SetFlashFactor(0.f); state.second->SetFlashFactor(0.f);
float startTime = GetDownloadStartTime(i);
if (scanTime >= startTime) const float startTime = GetDownloadStartTime(i);
if (scanTime >= startTime) {
x170_paneStates[i].first = 0.f; x170_paneStates[i].first = 0.f;
else } else {
x170_paneStates[i].first = -1.f; x170_paneStates[i].first = -1.f;
}
} }
} }
CAssetId strId = x14_scannableInfo->GetStringTableId(); const CAssetId strId = x14_scannableInfo->GetStringTableId();
if (strId.IsValid()) if (strId.IsValid()) {
x194_scanStr = g_SimplePool->GetObj({FOURCC('STRG'), strId}); x194_scanStr = g_SimplePool->GetObj({FOURCC('STRG'), strId});
}
for (int i = 0; i < 4; ++i) { for (size_t i = 0; i < CScannableObjectInfo::NumBuckets; ++i) {
int pos = x14_scannableInfo->GetBucket(i).x8_imagePos; const u32 pos = x14_scannableInfo->GetBucket(i).x8_imagePos;
CDataDot& dot = xbc_dataDots[i]; CDataDot& dot = xbc_dataDots[i];
if (pos != -1) { if (pos != UINT32_MAX) {
if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanTime) { if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanTime) {
dot.SetAlpha(0.f); dot.SetAlpha(0.f);
dot.SetDotState(CDataDot::EDotState::Done); dot.SetDotState(CDataDot::EDotState::Done);
@ -243,12 +255,14 @@ void CScanDisplay::StartScan(TUniqueId id, const CScannableObjectInfo& scanInfo,
} }
void CScanDisplay::StopScan() { void CScanDisplay::StopScan() {
if (xc_state == EScanState::Done || xc_state == EScanState::Inactive) if (xc_state == EScanState::Done || xc_state == EScanState::Inactive) {
return; return;
}
xc_state = EScanState::Done; xc_state = EScanState::Done;
for (int i = 0; i < 4; ++i) for (auto& dataDot : xbc_dataDots) {
xbc_dataDots[i].SetDesiredAlpha(0.f); dataDot.SetDesiredAlpha(0.f);
}
} }
void CScanDisplay::SetScanMessageTypeEffect(CGuiTextPane* pane, bool type) { void CScanDisplay::SetScanMessageTypeEffect(CGuiTextPane* pane, bool type) {
@ -310,25 +324,30 @@ void CScanDisplay::Update(float dt, float scanningTime) {
} }
} }
for (int i = 0; i < 4; ++i) { for (size_t i = 0; i < x170_paneStates.size(); ++i) {
if (x170_paneStates[i].second == nullptr) if (x170_paneStates[i].second == nullptr) {
continue; continue;
}
if (x170_paneStates[i].first > 0.f) { if (x170_paneStates[i].first > 0.f) {
x170_paneStates[i].first = std::max(0.f, x170_paneStates[i].first - dt); x170_paneStates[i].first = std::max(0.f, x170_paneStates[i].first - dt);
float tmp; float tmp;
if (x170_paneStates[i].first > g_tweakGui->GetScanPaneFadeOutTime()) if (x170_paneStates[i].first > g_tweakGui->GetScanPaneFadeOutTime()) {
tmp = 1.f - tmp = 1.f -
(x170_paneStates[i].first - g_tweakGui->GetScanPaneFadeOutTime()) / g_tweakGui->GetScanPaneFadeInTime(); (x170_paneStates[i].first - g_tweakGui->GetScanPaneFadeOutTime()) / g_tweakGui->GetScanPaneFadeInTime();
else } else {
tmp = x170_paneStates[i].first / g_tweakGui->GetScanPaneFadeOutTime(); tmp = x170_paneStates[i].first / g_tweakGui->GetScanPaneFadeOutTime();
}
x170_paneStates[i].second->SetFlashFactor(tmp * g_tweakGui->GetScanPaneFlashFactor() * x1a8_bodyAlpha); x170_paneStates[i].second->SetFlashFactor(tmp * g_tweakGui->GetScanPaneFlashFactor() * x1a8_bodyAlpha);
} }
float alphaMul =
const float alphaMul =
((xc_state == EScanState::Downloading) ? GetDownloadFraction(i, scanningTime) : 1.f) * x1a8_bodyAlpha; ((xc_state == EScanState::Downloading) ? GetDownloadFraction(i, scanningTime) : 1.f) * x1a8_bodyAlpha;
zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor(); zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor();
color.a() *= alphaMul; color.a() *= alphaMul;
x170_paneStates[i].second->SetColor(color); x170_paneStates[i].second->SetColor(color);
x170_paneStates[i].second->SetDeResFactor(1.f - alphaMul); x170_paneStates[i].second->SetDeResFactor(1.f - alphaMul);
if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanningTime) { if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanningTime) {
CDataDot& dot = xbc_dataDots[i]; CDataDot& dot = xbc_dataDots[i];
switch (dot.GetDotState()) { switch (dot.GetDotState()) {
@ -338,7 +357,7 @@ void CScanDisplay::Update(float dt, float scanningTime) {
dot.StartTransitionTo(zeus::skZero2f, g_tweakGui->GetScanAppearanceDuration()); dot.StartTransitionTo(zeus::skZero2f, g_tweakGui->GetScanAppearanceDuration());
break; break;
case CDataDot::EDotState::RevealPane: { case CDataDot::EDotState::RevealPane: {
float tmp = dot.GetTransitionFactor(); const float tmp = dot.GetTransitionFactor();
if (tmp == 0.f) { if (tmp == 0.f) {
dot.SetDotState(CDataDot::EDotState::Done); dot.SetDotState(CDataDot::EDotState::Done);
dot.SetDesiredAlpha(0.f); dot.SetDesiredAlpha(0.f);
@ -353,7 +372,7 @@ void CScanDisplay::Update(float dt, float scanningTime) {
} }
} }
for (int i = 0; i < 4; ++i) { for (size_t i = 0; i < xbc_dataDots.size(); ++i) {
CDataDot& dot = xbc_dataDots[i]; CDataDot& dot = xbc_dataDots[i];
switch (dot.GetDotState()) { switch (dot.GetDotState()) {
case CDataDot::EDotState::Hidden: case CDataDot::EDotState::Hidden:

View File

@ -79,8 +79,8 @@ private:
float x1b0_aPulse = 1.f; float x1b0_aPulse = 1.f;
bool x1b4_scanComplete = false; bool x1b4_scanComplete = false;
float GetDownloadStartTime(int idx) const; float GetDownloadStartTime(size_t idx) const;
float GetDownloadFraction(int idx, float scanningTime) const; float GetDownloadFraction(size_t idx, float scanningTime) const;
static void SetScanMessageTypeEffect(CGuiTextPane* pane, bool type); static void SetScanMessageTypeEffect(CGuiTextPane* pane, bool type);
public: public:

View File

@ -27,8 +27,8 @@ class CTextExecuteBuffer {
CBlockInstruction* xa0_curBlock = nullptr; CBlockInstruction* xa0_curBlock = nullptr;
CLineInstruction* xa4_curLine = nullptr; CLineInstruction* xa4_curLine = nullptr;
InstList::iterator xa8_curWordIt; InstList::iterator xa8_curWordIt;
s32 xac_curY; s32 xac_curY = 0;
s32 xb0_curX; s32 xb0_curX = 0;
s32 xb4_curWordX = 0; s32 xb4_curWordX = 0;
s32 xb8_curWordY = 0; s32 xb8_curWordY = 0;
s32 xbc_spaceDistance = 0; s32 xbc_spaceDistance = 0;
@ -37,7 +37,7 @@ class CTextExecuteBuffer {
u32 xd8_ = 0; u32 xd8_ = 0;
public: public:
CTextExecuteBuffer() { xa8_curWordIt = x0_instList.begin(); } CTextExecuteBuffer() : xa8_curWordIt{x0_instList.begin()} {}
CTextRenderBuffer BuildRenderBuffer(CGuiWidget::EGuiModelDrawFlags df) const; CTextRenderBuffer BuildRenderBuffer(CGuiWidget::EGuiModelDrawFlags df) const;
CTextRenderBuffer BuildRenderBufferPage(InstList::const_iterator start, InstList::const_iterator pgStart, CTextRenderBuffer BuildRenderBufferPage(InstList::const_iterator start, InstList::const_iterator pgStart,

View File

@ -214,10 +214,11 @@ void CLogBookScreen::UpdateBodyImagesAndText() {
pane->SetAnimationParms(zeus::skZero2f, 0.f, 0.f); pane->SetAnimationParms(zeus::skZero2f, 0.f, 0.f);
} }
for (int i = 0; i < 4; ++i) { for (size_t i = 0; i < CScannableObjectInfo::NumBuckets; ++i) {
const CScannableObjectInfo::SBucket& bucket = scan->GetBucket(i); const CScannableObjectInfo::SBucket& bucket = scan->GetBucket(i);
if (bucket.x8_imagePos == UINT32_MAX) if (bucket.x8_imagePos == UINT32_MAX) {
continue; continue;
}
CAuiImagePane* pane = xf0_imagePanes[bucket.x8_imagePos]; CAuiImagePane* pane = xf0_imagePanes[bucket.x8_imagePos];
if (bucket.x14_interval > 0.f) { if (bucket.x14_interval > 0.f) {
pane->SetAnimationParms(zeus::CVector2f(bucket.xc_size.x, bucket.xc_size.y), bucket.x14_interval, pane->SetAnimationParms(zeus::CVector2f(bucket.xc_size.x, bucket.xc_size.y), bucket.x14_interval,

View File

@ -536,7 +536,7 @@ void CPauseScreenBase::OnWidgetScroll(CGuiWidget* widget, const boo::SScrollDelt
} }
} }
std::string CPauseScreenBase::GetImagePaneName(u32 i) { std::string CPauseScreenBase::GetImagePaneName(size_t i) {
static constexpr std::array PaneSuffixes{ static constexpr std::array PaneSuffixes{
"0", "1", "2", "3", "01", "12", "23", "012", "123", "0123", "0", "1", "2", "3", "01", "12", "23", "012", "123", "0123",
"4", "5", "6", "7", "45", "56", "67", "456", "567", "4567", "4", "5", "6", "7", "45", "56", "67", "456", "567", "4567",

View File

@ -102,7 +102,7 @@ protected:
void OnWidgetScroll(CGuiWidget* widget, const boo::SScrollDelta& delta, int accumX, int accumY); void OnWidgetScroll(CGuiWidget* widget, const boo::SScrollDelta& delta, int accumX, int accumY);
public: public:
static std::string GetImagePaneName(u32 i); static std::string GetImagePaneName(size_t i);
CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg, bool isLogBook = false); CPauseScreenBase(const CStateManager& mgr, CGuiFrame& frame, const CStringTable& pauseStrg, bool isLogBook = false);

View File

@ -714,6 +714,7 @@ void CMain::Init(const hecl::Runtime::FileStoreManager& storeMgr, hecl::CVarMana
InitializeDiscord(); InitializeDiscord();
m_mainWindow = window; m_mainWindow = window;
m_cvarMgr = cvarMgr; m_cvarMgr = cvarMgr;
m_cvarCommons = std::make_unique<hecl::CVarCommons>(*m_cvarMgr);
m_console = std::make_unique<hecl::Console>(m_cvarMgr); m_console = std::make_unique<hecl::Console>(m_cvarMgr);
m_console->init(window); m_console->init(window);
m_console->registerCommand( m_console->registerCommand(
@ -847,16 +848,16 @@ bool CMain::Proc() {
} }
float dt = 1 / 60.f; float dt = 1 / 60.f;
#if MP1_VARIABLE_DELTA_TIME if (m_cvarCommons->m_variableDt->toBoolean()) {
auto now = delta_clock::now(); auto now = delta_clock::now();
if (m_firstFrame) { if (m_firstFrame) {
m_firstFrame = false; m_firstFrame = false;
} else { } else {
using delta_duration = std::chrono::duration<float, std::ratio<1>>; using delta_duration = std::chrono::duration<float, std::ratio<1>>;
dt = std::min(std::chrono::duration_cast<delta_duration>(now - m_prevFrameTime).count(), dt); dt = std::min(std::chrono::duration_cast<delta_duration>(now - m_prevFrameTime).count(), 1 / 30.f);
}
m_prevFrameTime = now;
} }
m_prevFrameTime = now;
#endif
m_console->proc(); m_console->proc();
if (!m_console->isOpen()) { if (!m_console->isOpen()) {

View File

@ -3,9 +3,6 @@
#ifndef MP1_USE_BOO #ifndef MP1_USE_BOO
#define MP1_USE_BOO 0 #define MP1_USE_BOO 0
#endif #endif
#ifndef MP1_VARIABLE_DELTA_TIME
#define MP1_VARIABLE_DELTA_TIME 1
#endif
#include "Runtime/IMain.hpp" #include "Runtime/IMain.hpp"
#include "Runtime/MP1/CTweaks.hpp" #include "Runtime/MP1/CTweaks.hpp"
@ -41,6 +38,7 @@
#include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp" #include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp"
#include "DataSpec/DNAMP1/Tweaks/CTweakGame.hpp" #include "DataSpec/DNAMP1/Tweaks/CTweakGame.hpp"
#include "hecl/Console.hpp" #include "hecl/Console.hpp"
#include "hecl/CVarCommons.hpp"
struct DiscordUser; struct DiscordUser;
@ -234,6 +232,7 @@ private:
boo::IWindow* m_mainWindow = nullptr; boo::IWindow* m_mainWindow = nullptr;
hecl::CVarManager* m_cvarMgr = nullptr; hecl::CVarManager* m_cvarMgr = nullptr;
std::unique_ptr<hecl::CVarCommons> m_cvarCommons;
std::unique_ptr<hecl::Console> m_console; std::unique_ptr<hecl::Console> m_console;
// Warmup state // Warmup state
std::vector<SObjectTag> m_warmupTags; std::vector<SObjectTag> m_warmupTags;
@ -242,11 +241,9 @@ private:
bool m_loadedPersistentResources = false; bool m_loadedPersistentResources = false;
bool m_doQuit = false; bool m_doQuit = false;
#if MP1_VARIABLE_DELTA_TIME
bool m_firstFrame = true; bool m_firstFrame = true;
using delta_clock = std::chrono::high_resolution_clock; using delta_clock = std::chrono::high_resolution_clock;
std::chrono::time_point<delta_clock> m_prevFrameTime; std::chrono::time_point<delta_clock> m_prevFrameTime;
#endif
void InitializeSubsystems(); void InitializeSubsystems();
static void InitializeDiscord(); static void InitializeDiscord();

View File

@ -1136,8 +1136,7 @@ void CElementGen::RenderLines() {
m_lineRenderer->Reset(); m_lineRenderer->Reset();
for (size_t i = 0; i < x30_particles.size(); ++i) { for (auto& particle : x30_particles) {
CParticle& particle = x30_particles[i];
g_currentParticle = &particle; g_currentParticle = &particle;
int partFrame = x74_curFrame - particle.x28_startFrame; int partFrame = x74_curFrame - particle.x28_startFrame;

View File

@ -60,7 +60,7 @@ private:
int x70_internalStartFrame = 0; int x70_internalStartFrame = 0;
int x74_curFrame = 0; int x74_curFrame = 0;
double x78_curSeconds = 0.f; double x78_curSeconds = 0.f;
float x80_timeDeltaScale; float x80_timeDeltaScale = 0.f;
int x84_prevFrame = -1; int x84_prevFrame = -1;
bool x88_particleEmission = true; bool x88_particleEmission = true;
float x8c_generatorRemainder = 0.f; float x8c_generatorRemainder = 0.f;

View File

@ -137,7 +137,7 @@ class CIESampleAndHold : public CIntElement {
mutable int x8_nextSampleFrame = 0; mutable int x8_nextSampleFrame = 0;
std::unique_ptr<CIntElement> xc_waitFramesMin; std::unique_ptr<CIntElement> xc_waitFramesMin;
std::unique_ptr<CIntElement> x10_waitFramesMax; std::unique_ptr<CIntElement> x10_waitFramesMax;
mutable int x14_holdVal; mutable int x14_holdVal = 0;
public: public:
CIESampleAndHold(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c) CIESampleAndHold(std::unique_ptr<CIntElement>&& a, std::unique_ptr<CIntElement>&& b, std::unique_ptr<CIntElement>&& c)

View File

@ -1,5 +1,7 @@
#include "Runtime/Particle/CParticleElectric.hpp" #include "Runtime/Particle/CParticleElectric.hpp"
#include <algorithm>
#include "Runtime/GameGlobalObjects.hpp" #include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp" #include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Graphics/CGraphics.hpp" #include "Runtime/Graphics/CGraphics.hpp"
@ -31,18 +33,21 @@ CParticleElectric::CParticleElectric(const TToken<CElectricDescription>& token)
CElectricDescription* desc = x1c_elecDesc.GetObj(); CElectricDescription* desc = x1c_elecDesc.GetObj();
if (CIntElement* sseg = desc->x10_SSEG.get()) if (CIntElement* sseg = desc->x10_SSEG.get()) {
sseg->GetValue(x28_currentFrame, x150_SSEG); sseg->GetValue(x28_currentFrame, x150_SSEG);
}
if (CIntElement* scnt = desc->xc_SCNT.get()) if (CIntElement* scnt = desc->xc_SCNT.get()) {
scnt->GetValue(x28_currentFrame, x154_SCNT); scnt->GetValue(x28_currentFrame, x154_SCNT);
}
x154_SCNT = std::min(x154_SCNT, 32); x154_SCNT = std::min(x154_SCNT, 32);
if (CIntElement* life = desc->x0_LIFE.get()) if (CIntElement* life = desc->x0_LIFE.get()) {
life->GetValue(0, x2c_LIFE); life->GetValue(0, x2c_LIFE);
else } else {
x2c_LIFE = INT_MAX; x2c_LIFE = INT_MAX;
}
if (desc->x40_SSWH) { if (desc->x40_SSWH) {
x450_27_haveSSWH = true; x450_27_haveSSWH = true;
@ -84,8 +89,9 @@ CParticleElectric::CParticleElectric(const TToken<CElectricDescription>& token)
} }
void CParticleElectric::RenderSwooshes() { void CParticleElectric::RenderSwooshes() {
for (CParticleElectricManager& elec : x3e8_electricManagers) for (const CParticleElectricManager& elec : x3e8_electricManagers) {
x1e0_swooshGenerators[elec.x0_idx]->Render(); x1e0_swooshGenerators[elec.x0_idx]->Render();
}
} }
void CParticleElectric::SetupLineGXMaterial() { void CParticleElectric::SetupLineGXMaterial() {
@ -94,18 +100,21 @@ void CParticleElectric::SetupLineGXMaterial() {
void CParticleElectric::DrawLineStrip(const std::vector<zeus::CVector3f>& verts, float width, void CParticleElectric::DrawLineStrip(const std::vector<zeus::CVector3f>& verts, float width,
const zeus::CColor& color) { const zeus::CColor& color) {
size_t useIdx = m_nextLineRenderer; const size_t useIdx = m_nextLineRenderer;
if (++m_nextLineRenderer > m_lineRenderers.size()) if (++m_nextLineRenderer > m_lineRenderers.size()) {
m_lineRenderers.resize(m_nextLineRenderer); m_lineRenderers.resize(m_nextLineRenderer);
if (!m_lineRenderers[useIdx]) }
if (!m_lineRenderers[useIdx]) {
m_lineRenderers[useIdx] = m_lineRenderers[useIdx] =
std::make_unique<CLineRenderer>(CLineRenderer::EPrimitiveMode::LineStrip, x150_SSEG, nullptr, true, true); std::make_unique<CLineRenderer>(CLineRenderer::EPrimitiveMode::LineStrip, x150_SSEG, nullptr, true, true);
}
CLineRenderer& renderer = *m_lineRenderers[useIdx]; CLineRenderer& renderer = *m_lineRenderers[useIdx];
zeus::CColor useColor = x1b8_moduColor * color; const zeus::CColor useColor = x1b8_moduColor * color;
renderer.Reset(); renderer.Reset();
for (const zeus::CVector3f& vert : verts) for (const zeus::CVector3f& vert : verts) {
renderer.AddVertex(vert, useColor, width); renderer.AddVertex(vert, useColor, width);
}
renderer.Render(g_Renderer->IsThermalVisorHotPass()); renderer.Render(g_Renderer->IsThermalVisorHotPass());
} }
@ -122,12 +131,15 @@ void CParticleElectric::RenderLines() {
SetupLineGXMaterial(); SetupLineGXMaterial();
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (CParticleElectricManager& elec : x3e8_electricManagers) {
CLineManager& line = *x2e4_lineManagers[elec.x0_idx]; CLineManager& line = *x2e4_lineManagers[elec.x0_idx];
if (x1c_elecDesc->x28_LWD1) if (x1c_elecDesc->x28_LWD1) {
DrawLineStrip(line.x0_verts, line.x10_widths[0], line.x1c_colors[0]); DrawLineStrip(line.x0_verts, line.x10_widths[0], line.x1c_colors[0]);
if (x1c_elecDesc->x2c_LWD2) }
if (x1c_elecDesc->x2c_LWD2) {
DrawLineStrip(line.x0_verts, line.x10_widths[1], line.x1c_colors[1]); DrawLineStrip(line.x0_verts, line.x10_widths[1], line.x1c_colors[1]);
if (x1c_elecDesc->x30_LWD3) }
if (x1c_elecDesc->x30_LWD3) {
DrawLineStrip(line.x0_verts, line.x10_widths[2], line.x1c_colors[2]); DrawLineStrip(line.x0_verts, line.x10_widths[2], line.x1c_colors[2]);
}
} }
// Enable culling // Enable culling
@ -140,22 +152,28 @@ void CParticleElectric::UpdateCachedTransform() {
x450_29_transformDirty = false; x450_29_transformDirty = false;
} }
void CParticleElectric::UpdateLine(int idx, int frame) { void CParticleElectric::UpdateLine(size_t idx, int frame) {
CLineManager& line = *x2e4_lineManagers[idx]; CLineManager& line = *x2e4_lineManagers[idx];
if (CColorElement* lcl1 = x1c_elecDesc->x34_LCL1.get()) if (CColorElement* lcl1 = x1c_elecDesc->x34_LCL1.get()) {
lcl1->GetValue(frame, line.x1c_colors[0]); lcl1->GetValue(frame, line.x1c_colors[0]);
if (CColorElement* lcl2 = x1c_elecDesc->x38_LCL2.get()) }
if (CColorElement* lcl2 = x1c_elecDesc->x38_LCL2.get()) {
lcl2->GetValue(frame, line.x1c_colors[1]); lcl2->GetValue(frame, line.x1c_colors[1]);
if (CColorElement* lcl3 = x1c_elecDesc->x3c_LCL3.get()) }
if (CColorElement* lcl3 = x1c_elecDesc->x3c_LCL3.get()) {
lcl3->GetValue(frame, line.x1c_colors[2]); lcl3->GetValue(frame, line.x1c_colors[2]);
}
if (CRealElement* lwd1 = x1c_elecDesc->x28_LWD1.get()) if (CRealElement* lwd1 = x1c_elecDesc->x28_LWD1.get()) {
lwd1->GetValue(frame, line.x10_widths[0]); lwd1->GetValue(frame, line.x10_widths[0]);
if (CRealElement* lwd2 = x1c_elecDesc->x2c_LWD2.get()) }
if (CRealElement* lwd2 = x1c_elecDesc->x2c_LWD2.get()) {
lwd2->GetValue(frame, line.x10_widths[1]); lwd2->GetValue(frame, line.x10_widths[1]);
if (CRealElement* lwd3 = x1c_elecDesc->x30_LWD3.get()) }
if (CRealElement* lwd3 = x1c_elecDesc->x30_LWD3.get()) {
lwd3->GetValue(frame, line.x10_widths[2]); lwd3->GetValue(frame, line.x10_widths[2]);
}
} }
void CParticleElectric::UpdateElectricalEffects() { void CParticleElectric::UpdateElectricalEffects() {
@ -163,28 +181,32 @@ void CParticleElectric::UpdateElectricalEffects() {
CParticleElectricManager& elec = *it; CParticleElectricManager& elec = *it;
if (elec.x4_slif <= 1) { if (elec.x4_slif <= 1) {
x1bc_allocated[elec.x0_idx] = false; x1bc_allocated[elec.x0_idx] = false;
if (elec.x10_gpsmIdx != -1) if (elec.x10_gpsmIdx != -1) {
x400_gpsmGenerators[elec.x10_gpsmIdx]->SetParticleEmission(false); x400_gpsmGenerators[elec.x10_gpsmIdx]->SetParticleEmission(false);
if (elec.x14_epsmIdx != -1) }
if (elec.x14_epsmIdx != -1) {
x410_epsmGenerators[elec.x14_epsmIdx]->SetParticleEmission(false); x410_epsmGenerators[elec.x14_epsmIdx]->SetParticleEmission(false);
}
it = x3e8_electricManagers.erase(it); it = x3e8_electricManagers.erase(it);
continue; continue;
} }
CParticleGlobals::instance()->SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame); CParticleGlobals::instance()->SetParticleLifetime(int(elec.xc_endFrame - elec.x8_startFrame));
int frame = x28_currentFrame - elec.x8_startFrame; const int frame = x28_currentFrame - int(elec.x8_startFrame);
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame); CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame);
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
zeus::CColor color = zeus::skWhite; zeus::CColor color = zeus::skWhite;
if (CColorElement* colr = x1c_elecDesc->x14_COLR.get()) if (CColorElement* colr = x1c_elecDesc->x14_COLR.get()) {
colr->GetValue(frame, color); colr->GetValue(frame, color);
}
swoosh.SetModulationColor(color * x1b8_moduColor); swoosh.SetModulationColor(color * x1b8_moduColor);
} }
if (x450_28_haveLWD) if (x450_28_haveLWD) {
UpdateLine(elec.x0_idx, frame); UpdateLine(elec.x0_idx, frame);
}
elec.x4_slif -= 1; elec.x4_slif -= 1;
++it; ++it;
@ -192,28 +214,34 @@ void CParticleElectric::UpdateElectricalEffects() {
} }
void CParticleElectric::CalculateFractal(int start, int end, float ampl, float ampd) { void CParticleElectric::CalculateFractal(int start, int end, float ampl, float ampd) {
float tmp = (end - start) / float(x430_fractalMags.size()) * ampl; const float tmp = float(end - start) / float(x430_fractalMags.size()) * ampl;
int storeIdx = (start + end) / 2; const int storeIdx = (start + end) / 2;
x430_fractalMags[storeIdx] = (x430_fractalMags[start] + x430_fractalMags[end]) * 0.5f + tmp * x14c_randState.Float() - x430_fractalMags[storeIdx] = (x430_fractalMags[start] + x430_fractalMags[end]) * 0.5f + tmp * x14c_randState.Float() -
tmp * 0.5f + ampd * x14c_randState.Float() - ampd * 0.5f; tmp * 0.5f + ampd * x14c_randState.Float() - ampd * 0.5f;
if ((start + end) & 1) if (((start + end) & 1) != 0) {
x430_fractalMags[end - 1] = x430_fractalMags[end]; x430_fractalMags[end - 1] = x430_fractalMags[end];
}
if (storeIdx - start > 1) if (storeIdx - start > 1) {
CalculateFractal(start, storeIdx, ampl, ampd); CalculateFractal(start, storeIdx, ampl, ampd);
if (end - storeIdx > 1) }
if (end - storeIdx > 1) {
CalculateFractal(storeIdx, end, ampl, ampd); CalculateFractal(storeIdx, end, ampl, ampd);
}
} }
void CParticleElectric::CalculatePoints() { void CParticleElectric::CalculatePoints() {
zeus::CVector3f pos, vel; zeus::CVector3f pos, vel;
if (CEmitterElement* iemt = x1c_elecDesc->x18_IEMT.get()) if (CEmitterElement* iemt = x1c_elecDesc->x18_IEMT.get()) {
iemt->GetValue(x28_currentFrame, pos, vel); iemt->GetValue(x28_currentFrame, pos, vel);
}
if (x178_overrideIPos) if (x178_overrideIPos) {
pos = *x178_overrideIPos; pos = *x178_overrideIPos;
if (x188_overrideIVel) }
if (x188_overrideIVel) {
vel = *x188_overrideIVel; vel = *x188_overrideIVel;
}
rstl::reserved_vector<zeus::CVector3f, 4> points; rstl::reserved_vector<zeus::CVector3f, 4> points;
@ -227,13 +255,16 @@ void CParticleElectric::CalculatePoints() {
zeus::CVector3f fpos = zeus::skForward; zeus::CVector3f fpos = zeus::skForward;
zeus::CVector3f fvel; zeus::CVector3f fvel;
if (CEmitterElement* femt = x1c_elecDesc->x1c_FEMT.get()) if (CEmitterElement* femt = x1c_elecDesc->x1c_FEMT.get()) {
femt->GetValue(x28_currentFrame, fpos, fvel); femt->GetValue(x28_currentFrame, fpos, fvel);
}
if (x198_overrideFPos) if (x198_overrideFPos) {
fpos = *x198_overrideFPos; fpos = *x198_overrideFPos;
if (x1a8_overrideFVel) }
if (x1a8_overrideFVel) {
fvel = *x1a8_overrideFVel; fvel = *x1a8_overrideFVel;
}
if (!fvel.isZero()) { if (!fvel.isZero()) {
if (points.size() == 3) { if (points.size() == 3) {
@ -249,21 +280,21 @@ void CParticleElectric::CalculatePoints() {
} }
if (points.size() == 4) { if (points.size() == 4) {
int segs = x150_SSEG - 1; const int segs = x150_SSEG - 1;
float segDiv = 1.f / float(segs); const float segDiv = 1.f / float(segs);
float curDiv = segDiv; float curDiv = segDiv;
for (int i = 1; i < segs; ++i) { for (int i = 1; i < segs; ++i) {
float t = segDiv * x14c_randState.Range(-0.45f, 0.45f) + curDiv; const float t = segDiv * x14c_randState.Range(-0.45f, 0.45f) + curDiv;
x420_calculatedVerts[i] = zeus::getBezierPoint(points[0], points[1], points[2], points[3], t); x420_calculatedVerts[i] = zeus::getBezierPoint(points[0], points[1], points[2], points[3], t);
curDiv += segDiv; curDiv += segDiv;
} }
x420_calculatedVerts[segs] = points[3]; x420_calculatedVerts[segs] = points[3];
} else { } else {
x420_calculatedVerts[0] = pos; x420_calculatedVerts[0] = pos;
int segs = x150_SSEG - 1; const int segs = x150_SSEG - 1;
float segDiv = 1.f / float(segs); const float segDiv = 1.f / float(segs);
zeus::CVector3f accum = x420_calculatedVerts[0]; zeus::CVector3f accum = x420_calculatedVerts[0];
zeus::CVector3f segDelta = (fpos - pos) * segDiv; const zeus::CVector3f segDelta = (fpos - pos) * segDiv;
for (int i = 1; i < segs; ++i) { for (int i = 1; i < segs; ++i) {
float r = x14c_randState.Range(-0.45f, 0.45f); float r = x14c_randState.Range(-0.45f, 0.45f);
x420_calculatedVerts[i] = segDelta * r + accum; x420_calculatedVerts[i] = segDelta * r + accum;
@ -272,8 +303,9 @@ void CParticleElectric::CalculatePoints() {
x420_calculatedVerts[segs] = fpos; x420_calculatedVerts[segs] = fpos;
} }
for (int i = 0; i < x150_SSEG; ++i) for (int i = 0; i < x150_SSEG; ++i) {
x430_fractalMags[i] = 0.f; x430_fractalMags[i] = 0.f;
}
float amplVal = 1.f; float amplVal = 1.f;
if (CRealElement* ampl = x1c_elecDesc->x20_AMPL.get()) { if (CRealElement* ampl = x1c_elecDesc->x20_AMPL.get()) {
@ -282,8 +314,9 @@ void CParticleElectric::CalculatePoints() {
} }
float ampdVal = 0.f; float ampdVal = 0.f;
if (CRealElement* ampd = x1c_elecDesc->x24_AMPD.get()) if (CRealElement* ampd = x1c_elecDesc->x24_AMPD.get()) {
ampd->GetValue(x28_currentFrame, ampdVal); ampd->GetValue(x28_currentFrame, ampdVal);
}
CalculateFractal(0, x420_calculatedVerts.size() - 1, amplVal, ampdVal); CalculateFractal(0, x420_calculatedVerts.size() - 1, amplVal, ampdVal);
@ -294,55 +327,63 @@ void CParticleElectric::CalculatePoints() {
v0.normalize(); v0.normalize();
v1.normalize(); v1.normalize();
float dot = v0.dot(v1); float dot = v0.dot(v1);
if (dot < 0) if (dot < 0) {
dot = -dot; dot = -dot;
if (std::fabs(dot - 1.f) < 0.00001f) }
if (std::fabs(dot - 1.f) < 0.00001f) {
upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2]; upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2];
else } else {
upVec = v0.cross(v1).normalized(); upVec = v0.cross(v1).normalized();
}
} else if (x420_calculatedVerts[0] != x420_calculatedVerts[1]) { } else if (x420_calculatedVerts[0] != x420_calculatedVerts[1]) {
upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2]; upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2];
} }
float commonRand = x14c_randState.Range(0.f, 360.f); const float commonRand = x14c_randState.Range(0.f, 360.f);
for (int i = 1; i < x420_calculatedVerts.size() - 1; ++i) { for (size_t i = 1; i < x420_calculatedVerts.size() - 1; ++i) {
zeus::CVector3f delta = x420_calculatedVerts[i] - x420_calculatedVerts[i - 1]; const zeus::CVector3f delta = x420_calculatedVerts[i] - x420_calculatedVerts[i - 1];
if (!delta.isZero()) { if (!delta.isZero()) {
zeus::CRelAngle angle = const zeus::CRelAngle angle =
zeus::degToRad(x430_fractalMags[i] / amplVal * 16.f * x14c_randState.Range(-1.f, 1.f) + commonRand); zeus::degToRad(x430_fractalMags[i] / amplVal * 16.f * x14c_randState.Range(-1.f, 1.f) + commonRand);
x440_fractalOffsets[i] = zeus::CQuaternion::fromAxisAngle(delta, angle).transform(x430_fractalMags[i] * upVec); x440_fractalOffsets[i] = zeus::CQuaternion::fromAxisAngle(delta, angle).transform(x430_fractalMags[i] * upVec);
} }
} }
for (int i = 1; i < x420_calculatedVerts.size() - 1; ++i) for (size_t i = 1; i < x420_calculatedVerts.size() - 1; ++i) {
x420_calculatedVerts[i] += x440_fractalOffsets[i]; x420_calculatedVerts[i] += x440_fractalOffsets[i];
}
if (x1c_elecDesc->x70_ZERY) if (x1c_elecDesc->x70_ZERY) {
for (int i = 0; i < x420_calculatedVerts.size(); ++i) for (auto& calculatedVert : x420_calculatedVerts) {
x420_calculatedVerts[i].y() = 0.f; calculatedVert.y() = 0.f;
}
}
} }
void CParticleElectric::CreateNewParticles(int count) { void CParticleElectric::CreateNewParticles(int count) {
int allocIdx = 0; size_t allocIdx = 0;
for (int i = 0; i < count; ++i) {
if (x3e8_electricManagers.size() < x154_SCNT) {
zeus::CTransform cachedRot = xf8_cachedXf.getRotation();
int toAdd = x1bc_allocated.size() - allocIdx; for (int i = 0; i < count; ++i) {
for (int j = 0; j < toAdd; ++j, ++allocIdx) { if (x3e8_electricManagers.size() < size_t(x154_SCNT)) {
if (x1bc_allocated[allocIdx]) const zeus::CTransform cachedRot = xf8_cachedXf.getRotation();
const size_t toAdd = x1bc_allocated.size() - allocIdx;
for (size_t j = 0; j < toAdd; ++j, ++allocIdx) {
if (x1bc_allocated[allocIdx]) {
continue; continue;
}
x1bc_allocated[allocIdx] = true; x1bc_allocated[allocIdx] = true;
int lifetime = 1; int lifetime = 1;
if (CIntElement* slif = x1c_elecDesc->x4_SLIF.get()) if (CIntElement* slif = x1c_elecDesc->x4_SLIF.get()) {
slif->GetValue(x28_currentFrame, lifetime); slif->GetValue(x28_currentFrame, lifetime);
}
x3e8_electricManagers.emplace_back(allocIdx, lifetime, x28_currentFrame); x3e8_electricManagers.emplace_back(allocIdx, lifetime, x28_currentFrame);
CParticleElectricManager& elec = x3e8_electricManagers.back(); CParticleElectricManager& elec = x3e8_electricManagers.back();
CParticleGlobals::instance()->SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame); CParticleGlobals::instance()->SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame);
int frame = x28_currentFrame - elec.x8_startFrame; const int frame = x28_currentFrame - int(elec.x8_startFrame);
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame); CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame);
CalculatePoints(); CalculatePoints();
@ -354,8 +395,9 @@ void CParticleElectric::CreateNewParticles(int count) {
swoosh.SetGlobalScale(xe0_globalScale); swoosh.SetGlobalScale(xe0_globalScale);
swoosh.SetLocalScale(xec_localScale); swoosh.SetLocalScale(xec_localScale);
zeus::CColor color = zeus::skWhite; zeus::CColor color = zeus::skWhite;
if (CColorElement* colr = x1c_elecDesc->x14_COLR.get()) if (CColorElement* colr = x1c_elecDesc->x14_COLR.get()) {
colr->GetValue(frame, color); colr->GetValue(frame, color);
}
swoosh.SetModulationColor(color * x1b8_moduColor); swoosh.SetModulationColor(color * x1b8_moduColor);
swoosh.DoElectricCreate(x420_calculatedVerts); swoosh.DoElectricCreate(x420_calculatedVerts);
} }
@ -366,8 +408,9 @@ void CParticleElectric::CreateNewParticles(int count) {
UpdateLine(allocIdx, 0); UpdateLine(allocIdx, 0);
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
x130_buildBounds = zeus::CAABox(); x130_buildBounds = zeus::CAABox();
for (const zeus::CVector3f& vec : x420_calculatedVerts) for (const zeus::CVector3f& vec : x420_calculatedVerts) {
x130_buildBounds.accumulateBounds(vec); x130_buildBounds.accumulateBounds(vec);
}
line.x28_aabb = x130_buildBounds; line.x28_aabb = x130_buildBounds;
} }
} }
@ -376,7 +419,7 @@ void CParticleElectric::CreateNewParticles(int count) {
for (int k = 0; k < x154_SCNT; ++k) { for (int k = 0; k < x154_SCNT; ++k) {
CElementGen& gen = *x400_gpsmGenerators[k]; CElementGen& gen = *x400_gpsmGenerators[k];
if (!gen.GetParticleEmission()) { if (!gen.GetParticleEmission()) {
zeus::CTransform scale = const zeus::CTransform scale =
zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale); zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale);
gen.SetTranslation(scale * x420_calculatedVerts.front()); gen.SetTranslation(scale * x420_calculatedVerts.front());
gen.SetParticleEmission(true); gen.SetParticleEmission(true);
@ -390,7 +433,7 @@ void CParticleElectric::CreateNewParticles(int count) {
for (int k = 0; k < x154_SCNT; ++k) { for (int k = 0; k < x154_SCNT; ++k) {
CElementGen& gen = *x410_epsmGenerators[k]; CElementGen& gen = *x410_epsmGenerators[k];
if (!gen.GetParticleEmission()) { if (!gen.GetParticleEmission()) {
zeus::CTransform scale = const zeus::CTransform scale =
zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale); zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale);
gen.SetTranslation(scale * x420_calculatedVerts.back()); gen.SetTranslation(scale * x420_calculatedVerts.back());
gen.SetParticleEmission(true); gen.SetParticleEmission(true);
@ -411,8 +454,7 @@ void CParticleElectric::AddElectricalEffects() {
if (CRealElement* grat = x1c_elecDesc->x8_GRAT.get()) { if (CRealElement* grat = x1c_elecDesc->x8_GRAT.get()) {
if (grat->GetValue(x28_currentFrame, genRate)) { if (grat->GetValue(x28_currentFrame, genRate)) {
x3e8_electricManagers.clear(); x3e8_electricManagers.clear();
for (int i = 0; i < x1bc_allocated.size(); ++i) std::fill(x1bc_allocated.begin(), x1bc_allocated.end(), false);
x1bc_allocated[i] = false;
return; return;
} else { } else {
genRate = std::max(0.f, genRate); genRate = std::max(0.f, genRate);
@ -420,9 +462,9 @@ void CParticleElectric::AddElectricalEffects() {
} }
x15c_genRem += genRate; x15c_genRem += genRate;
int partCount = std::floor(x15c_genRem); const float partCount = std::floor(x15c_genRem);
x15c_genRem -= partCount; x15c_genRem -= partCount;
CreateNewParticles(partCount); CreateNewParticles(int(partCount));
} }
void CParticleElectric::BuildBounds() { void CParticleElectric::BuildBounds() {
@ -434,14 +476,15 @@ void CParticleElectric::BuildBounds() {
x160_systemBounds = zeus::CAABox(); x160_systemBounds = zeus::CAABox();
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; const CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
if (auto bounds = swoosh.GetBounds()) if (const auto bounds = swoosh.GetBounds()) {
x160_systemBounds.accumulateBounds(*bounds); x160_systemBounds.accumulateBounds(*bounds);
}
} }
} else if (x450_28_haveLWD) { } else if (x450_28_haveLWD) {
zeus::CAABox tmp = zeus::CAABox(); zeus::CAABox tmp = zeus::CAABox();
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CLineManager& line = *x2e4_lineManagers[elec.x0_idx]; CLineManager& line = *x2e4_lineManagers[elec.x0_idx];
tmp.accumulateBounds(line.x28_aabb); tmp.accumulateBounds(line.x28_aabb);
} }
@ -453,44 +496,52 @@ void CParticleElectric::BuildBounds() {
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (auto bounds = x400_gpsmGenerators[i]->GetBounds()) if (auto bounds = x400_gpsmGenerators[i]->GetBounds()) {
x160_systemBounds.accumulateBounds(*bounds); x160_systemBounds.accumulateBounds(*bounds);
}
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (auto bounds = x410_epsmGenerators[i]->GetBounds()) if (auto bounds = x410_epsmGenerators[i]->GetBounds()) {
x160_systemBounds.accumulateBounds(*bounds); x160_systemBounds.accumulateBounds(*bounds);
}
}
} }
} }
bool CParticleElectric::Update(double dt) { bool CParticleElectric::Update(double dt) {
CGlobalRandom gr(x14c_randState); [[maybe_unused]] CGlobalRandom gr(x14c_randState);
bool ret = false; bool ret = false;
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (!x400_gpsmGenerators[i]->IsSystemDeletable()) if (!x400_gpsmGenerators[i]->IsSystemDeletable()) {
break; break;
}
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (!x410_epsmGenerators[i]->IsSystemDeletable()) if (!x410_epsmGenerators[i]->IsSystemDeletable()) {
break; break;
}
}
} }
bool emitting = x450_24_emitting && x28_currentFrame < x2c_LIFE; const bool emitting = x450_24_emitting && x28_currentFrame < x2c_LIFE;
double evalTime = x28_currentFrame / 60.0; double evalTime = x28_currentFrame / 60.0;
x30_curTime += dt; x30_curTime += dt;
if (x450_29_transformDirty) { if (x450_29_transformDirty) {
UpdateCachedTransform(); UpdateCachedTransform();
zeus::CTransform globalOrient = xf8_cachedXf.getRotation(); const zeus::CTransform globalOrient = xf8_cachedXf.getRotation();
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalTranslation(xf8_cachedXf.origin); swoosh.SetGlobalTranslation(xf8_cachedXf.origin);
swoosh.SetGlobalOrientation(globalOrient); swoosh.SetGlobalOrientation(globalOrient);
@ -500,7 +551,7 @@ bool CParticleElectric::Update(double dt) {
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CElementGen& gen = *x400_gpsmGenerators[elec.x0_idx]; CElementGen& gen = *x400_gpsmGenerators[elec.x0_idx];
gen.SetGlobalTranslation(xf8_cachedXf.origin); gen.SetGlobalTranslation(xf8_cachedXf.origin);
gen.SetGlobalOrientation(globalOrient); gen.SetGlobalOrientation(globalOrient);
@ -510,7 +561,7 @@ bool CParticleElectric::Update(double dt) {
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CElementGen& gen = *x410_epsmGenerators[elec.x0_idx]; CElementGen& gen = *x410_epsmGenerators[elec.x0_idx];
gen.SetGlobalTranslation(xf8_cachedXf.origin); gen.SetGlobalTranslation(xf8_cachedXf.origin);
gen.SetGlobalOrientation(globalOrient); gen.SetGlobalOrientation(globalOrient);
@ -529,19 +580,25 @@ bool CParticleElectric::Update(double dt) {
AddElectricalEffects(); AddElectricalEffects();
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
if (x28_currentFrame >= x2c_LIFE) if (x28_currentFrame >= x2c_LIFE) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->EndLifetime(); x400_gpsmGenerators[i]->EndLifetime();
for (int i = 0; i < x154_SCNT; ++i) }
}
for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->Update(1.0 / 60.0); x400_gpsmGenerators[i]->Update(1.0 / 60.0);
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
if (x28_currentFrame >= x2c_LIFE) if (x28_currentFrame >= x2c_LIFE) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->EndLifetime(); x410_epsmGenerators[i]->EndLifetime();
for (int i = 0; i < x154_SCNT; ++i) }
}
for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->Update(1.0 / 60.0); x410_epsmGenerators[i]->Update(1.0 / 60.0);
}
} }
ret = true; ret = true;
@ -549,8 +606,9 @@ bool CParticleElectric::Update(double dt) {
x28_currentFrame += 1; x28_currentFrame += 1;
} }
if (ret) if (ret) {
BuildBounds(); BuildBounds();
}
return ret; return ret;
} }
@ -559,23 +617,28 @@ void CParticleElectric::Render(const CActorLights* lights) {
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CParticleElectric::Render {}"), SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CParticleElectric::Render {}"),
*x1c_elecDesc.GetObjectTag()).c_str(), zeus::skYellow); *x1c_elecDesc.GetObjectTag()).c_str(), zeus::skYellow);
if (x3e8_electricManagers.size()) { if (!x3e8_electricManagers.empty()) {
if (x450_29_transformDirty) if (x450_29_transformDirty) {
UpdateCachedTransform(); UpdateCachedTransform();
if (x450_27_haveSSWH) }
if (x450_27_haveSSWH) {
RenderSwooshes(); RenderSwooshes();
if (x450_28_haveLWD) }
if (x450_28_haveLWD) {
RenderLines(); RenderLines();
}
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->Render(lights); x400_gpsmGenerators[i]->Render(lights);
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->Render(lights); x410_epsmGenerators[i]->Render(lights);
}
} }
} }
@ -595,20 +658,22 @@ void CParticleElectric::SetGlobalOrientation(const zeus::CTransform& orientation
x450_29_transformDirty = true; x450_29_transformDirty = true;
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalOrientation(xb0_globalOrientation); swoosh.SetGlobalOrientation(xb0_globalOrientation);
} }
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation); x400_gpsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation);
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation); x410_epsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation);
}
} }
} }
@ -617,20 +682,22 @@ void CParticleElectric::SetGlobalTranslation(const zeus::CVector3f& translation)
x450_29_transformDirty = true; x450_29_transformDirty = true;
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalTranslation(xa4_globalTranslation); swoosh.SetGlobalTranslation(xa4_globalTranslation);
} }
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation); x400_gpsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation);
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation); x410_epsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation);
}
} }
} }
@ -644,20 +711,22 @@ void CParticleElectric::SetLocalScale(const zeus::CVector3f& scale) {
x450_29_transformDirty = true; x450_29_transformDirty = true;
if (x450_27_haveSSWH) { if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetLocalScale(xec_localScale); swoosh.SetLocalScale(xec_localScale);
} }
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators[i]->SetLocalScale(xec_localScale); x400_gpsmGenerators[i]->SetLocalScale(xec_localScale);
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators[i]->SetLocalScale(xec_localScale); x410_epsmGenerators[i]->SetLocalScale(xec_localScale);
}
} }
} }
@ -678,22 +747,28 @@ const zeus::CVector3f& CParticleElectric::GetGlobalScale() const { return xe0_gl
const zeus::CColor& CParticleElectric::GetModulationColor() const { return x1b8_moduColor; } const zeus::CColor& CParticleElectric::GetModulationColor() const { return x1b8_moduColor; }
bool CParticleElectric::IsSystemDeletable() const { bool CParticleElectric::IsSystemDeletable() const {
if (x450_24_emitting && x28_currentFrame < x2c_LIFE) if (x450_24_emitting && x28_currentFrame < x2c_LIFE) {
return false; return false;
}
if (x3e8_electricManagers.size()) if (!x3e8_electricManagers.empty()) {
return false; return false;
}
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (!x400_gpsmGenerators[i]->IsSystemDeletable()) if (!x400_gpsmGenerators[i]->IsSystemDeletable()) {
return false; return false;
}
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
if (!x410_epsmGenerators[i]->IsSystemDeletable()) if (!x410_epsmGenerators[i]->IsSystemDeletable()) {
return false; return false;
}
}
} }
return true; return true;
@ -711,38 +786,46 @@ u32 CParticleElectric::GetParticleCount() const {
u32 ret = 0; u32 ret = 0;
for (const CParticleElectricManager& elec : x3e8_electricManagers) { for (const CParticleElectricManager& elec : x3e8_electricManagers) {
if (x450_27_haveSSWH) if (x450_27_haveSSWH) {
ret += x1e0_swooshGenerators[elec.x0_idx]->GetParticleCount(); ret += x1e0_swooshGenerators[elec.x0_idx]->GetParticleCount();
if (x450_28_haveLWD) }
if (x450_28_haveLWD) {
ret += x150_SSEG; ret += x150_SSEG;
}
} }
if (x450_25_haveGPSM) { if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
ret += x400_gpsmGenerators[i]->GetParticleCount(); ret += x400_gpsmGenerators[i]->GetParticleCount();
}
} }
if (x450_26_haveEPSM) { if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i) for (int i = 0; i < x154_SCNT; ++i) {
ret += x410_epsmGenerators[i]->GetParticleCount(); ret += x410_epsmGenerators[i]->GetParticleCount();
}
} }
return ret; return ret;
} }
bool CParticleElectric::SystemHasLight() const { bool CParticleElectric::SystemHasLight() const {
if (x450_25_haveGPSM) if (x450_25_haveGPSM) {
return x400_gpsmGenerators.front()->SystemHasLight(); return x400_gpsmGenerators.front()->SystemHasLight();
else if (x450_26_haveEPSM) }
if (x450_26_haveEPSM) {
return x410_epsmGenerators.front()->SystemHasLight(); return x410_epsmGenerators.front()->SystemHasLight();
}
return false; return false;
} }
CLight CParticleElectric::GetLight() const { CLight CParticleElectric::GetLight() const {
if (x450_25_haveGPSM) if (x450_25_haveGPSM) {
return x400_gpsmGenerators.front()->GetLight(); return x400_gpsmGenerators.front()->GetLight();
else if (x450_26_haveEPSM) }
if (x450_26_haveEPSM) {
return x410_epsmGenerators.front()->GetLight(); return x410_epsmGenerators.front()->GetLight();
}
return CLight::BuildLocalAmbient(GetGlobalTranslation(), zeus::skOrange); return CLight::BuildLocalAmbient(GetGlobalTranslation(), zeus::skOrange);
} }

View File

@ -100,7 +100,7 @@ private:
void RenderLines(); void RenderLines();
void RenderSwooshes(); void RenderSwooshes();
void UpdateCachedTransform(); void UpdateCachedTransform();
void UpdateLine(int idx, int frame); void UpdateLine(size_t idx, int frame);
void UpdateElectricalEffects(); void UpdateElectricalEffects();
void CalculateFractal(int start, int end, float ampl, float ampd); void CalculateFractal(int start, int end, float ampl, float ampd);
void CalculatePoints(); void CalculatePoints();

View File

@ -21,24 +21,24 @@ public:
float m_EmitterTimeReal = 0.f; float m_EmitterTimeReal = 0.f;
void SetEmitterTime(int frame) { void SetEmitterTime(int frame) {
m_EmitterTime = frame; m_EmitterTime = frame;
m_EmitterTimeReal = frame; m_EmitterTimeReal = float(frame);
} }
int m_ParticleLifetime = 0; int m_ParticleLifetime = 0;
float m_ParticleLifetimeReal = 0.f; float m_ParticleLifetimeReal = 0.f;
void SetParticleLifetime(int frame) { void SetParticleLifetime(int frame) {
m_ParticleLifetime = frame; m_ParticleLifetime = frame;
m_ParticleLifetimeReal = frame; m_ParticleLifetimeReal = float(frame);
} }
int m_ParticleLifetimePercentage = 0; int m_ParticleLifetimePercentage = 0;
float m_ParticleLifetimePercentageReal = 0.f; float m_ParticleLifetimePercentageReal = 0.f;
float m_ParticleLifetimePercentageRemainder = 0.f; float m_ParticleLifetimePercentageRemainder = 0.f;
void UpdateParticleLifetimeTweenValues(int frame) { void UpdateParticleLifetimeTweenValues(int frame) {
float lt = m_ParticleLifetime != 0.0f ? m_ParticleLifetime : 1.0f; const float lt = m_ParticleLifetime != 0 ? float(m_ParticleLifetime) : 1.0f;
m_ParticleLifetimePercentageReal = 100.0f * frame / lt; m_ParticleLifetimePercentageReal = 100.0f * float(frame) / lt;
m_ParticleLifetimePercentage = int(m_ParticleLifetimePercentageReal); m_ParticleLifetimePercentage = int(m_ParticleLifetimePercentageReal);
m_ParticleLifetimePercentageRemainder = m_ParticleLifetimePercentageReal - m_ParticleLifetimePercentage; m_ParticleLifetimePercentageRemainder = m_ParticleLifetimePercentageReal - float(m_ParticleLifetimePercentage);
m_ParticleLifetimePercentage = zeus::clamp(0, m_ParticleLifetimePercentage, 100); m_ParticleLifetimePercentage = zeus::clamp(0, m_ParticleLifetimePercentage, 100);
} }

View File

@ -28,38 +28,43 @@ CParticleSwoosh::CParticleSwoosh(const TToken<CSwooshDescription>& desc, int len
, x1d1_24_constantUv(false) { , x1d1_24_constantUv(false) {
++g_ParticleSystemAliveCount; ++g_ParticleSystemAliveCount;
if (leng > 0) if (leng > 0) {
x1b4_LENG = leng; x1b4_LENG = leng;
else if (CIntElement* leng = x1c_desc->x10_LENG.get()) } else if (CIntElement* lengElement = x1c_desc->x10_LENG.get()) {
leng->GetValue(0, x1b4_LENG); lengElement->GetValue(0, x1b4_LENG);
}
x1b4_LENG += 1; x1b4_LENG += 1;
if (CIntElement* side = x1c_desc->x18_SIDE.get()) if (CIntElement* side = x1c_desc->x18_SIDE.get()) {
side->GetValue(0, x1b8_SIDE); side->GetValue(0, x1b8_SIDE);
}
x1d0_28_LLRD = x1c_desc->x44_24_LLRD; x1d0_28_LLRD = x1c_desc->x44_24_LLRD;
x1d0_29_VLS1 = x1c_desc->x44_26_VLS1; x1d0_29_VLS1 = x1c_desc->x44_26_VLS1;
x1d0_30_VLS2 = x1c_desc->x44_27_VLS2; x1d0_30_VLS2 = x1c_desc->x44_27_VLS2;
if (IsValid()) { if (IsValid()) {
if (CIntElement* pslt = x1c_desc->x0_PSLT.get()) if (CIntElement* pslt = x1c_desc->x0_PSLT.get()) {
pslt->GetValue(0, x2c_PSLT); pslt->GetValue(0, x2c_PSLT);
else } else {
x2c_PSLT = INT_MAX; x2c_PSLT = INT_MAX;
}
x1d0_25_AALP = x1c_desc->x44_31_AALP; x1d0_25_AALP = x1c_desc->x44_31_AALP;
if (CIntElement* spln = x1c_desc->x38_SPLN.get()) if (CIntElement* spln = x1c_desc->x38_SPLN.get()) {
spln->GetValue(0, x1b0_SPLN); spln->GetValue(0, x1b0_SPLN);
if (x1b0_SPLN < 0) }
if (x1b0_SPLN < 0) {
x1b0_SPLN = 0; x1b0_SPLN = 0;
}
x15c_swooshes.clear(); x15c_swooshes.clear();
x15c_swooshes.reserve(x1b4_LENG); x15c_swooshes.reserve(x1b4_LENG);
for (int i = 0; i < x1b4_LENG; ++i) for (int i = 0; i < x1b4_LENG; ++i) {
x15c_swooshes.emplace_back(zeus::skZero3f, zeus::skZero3f, 0.f, 0.f, 0, false, x15c_swooshes.emplace_back(zeus::skZero3f, zeus::skZero3f, 0.f, 0.f, 0, false, zeus::CTransform(), zeus::skZero3f,
zeus::CTransform(), zeus::skZero3f, 0.f, 0.f, 0.f, 0.f, zeus::skClear);
zeus::skClear); }
SetOrientation(zeus::CTransform()); SetOrientation(zeus::CTransform());
@ -69,11 +74,11 @@ CParticleSwoosh::CParticleSwoosh(const TToken<CSwooshDescription>& desc, int len
x19c_p3.resize(x1b8_SIDE); x19c_p3.resize(x1b8_SIDE);
if (x1c_desc->x44_29_WIRE) { if (x1c_desc->x44_29_WIRE) {
int maxVerts = x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 12; const int maxVerts = x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 12;
m_lineRenderer.reset( m_lineRenderer.reset(
new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, nullptr, x1d0_25_AALP)); new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, nullptr, x1d0_25_AALP));
} else { } else {
int maxVerts = x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 4; const auto maxVerts = size_t(x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 4);
m_cachedVerts.reserve(maxVerts); m_cachedVerts.reserve(maxVerts);
CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
m_vertBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(CParticleSwooshShaders::Vert), maxVerts); m_vertBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(CParticleSwooshShaders::Vert), maxVerts);
@ -133,14 +138,16 @@ void CParticleSwoosh::UpdateTranslationAndOrientation() {
swoosh.x68_frame = x28_curFrame - swoosh.x70_startFrame; swoosh.x68_frame = x28_curFrame - swoosh.x70_startFrame;
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(swoosh.x68_frame); CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(swoosh.x68_frame);
if (x1c_desc->x44_28_SROT) { if (x1c_desc->x44_28_SROT) {
if (CRealElement* irot = x1c_desc->x1c_IROT.get()) if (CRealElement* irot = x1c_desc->x1c_IROT.get()) {
irot->GetValue(x28_curFrame, swoosh.x30_irot); irot->GetValue(x28_curFrame, swoosh.x30_irot);
}
swoosh.x34_rotm = 0.f; swoosh.x34_rotm = 0.f;
} else { } else {
if (CRealElement* rotm = x1c_desc->x20_ROTM.get()) if (CRealElement* rotm = x1c_desc->x20_ROTM.get()) {
rotm->GetValue(x28_curFrame, swoosh.x34_rotm); rotm->GetValue(x28_curFrame, swoosh.x34_rotm);
else } else {
swoosh.x34_rotm = 0.f; swoosh.x34_rotm = 0.f;
}
} }
if (CModVectorElement* velm = x1c_desc->x30_VELM.get()) { if (CModVectorElement* velm = x1c_desc->x30_VELM.get()) {
@ -196,8 +203,9 @@ void CParticleSwoosh::UpdateTranslationAndOrientation() {
} }
bool CParticleSwoosh::Update(double dt) { bool CParticleSwoosh::Update(double dt) {
if (!IsValid()) if (!IsValid()) {
return false; return false;
}
CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG); CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG);
CParticleGlobals::instance()->SetEmitterTime(x28_curFrame); CParticleGlobals::instance()->SetEmitterTime(x28_curFrame);
@ -206,24 +214,27 @@ bool CParticleSwoosh::Update(double dt) {
double evalTime = x28_curFrame / 60.0; double evalTime = x28_curFrame / 60.0;
float time = 1.f; float time = 1.f;
if (CRealElement* timeElem = x1c_desc->x4_TIME.get()) if (CRealElement* timeElem = x1c_desc->x4_TIME.get()) {
timeElem->GetValue(x28_curFrame, time); timeElem->GetValue(x28_curFrame, time);
}
x30_curTime += std::max(0.0, dt * time); x30_curTime += std::max(0.0, dt * time);
while (x1d0_26_forceOneUpdate || evalTime < x30_curTime) { while (x1d0_26_forceOneUpdate || evalTime < x30_curTime) {
x1d0_26_forceOneUpdate = false; x1d0_26_forceOneUpdate = false;
x158_curParticle += 1; x158_curParticle += 1;
if (x158_curParticle >= x15c_swooshes.size()) if (x158_curParticle >= x15c_swooshes.size()) {
x158_curParticle = 0; x158_curParticle = 0;
}
if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) { if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) {
UpdateSwooshTranslation(x38_translation); UpdateSwooshTranslation(x38_translation);
if (CRealElement* irot = x1c_desc->x1c_IROT.get()) if (CRealElement* irot = x1c_desc->x1c_IROT.get()) {
irot->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x30_irot); irot->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x30_irot);
else } else {
x15c_swooshes[x158_curParticle].x30_irot = 0.f; x15c_swooshes[x158_curParticle].x30_irot = 0.f;
}
x15c_swooshes[x158_curParticle].x34_rotm = 0.f; x15c_swooshes[x158_curParticle].x34_rotm = 0.f;
x15c_swooshes[x158_curParticle].x70_startFrame = x28_curFrame; x15c_swooshes[x158_curParticle].x70_startFrame = x28_curFrame;
@ -240,20 +251,23 @@ bool CParticleSwoosh::Update(double dt) {
x15c_swooshes[x158_curParticle].x74_velocity = x44_orientation * x15c_swooshes[x158_curParticle].x74_velocity; x15c_swooshes[x158_curParticle].x74_velocity = x44_orientation * x15c_swooshes[x158_curParticle].x74_velocity;
} }
if (CVectorElement* pofs = x1c_desc->x24_POFS.get()) if (CVectorElement* pofs = x1c_desc->x24_POFS.get()) {
pofs->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x18_offset); pofs->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x18_offset);
}
x15c_swooshes[x158_curParticle].x24_useOffset = x15c_swooshes[x158_curParticle].x18_offset; x15c_swooshes[x158_curParticle].x24_useOffset = x15c_swooshes[x158_curParticle].x18_offset;
if (CColorElement* colr = x1c_desc->x14_COLR.get()) if (CColorElement* colr = x1c_desc->x14_COLR.get()) {
colr->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x6c_color); colr->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x6c_color);
else } else {
x15c_swooshes[x158_curParticle].x6c_color = zeus::skWhite; x15c_swooshes[x158_curParticle].x6c_color = zeus::skWhite;
}
int tspn = 0; int tspn = 0;
if (CIntElement* tspnElem = x1c_desc->x40_TSPN.get()) if (CIntElement* tspnElem = x1c_desc->x40_TSPN.get()) {
tspnElem->GetValue(x28_curFrame, tspn); tspnElem->GetValue(x28_curFrame, tspn);
x1cc_TSPN = tspn; }
x1cc_TSPN = float(tspn);
} else if (x15c_swooshes[x158_curParticle].x0_active) { } else if (x15c_swooshes[x158_curParticle].x0_active) {
x1ac_particleCount = std::max(0, int(x1ac_particleCount) - 1); x1ac_particleCount = std::max(0, int(x1ac_particleCount) - 1);
x15c_swooshes[x158_curParticle].x0_active = false; x15c_swooshes[x158_curParticle].x0_active = false;
@ -270,28 +284,32 @@ bool CParticleSwoosh::Update(double dt) {
zeus::CVector3f CParticleSwoosh::GetSplinePoint(const zeus::CVector3f& p0, const zeus::CVector3f& p1, zeus::CVector3f CParticleSwoosh::GetSplinePoint(const zeus::CVector3f& p0, const zeus::CVector3f& p1,
const zeus::CVector3f& p2, const zeus::CVector3f& p3, float t) { const zeus::CVector3f& p2, const zeus::CVector3f& p3, float t) {
if (t > 0.f) if (t > 0.f) {
return p1; return p1;
if (t >= 1.f) }
if (t >= 1.f) {
return p2; return p2;
}
// Tricubic spline interpolation // Tricubic spline interpolation
float t2 = t * t; const float t2 = t * t;
float t3 = t2 * t; const float t3 = t2 * t;
float p0Coef = -0.5f * t3 + t2 - 0.5f * t; const float p0Coef = -0.5f * t3 + t2 - 0.5f * t;
float p1Coef = 1.5f * t3 - 2.5f * t2 + 1.f; const float p1Coef = 1.5f * t3 - 2.5f * t2 + 1.f;
float p2Coef = -1.5f * t3 + 2.f * t2 + 0.5f * t; const float p2Coef = -1.5f * t3 + 2.f * t2 + 0.5f * t;
float p3Coef = 0.5f * t3 + 0.5f * t2; const float p3Coef = 0.5f * t3 + 0.5f * t2;
return p0 * p0Coef + p1 * p1Coef + p2 * p2Coef + p3 * p3Coef; return p0 * p0Coef + p1 * p1Coef + p2 * p2Coef + p3 * p3Coef;
} }
int CParticleSwoosh::WrapIndex(int i) const { int CParticleSwoosh::WrapIndex(int i) const {
while (i < 0) while (i < 0) {
i += x1b4_LENG; i += x1b4_LENG;
while (i >= x1b4_LENG) }
while (i >= x1b4_LENG) {
i -= x1b4_LENG; i -= x1b4_LENG;
}
return i; return i;
} }
@ -304,112 +322,125 @@ void CParticleSwoosh::RenderNSidedSpline() {
} }
bool cros = x1c_desc->x44_25_CROS; bool cros = x1c_desc->x44_25_CROS;
if (x1b8_SIDE >= 4 || x1b8_SIDE & 0x1) if (x1b8_SIDE >= 4 || (x1b8_SIDE & 0x1) != 0) {
cros = false; cros = false;
}
int curIdx = x158_curParticle; int curIdx = x158_curParticle;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
bool a0 = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active; const bool a0 = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active;
bool a1 = x15c_swooshes[WrapIndex(curIdx)].x0_active; const bool a1 = x15c_swooshes[WrapIndex(curIdx)].x0_active;
if (!a1 || (a1 && !a0)) { if (!a1 || (a1 && !a0)) {
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
continue; continue;
} }
SSwooshData& refSwoosh = x15c_swooshes[curIdx]; const SSwooshData& refSwoosh = x15c_swooshes[curIdx];
float sideDiv = 360.f / float(x1b8_SIDE); const float sideDiv = 360.f / float(x1b8_SIDE);
for (int j = 0; j < 4; ++j) { for (int j = 0; j < 4; ++j) {
int crossRefIdx = 0; int crossRefIdx = 0;
if (j == 0) { if (j == 0) {
crossRefIdx = WrapIndex(curIdx + 1); crossRefIdx = WrapIndex(curIdx + 1);
if (!x15c_swooshes[crossRefIdx].x0_active) if (!x15c_swooshes[crossRefIdx].x0_active) {
crossRefIdx = curIdx; crossRefIdx = curIdx;
}
} else if (j == 1) { } else if (j == 1) {
crossRefIdx = WrapIndex(curIdx); crossRefIdx = WrapIndex(curIdx);
} else if (j == 2) { } else if (j == 2) {
crossRefIdx = WrapIndex(curIdx - 1); crossRefIdx = WrapIndex(curIdx - 1);
} else if (j == 3) { } else if (j == 3) {
crossRefIdx = WrapIndex(curIdx - 2); crossRefIdx = WrapIndex(curIdx - 2);
if (!x15c_swooshes[crossRefIdx].x0_active) if (!x15c_swooshes[crossRefIdx].x0_active) {
crossRefIdx = WrapIndex(curIdx - 1); crossRefIdx = WrapIndex(curIdx - 1);
}
} }
if (x1b4_LENG == 2) { if (x1b4_LENG == 2) {
if (j == 0) if (j == 0) {
crossRefIdx = WrapIndex(curIdx); crossRefIdx = WrapIndex(curIdx);
if (j == 3) }
if (j == 3) {
crossRefIdx = WrapIndex(curIdx - 1); crossRefIdx = WrapIndex(curIdx - 1);
}
} else if (x158_curParticle == curIdx && j == 0) { } else if (x158_curParticle == curIdx && j == 0) {
crossRefIdx = x158_curParticle; crossRefIdx = x158_curParticle;
} else { } else {
if (WrapIndex(x158_curParticle + 2) == curIdx && j == 3) if (WrapIndex(x158_curParticle + 2) == curIdx && j == 3) {
crossRefIdx = WrapIndex(x158_curParticle + 1); crossRefIdx = WrapIndex(x158_curParticle + 1);
else if (x1ac_particleCount - 2 == i && j == 3) } else if (x1ac_particleCount - 2 == i && j == 3) {
crossRefIdx = 0; crossRefIdx = 0;
}
} }
SSwooshData& crossSwoosh = x15c_swooshes[crossRefIdx]; const SSwooshData& crossSwoosh = x15c_swooshes[crossRefIdx];
for (int k = 0; k < x1b8_SIDE; ++k) { for (int k = 0; k < x1b8_SIDE; ++k) {
float n = sideDiv * k; const float n = sideDiv * k;
float ang = zeus::degToRad(n + crossSwoosh.x30_irot + crossSwoosh.x34_rotm); float ang = zeus::degToRad(n + crossSwoosh.x30_irot + crossSwoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) { if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF; ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) if (ang > M_PIF) {
ang -= 2.f * M_PIF; ang -= 2.f * M_PIF;
else if (ang < -M_PIF) } else if (ang < -M_PIF) {
ang += 2.f * M_PIF; ang += 2.f * M_PIF;
}
} }
float z = std::sin(ang); const float z = std::sin(ang);
float x = std::cos(ang); const float x = std::cos(ang);
float rad = (n > 0.f && n <= 180.f) ? crossSwoosh.x4_leftRad : crossSwoosh.x8_rightRad; const float rad = (n > 0.f && n <= 180.f) ? crossSwoosh.x4_leftRad : crossSwoosh.x8_rightRad;
zeus::CVector3f offset = crossSwoosh.xc_translation + crossSwoosh.x24_useOffset; const zeus::CVector3f offset = crossSwoosh.xc_translation + crossSwoosh.x24_useOffset;
if (j == 0) if (j == 0) {
x16c_p0[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset; x16c_p0[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
else if (j == 1) } else if (j == 1) {
x17c_p1[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset; x17c_p1[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
else if (j == 2) } else if (j == 2) {
x18c_p2[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset; x18c_p2[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
else if (j == 3) } else if (j == 3) {
x19c_p3[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset; x19c_p3[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
}
} }
} }
if (x1c_desc->x3c_TEXR) { if (x1c_desc->x3c_TEXR) {
if (x1ec_TSPN > 0) if (x1ec_TSPN > 0) {
x1d4_uvs.xMin = float((i % x1ec_TSPN) * x1e8_uvSpan); x1d4_uvs.xMin = float((i % x1ec_TSPN) * x1e8_uvSpan);
else } else {
x1d4_uvs.xMin = float(i * x1e8_uvSpan); x1d4_uvs.xMin = float(i * x1e8_uvSpan);
}
} }
float segUvSpan = x1e8_uvSpan / float(x1b0_SPLN + 1); const float segUvSpan = x1e8_uvSpan / float(x1b0_SPLN + 1);
for (int j = 0; j < x1b0_SPLN + 1; ++j) { for (int j = 0; j < x1b0_SPLN + 1; ++j) {
float t0 = j / float(x1b0_SPLN + 1); const float t0 = j / float(x1b0_SPLN + 1);
float t1 = (j + 1) / float(x1b0_SPLN + 1); const float t1 = (j + 1) / float(x1b0_SPLN + 1);
int faces = x1b8_SIDE; int faces = x1b8_SIDE;
if (x1b8_SIDE <= 2) if (x1b8_SIDE <= 2) {
faces = 1; faces = 1;
else if (cros) } else if (cros) {
faces = x1b8_SIDE / 2; faces = x1b8_SIDE / 2;
}
x1d4_uvs.xMax = x1d4_uvs.xMin + segUvSpan; x1d4_uvs.xMax = x1d4_uvs.xMin + segUvSpan;
for (int k = 0; k < faces; ++k) { for (int k = 0; k < faces; ++k) {
int otherK = k + 1; int otherK = k + 1;
if (k + 1 >= x1b8_SIDE) if (k + 1 >= x1b8_SIDE) {
otherK = 0; otherK = 0;
zeus::CColor color = refSwoosh.x6c_color * x20c_moduColor; }
const zeus::CColor color = refSwoosh.x6c_color * x20c_moduColor;
if (cros) { if (cros) {
otherK = k + x1b8_SIDE / 2; otherK = k + x1b8_SIDE / 2;
zeus::CVector3f v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0); const auto v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0);
zeus::CVector3f v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0); const auto v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0);
zeus::CVector3f v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1); const auto v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1);
zeus::CVector3f v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1); const auto v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1);
m_cachedVerts.push_back({v0, {x1d4_uvs.xMin, x1d4_uvs.yMin}, color}); m_cachedVerts.push_back({v0, {x1d4_uvs.xMin, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {x1d4_uvs.xMin, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {x1d4_uvs.xMin, x1d4_uvs.yMax}, color});
@ -417,10 +448,10 @@ void CParticleSwoosh::RenderNSidedSpline() {
m_cachedVerts.push_back({v3, {x1d4_uvs.xMax, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v3, {x1d4_uvs.xMax, x1d4_uvs.yMax}, color});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4); CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
} else { } else {
zeus::CVector3f v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0); const auto v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0);
zeus::CVector3f v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0); const auto v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0);
zeus::CVector3f v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1); const auto v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1);
zeus::CVector3f v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1); const auto v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1);
if (x1bc_prim == GX::LINES) { if (x1bc_prim == GX::LINES) {
m_lineRenderer->AddVertex(v0, color, 1.f); m_lineRenderer->AddVertex(v0, color, 1.f);
@ -445,57 +476,65 @@ void CParticleSwoosh::RenderNSidedSpline() {
} }
} }
if (x1c_desc->x3c_TEXR && x1b0_SPLN > 0) if (x1c_desc->x3c_TEXR && x1b0_SPLN > 0) {
x1d4_uvs.xMin += segUvSpan; x1d4_uvs.xMin += segUvSpan;
}
} }
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
} }
if (x1bc_prim == GX::LINES) if (x1bc_prim == GX::LINES) {
m_lineRenderer->Render(g_Renderer->IsThermalVisorHotPass()); m_lineRenderer->Render(g_Renderer->IsThermalVisorHotPass());
}
} }
void CParticleSwoosh::RenderNSidedNoSpline() { RenderNSidedSpline(); } void CParticleSwoosh::RenderNSidedNoSpline() { RenderNSidedSpline(); }
void CParticleSwoosh::Render3SidedSolidSpline() { void CParticleSwoosh::Render3SidedSolidSpline() {
if (x15c_swooshes.size() < 2) if (x15c_swooshes.size() < 2) {
return; return;
}
int curIdx = x158_curParticle; int curIdx = x158_curParticle;
float curUvSpan = -x1e8_uvSpan; float curUvSpan = -x1e8_uvSpan;
zeus::CColor prevColor0 = zeus::skClear; zeus::CColor prevColor0 = zeus::skClear;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm); float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang1) > M_PIF) { if (std::fabs(ang1) > M_PIF) {
ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF; ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang1 > M_PIF) if (ang1 > M_PIF) {
ang1 -= 2.f * M_PIF; ang1 -= 2.f * M_PIF;
else if (ang1 < -M_PIF) } else if (ang1 < -M_PIF) {
ang1 += 2.f * M_PIF; ang1 += 2.f * M_PIF;
}
} }
zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad); const zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad);
float ang2 = ang1 + 2.0943952f; // +120 degrees float ang2 = ang1 + 2.0943952f; // +120 degrees
if (ang2 > M_PIF) if (ang2 > M_PIF) {
ang2 -= 2.f * M_PIF; ang2 -= 2.f * M_PIF;
}
zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad); const zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad);
float ang3 = ang2 + 2.0943952f; // +120 degrees float ang3 = ang2 + 2.0943952f; // +120 degrees
if (ang3 > M_PIF) if (ang3 > M_PIF) {
ang3 -= 2.f * M_PIF; ang3 -= 2.f * M_PIF;
}
zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad); const zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad);
if (i == 2) { if (i == 2) {
x19c_p3[0] = x17c_p1[0] * 2.f - x16c_p0[0]; x19c_p3[0] = x17c_p1[0] * 2.f - x16c_p0[0];
@ -515,15 +554,15 @@ void CParticleSwoosh::Render3SidedSolidSpline() {
x17c_p1[1] = x16c_p0[1]; x17c_p1[1] = x16c_p0[1];
x17c_p1[2] = x16c_p0[2]; x17c_p1[2] = x16c_p0[2];
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
x16c_p0[0] = swoosh.x38_orientation * ang1Vec + useOffset; x16c_p0[0] = swoosh.x38_orientation * ang1Vec + useOffset;
x16c_p0[1] = swoosh.x38_orientation * ang2Vec + useOffset; x16c_p0[1] = swoosh.x38_orientation * ang2Vec + useOffset;
x16c_p0[2] = swoosh.x38_orientation * ang3Vec + useOffset; x16c_p0[2] = swoosh.x38_orientation * ang3Vec + useOffset;
zeus::CColor useColor0 = prevColor0; const zeus::CColor useColor0 = prevColor0;
if (swoosh.x0_active) { if (swoosh.x0_active) {
zeus::CColor prevColor1 = prevColor0; const zeus::CColor prevColor1 = prevColor0;
prevColor0 = swoosh.x6c_color * x20c_moduColor; prevColor0 = swoosh.x6c_color * x20c_moduColor;
float prevUvSpan = curUvSpan; float prevUvSpan = curUvSpan;
curUvSpan += x1e8_uvSpan; curUvSpan += x1e8_uvSpan;
@ -583,8 +622,9 @@ void CParticleSwoosh::Render3SidedSolidSpline() {
} }
void CParticleSwoosh::Render3SidedSolidNoSplineNoGaps() { void CParticleSwoosh::Render3SidedSolidNoSplineNoGaps() {
if (x15c_swooshes.size() < 2) if (x15c_swooshes.size() < 2) {
return; return;
}
std::array<zeus::CVector3f, 2> p0; std::array<zeus::CVector3f, 2> p0;
std::array<zeus::CVector3f, 2> p1; std::array<zeus::CVector3f, 2> p1;
@ -595,36 +635,40 @@ void CParticleSwoosh::Render3SidedSolidNoSplineNoGaps() {
zeus::CColor c0 = zeus::skClear; zeus::CColor c0 = zeus::skClear;
float uv0 = -x1e8_uvSpan; float uv0 = -x1e8_uvSpan;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm); float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang1) > M_PIF) { if (std::fabs(ang1) > M_PIF) {
ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF; ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang1 > M_PIF) if (ang1 > M_PIF) {
ang1 -= 2.f * M_PIF; ang1 -= 2.f * M_PIF;
else if (ang1 < -M_PIF) } else if (ang1 < -M_PIF) {
ang1 += 2.f * M_PIF; ang1 += 2.f * M_PIF;
}
} }
zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad); const zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad);
float ang2 = ang1 + 2.0943952f; // +120 degrees float ang2 = ang1 + 2.0943952f; // +120 degrees
if (ang2 > M_PIF) if (ang2 > M_PIF) {
ang2 -= 2.f * M_PIF; ang2 -= 2.f * M_PIF;
}
zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad); const zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad);
float ang3 = ang2 + 2.0943952f; // +120 degrees float ang3 = ang2 + 2.0943952f; // +120 degrees
if (ang3 > M_PIF) if (ang3 > M_PIF) {
ang3 -= 2.f * M_PIF; ang3 -= 2.f * M_PIF;
}
zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad); const zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad);
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
p0[i & 1] = swoosh.x38_orientation * ang1Vec + useOffset; p0[i & 1] = swoosh.x38_orientation * ang1Vec + useOffset;
p1[i & 1] = swoosh.x38_orientation * ang2Vec + useOffset; p1[i & 1] = swoosh.x38_orientation * ang2Vec + useOffset;
p2[i & 1] = swoosh.x38_orientation * ang3Vec + useOffset; p2[i & 1] = swoosh.x38_orientation * ang3Vec + useOffset;
@ -640,10 +684,10 @@ void CParticleSwoosh::Render3SidedSolidNoSplineNoGaps() {
} }
lastActive = true; lastActive = true;
zeus::CColor c1 = c0; const zeus::CColor c1 = c0;
c0 = swoosh.x6c_color * x20c_moduColor; c0 = swoosh.x6c_color * x20c_moduColor;
float uv1 = uv0; const float uv1 = uv0;
uv0 += x1e8_uvSpan; uv0 += x1e8_uvSpan;
m_cachedVerts.push_back({p0[i & 1], {uv0, x1d4_uvs.yMin}, c0}); m_cachedVerts.push_back({p0[i & 1], {uv0, x1d4_uvs.yMin}, c0});
@ -673,12 +717,13 @@ void CParticleSwoosh::Render2SidedNoSplineGaps() {
bool streaming = false; bool streaming = false;
int curIdx = x158_curParticle; int curIdx = x158_curParticle;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
bool otherActive = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active; const bool otherActive = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active;
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 2; curIdx = x15c_swooshes.size() - 2;
}
if (!swoosh.x0_active) { if (!swoosh.x0_active) {
if (streaming) { if (streaming) {
@ -689,10 +734,12 @@ void CParticleSwoosh::Render2SidedNoSplineGaps() {
} }
if (!streaming) { if (!streaming) {
if (!otherActive) if (!otherActive) {
continue; continue;
if (i >= x15c_swooshes.size() - 2) }
if (i >= x15c_swooshes.size() - 2) {
continue; continue;
}
streaming = true; streaming = true;
drawStart = m_cachedVerts.size(); drawStart = m_cachedVerts.size();
} }
@ -700,24 +747,25 @@ void CParticleSwoosh::Render2SidedNoSplineGaps() {
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm); float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) { if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF; ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) if (ang > M_PIF) {
ang -= 2.f * M_PIF; ang -= 2.f * M_PIF;
else if (ang < -M_PIF) } else if (ang < -M_PIF) {
ang += 2.f * M_PIF; ang += 2.f * M_PIF;
}
} }
float sinAng = std::sin(ang); const float sinAng = std::sin(ang);
float cosAng = std::cos(ang); const float cosAng = std::cos(ang);
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
zeus::CVector3f v0 = const zeus::CVector3f v0 =
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) + swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset; useOffset;
zeus::CVector3f v1 = const zeus::CVector3f v1 =
swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) + swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) +
useOffset; useOffset;
zeus::CColor color = swoosh.x6c_color * x20c_moduColor; const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
m_cachedVerts.push_back({v0, {1.f, x1d4_uvs.yMin}, color}); m_cachedVerts.push_back({v0, {1.f, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {1.f, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {1.f, x1d4_uvs.yMax}, color});
@ -734,43 +782,47 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
int curIdx = x158_curParticle; int curIdx = x158_curParticle;
int particleCount = x1ac_particleCount; int particleCount = x1ac_particleCount;
float uvOffset = 0.f; float uvOffset = 0.f;
if (x1c_desc->x3c_TEXR) { if (x1c_desc->x3c_TEXR) {
if (x1c_desc->x45_25_ORNT) { if (x1c_desc->x45_25_ORNT) {
zeus::CVector3f camToParticle = const zeus::CVector3f camToParticle =
((zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf).inverse() * ((zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf).inverse() *
CGraphics::g_ViewMatrix) CGraphics::g_ViewMatrix)
.origin; .origin;
zeus::CVector3f dotVec = zeus::skZero3f; zeus::CVector3f dotVec = zeus::skZero3f;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
if (swoosh.x0_active) { if (swoosh.x0_active) {
particleCount -= 1; particleCount -= 1;
int otherIdx = curIdx - 1; int otherIdx = curIdx - 1;
if (otherIdx < 0) if (otherIdx < 0) {
otherIdx = x15c_swooshes.size() - 1; otherIdx = x15c_swooshes.size() - 1;
}
SSwooshData& otherSwoosh = x15c_swooshes[otherIdx]; const SSwooshData& otherSwoosh = x15c_swooshes[otherIdx];
zeus::CVector3f delta = otherSwoosh.xc_translation - swoosh.xc_translation; zeus::CVector3f delta = otherSwoosh.xc_translation - swoosh.xc_translation;
if (otherIdx == x158_curParticle) if (otherIdx == x158_curParticle) {
delta = swoosh.xc_translation - x15c_swooshes[(curIdx + 1) % x15c_swooshes.size()].xc_translation; delta = swoosh.xc_translation - x15c_swooshes[(curIdx + 1) % x15c_swooshes.size()].xc_translation;
}
if (delta.canBeNormalized()) { if (delta.canBeNormalized()) {
zeus::CVector3f deltaCross = delta.cross(camToParticle - swoosh.xc_translation); zeus::CVector3f deltaCross = delta.cross(camToParticle - swoosh.xc_translation);
if (deltaCross.canBeNormalized()) { if (deltaCross.canBeNormalized()) {
deltaCross.normalize(); deltaCross.normalize();
dotVec = (deltaCross.dot(dotVec) < 0.f ? -1.f : 1.f) * deltaCross; dotVec = (deltaCross.dot(dotVec) < 0.f ? -1.f : 1.f) * deltaCross;
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
zeus::CVector3f v0 = dotVec * swoosh.x4_leftRad + useOffset; const zeus::CVector3f v0 = dotVec * swoosh.x4_leftRad + useOffset;
zeus::CVector3f v1 = dotVec * -swoosh.x8_rightRad + useOffset; const zeus::CVector3f v1 = dotVec * -swoosh.x8_rightRad + useOffset;
zeus::CColor color = swoosh.x6c_color * x20c_moduColor; const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color}); m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
@ -782,21 +834,23 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
} }
if (x1ec_TSPN > 0) if (x1ec_TSPN > 0) {
uvOffset += x1e8_uvSpan; uvOffset += x1e8_uvSpan;
else } else {
uvOffset = float(i * x1e8_uvSpan); uvOffset = float(i * x1e8_uvSpan);
}
} }
} }
} }
} }
} else { } else {
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
if (swoosh.x0_active) { if (swoosh.x0_active) {
particleCount -= 1; particleCount -= 1;
@ -804,24 +858,25 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm); float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) { if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF; ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) if (ang > M_PIF) {
ang -= 2.f * M_PIF; ang -= 2.f * M_PIF;
else if (ang < -M_PIF) } else if (ang < -M_PIF) {
ang += 2.f * M_PIF; ang += 2.f * M_PIF;
}
} }
float sinAng = std::sin(ang); float sinAng = std::sin(ang);
float cosAng = std::cos(ang); float cosAng = std::cos(ang);
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
zeus::CVector3f v0 = const zeus::CVector3f v0 =
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) + swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset; useOffset;
zeus::CVector3f v1 = swoosh.x38_orientation * const zeus::CVector3f v1 = swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f,
zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) + -sinAng * swoosh.x8_rightRad) +
useOffset; useOffset;
zeus::CColor color = swoosh.x6c_color * x20c_moduColor; const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color}); m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
@ -833,43 +888,46 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color}); m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
} }
if (x1ec_TSPN > 0) if (x1ec_TSPN > 0) {
uvOffset += x1e8_uvSpan; uvOffset += x1e8_uvSpan;
else } else {
uvOffset = float(i* x1e8_uvSpan); uvOffset = float(i * x1e8_uvSpan);
}
} }
} }
} }
} else { } else {
for (size_t i = 0; i < x15c_swooshes.size(); ++i) { for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
SSwooshData& swoosh = x15c_swooshes[curIdx]; const SSwooshData& swoosh = x15c_swooshes[curIdx];
curIdx -= 1; curIdx -= 1;
if (curIdx < 0) if (curIdx < 0) {
curIdx = x15c_swooshes.size() - 1; curIdx = x15c_swooshes.size() - 1;
}
if (swoosh.x0_active) { if (swoosh.x0_active) {
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm); float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) { if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF; ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) if (ang > M_PIF) {
ang -= 2.f * M_PIF; ang -= 2.f * M_PIF;
else if (ang < -M_PIF) } else if (ang < -M_PIF) {
ang += 2.f * M_PIF; ang += 2.f * M_PIF;
}
} }
float sinAng = std::sin(ang); const float sinAng = std::sin(ang);
float cosAng = std::cos(ang); const float cosAng = std::cos(ang);
zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset; const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
zeus::CVector3f v0 = const zeus::CVector3f v0 =
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) + swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset; useOffset;
zeus::CVector3f v1 = const zeus::CVector3f v1 =
swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) + swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) +
useOffset; useOffset;
zeus::CColor color = swoosh.x6c_color * x20c_moduColor; const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
m_cachedVerts.push_back({v0, {}, color}); m_cachedVerts.push_back({v0, {}, color});
m_cachedVerts.push_back({v1, {}, color}); m_cachedVerts.push_back({v1, {}, color});
} }
@ -880,14 +938,17 @@ void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
} }
void CParticleSwoosh::Render(const CActorLights*) { void CParticleSwoosh::Render(const CActorLights*) {
if (x1b4_LENG < 2 || x1ac_particleCount <= 1) if (x1b4_LENG < 2 || x1ac_particleCount <= 1) {
return; return;
}
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CParticleSwoosh::Render {}"), SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CParticleSwoosh::Render {}"),
*x1c_desc.GetObjectTag()).c_str(), zeus::skYellow); *x1c_desc.GetObjectTag()).c_str(), zeus::skYellow);
m_cachedVerts.clear(); m_cachedVerts.clear();
if (m_dataBind[0]) if (m_dataBind[0]) {
CGraphics::SetShaderDataBinding(m_dataBind[g_Renderer->IsThermalVisorHotPass()]); CGraphics::SetShaderDataBinding(m_dataBind[g_Renderer->IsThermalVisorHotPass()]);
}
CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG); CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG);
CGlobalRandom gr(x1c0_rand); CGlobalRandom gr(x1c0_rand);
@ -910,15 +971,18 @@ void CParticleSwoosh::Render(const CActorLights*) {
x1d0_31_constantTex = texr->HasConstantTexture(); x1d0_31_constantTex = texr->HasConstantTexture();
x1d1_24_constantUv = texr->HasConstantUV(); x1d1_24_constantUv = texr->HasConstantUV();
if (CIntElement* tspn = x1c_desc->x40_TSPN.get()) if (CIntElement* tspn = x1c_desc->x40_TSPN.get()) {
tspn->GetValue(x28_curFrame, x1ec_TSPN); tspn->GetValue(x28_curFrame, x1ec_TSPN);
}
if (x1ec_TSPN <= 0) if (x1ec_TSPN <= 0) {
x1ec_TSPN = x15c_swooshes.size() - 1; x1ec_TSPN = x15c_swooshes.size() - 1;
}
x1e8_uvSpan = 1.f; x1e8_uvSpan = 1.f;
if (x1ec_TSPN > 0) if (x1ec_TSPN > 0) {
x1e8_uvSpan = 1.f / float(x1ec_TSPN); x1e8_uvSpan = 1.f / float(x1ec_TSPN);
}
// TEV0 modulate // TEV0 modulate
} else { } else {
@ -929,29 +993,33 @@ void CParticleSwoosh::Render(const CActorLights*) {
if (x1b8_SIDE == 2) { if (x1b8_SIDE == 2) {
if (x1b0_SPLN <= 0) { if (x1b0_SPLN <= 0) {
if (x1d0_27_renderGaps) if (x1d0_27_renderGaps) {
Render2SidedNoSplineGaps(); Render2SidedNoSplineGaps();
else } else {
Render2SidedNoSplineNoGaps(); Render2SidedNoSplineNoGaps();
}
} else { } else {
Render2SidedSpline(); Render2SidedSpline();
} }
} else if (x1b8_SIDE == 3) { } else if (x1b8_SIDE == 3) {
if (x1b0_SPLN > 0) if (x1b0_SPLN > 0) {
Render3SidedSolidSpline(); Render3SidedSolidSpline();
else } else {
Render3SidedSolidNoSplineNoGaps(); Render3SidedSolidNoSplineNoGaps();
}
} else { } else {
if (x1b0_SPLN > 0) if (x1b0_SPLN > 0) {
RenderNSidedSpline(); RenderNSidedSpline();
else } else {
RenderNSidedNoSpline(); RenderNSidedNoSpline();
}
} }
zeus::CMatrix4f mvp = CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f(); zeus::CMatrix4f mvp = CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f();
m_uniformBuf->load(&mvp, sizeof(zeus::CMatrix4f)); m_uniformBuf->load(&mvp, sizeof(zeus::CMatrix4f));
if (m_cachedVerts.size()) if (m_cachedVerts.size()) {
m_vertBuf->load(m_cachedVerts.data(), m_cachedVerts.size() * sizeof(CParticleSwooshShaders::Vert)); m_vertBuf->load(m_cachedVerts.data(), m_cachedVerts.size() * sizeof(CParticleSwooshShaders::Vert));
}
} }
void CParticleSwoosh::SetOrientation(const zeus::CTransform& xf) { void CParticleSwoosh::SetOrientation(const zeus::CTransform& xf) {
@ -994,18 +1062,19 @@ const zeus::CVector3f& CParticleSwoosh::GetGlobalScale() const { return xe0_glob
const zeus::CColor& CParticleSwoosh::GetModulationColor() const { return x20c_moduColor; } const zeus::CColor& CParticleSwoosh::GetModulationColor() const { return x20c_moduColor; }
bool CParticleSwoosh::IsSystemDeletable() const { bool CParticleSwoosh::IsSystemDeletable() const {
if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) {
return false; return false;
}
return GetParticleCount() < 2; return GetParticleCount() < 2;
} }
std::optional<zeus::CAABox> CParticleSwoosh::GetBounds() const { std::optional<zeus::CAABox> CParticleSwoosh::GetBounds() const {
if (GetParticleCount() <= 1) { if (GetParticleCount() <= 1) {
zeus::CVector3f trans = x38_translation + xa4_globalTranslation; const zeus::CVector3f trans = x38_translation + xa4_globalTranslation;
return zeus::CAABox(trans, trans); return zeus::CAABox(trans, trans);
} else { } else {
zeus::CTransform xf = zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf; const zeus::CTransform xf = zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf;
return zeus::CAABox(x1f0_aabbMin - x208_maxRadius, x1fc_aabbMax + x208_maxRadius).getTransformedAABox(xf); return zeus::CAABox(x1f0_aabbMin - x208_maxRadius, x1fc_aabbMax + x208_maxRadius).getTransformedAABox(xf);
} }
} }

View File

@ -34,7 +34,7 @@ class CParticleSwoosh : public CParticleGen {
float x30_irot; // Rotation bias once per system update float x30_irot; // Rotation bias once per system update
float x34_rotm; // Rotation bias once per particle instance float x34_rotm; // Rotation bias once per particle instance
zeus::CTransform x38_orientation; // Updated by user code zeus::CTransform x38_orientation; // Updated by user code
int x68_frame; // Frame index of evaluated data int x68_frame = 0; // Frame index of evaluated data
zeus::CColor x6c_color; // Updated by COLR zeus::CColor x6c_color; // Updated by COLR
int x70_startFrame; int x70_startFrame;
zeus::CVector3f x74_velocity; zeus::CVector3f x74_velocity;
@ -79,11 +79,11 @@ class CParticleSwoosh : public CParticleGen {
int x1b0_SPLN = 0; int x1b0_SPLN = 0;
int x1b4_LENG = 0; int x1b4_LENG = 0;
int x1b8_SIDE = 0; int x1b8_SIDE = 0;
GX::Primitive x1bc_prim; GX::Primitive x1bc_prim{};
CRandom16 x1c0_rand; CRandom16 x1c0_rand;
float x1c4_ = 0.f; float x1c4_ = 0.f;
float x1c8_ = 0.f; float x1c8_ = 0.f;
float x1cc_TSPN; float x1cc_TSPN = 0.f;
bool x1d0_24_emitting : 1; bool x1d0_24_emitting : 1;
bool x1d0_25_AALP : 1; bool x1d0_25_AALP : 1;
bool x1d0_26_forceOneUpdate : 1; bool x1d0_26_forceOneUpdate : 1;

View File

@ -28,7 +28,7 @@ constexpr std::array skComboNames{
}; };
constexpr std::array<u16, 5> skSoundId{ constexpr std::array<u16, 5> skSoundId{
1810, 1837, 1847, 1842, 1810, SFXsfx0712, SFXsfx072D, SFXwpn_combo_wavebuster, SFXwpn_combo_flamethrower, SFXsfx0712,
}; };
CAuxWeapon::CAuxWeapon(TUniqueId playerId) CAuxWeapon::CAuxWeapon(TUniqueId playerId)

View File

@ -35,60 +35,74 @@ CEnergyProjectile::CEnergyProjectile(bool active, const TToken<CWeaponDescriptio
} }
void CEnergyProjectile::PlayImpactSound(const zeus::CVector3f& pos, EWeaponCollisionResponseTypes type) { void CEnergyProjectile::PlayImpactSound(const zeus::CVector3f& pos, EWeaponCollisionResponseTypes type) {
s32 sfxId = x170_projectile.GetSoundIdForCollision(type); const s32 sfxId = x170_projectile.GetSoundIdForCollision(type);
if (sfxId >= 0) { if (sfxId < 0) {
CAudioSys::C3DEmitterParmData parmData = {}; return;
parmData.x18_maxDist = x170_projectile.GetAudibleRange();
parmData.x1c_distComp = x170_projectile.GetAudibleFallOff();
parmData.x20_flags = 0x1; // Continuous parameter update
parmData.x24_sfxId = CSfxManager::TranslateSFXID(u16(sfxId));
parmData.x26_maxVol = 1.f;
parmData.x27_minVol = 0.16f;
parmData.x29_prio = 0x7f;
CSfxHandle hnd = CSfxManager::AddEmitter(parmData, true, 0x7f, false, kInvalidAreaId);
if (x2e4_26_waterUpdate)
CSfxManager::PitchBend(hnd, -1.f);
} }
CAudioSys::C3DEmitterParmData parmData = {};
parmData.x18_maxDist = x170_projectile.GetAudibleRange();
parmData.x1c_distComp = x170_projectile.GetAudibleFallOff();
parmData.x20_flags = 0x1; // Continuous parameter update
parmData.x24_sfxId = CSfxManager::TranslateSFXID(u16(sfxId));
parmData.x26_maxVol = 1.f;
parmData.x27_minVol = 0.16f;
parmData.x29_prio = 0x7f;
const CSfxHandle hnd = CSfxManager::AddEmitter(parmData, true, 0x7f, false, kInvalidAreaId);
if (!x2e4_26_waterUpdate) {
return;
}
CSfxManager::PitchBend(hnd, -1.f);
} }
void CEnergyProjectile::ChangeProjectileOwner(TUniqueId owner, CStateManager& mgr) { void CEnergyProjectile::ChangeProjectileOwner(TUniqueId owner, CStateManager& mgr) {
if (TCastToConstPtr<CActor> act = mgr.GetObjectById(owner)) { const TCastToConstPtr<CActor> act = mgr.GetObjectById(owner);
float rDam = g_tweakPlayerGun->GetRichochetDamage(u32(x110_origDamageInfo.GetWeaponMode().GetType())); if (!act) {
x110_origDamageInfo.MultiplyDamageAndRadius(rDam); return;
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
xec_ownerId = owner;
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
/* Can now damage Player */
xf8_filter.ExcludeList().Add(EMaterialTypes::Character);
xf8_filter.ExcludeList().Remove(EMaterialTypes::Player);
xf8_filter = CMaterialFilter::MakeIncludeExclude(xf8_filter.GetIncludeList(), xf8_filter.GetExcludeList());
} }
const float rDam = g_tweakPlayerGun->GetRichochetDamage(u32(x110_origDamageInfo.GetWeaponMode().GetType()));
x110_origDamageInfo.MultiplyDamageAndRadius(rDam);
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
xec_ownerId = owner;
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
/* Can now damage Player */
xf8_filter.ExcludeList().Add(EMaterialTypes::Character);
xf8_filter.ExcludeList().Remove(EMaterialTypes::Player);
xf8_filter = CMaterialFilter::MakeIncludeExclude(xf8_filter.GetIncludeList(), xf8_filter.GetExcludeList());
} }
void CEnergyProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) { void CEnergyProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
switch (msg) { switch (msg) {
case EScriptObjectMessage::Deleted: case EScriptObjectMessage::Deleted:
if (x2e4_24_active) if (x2e4_24_active) {
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType); mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
}
if (x2e8_sfx) { if (x2e8_sfx) {
CSfxManager::RemoveEmitter(x2e8_sfx); CSfxManager::RemoveEmitter(x2e8_sfx);
x2e8_sfx.reset(); x2e8_sfx.reset();
} }
break; break;
case EScriptObjectMessage::Registered: { case EScriptObjectMessage::Registered: {
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) {
if (ps1->SystemHasLight()) if (ps1->SystemHasLight()) {
CreateProjectileLight("ProjectileLight_GameProjectile", ps1->GetLight(), mgr); CreateProjectileLight("ProjectileLight_GameProjectile", ps1->GetLight(), mgr);
TLockedToken<CWeaponDescription> desc = x170_projectile.GetWeaponDescription(); }
s32 sfx = desc->xa8_PJFX; }
const TLockedToken<CWeaponDescription> desc = x170_projectile.GetWeaponDescription();
const s32 sfx = desc->xa8_PJFX;
if (sfx != -1) { if (sfx != -1) {
float range = 50.f; float range = 50.f;
float falloff = 0.2f; float falloff = 0.2f;
if (CRealElement* rnge = desc->xac_RNGE.get()) if (CRealElement* rnge = desc->xac_RNGE.get()) {
rnge->GetValue(0, range); rnge->GetValue(0, range);
if (CRealElement* foff = desc->xb0_FOFF.get()) }
if (CRealElement* foff = desc->xb0_FOFF.get()) {
foff->GetValue(0, falloff); foff->GetValue(0, falloff);
}
CAudioSys::C3DEmitterParmData parmData = {}; CAudioSys::C3DEmitterParmData parmData = {};
parmData.x0_pos = x170_projectile.GetTranslation(); parmData.x0_pos = x170_projectile.GetTranslation();
@ -117,22 +131,27 @@ void CEnergyProjectile::Accept(IVisitor& visitor) { visitor.Visit(this); }
static constexpr u64 kCheckMaterial = 0xE3FFFE; static constexpr u64 kCheckMaterial = 0xE3FFFE;
void CEnergyProjectile::ResolveCollisionWithWorld(const CRayCastResult& res, CStateManager& mgr) { void CEnergyProjectile::ResolveCollisionWithWorld(const CRayCastResult& res, CStateManager& mgr) {
EWeaponCollisionResponseTypes crType = CCollisionResponseData::GetWorldCollisionResponseType( const auto crType = CCollisionResponseData::GetWorldCollisionResponseType(
CMaterialList::BitPosition((res.GetMaterial().GetValue() & 0xffffffff) & kCheckMaterial)); CMaterialList::BitPosition((res.GetMaterial().GetValue() & 0xffffffff) & kCheckMaterial));
if ((xe8_projectileAttribs & (EProjectileAttrib::Wave | EProjectileAttrib::ComboShot)) !=
if ((xe8_projectileAttribs & (EProjectileAttrib::Wave | EProjectileAttrib::ComboShot)) ==
(EProjectileAttrib::Wave | EProjectileAttrib::ComboShot)) { (EProjectileAttrib::Wave | EProjectileAttrib::ComboShot)) {
/* Not wavebuster */ return;
if (Explode(res.GetPoint(), res.GetPlane().normal(), crType, mgr, CDamageVulnerability::NormalVulnerabilty(),
kInvalidUniqueId))
mgr.ApplyDamageToWorld(xec_ownerId, *this, res.GetPoint(), x12c_curDamageInfo, xf8_filter);
x2c2_lastResolvedObj = kInvalidUniqueId;
} }
// Not wavebuster
if (Explode(res.GetPoint(), res.GetPlane().normal(), crType, mgr, CDamageVulnerability::NormalVulnerabilty(),
kInvalidUniqueId)) {
mgr.ApplyDamageToWorld(xec_ownerId, *this, res.GetPoint(), x12c_curDamageInfo, xf8_filter);
}
x2c2_lastResolvedObj = kInvalidUniqueId;
} }
void CEnergyProjectile::ResolveCollisionWithActor(const CRayCastResult& res, CActor& act, CStateManager& mgr) { void CEnergyProjectile::ResolveCollisionWithActor(const CRayCastResult& res, CActor& act, CStateManager& mgr) {
x2c2_lastResolvedObj = act.GetUniqueId(); x2c2_lastResolvedObj = act.GetUniqueId();
EWeaponCollisionResponseTypes crType = act.GetCollisionResponseType( const auto crType = act.GetCollisionResponseType(res.GetPoint(), x34_transform.basis[1].normalized(),
res.GetPoint(), x34_transform.basis[1].normalized(), x12c_curDamageInfo.GetWeaponMode(), xe8_projectileAttribs); x12c_curDamageInfo.GetWeaponMode(), xe8_projectileAttribs);
act.Touch(*this, mgr); act.Touch(*this, mgr);
const CDamageVulnerability* dVuln = act.GetDamageVulnerability(); const CDamageVulnerability* dVuln = act.GetDamageVulnerability();
if (!Explode(res.GetPoint(), res.GetPlane().normal(), crType, mgr, *dVuln, act.GetUniqueId())) { if (!Explode(res.GetPoint(), res.GetPlane().normal(), crType, mgr, *dVuln, act.GetUniqueId())) {
@ -142,7 +161,7 @@ void CEnergyProjectile::ResolveCollisionWithActor(const CRayCastResult& res, CAc
CGameProjectile::ResolveCollisionWithActor(res, act, mgr); CGameProjectile::ResolveCollisionWithActor(res, act, mgr);
ApplyDamageToActors(mgr, x12c_curDamageInfo); ApplyDamageToActors(mgr, x12c_curDamageInfo);
} }
if (TCastToPtr<CEnergyProjectile> proj = act) { if (const TCastToPtr<CEnergyProjectile> proj = act) {
proj->Explode(GetTranslation(), x34_transform.basis[1], EWeaponCollisionResponseTypes::OtherProjectile, mgr, proj->Explode(GetTranslation(), x34_transform.basis[1], EWeaponCollisionResponseTypes::OtherProjectile, mgr,
*GetDamageVulnerability(), GetUniqueId()); *GetDamageVulnerability(), GetUniqueId());
} }
@ -151,31 +170,36 @@ void CEnergyProjectile::ResolveCollisionWithActor(const CRayCastResult& res, CAc
void CEnergyProjectile::Think(float dt, CStateManager& mgr) { void CEnergyProjectile::Think(float dt, CStateManager& mgr) {
CWeapon::Think(dt, mgr); CWeapon::Think(dt, mgr);
if (mgr.GetWorld()->GetCurrentAreaId() != GetAreaIdAlways() && if (mgr.GetWorld()->GetCurrentAreaId() != GetAreaIdAlways() &&
(xe8_projectileAttribs & EProjectileAttrib::ArmCannon) == EProjectileAttrib::ArmCannon) (xe8_projectileAttribs & EProjectileAttrib::ArmCannon) == EProjectileAttrib::ArmCannon) {
mgr.SetActorAreaId(*this, mgr.GetWorld()->GetCurrentAreaId()); mgr.SetActorAreaId(*this, mgr.GetWorld()->GetCurrentAreaId());
}
UpdateProjectileMovement(dt, mgr); UpdateProjectileMovement(dt, mgr);
TUniqueId id = kInvalidUniqueId; TUniqueId id = kInvalidUniqueId;
CRayCastResult res = DoCollisionCheck(id, mgr); const CRayCastResult res = DoCollisionCheck(id, mgr);
if (res.IsValid()) { if (res.IsValid()) {
if (TCastToPtr<CActor> act = mgr.ObjectById(id)) if (const TCastToPtr<CActor> act = mgr.ObjectById(id)) {
ResolveCollisionWithActor(res, *act, mgr); ResolveCollisionWithActor(res, *act, mgr);
else } else {
ResolveCollisionWithWorld(res, mgr); ResolveCollisionWithWorld(res, mgr);
}
} }
x170_projectile.UpdateParticleFX(); x170_projectile.UpdateParticleFX();
if (x2e4_24_active && x3d0_26_) if (x2e4_24_active && x3d0_26_) {
Explode(GetTranslation(), zeus::skUp, EWeaponCollisionResponseTypes::Default, mgr, Explode(GetTranslation(), zeus::skUp, EWeaponCollisionResponseTypes::Default, mgr,
CDamageVulnerability::NormalVulnerabilty(), kInvalidUniqueId); CDamageVulnerability::NormalVulnerabilty(), kInvalidUniqueId);
}
if (x2c8_projectileLight != kInvalidUniqueId) { if (x2c8_projectileLight != kInvalidUniqueId) {
if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight)) { if (const TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight)) {
light->SetTransform(GetTransform()); light->SetTransform(GetTransform());
light->SetTranslation(GetTranslation()); light->SetTranslation(GetTranslation());
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) {
if (ps1->SystemHasLight()) if (ps1->SystemHasLight()) {
light->SetLight(ps1->GetLight()); light->SetLight(ps1->GetLight());
}
}
} }
} }
@ -185,20 +209,22 @@ void CEnergyProjectile::Think(float dt, CStateManager& mgr) {
} }
x3d4_curTime += dt; x3d4_curTime += dt;
if (x3d4_curTime > 45.f || x170_projectile.IsSystemDeletable() || x3d0_24_dead) if (x3d4_curTime > 45.f || x170_projectile.IsSystemDeletable() || x3d0_24_dead) {
mgr.FreeScriptObject(GetUniqueId()); mgr.FreeScriptObject(GetUniqueId());
}
} }
void CEnergyProjectile::Render(CStateManager& mgr) { void CEnergyProjectile::Render(CStateManager& mgr) {
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CEnergyProjectile::Render WPSC_{}"), x2cc_wpscId).c_str(), zeus::skOrange); SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CEnergyProjectile::Render WPSC_{}"), x2cc_wpscId).c_str(), zeus::skOrange);
CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetActiveVisor(mgr); const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
if (visor == CPlayerState::EPlayerVisor::Combat) { if (visor == CPlayerState::EPlayerVisor::Combat) {
if ((xe8_projectileAttribs & EProjectileAttrib::Charged) == EProjectileAttrib::Charged || if ((xe8_projectileAttribs & EProjectileAttrib::Charged) == EProjectileAttrib::Charged ||
(xe8_projectileAttribs & EProjectileAttrib::ComboShot) == EProjectileAttrib::ComboShot) { (xe8_projectileAttribs & EProjectileAttrib::ComboShot) == EProjectileAttrib::ComboShot) {
float warpTime = 1.f - float(x170_projectile.GameTime()); const float warpTime = 1.f - float(x170_projectile.GameTime());
if (warpTime > 0.f) if (warpTime > 0.f) {
mgr.DrawSpaceWarp(GetTranslation(), warpTime * 0.75f); mgr.DrawSpaceWarp(GetTranslation(), warpTime * 0.75f);
}
} }
} }
@ -222,11 +248,12 @@ void CEnergyProjectile::Render(CStateManager& mgr) {
} }
void CEnergyProjectile::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) { void CEnergyProjectile::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
auto bounds = x170_projectile.GetBounds(); const auto bounds = x170_projectile.GetBounds();
if (bounds && !frustum.aabbFrustumTest(*bounds)) if (bounds && !frustum.aabbFrustumTest(*bounds)) {
return; return;
}
CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetActiveVisor(mgr); const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
if (visor != CPlayerState::EPlayerVisor::XRay && if (visor != CPlayerState::EPlayerVisor::XRay &&
((xe8_projectileAttribs & EProjectileAttrib::Ice) != EProjectileAttrib::Ice || ((xe8_projectileAttribs & EProjectileAttrib::Ice) != EProjectileAttrib::Ice ||
mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot)) { mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot)) {
@ -247,7 +274,8 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
bool retargetPlayer = false; bool retargetPlayer = false;
bool deflect = false; bool deflect = false;
zeus::CVector3f targetPos; zeus::CVector3f targetPos;
EVulnerability vulnType = dVuln.GetVulnerability(x12c_curDamageInfo.GetWeaponMode(), false); const EVulnerability vulnType = dVuln.GetVulnerability(x12c_curDamageInfo.GetWeaponMode(), false);
if (vulnType == EVulnerability::Deflect) { if (vulnType == EVulnerability::Deflect) {
deflect = true; deflect = true;
EDeflectType deflectType = dVuln.GetDeflectionType(x12c_curDamageInfo.GetWeaponMode()); EDeflectType deflectType = dVuln.GetDeflectionType(x12c_curDamageInfo.GetWeaponMode());
@ -259,17 +287,19 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
case EDeflectType::Three: case EDeflectType::Three:
if (deflectType != EDeflectType::Two || if (deflectType != EDeflectType::Two ||
(xf0_weaponType != EWeaponType::Missile && (xf0_weaponType != EWeaponType::Missile &&
(xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::ComboShot)) (xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::ComboShot)) {
if (xf8_filter.GetExcludeList().HasMaterial(EMaterialTypes::Player)) if (xf8_filter.GetExcludeList().HasMaterial(EMaterialTypes::Player)) {
retargetPlayer = true; retargetPlayer = true;
}
}
break; break;
default: default:
break; break;
} }
if (retargetPlayer) { if (retargetPlayer) {
float ang = mgr.GetActiveRandom()->Range(0.f, 2.f * M_PIF); const float ang = mgr.GetActiveRandom()->Range(0.f, 2.f * M_PIF);
float y = std::sin(ang); const float y = std::sin(ang);
float x = std::cos(ang); const float x = std::cos(ang);
targetPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f) + zeus::CVector3f(x, 0.f, y); targetPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f) + zeus::CVector3f(x, 0.f, y);
ChangeProjectileOwner(hitActor, mgr); ChangeProjectileOwner(hitActor, mgr);
} }
@ -278,7 +308,8 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
if (vulnType != EVulnerability::Immune && !deflect) { if (vulnType != EVulnerability::Immune && !deflect) {
deflect = deflect =
(type == EWeaponCollisionResponseTypes::Unknown15 || type == EWeaponCollisionResponseTypes::EnemyShielded || (type == EWeaponCollisionResponseTypes::Unknown15 || type == EWeaponCollisionResponseTypes::EnemyShielded ||
(type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect)); (type >= EWeaponCollisionResponseTypes::Unknown69 &&
type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect));
} }
SetTranslation(offsetPos); SetTranslation(offsetPos);
@ -309,29 +340,30 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
zeus::CVector3f scale = zeus::skOne3f; zeus::CVector3f scale = zeus::skOne3f;
bool camClose = false; bool camClose = false;
if (mgr.GetPlayer().GetCameraState() == CPlayer::EPlayerCameraState::FirstPerson) { if (mgr.GetPlayer().GetCameraState() == CPlayer::EPlayerCameraState::FirstPerson) {
float mag = (offsetPos - mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation()).magnitude(); const float mag = (offsetPos - mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation()).magnitude();
if (mag < 4.f) { if (mag < 4.f) {
scale = zeus::CVector3f(0.75f * (mag * 0.25f) + 0.25f); scale = zeus::CVector3f(0.75f * (mag * 0.25f) + 0.25f);
camClose = true; camClose = true;
} }
} }
u32 explodeFlags = 0x8; u32 explodeFlags = 0x8;
if ((xe8_projectileAttribs & EProjectileAttrib::Ice) == EProjectileAttrib::Ice) if ((xe8_projectileAttribs & EProjectileAttrib::Ice) == EProjectileAttrib::Ice) {
explodeFlags |= 0x4; explodeFlags |= 0x4;
if (camClose) }
if (camClose) {
explodeFlags |= 0x2; explodeFlags |= 0x2;
CEntityInfo explosionInfo(GetAreaIdAlways(), CEntity::NullConnectionList); }
CExplosion* explosion = const CEntityInfo explosionInfo(GetAreaIdAlways(), CEntity::NullConnectionList);
new CExplosion(*particle, mgr.AllocateUniqueId(), true, explosionInfo, "Projectile collision response", auto* explosion = new CExplosion(*particle, mgr.AllocateUniqueId(), true, explosionInfo,
particleXf, explodeFlags, scale, zeus::skWhite); "Projectile collision response", particleXf, explodeFlags, scale, zeus::skWhite);
mgr.AddObject(explosion); mgr.AddObject(explosion);
if (TCastToPtr<CActor> hActor = mgr.ObjectById(hitActor)) { if (const TCastToPtr<CActor> hActor = mgr.ObjectById(hitActor)) {
bool validPlat = false; bool validPlat = false;
CScriptPlatform* plat = TCastToPtr<CScriptPlatform>(hActor.GetPtr()).GetPtr(); CScriptPlatform* plat = TCastToPtr<CScriptPlatform>(hActor.GetPtr()).GetPtr();
validPlat = plat != nullptr; validPlat = plat != nullptr;
if (!validPlat && hActor->GetMaterialList().HasMaterial(EMaterialTypes::Bomb)) { if (!validPlat && hActor->GetMaterialList().HasMaterial(EMaterialTypes::Bomb)) {
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) { for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) {
if (TCastToPtr<CScriptPlatform> otherPlat = ent) { if (const TCastToPtr<CScriptPlatform> otherPlat = ent) {
if (otherPlat->IsSlave(hitActor)) { if (otherPlat->IsSlave(hitActor)) {
plat = otherPlat.GetPtr(); plat = otherPlat.GetPtr();
validPlat = true; validPlat = true;
@ -340,8 +372,9 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
} }
} }
} }
if (validPlat) if (validPlat) {
plat->AddSlave(explosion->GetUniqueId(), mgr); plat->AddSlave(explosion->GetUniqueId(), mgr);
}
} }
} else { } else {
x3d0_24_dead = true; x3d0_24_dead = true;
@ -349,13 +382,14 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
if ((xe8_projectileAttribs & (EProjectileAttrib::ComboShot | EProjectileAttrib::Ice)) == if ((xe8_projectileAttribs & (EProjectileAttrib::ComboShot | EProjectileAttrib::Ice)) ==
(EProjectileAttrib::ComboShot | EProjectileAttrib::Ice)) { (EProjectileAttrib::ComboShot | EProjectileAttrib::Ice)) {
/* Ice Spreader */ // Ice Spreader
TLockedToken<CGenDescription> iceSpreadParticle = g_SimplePool->GetObj("IceSpread1"); const TLockedToken<CGenDescription> iceSpreadParticle = g_SimplePool->GetObj("IceSpread1");
u32 flags = (xe6_27_thermalVisorFlags & 0x2) == 0 ? 1 : 0; u32 flags = (xe6_27_thermalVisorFlags & 0x2) == 0 ? 1 : 0;
flags |= 0x2; flags |= 0x2;
CIceImpact* iceImpact =
new CIceImpact(iceSpreadParticle, mgr.AllocateUniqueId(), GetAreaIdAlways(), true, "Ice spread explosion", auto* iceImpact = new CIceImpact(iceSpreadParticle, mgr.AllocateUniqueId(), GetAreaIdAlways(), true,
particleXf, flags, zeus::skOne3f, zeus::skWhite); "Ice spread explosion", particleXf, flags, zeus::skOne3f, zeus::skWhite);
mgr.AddObject(iceImpact); mgr.AddObject(iceImpact);
} }
} }

View File

@ -83,8 +83,7 @@ void CFluidPlane::AddRipple(const CRipple& ripple, const CScriptWater& water, CS
mgr.GetFluidPlaneManager()->RippleManager().AddRipple(ripple); mgr.GetFluidPlaneManager()->RippleManager().AddRipple(ripple);
} }
void CFluidPlane::RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], void CFluidPlane::RenderStripWithRipples(float curY, const Heights& heights, const Flags& flags, int startYDiv,
const u8 (&flags)[9][9], int startYDiv,
const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info,
std::vector<CFluidPlaneShader::Vertex>& vOut, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut) { std::vector<CFluidPlaneShader::PatchVertex>& pvOut) {
@ -310,8 +309,7 @@ void CFluidPlane::RenderStripWithRipples(float curY, const CFluidPlaneRender::SH
} }
} }
void CFluidPlane::RenderPatch(const CFluidPlaneRender::SPatchInfo& info, void CFluidPlane::RenderPatch(const CFluidPlaneRender::SPatchInfo& info, const Heights& heights, const Flags& flags,
const CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9],
bool noRipples, bool flagIs1, std::vector<CFluidPlaneShader::Vertex>& vOut, bool noRipples, bool flagIs1, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut) { std::vector<CFluidPlaneShader::PatchVertex>& pvOut) {
if (noRipples) { if (noRipples) {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <array>
#include <cmath> #include <cmath>
#include <optional> #include <optional>
#include <vector> #include <vector>
@ -84,10 +85,10 @@ public:
struct SRippleInfo { struct SRippleInfo {
const CRipple& x0_ripple; const CRipple& x0_ripple;
int x4_fromX; int x4_fromX = 0;
int x8_toX; int x8_toX = 0;
int xc_fromY; int xc_fromY = 0;
int x10_toY; int x10_toY = 0;
int x14_gfromX; int x14_gfromX;
int x18_gtoX; int x18_gtoX;
int x1c_gfromY; int x1c_gfromY;
@ -116,6 +117,10 @@ public:
}; };
class CFluidPlane { class CFluidPlane {
public:
using Flags = std::array<std::array<u8, 9>, 9>;
using Heights = std::array<std::array<CFluidPlaneRender::SHFieldSample, 46>, 46>;
protected: protected:
CAssetId x4_texPattern1Id; CAssetId x4_texPattern1Id;
CAssetId x8_texPattern2Id; CAssetId x8_texPattern2Id;
@ -135,12 +140,12 @@ protected:
float ProjectRippleVelocity(float baseI, float velDot) const; float ProjectRippleVelocity(float baseI, float velDot) const;
float CalculateRippleIntensity(float baseI) const; float CalculateRippleIntensity(float baseI) const;
virtual void RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], virtual void RenderStripWithRipples(float curY, const Heights& heights, const Flags& flags, int startYDiv,
const u8 (&flags)[9][9], int startYDiv, const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info,
std::vector<CFluidPlaneShader::Vertex>& vOut, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut); std::vector<CFluidPlaneShader::PatchVertex>& pvOut);
void RenderPatch(const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], void RenderPatch(const CFluidPlaneRender::SPatchInfo& info, const Heights& heights, const Flags& flags,
const u8 (&flags)[9][9], bool noRipples, bool flagIs1, std::vector<CFluidPlaneShader::Vertex>& vOut, bool noRipples, bool flagIs1, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut); std::vector<CFluidPlaneShader::PatchVertex>& pvOut);
public: public:

View File

@ -110,14 +110,15 @@ void CFluidPlaneCPU::CalculateLightmapMatrix(const zeus::CTransform& areaXf, con
} }
static bool sSineWaveInitialized = false; static bool sSineWaveInitialized = false;
static float sGlobalSineWave[256] = {}; static CFluidPlaneCPU::SineTable sGlobalSineWave{};
static const float* InitializeSineWave() { static void InitializeSineWave() {
if (sSineWaveInitialized) if (sSineWaveInitialized) {
return sGlobalSineWave; return;
for (int i = 0; i < 256; ++i) }
sGlobalSineWave[i] = std::sin(2.f * M_PIF * (i / 256.f)); for (size_t i = 0; i < sGlobalSineWave.size(); ++i) {
sGlobalSineWave[i] = std::sin(2.f * M_PIF * (float(i) / 256.f));
}
sSineWaveInitialized = true; sSineWaveInitialized = true;
return sGlobalSineWave;
} }
#define kEnableWaterBumpMaps true #define kEnableWaterBumpMaps true
@ -303,8 +304,7 @@ bool CFluidPlaneCPU::PrepareRipple(const CRipple& ripple, const CFluidPlaneRende
return !(rippleOut.x14_gfromX > rippleOut.x18_gtoX || rippleOut.x1c_gfromY > rippleOut.x20_gtoY); return !(rippleOut.x14_gfromX > rippleOut.x18_gtoX || rippleOut.x1c_gfromY > rippleOut.x20_gtoY);
} }
void CFluidPlaneCPU::ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (&heights)[46][46], void CFluidPlaneCPU::ApplyTurbulence(float t, Heights& heights, const Flags& flags, const SineTable& sineWave,
const u8 (&flags)[9][9], const float sineWave[256],
const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info,
const zeus::CVector3f& areaCenter) const { const zeus::CVector3f& areaCenter) const {
if (!HasTurbulence()) { if (!HasTurbulence()) {
@ -334,9 +334,8 @@ void CFluidPlaneCPU::ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (
} }
} }
void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, Heights& heights, Flags& flags,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const {
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info) const {
float lookupT = 256.f * float lookupT = 256.f *
(1.f - rippleInfo.x0_ripple.GetTime() * rippleInfo.x0_ripple.GetOOTimeFalloff() * (1.f - rippleInfo.x0_ripple.GetTime() * rippleInfo.x0_ripple.GetOOTimeFalloff() *
rippleInfo.x0_ripple.GetOOTimeFalloff()) * rippleInfo.x0_ripple.GetOOTimeFalloff()) *
@ -409,8 +408,9 @@ void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInf
float divDist = (divDistSq != 0.f) ? std::sqrt(divDistSq) : 0.f; float divDist = (divDistSq != 0.f) ? std::sqrt(divDistSq) : 0.f;
if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) { if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) {
heights[k][l].height += rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() * heights[k][l].height +=
sineWave[int(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff]; rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[size_t(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
} else { } else {
heights[k][l].height += 0.f; heights[k][l].height += 0.f;
} }
@ -460,8 +460,9 @@ void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInf
float divDist = (divDistSq != 0.f) ? std::sqrt(divDistSq) : 0.f; float divDist = (divDistSq != 0.f) ? std::sqrt(divDistSq) : 0.f;
if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) { if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) {
heights[k][l].height += rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() * heights[k][l].height +=
sineWave[int(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff]; rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[size_t(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
} else { } else {
heights[k][l].height += 0.f; heights[k][l].height += 0.f;
} }
@ -485,8 +486,8 @@ void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInf
} }
void CFluidPlaneCPU::ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos, void CFluidPlaneCPU::ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], Heights& heights, Flags& flags, const SineTable& sineWave,
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info) const { const CFluidPlaneRender::SPatchInfo& info) const {
for (const CFluidPlaneRender::SRippleInfo& rippleInfo : rippleInfos) for (const CFluidPlaneRender::SRippleInfo& rippleInfo : rippleInfos)
ApplyRipple(rippleInfo, heights, flags, sineWave, info); ApplyRipple(rippleInfo, heights, flags, sineWave, info);
for (int i = 0; i < CFluidPlaneRender::numTilesInHField; ++i) for (int i = 0; i < CFluidPlaneRender::numTilesInHField; ++i)
@ -499,7 +500,7 @@ void CFluidPlaneCPU::ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender:
flags[CFluidPlaneRender::numTilesInHField + 1][i + 1] |= 2; flags[CFluidPlaneRender::numTilesInHField + 1][i + 1] |= 2;
} }
void CFluidPlaneCPU::UpdatePatchNoNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9], void CFluidPlaneCPU::UpdatePatchNoNormals(Heights& heights, const Flags& flags,
const CFluidPlaneRender::SPatchInfo& info) { const CFluidPlaneRender::SPatchInfo& info) {
for (int i = 1; i <= (info.x1_ySubdivs + CFluidPlaneRender::numSubdivisionsInTile - 2) / for (int i = 1; i <= (info.x1_ySubdivs + CFluidPlaneRender::numSubdivisionsInTile - 2) /
CFluidPlaneRender::numSubdivisionsInTile; CFluidPlaneRender::numSubdivisionsInTile;
@ -558,8 +559,8 @@ void CFluidPlaneCPU::UpdatePatchNoNormals(CFluidPlaneRender::SHFieldSample (&hei
} }
} }
void CFluidPlaneCPU::UpdatePatchWithNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46], void CFluidPlaneCPU::UpdatePatchWithNormals(Heights& heights, const Flags& flags,
const u8 (&flags)[9][9], const CFluidPlaneRender::SPatchInfo& info) { const CFluidPlaneRender::SPatchInfo& info) {
float normalScale = -(2.f * info.x18_rippleResolution); float normalScale = -(2.f * info.x18_rippleResolution);
float nz = 0.25f * 2.f * info.x18_rippleResolution; float nz = 0.25f * 2.f * info.x18_rippleResolution;
int curGridY = info.x2e_tileY * info.x2a_gridDimX - 1 + info.x28_tileX; int curGridY = info.x2e_tileY * info.x2a_gridDimX - 1 + info.x28_tileX;
@ -696,11 +697,9 @@ void CFluidPlaneCPU::UpdatePatchWithNormals(CFluidPlaneRender::SHFieldSample (&h
} }
} }
bool CFluidPlaneCPU::UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info, bool CFluidPlaneCPU::UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info, Heights& heights, Flags& flags,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const zeus::CVector3f& areaCenter, const std::optional<CRippleManager>& rippleManager,
const zeus::CVector3f& areaCenter, int fromX, int toX, int fromY, int toY) const {
const std::optional<CRippleManager>& rippleManager, int fromX, int toX,
int fromY, int toY) const {
rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32> rippleInfos; rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32> rippleInfos;
if (rippleManager) { if (rippleManager) {
for (const CRipple& ripple : rippleManager->GetRipples()) { for (const CRipple& ripple : rippleManager->GetRipples()) {
@ -730,10 +729,10 @@ bool CFluidPlaneCPU::UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo
return false; return false;
} }
/* Used to be part of locked cache // Used to be part of locked cache
* These are too big for stack allocation */ // These are too big for stack allocation
static CFluidPlaneRender::SHFieldSample lc_heights[46][46] = {}; static CFluidPlane::Heights lc_heights{};
static u8 lc_flags[9][9] = {}; static CFluidPlane::Flags lc_flags{};
void CFluidPlaneCPU::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf, void CFluidPlaneCPU::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum, const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum,

View File

@ -12,6 +12,9 @@ namespace urde {
class CFluidUVMotion; class CFluidUVMotion;
class CFluidPlaneCPU : public CFluidPlane { class CFluidPlaneCPU : public CFluidPlane {
public:
using SineTable = std::array<float, 256>;
protected: protected:
class CTurbulence { class CTurbulence {
float x0_speed; float x0_speed;
@ -60,28 +63,22 @@ protected:
u32 m_maxVertCount; u32 m_maxVertCount;
bool m_tessellation = false; bool m_tessellation = false;
bool m_cachedDoubleLightmapBlend; bool m_cachedDoubleLightmapBlend = false;
bool m_cachedAdditive; bool m_cachedAdditive = false;
static bool PrepareRipple(const CRipple& ripple, const CFluidPlaneRender::SPatchInfo& info, static bool PrepareRipple(const CRipple& ripple, const CFluidPlaneRender::SPatchInfo& info,
CFluidPlaneRender::SRippleInfo& rippleOut); CFluidPlaneRender::SRippleInfo& rippleOut);
void ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9], void ApplyTurbulence(float t, Heights& heights, const Flags& flags, const SineTable& sineWave,
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info, const zeus::CVector3f& areaCenter) const;
const zeus::CVector3f& areaCenter) const; void ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, Heights& heights, Flags& flags,
void ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const;
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const float sineWave[256], void ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos, Heights& heights,
const CFluidPlaneRender::SPatchInfo& info) const; Flags& flags, const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const;
void ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos, static void UpdatePatchNoNormals(Heights& heights, const Flags& flags, const CFluidPlaneRender::SPatchInfo& info);
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const float sineWave[256], static void UpdatePatchWithNormals(Heights& heights, const Flags& flags, const CFluidPlaneRender::SPatchInfo& info);
const CFluidPlaneRender::SPatchInfo& info) const; bool UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info, Heights& heights, Flags& flags,
static void UpdatePatchNoNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9], const zeus::CVector3f& areaCenter, const std::optional<CRippleManager>& rippleManager, int fromX,
const CFluidPlaneRender::SPatchInfo& info); int toX, int fromY, int toY) const;
static void UpdatePatchWithNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9],
const CFluidPlaneRender::SPatchInfo& info);
bool UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9],
const zeus::CVector3f& areaCenter, const std::optional<CRippleManager>& rippleManager,
int fromX, int toX, int fromY, int toY) const;
public: public:
CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap, CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap,

View File

@ -51,10 +51,10 @@ CFluidPlaneShader::RenderSetupInfo CFluidPlaneDoor::RenderSetup(const CStateMana
return out; return out;
} }
/* Used to be part of locked cache // Used to be part of locked cache
* These are too big for stack allocation */ // These are too big for stack allocation
static CFluidPlaneRender::SHFieldSample lc_heights[46][46] = {}; static CFluidPlane::Heights lc_heights{};
static u8 lc_flags[9][9] = {}; static CFluidPlane::Flags lc_flags{};
void CFluidPlaneDoor::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, void CFluidPlaneDoor::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb,
const zeus::CTransform& xf, const zeus::CTransform& areaXf, bool noNormals, const zeus::CTransform& xf, const zeus::CTransform& areaXf, bool noNormals,

View File

@ -17,8 +17,7 @@ CFluidPlaneGPU::CFluidPlaneGPU(CAssetId texPattern1, CAssetId texPattern2, CAsse
m_tessellation = true; m_tessellation = true;
} }
void CFluidPlaneGPU::RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], void CFluidPlaneGPU::RenderStripWithRipples(float curY, const Heights& heights, const Flags& flags, int startYDiv,
const u8 (&flags)[9][9], int startYDiv,
const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info,
std::vector<CFluidPlaneShader::Vertex>& vOut, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut) { std::vector<CFluidPlaneShader::PatchVertex>& pvOut) {

View File

@ -17,9 +17,8 @@ public:
float turbAmplitudeMin, float specularMin, float specularMax, float reflectionBlend, float turbAmplitudeMin, float specularMin, float specularMax, float reflectionBlend,
float reflectionSize, float rippleIntensity, u32 maxVertCount); float reflectionSize, float rippleIntensity, u32 maxVertCount);
void RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], void RenderStripWithRipples(float curY, const Heights& heights, const Flags& flags, int startYDiv,
const u8 (&flags)[9][9], int startYDiv, const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SPatchInfo& info, std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut) override; std::vector<CFluidPlaneShader::PatchVertex>& pvOut) override;
}; };

View File

@ -283,8 +283,9 @@ CMorphBall::CMorphBall(CPlayer& player, float radius)
kSpiderBallCollisionRadius = GetBallRadius() + 0.2f; kSpiderBallCollisionRadius = GetBallRadius() + 0.2f;
for (int i = 0; i < 32; ++i) for (size_t i = 0; i < x19e4_spiderElectricGens.capacity(); ++i) {
x19e4_spiderElectricGens.emplace_back(std::make_unique<CParticleSwoosh>(x19a0_spiderElectric, 0), false); x19e4_spiderElectricGens.emplace_back(std::make_unique<CParticleSwoosh>(x19a0_spiderElectric, 0), false);
}
LoadAnimationTokens("SamusBallANCS"); LoadAnimationTokens("SamusBallANCS");
InitializeWakeEffects(); InitializeWakeEffects();
@ -303,10 +304,9 @@ void CMorphBall::LoadAnimationTokens(std::string_view ancsName) {
} }
void CMorphBall::InitializeWakeEffects() { void CMorphBall::InitializeWakeEffects() {
TToken<CGenDescription> nullParticle = const TToken<CGenDescription> nullParticle =
CToken(TObjOwnerDerivedFromIObj<CGenDescription>::GetNewDerivedObject(std::make_unique<CGenDescription>())); CToken(TObjOwnerDerivedFromIObj<CGenDescription>::GetNewDerivedObject(std::make_unique<CGenDescription>()));
for (int i = 0; i < 8; ++i) x1b84_wakeEffects.resize(x1b84_wakeEffects.capacity(), nullParticle);
x1b84_wakeEffects.push_back(nullParticle);
x1b84_wakeEffects[2] = g_SimplePool->GetObj("DirtWake"); x1b84_wakeEffects[2] = g_SimplePool->GetObj("DirtWake");
x1b84_wakeEffects[0] = g_SimplePool->GetObj("PhazonWake"); x1b84_wakeEffects[0] = g_SimplePool->GetObj("PhazonWake");
@ -317,7 +317,7 @@ void CMorphBall::InitializeWakeEffects() {
x1b84_wakeEffects[6] = g_SimplePool->GetObj("SandWake"); x1b84_wakeEffects[6] = g_SimplePool->GetObj("SandWake");
x1b84_wakeEffects[7] = g_SimplePool->GetObj("RainWake"); x1b84_wakeEffects[7] = g_SimplePool->GetObj("RainWake");
x1bc8_wakeEffectGens.resize(8); x1bc8_wakeEffectGens.resize(x1b84_wakeEffects.capacity());
x1bc8_wakeEffectGens[2] = std::make_unique<CElementGen>(x1b84_wakeEffects[2]); x1bc8_wakeEffectGens[2] = std::make_unique<CElementGen>(x1b84_wakeEffects[2]);
x1bc8_wakeEffectGens[0] = std::make_unique<CElementGen>(x1b84_wakeEffects[0]); x1bc8_wakeEffectGens[0] = std::make_unique<CElementGen>(x1b84_wakeEffects[0]);
x1bc8_wakeEffectGens[1] = std::make_unique<CElementGen>(x1b84_wakeEffects[1]); x1bc8_wakeEffectGens[1] = std::make_unique<CElementGen>(x1b84_wakeEffects[1]);

View File

@ -27,7 +27,7 @@ private:
CPFArea* x0_area; CPFArea* x0_area;
rstl::reserved_vector<zeus::CVector3f, 16> x4_waypoints; rstl::reserved_vector<zeus::CVector3f, 16> x4_waypoints;
u32 xc8_curWaypoint = 0; u32 xc8_curWaypoint = 0;
EResult xcc_result; EResult xcc_result{};
float xd0_chHeight; float xd0_chHeight;
float xd4_chRadius; float xd4_chRadius;
float xd8_padding = 10.f; float xd8_padding = 10.f;

View File

@ -15,7 +15,7 @@ class CScriptPickup : public CPhysicsActor {
float x268_fadeInTime; float x268_fadeInTime;
float x26c_lifeTime; float x26c_lifeTime;
float x270_curTime = 0.f; float x270_curTime = 0.f;
float x274_tractorTime; float x274_tractorTime = 0.f;
float x278_delayTimer; float x278_delayTimer;
TLockedToken<CGenDescription> x27c_pickupParticleDesc; TLockedToken<CGenDescription> x27c_pickupParticleDesc;

View File

@ -78,7 +78,7 @@ class CScriptSpindleCamera : public CGameCamera {
float x328_maxAzimuthInterpTimer = 0.f; float x328_maxAzimuthInterpTimer = 0.f;
bool x32c_outsideClampedAzimuth = false; bool x32c_outsideClampedAzimuth = false;
zeus::CVector3f x330_lookDir; zeus::CVector3f x330_lookDir;
bool x33c_24_inResetThink; bool x33c_24_inResetThink = false;
float GetInVar(const SSpindleProperty& seg) const { return x18c_inVars[int(seg.x4_input)]; } float GetInVar(const SSpindleProperty& seg) const { return x18c_inVars[int(seg.x4_input)]; }

View File

@ -78,10 +78,10 @@ void CStateMachineState::Update(CStateManager& mgr, CAi& ai, float delta) {
if (andPassed && state) { if (andPassed && state) {
x4_state->CallFunc(mgr, ai, EStateMsg::Deactivate, 0.f); x4_state->CallFunc(mgr, ai, EStateMsg::Deactivate, 0.f);
x4_state = state; x4_state = state;
#ifndef NDEBUG //#ifndef NDEBUG
fmt::print(FMT_STRING("{} {} {} - {} {}\n"), ai.GetUniqueId(), ai.GetEditorId(), ai.GetName(), // fmt::print(FMT_STRING("{} {} {} - {} {}\n"), ai.GetUniqueId(), ai.GetEditorId(), ai.GetName(),
state->xc_name, int(state - x0_machine->GetStateVector().data())); // state->xc_name, int(state - x0_machine->GetStateVector().data()));
#endif //#endif
x8_time = 0.f; x8_time = 0.f;
x18_24_codeTrigger = false; x18_24_codeTrigger = false;
xc_random = mgr.GetActiveRandom()->Float(); xc_random = mgr.GetActiveRandom()->Float();

View File

@ -50,8 +50,8 @@ class CAiState {
friend class CStateMachineState; friend class CStateMachineState;
CAiStateFunc x0_func; CAiStateFunc x0_func;
char xc_name[32] = {}; char xc_name[32] = {};
u32 x2c_numTriggers; u32 x2c_numTriggers = 0;
CAiTrigger* x30_firstTrigger; CAiTrigger* x30_firstTrigger = nullptr;
public: public:
CAiState(CAiStateFunc func, const char* name) { CAiState(CAiStateFunc func, const char* name) {
@ -88,7 +88,7 @@ class CStateMachineState {
float x8_time = 0.f; float x8_time = 0.f;
float xc_random = 0.f; float xc_random = 0.f;
float x10_delay = 0.f; float x10_delay = 0.f;
float x14_; float x14_ = 0.f;
bool x18_24_codeTrigger : 1; bool x18_24_codeTrigger : 1;
public: public:

View File

@ -69,9 +69,9 @@ void CVisorFlare::Update(float dt, const zeus::CVector3f& pos, const CActor* act
mgr.SetThermalColdScale2(mgr.GetThermalColdScale2() + x24_); mgr.SetThermalColdScale2(mgr.GetThermalColdScale2() + x24_);
} }
#ifndef NDEBUG //#ifndef NDEBUG
printf("%08X %f %f\n", act->GetEditorId().id, x24_, x28_); // printf("%08X %f %f\n", act->GetEditorId().id, x24_, x28_);
#endif //#endif
} }
} }

View File

@ -38,7 +38,7 @@ public:
CCollisionSurface x50_surface = CCollisionSurface x50_surface =
CCollisionSurface(zeus::CVector3f(0.f, 0.f, 1.f), zeus::CVector3f(0.f, 1.f, 0.f), CCollisionSurface(zeus::CVector3f(0.f, 0.f, 1.f), zeus::CVector3f(0.f, 1.f, 0.f),
zeus::CVector3f(1.f, 0.f, 0.f), 0xffffffff); zeus::CVector3f(1.f, 0.f, 0.f), 0xffffffff);
float x78_health; float x78_health = 0.f;
int x7c_framesNotOnSurface : 8; int x7c_framesNotOnSurface : 8;
int x7c_idx : 10; int x7c_idx : 10;
int x7c_remainingLaunchNotOnSurfaceFrames : 8; int x7c_remainingLaunchNotOnSurfaceFrames : 8;
@ -53,6 +53,7 @@ public:
: x0_xf(xf) : x0_xf(xf)
, x7c_framesNotOnSurface(0) , x7c_framesNotOnSurface(0)
, x7c_idx(idx) , x7c_idx(idx)
, x7c_remainingLaunchNotOnSurfaceFrames(0)
, x80_24_active(false) , x80_24_active(false)
, x80_25_inFrustum(false) , x80_25_inFrustum(false)
, x80_26_launched(false) , x80_26_launched(false)

View File

@ -1,5 +1,8 @@
#include "Runtime/World/CWorld.hpp" #include "Runtime/World/CWorld.hpp"
#include <algorithm>
#include <iterator>
#include "Runtime/CGameState.hpp" #include "Runtime/CGameState.hpp"
#include "Runtime/CInGameTweakManagerBase.hpp" #include "Runtime/CInGameTweakManagerBase.hpp"
#include "Runtime/CSimplePool.hpp" #include "Runtime/CSimplePool.hpp"
@ -44,15 +47,17 @@ const IGameArea* CDummyWorld::IGetAreaAlways(TAreaId id) const { return &x18_are
TAreaId CDummyWorld::IGetCurrentAreaId() const { return x3c_curAreaId; } TAreaId CDummyWorld::IGetCurrentAreaId() const { return x3c_curAreaId; }
TAreaId CDummyWorld::IGetAreaId(CAssetId id) const { TAreaId CDummyWorld::IGetAreaId(CAssetId id) const {
int ret = 0; if (!id.IsValid()) {
if (!id.IsValid())
return kInvalidAreaId; return kInvalidAreaId;
for (const CDummyGameArea& area : x18_areas) {
if (area.xc_mrea == id)
return ret;
++ret;
} }
return kInvalidAreaId;
const auto iter =
std::find_if(x18_areas.cbegin(), x18_areas.cend(), [id](const auto& area) { return area.xc_mrea == id; });
if (iter == x18_areas.cend()) {
return kInvalidAreaId;
}
return TAreaId(std::distance(x18_areas.cbegin(), iter));
} }
CWorld::CRelay::CRelay(CInputStream& in) { CWorld::CRelay::CRelay(CInputStream& in) {
@ -226,15 +231,17 @@ const IGameArea* CWorld::IGetAreaAlways(TAreaId id) const { return GetAreaAlways
TAreaId CWorld::IGetCurrentAreaId() const { return x68_curAreaId; } TAreaId CWorld::IGetCurrentAreaId() const { return x68_curAreaId; }
TAreaId CWorld::IGetAreaId(CAssetId id) const { TAreaId CWorld::IGetAreaId(CAssetId id) const {
int ret = 0; if (!id.IsValid()) {
if (!id.IsValid())
return kInvalidAreaId; return kInvalidAreaId;
for (const std::unique_ptr<CGameArea>& area : x18_areas) {
if (area->x84_mrea == id)
return ret;
++ret;
} }
return kInvalidAreaId;
const auto iter =
std::find_if(x18_areas.cbegin(), x18_areas.cend(), [id](const auto& area) { return area->x84_mrea == id; });
if (iter == x18_areas.cend()) {
return kInvalidAreaId;
}
return TAreaId(std::distance(x18_areas.cbegin(), iter));
} }
void CWorld::MoveToChain(CGameArea* area, EChain chain) { void CWorld::MoveToChain(CGameArea* area, EChain chain) {
@ -705,19 +712,20 @@ bool CWorld::AreSkyNeedsMet() const {
} }
TAreaId CWorld::GetAreaIdForSaveId(s32 saveId) const { TAreaId CWorld::GetAreaIdForSaveId(s32 saveId) const {
if (saveId == -1) if (saveId == -1) {
return kInvalidAreaId; return kInvalidAreaId;
if (x18_areas.size() <= 0)
return kInvalidAreaId;
TAreaId cur = 0;
for (const auto& area : x18_areas) {
if (area->x88_areaId == saveId)
return cur;
++cur;
} }
return kInvalidAreaId; if (x18_areas.empty()) {
return kInvalidAreaId;
}
const auto iter = std::find_if(x18_areas.cbegin(), x18_areas.cend(),
[saveId](const auto& area) { return area->x88_areaId == saveId; });
if (iter == x18_areas.cend()) {
return kInvalidAreaId;
}
return TAreaId(std::distance(x18_areas.cbegin(), iter));
} }
} // namespace urde } // namespace urde

View File

@ -171,7 +171,7 @@ public:
void CycleLoadPauseState(); void CycleLoadPauseState();
CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId); CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId);
~CWorld(); ~CWorld() override;
bool DoesAreaExist(TAreaId area) const; bool DoesAreaExist(TAreaId area) const;
const std::vector<std::unique_ptr<CGameArea>>& GetGameAreas() const { return x18_areas; } const std::vector<std::unique_ptr<CGameArea>>& GetGameAreas() const { return x18_areas; }

BIN
assets/urde-screen1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

2
hecl

@ -1 +1 @@
Subproject commit f64ed44fe8164b06ed5bef6344d9f743e2c5d638 Subproject commit d208592b2825188940064e462038e2ce90164101