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 {
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,
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;
ancs.getCharacterResInfo(chResInfo);
for (const auto& info : chResInfo) {
@ -49,11 +50,19 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
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);
for (auto it = attRange.first; it != attRange.second; ++it) {
auto cinfid = it->second.first.cinf;
auto cmdlid = it->second.first.cmdl;
const nod::Node* node;
@ -61,8 +70,9 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
if (force || cmdlPath.isNone()) {
cmdlPath.makeDirChain(false);
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh)) {
return false;
}
std::string bestName = pakRouter.getBestEntryName(*cmdlE);
hecl::SystemStringConv bestNameView(bestName);
@ -84,6 +94,15 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
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);
@ -253,17 +272,17 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn, const ANCSDNA& ancs, con
template bool
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,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool
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,
const SpecBase& dataspec, std::function<void(const hecl::SystemChar*)> fileChanged, bool force);
template bool
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,
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>
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,
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) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
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) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
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) {
hecl::blender::Connection& conn = btok.getBlenderConnection();
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");
static bool GetNoShare(std::string_view name) {
if (name == "UniverseArea.pak"sv)
return false;
std::string lowerName(name);
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
if (!lowerName.compare(0, 7, "metroid"))
return false;
if (!lowerName.compare(0, 5, "rs5fe"))
return false;
return true;
return !lowerName.starts_with("metroid"sv) && !lowerName.starts_with("frontend"sv) &&
!lowerName.starts_with("rs5fe"sv) && !lowerName.starts_with("universearea"sv);
}
PAKBridge::PAKBridge(const nod::Node& node, bool doExtract)

View File

@ -29,7 +29,7 @@ void ViewManager::InitMP1(MP1::CMain& main) {
if (!m_noShaderWarmup)
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().push_back(m_testGameView.get());
@ -62,17 +62,11 @@ void ViewManager::TestGameView::think() {
if (m_debugText) {
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 (showFrameIdx && showFrameIdx->toBoolean())
if (m_cvarCommons.m_debugOverlayShowFrameCounter->toBoolean())
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();
u32 ms = u64(igt * 1000) % 1000;
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);
}
if (g_StateManager->Player() && playerInfo && playerInfo->toBoolean()) {
if (g_StateManager->Player() && m_cvarCommons.m_debugOverlayPlayerInfo->toBoolean()) {
const CPlayer& pl = g_StateManager->GetPlayer();
const zeus::CQuaternion plQ = zeus::CQuaternion(pl.GetTransform().getRotation().buildMatrix3f());
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()),
zeus::radToDeg(camQ.pitch()), zeus::radToDeg(camQ.yaw()));
}
if (worldInfo && worldInfo->toBoolean()) {
if (m_cvarCommons.m_debugOverlayWorldInfo->toBoolean()) {
TLockedToken<CStringTable> tbl =
g_SimplePool->GetObj({FOURCC('STRG'), g_StateManager->GetWorld()->IGetStringTableAssetId()});
const urde::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
@ -107,7 +101,7 @@ void ViewManager::TestGameView::think() {
}
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)) {
const auto& layerStates = g_GameState->CurrentWorldState().GetLayerState();
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());
if (!overlayText.empty())

View File

@ -1,6 +1,7 @@
#pragma once
#include "hecl/CVarManager.hpp"
#include "hecl/CVarCommons.hpp"
#include "boo/audiodev/IAudioVoiceEngine.hpp"
#include "amuse/BooBackend.hpp"
#include "ProjectManager.hpp"
@ -57,9 +58,11 @@ class ViewManager final : public specter::IViewManager {
class TestGameView : public specter::View {
ViewManager& m_vm;
std::unique_ptr<specter::MultiLineTextView> m_debugText;
hecl::CVarCommons m_cvarCommons;
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 draw(boo::IGraphicsCommandQueue* gfxQ) override;
void think() override;

View File

@ -89,7 +89,6 @@ struct Application : boo::IApplicationCallback {
void initialize(boo::IApplication* app) {
zeus::detectCPU();
createGlobalCVars();
for (const boo::SystemString& arg : app->getArgs()) {
if (arg.find(_SYS_STR("--verbosity=")) == 0 || arg.find(_SYS_STR("-v=")) == 0) {
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(); }
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

View File

@ -3,6 +3,8 @@
**Official Discord Channel:** https://discord.gg/AMBVFuf
![URDE screenshot](assets/urde-screen1.png)
### 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.

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -219,7 +219,7 @@ void CGuiTextSupport::AutoSetExtent() {
void CGuiTextSupport::Render() {
CheckAndRebuildRenderBuffer();
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;
CGraphics::SetModelMatrix(oldModel * zeus::CTransform::Scale(1.f, 1.f, -1.f));
buf->Render(x2c_geometryColor, x10_curTimeMod900);

View File

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

View File

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

View File

@ -34,7 +34,7 @@ CHudDecoInterfaceCombat::CHudDecoInterfaceCombat(CGuiFrame& selHud) {
x78_basewidget_tickdeco0->SetColor(g_tweakGuiColors->GetTickDecoColor());
x38_basePosition = x7c_basewidget_frame->GetLocalPosition();
x44_baseRotation = x7c_basewidget_frame->GetLocalTransform().buildMatrix3f();
UpdateHudAlpha();
CHudDecoInterfaceCombat::UpdateHudAlpha();
}
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));
x234_sidesPositioner = FLT_MAX;
UpdateHudAlpha();
CHudDecoInterfaceScan::UpdateHudAlpha();
}
void CHudDecoInterfaceScan::UpdateVisibility() {
@ -377,7 +377,7 @@ CHudDecoInterfaceXRay::CHudDecoInterfaceXRay(CGuiFrame& selHud) {
if (CGuiWidget* w = selHud.FindWidget("model_threatslider"))
w->SetDepthWrite(true);
UpdateHudAlpha();
CHudDecoInterfaceXRay::UpdateHudAlpha();
}
void CHudDecoInterfaceXRay::UpdateVisibility() {
@ -482,7 +482,7 @@ CHudDecoInterfaceThermal::CHudDecoInterfaceThermal(CGuiFrame& selHud) {
}
x14_pivotPosition = x78_basewidget_pivot->GetIdlePosition();
UpdateHudAlpha();
CHudDecoInterfaceThermal::UpdateHudAlpha();
}
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,
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) {
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 (playerToEnemy.magnitude() > parms.x78_xyRadius || zDelta > parms.x7c_zRadius) {
return;
}
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) {
@ -66,29 +69,33 @@ void CHudRadarInterface::SetIsVisibleGame(bool v) {
}
void CHudRadarInterface::Update(float dt, const CStateManager& mgr) {
CPlayerState& playerState = *mgr.GetPlayerState();
float visorTransFactor = (playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Combat)
? playerState.GetVisorTransitionFactor()
: 0.f;
const CPlayerState& playerState = *mgr.GetPlayerState();
const float visorTransFactor = (playerState.GetCurrentVisor() == CPlayerState::EPlayerVisor::Combat)
? playerState.GetVisorTransitionFactor()
: 0.f;
zeus::CColor color = g_tweakGuiColors->GetRadarStuffColor();
color.a() *= g_GameState->GameOptions().GetHUDAlpha() / 255.f * visorTransFactor;
x40_BaseWidget_RadarStuff->SetColor(color);
bool tweakVis = g_tweakGui->GetHudVisMode() >= ITweakGui::EHudVisMode::Three;
if (tweakVis != x3c_25_visibleDebug) {
x3c_25_visibleDebug = tweakVis;
x40_BaseWidget_RadarStuff->SetVisibility(x3c_25_visibleDebug && x3c_24_visibleGame, ETraversalMode::Children);
const bool tweakVis = g_tweakGui->GetHudVisMode() >= ITweakGui::EHudVisMode::Three;
if (tweakVis == x3c_25_visibleDebug) {
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) {
alpha *= g_GameState->GameOptions().GetHUDAlpha() / 255.f;
if (g_tweakGui->GetHudVisMode() == ITweakGui::EHudVisMode::Zero || !x3c_24_visibleGame || !x0_txtrRadarPaint ||
!x0_txtrRadarPaint.IsLoaded())
!x0_txtrRadarPaint.IsLoaded()) {
return;
}
SRadarPaintDrawParms drawParms;
CPlayer& player = mgr.GetPlayer();
const CPlayer& player = mgr.GetPlayer();
if (player.IsOverrideRadarRadius()) {
drawParms.x78_xyRadius = player.GetRadarXYRadiusOverride();
drawParms.x7c_zRadius = player.GetRadarZRadiusOverride();
@ -102,13 +109,13 @@ void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
drawParms.x6c_scopeRadius = g_tweakGui->GetRadarScopeCoordRadius();
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::CRelAngle angleZ(camZ);
angleZ.makeRel();
drawParms.xc_preTranslate = zeus::CTransform::RotateY(angleZ);
drawParms.x3c_postTranslate = x40_BaseWidget_RadarStuff->GetWorldTransform();
float enemyRadius = g_tweakGui->GetRadarEnemyPaintRadius();
const float enemyRadius = g_tweakGui->GetRadarEnemyPaintRadius();
m_paintInsts.clear();
x44_camera->Draw(CGuiWidgetDrawParms{0.f, zeus::CVector3f{}});
@ -118,7 +125,7 @@ void CHudRadarInterface::Draw(const CStateManager& mgr, float alpha) {
playerColor.a() *= alpha;
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().z() - drawParms.x7c_zRadius, player.GetTranslation().x() + drawParms.x78_xyRadius,
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.x74_alpha = alpha;
for (TUniqueId id : nearList) {
if (TCastToConstPtr<CActor> act = mgr.GetObjectById(id)) {
if (!act->GetActive())
for (const TUniqueId id : nearList) {
if (const TCastToConstPtr<CActor> act = mgr.GetObjectById(id)) {
if (!act->GetActive()) {
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()) {
if (!boid.GetActive())
if (!boid.GetActive()) {
continue;
}
DrawRadarPaint(boid.GetTranslation(), radius, 0.5f, drawParms);
}
} else {

View File

@ -71,9 +71,10 @@ void CScanDisplay::CDataDot::SetDestPosition(const zeus::CVector2f& pos) {
CScanDisplay::CScanDisplay(const CGuiFrame& selHud) : xa0_selHud(selHud) {
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);
x170_paneStates.resize(4);
}
x170_paneStates.resize(x170_paneStates.capacity());
}
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));
}
float CScanDisplay::GetDownloadStartTime(int idx) const {
if (!x14_scannableInfo)
float CScanDisplay::GetDownloadStartTime(size_t idx) const {
if (!x14_scannableInfo) {
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();
}
float CScanDisplay::GetDownloadFraction(int idx, float scanningTime) const {
if (!x14_scannableInfo)
float CScanDisplay::GetDownloadFraction(size_t idx, float scanningTime) const {
if (!x14_scannableInfo) {
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 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"");
xac_scrollMessage->TextSupport().SetText(u"");
for (int i = 0; i < 20; ++i) {
CAuiImagePane* pane =
static_cast<CAuiImagePane*>(xa0_selHud.FindWidget(MP1::CPauseScreenBase::GetImagePaneName(i)));
for (size_t i = 0; i < 20; ++i) {
auto* pane = static_cast<CAuiImagePane*>(xa0_selHud.FindWidget(MP1::CPauseScreenBase::GetImagePaneName(i)));
zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor();
color.a() = 0.f;
pane->SetColor(color);
pane->SetTextureID0({}, g_SimplePool);
pane->SetAnimationParms(zeus::skZero2f, 0.f, 0.f);
int pos = -1;
for (int j = 0; j < 4; ++j) {
size_t pos = SIZE_MAX;
for (size_t j = 0; j < CScannableObjectInfo::NumBuckets; ++j) {
if (x14_scannableInfo->GetBucket(j).x8_imagePos == i) {
pos = j;
break;
}
}
if (pos >= 0)
if (pos != SIZE_MAX) {
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];
if (state.second) {
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->SetFlashFactor(0.f);
float startTime = GetDownloadStartTime(i);
if (scanTime >= startTime)
const float startTime = GetDownloadStartTime(i);
if (scanTime >= startTime) {
x170_paneStates[i].first = 0.f;
else
} else {
x170_paneStates[i].first = -1.f;
}
}
}
CAssetId strId = x14_scannableInfo->GetStringTableId();
if (strId.IsValid())
const CAssetId strId = x14_scannableInfo->GetStringTableId();
if (strId.IsValid()) {
x194_scanStr = g_SimplePool->GetObj({FOURCC('STRG'), strId});
}
for (int i = 0; i < 4; ++i) {
int pos = x14_scannableInfo->GetBucket(i).x8_imagePos;
for (size_t i = 0; i < CScannableObjectInfo::NumBuckets; ++i) {
const u32 pos = x14_scannableInfo->GetBucket(i).x8_imagePos;
CDataDot& dot = xbc_dataDots[i];
if (pos != -1) {
if (pos != UINT32_MAX) {
if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanTime) {
dot.SetAlpha(0.f);
dot.SetDotState(CDataDot::EDotState::Done);
@ -243,12 +255,14 @@ void CScanDisplay::StartScan(TUniqueId id, const CScannableObjectInfo& scanInfo,
}
void CScanDisplay::StopScan() {
if (xc_state == EScanState::Done || xc_state == EScanState::Inactive)
if (xc_state == EScanState::Done || xc_state == EScanState::Inactive) {
return;
}
xc_state = EScanState::Done;
for (int i = 0; i < 4; ++i)
xbc_dataDots[i].SetDesiredAlpha(0.f);
for (auto& dataDot : xbc_dataDots) {
dataDot.SetDesiredAlpha(0.f);
}
}
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) {
if (x170_paneStates[i].second == nullptr)
for (size_t i = 0; i < x170_paneStates.size(); ++i) {
if (x170_paneStates[i].second == nullptr) {
continue;
}
if (x170_paneStates[i].first > 0.f) {
x170_paneStates[i].first = std::max(0.f, x170_paneStates[i].first - dt);
float tmp;
if (x170_paneStates[i].first > g_tweakGui->GetScanPaneFadeOutTime())
if (x170_paneStates[i].first > g_tweakGui->GetScanPaneFadeOutTime()) {
tmp = 1.f -
(x170_paneStates[i].first - g_tweakGui->GetScanPaneFadeOutTime()) / g_tweakGui->GetScanPaneFadeInTime();
else
} else {
tmp = x170_paneStates[i].first / g_tweakGui->GetScanPaneFadeOutTime();
}
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;
zeus::CColor color = g_tweakGuiColors->GetScanDisplayImagePaneColor();
color.a() *= alphaMul;
x170_paneStates[i].second->SetColor(color);
x170_paneStates[i].second->SetDeResFactor(1.f - alphaMul);
if (GetDownloadStartTime(i) - g_tweakGui->GetScanAppearanceDuration() < scanningTime) {
CDataDot& dot = xbc_dataDots[i];
switch (dot.GetDotState()) {
@ -338,7 +357,7 @@ void CScanDisplay::Update(float dt, float scanningTime) {
dot.StartTransitionTo(zeus::skZero2f, g_tweakGui->GetScanAppearanceDuration());
break;
case CDataDot::EDotState::RevealPane: {
float tmp = dot.GetTransitionFactor();
const float tmp = dot.GetTransitionFactor();
if (tmp == 0.f) {
dot.SetDotState(CDataDot::EDotState::Done);
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];
switch (dot.GetDotState()) {
case CDataDot::EDotState::Hidden:

View File

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

View File

@ -27,8 +27,8 @@ class CTextExecuteBuffer {
CBlockInstruction* xa0_curBlock = nullptr;
CLineInstruction* xa4_curLine = nullptr;
InstList::iterator xa8_curWordIt;
s32 xac_curY;
s32 xb0_curX;
s32 xac_curY = 0;
s32 xb0_curX = 0;
s32 xb4_curWordX = 0;
s32 xb8_curWordY = 0;
s32 xbc_spaceDistance = 0;
@ -37,7 +37,7 @@ class CTextExecuteBuffer {
u32 xd8_ = 0;
public:
CTextExecuteBuffer() { xa8_curWordIt = x0_instList.begin(); }
CTextExecuteBuffer() : xa8_curWordIt{x0_instList.begin()} {}
CTextRenderBuffer BuildRenderBuffer(CGuiWidget::EGuiModelDrawFlags df) const;
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);
}
for (int i = 0; i < 4; ++i) {
for (size_t i = 0; i < CScannableObjectInfo::NumBuckets; ++i) {
const CScannableObjectInfo::SBucket& bucket = scan->GetBucket(i);
if (bucket.x8_imagePos == UINT32_MAX)
if (bucket.x8_imagePos == UINT32_MAX) {
continue;
}
CAuiImagePane* pane = xf0_imagePanes[bucket.x8_imagePos];
if (bucket.x14_interval > 0.f) {
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{
"0", "1", "2", "3", "01", "12", "23", "012", "123", "0123",
"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);
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@ class CParticleSwoosh : public CParticleGen {
float x30_irot; // Rotation bias once per system update
float x34_rotm; // Rotation bias once per particle instance
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
int x70_startFrame;
zeus::CVector3f x74_velocity;
@ -79,11 +79,11 @@ class CParticleSwoosh : public CParticleGen {
int x1b0_SPLN = 0;
int x1b4_LENG = 0;
int x1b8_SIDE = 0;
GX::Primitive x1bc_prim;
GX::Primitive x1bc_prim{};
CRandom16 x1c0_rand;
float x1c4_ = 0.f;
float x1c8_ = 0.f;
float x1cc_TSPN;
float x1cc_TSPN = 0.f;
bool x1d0_24_emitting : 1;
bool x1d0_25_AALP : 1;
bool x1d0_26_forceOneUpdate : 1;

View File

@ -28,7 +28,7 @@ constexpr std::array skComboNames{
};
constexpr std::array<u16, 5> skSoundId{
1810, 1837, 1847, 1842, 1810,
SFXsfx0712, SFXsfx072D, SFXwpn_combo_wavebuster, SFXwpn_combo_flamethrower, SFXsfx0712,
};
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) {
s32 sfxId = x170_projectile.GetSoundIdForCollision(type);
if (sfxId >= 0) {
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;
CSfxHandle hnd = CSfxManager::AddEmitter(parmData, true, 0x7f, false, kInvalidAreaId);
if (x2e4_26_waterUpdate)
CSfxManager::PitchBend(hnd, -1.f);
const s32 sfxId = x170_projectile.GetSoundIdForCollision(type);
if (sfxId < 0) {
return;
}
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) {
if (TCastToConstPtr<CActor> act = mgr.GetObjectById(owner)) {
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());
const TCastToConstPtr<CActor> act = mgr.GetObjectById(owner);
if (!act) {
return;
}
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) {
switch (msg) {
case EScriptObjectMessage::Deleted:
if (x2e4_24_active)
if (x2e4_24_active) {
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
}
if (x2e8_sfx) {
CSfxManager::RemoveEmitter(x2e8_sfx);
x2e8_sfx.reset();
}
break;
case EScriptObjectMessage::Registered: {
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1())
if (ps1->SystemHasLight())
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) {
if (ps1->SystemHasLight()) {
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) {
float range = 50.f;
float falloff = 0.2f;
if (CRealElement* rnge = desc->xac_RNGE.get())
if (CRealElement* rnge = desc->xac_RNGE.get()) {
rnge->GetValue(0, range);
if (CRealElement* foff = desc->xb0_FOFF.get())
}
if (CRealElement* foff = desc->xb0_FOFF.get()) {
foff->GetValue(0, falloff);
}
CAudioSys::C3DEmitterParmData parmData = {};
parmData.x0_pos = x170_projectile.GetTranslation();
@ -117,22 +131,27 @@ void CEnergyProjectile::Accept(IVisitor& visitor) { visitor.Visit(this); }
static constexpr u64 kCheckMaterial = 0xE3FFFE;
void CEnergyProjectile::ResolveCollisionWithWorld(const CRayCastResult& res, CStateManager& mgr) {
EWeaponCollisionResponseTypes crType = CCollisionResponseData::GetWorldCollisionResponseType(
const auto crType = CCollisionResponseData::GetWorldCollisionResponseType(
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)) {
/* 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;
return;
}
// 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) {
x2c2_lastResolvedObj = act.GetUniqueId();
EWeaponCollisionResponseTypes crType = act.GetCollisionResponseType(
res.GetPoint(), x34_transform.basis[1].normalized(), x12c_curDamageInfo.GetWeaponMode(), xe8_projectileAttribs);
const auto crType = act.GetCollisionResponseType(res.GetPoint(), x34_transform.basis[1].normalized(),
x12c_curDamageInfo.GetWeaponMode(), xe8_projectileAttribs);
act.Touch(*this, mgr);
const CDamageVulnerability* dVuln = act.GetDamageVulnerability();
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);
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,
*GetDamageVulnerability(), GetUniqueId());
}
@ -151,31 +170,36 @@ void CEnergyProjectile::ResolveCollisionWithActor(const CRayCastResult& res, CAc
void CEnergyProjectile::Think(float dt, CStateManager& mgr) {
CWeapon::Think(dt, mgr);
if (mgr.GetWorld()->GetCurrentAreaId() != GetAreaIdAlways() &&
(xe8_projectileAttribs & EProjectileAttrib::ArmCannon) == EProjectileAttrib::ArmCannon)
(xe8_projectileAttribs & EProjectileAttrib::ArmCannon) == EProjectileAttrib::ArmCannon) {
mgr.SetActorAreaId(*this, mgr.GetWorld()->GetCurrentAreaId());
}
UpdateProjectileMovement(dt, mgr);
TUniqueId id = kInvalidUniqueId;
CRayCastResult res = DoCollisionCheck(id, mgr);
const CRayCastResult res = DoCollisionCheck(id, mgr);
if (res.IsValid()) {
if (TCastToPtr<CActor> act = mgr.ObjectById(id))
if (const TCastToPtr<CActor> act = mgr.ObjectById(id)) {
ResolveCollisionWithActor(res, *act, mgr);
else
} else {
ResolveCollisionWithWorld(res, mgr);
}
}
x170_projectile.UpdateParticleFX();
if (x2e4_24_active && x3d0_26_)
if (x2e4_24_active && x3d0_26_) {
Explode(GetTranslation(), zeus::skUp, EWeaponCollisionResponseTypes::Default, mgr,
CDamageVulnerability::NormalVulnerabilty(), 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->SetTranslation(GetTranslation());
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1())
if (ps1->SystemHasLight())
if (CElementGen* ps1 = x170_projectile.GetAttachedPS1()) {
if (ps1->SystemHasLight()) {
light->SetLight(ps1->GetLight());
}
}
}
}
@ -185,20 +209,22 @@ void CEnergyProjectile::Think(float dt, CStateManager& mgr) {
}
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());
}
}
void CEnergyProjectile::Render(CStateManager& mgr) {
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 ((xe8_projectileAttribs & EProjectileAttrib::Charged) == EProjectileAttrib::Charged ||
(xe8_projectileAttribs & EProjectileAttrib::ComboShot) == EProjectileAttrib::ComboShot) {
float warpTime = 1.f - float(x170_projectile.GameTime());
if (warpTime > 0.f)
const float warpTime = 1.f - float(x170_projectile.GameTime());
if (warpTime > 0.f) {
mgr.DrawSpaceWarp(GetTranslation(), warpTime * 0.75f);
}
}
}
@ -222,11 +248,12 @@ void CEnergyProjectile::Render(CStateManager& mgr) {
}
void CEnergyProjectile::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
auto bounds = x170_projectile.GetBounds();
if (bounds && !frustum.aabbFrustumTest(*bounds))
const auto bounds = x170_projectile.GetBounds();
if (bounds && !frustum.aabbFrustumTest(*bounds)) {
return;
}
CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr);
if (visor != CPlayerState::EPlayerVisor::XRay &&
((xe8_projectileAttribs & EProjectileAttrib::Ice) != EProjectileAttrib::Ice ||
mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot)) {
@ -247,7 +274,8 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
bool retargetPlayer = false;
bool deflect = false;
zeus::CVector3f targetPos;
EVulnerability vulnType = dVuln.GetVulnerability(x12c_curDamageInfo.GetWeaponMode(), false);
const EVulnerability vulnType = dVuln.GetVulnerability(x12c_curDamageInfo.GetWeaponMode(), false);
if (vulnType == EVulnerability::Deflect) {
deflect = true;
EDeflectType deflectType = dVuln.GetDeflectionType(x12c_curDamageInfo.GetWeaponMode());
@ -259,17 +287,19 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
case EDeflectType::Three:
if (deflectType != EDeflectType::Two ||
(xf0_weaponType != EWeaponType::Missile &&
(xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::ComboShot))
if (xf8_filter.GetExcludeList().HasMaterial(EMaterialTypes::Player))
(xe8_projectileAttribs & EProjectileAttrib::ComboShot) != EProjectileAttrib::ComboShot)) {
if (xf8_filter.GetExcludeList().HasMaterial(EMaterialTypes::Player)) {
retargetPlayer = true;
}
}
break;
default:
break;
}
if (retargetPlayer) {
float ang = mgr.GetActiveRandom()->Range(0.f, 2.f * M_PIF);
float y = std::sin(ang);
float x = std::cos(ang);
const float ang = mgr.GetActiveRandom()->Range(0.f, 2.f * M_PIF);
const float y = std::sin(ang);
const float x = std::cos(ang);
targetPos = mgr.GetPlayer().GetAimPosition(mgr, 0.f) + zeus::CVector3f(x, 0.f, y);
ChangeProjectileOwner(hitActor, mgr);
}
@ -278,7 +308,8 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
if (vulnType != EVulnerability::Immune && !deflect) {
deflect =
(type == EWeaponCollisionResponseTypes::Unknown15 || type == EWeaponCollisionResponseTypes::EnemyShielded ||
(type >= EWeaponCollisionResponseTypes::Unknown69 && type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect));
(type >= EWeaponCollisionResponseTypes::Unknown69 &&
type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect));
}
SetTranslation(offsetPos);
@ -309,29 +340,30 @@ bool CEnergyProjectile::Explode(const zeus::CVector3f& pos, const zeus::CVector3
zeus::CVector3f scale = zeus::skOne3f;
bool camClose = false;
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) {
scale = zeus::CVector3f(0.75f * (mag * 0.25f) + 0.25f);
camClose = true;
}
}
u32 explodeFlags = 0x8;
if ((xe8_projectileAttribs & EProjectileAttrib::Ice) == EProjectileAttrib::Ice)
if ((xe8_projectileAttribs & EProjectileAttrib::Ice) == EProjectileAttrib::Ice) {
explodeFlags |= 0x4;
if (camClose)
}
if (camClose) {
explodeFlags |= 0x2;
CEntityInfo explosionInfo(GetAreaIdAlways(), CEntity::NullConnectionList);
CExplosion* explosion =
new CExplosion(*particle, mgr.AllocateUniqueId(), true, explosionInfo, "Projectile collision response",
particleXf, explodeFlags, scale, zeus::skWhite);
}
const CEntityInfo explosionInfo(GetAreaIdAlways(), CEntity::NullConnectionList);
auto* explosion = new CExplosion(*particle, mgr.AllocateUniqueId(), true, explosionInfo,
"Projectile collision response", particleXf, explodeFlags, scale, zeus::skWhite);
mgr.AddObject(explosion);
if (TCastToPtr<CActor> hActor = mgr.ObjectById(hitActor)) {
if (const TCastToPtr<CActor> hActor = mgr.ObjectById(hitActor)) {
bool validPlat = false;
CScriptPlatform* plat = TCastToPtr<CScriptPlatform>(hActor.GetPtr()).GetPtr();
validPlat = plat != nullptr;
if (!validPlat && hActor->GetMaterialList().HasMaterial(EMaterialTypes::Bomb)) {
for (CEntity* ent : mgr.GetPlatformAndDoorObjectList()) {
if (TCastToPtr<CScriptPlatform> otherPlat = ent) {
if (const TCastToPtr<CScriptPlatform> otherPlat = ent) {
if (otherPlat->IsSlave(hitActor)) {
plat = otherPlat.GetPtr();
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);
}
}
} else {
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)) ==
(EProjectileAttrib::ComboShot | EProjectileAttrib::Ice)) {
/* Ice Spreader */
TLockedToken<CGenDescription> iceSpreadParticle = g_SimplePool->GetObj("IceSpread1");
// Ice Spreader
const TLockedToken<CGenDescription> iceSpreadParticle = g_SimplePool->GetObj("IceSpread1");
u32 flags = (xe6_27_thermalVisorFlags & 0x2) == 0 ? 1 : 0;
flags |= 0x2;
CIceImpact* iceImpact =
new CIceImpact(iceSpreadParticle, mgr.AllocateUniqueId(), GetAreaIdAlways(), true, "Ice spread explosion",
particleXf, flags, zeus::skOne3f, zeus::skWhite);
auto* iceImpact = new CIceImpact(iceSpreadParticle, mgr.AllocateUniqueId(), GetAreaIdAlways(), true,
"Ice spread explosion", particleXf, flags, zeus::skOne3f, zeus::skWhite);
mgr.AddObject(iceImpact);
}
}

View File

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

View File

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

View File

@ -110,14 +110,15 @@ void CFluidPlaneCPU::CalculateLightmapMatrix(const zeus::CTransform& areaXf, con
}
static bool sSineWaveInitialized = false;
static float sGlobalSineWave[256] = {};
static const float* InitializeSineWave() {
if (sSineWaveInitialized)
return sGlobalSineWave;
for (int i = 0; i < 256; ++i)
sGlobalSineWave[i] = std::sin(2.f * M_PIF * (i / 256.f));
static CFluidPlaneCPU::SineTable sGlobalSineWave{};
static void InitializeSineWave() {
if (sSineWaveInitialized) {
return;
}
for (size_t i = 0; i < sGlobalSineWave.size(); ++i) {
sGlobalSineWave[i] = std::sin(2.f * M_PIF * (float(i) / 256.f));
}
sSineWaveInitialized = true;
return sGlobalSineWave;
}
#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);
}
void CFluidPlaneCPU::ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (&heights)[46][46],
const u8 (&flags)[9][9], const float sineWave[256],
void CFluidPlaneCPU::ApplyTurbulence(float t, Heights& heights, const Flags& flags, const SineTable& sineWave,
const CFluidPlaneRender::SPatchInfo& info,
const zeus::CVector3f& areaCenter) const {
if (!HasTurbulence()) {
@ -334,9 +334,8 @@ void CFluidPlaneCPU::ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (
}
}
void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9],
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info) const {
void CFluidPlaneCPU::ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, Heights& heights, Flags& flags,
const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const {
float lookupT = 256.f *
(1.f - rippleInfo.x0_ripple.GetTime() * 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;
if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) {
heights[k][l].height += rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[int(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
heights[k][l].height +=
rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[size_t(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
} else {
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;
if (u8 rippleV = CFluidPlaneManager::RippleValues[lifeIdx][int(divDist * distFalloff)]) {
heights[k][l].height += rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[int(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
heights[k][l].height +=
rippleV * rippleInfo.x0_ripple.GetLookupAmplitude() *
sineWave[size_t(divDist * rippleInfo.x0_ripple.GetLookupPhase() + lookupT) & 0xff];
} else {
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,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9],
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info) const {
Heights& heights, Flags& flags, const SineTable& sineWave,
const CFluidPlaneRender::SPatchInfo& info) const {
for (const CFluidPlaneRender::SRippleInfo& rippleInfo : rippleInfos)
ApplyRipple(rippleInfo, heights, flags, sineWave, info);
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;
}
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) {
for (int i = 1; i <= (info.x1_ySubdivs + CFluidPlaneRender::numSubdivisionsInTile - 2) /
CFluidPlaneRender::numSubdivisionsInTile;
@ -558,8 +559,8 @@ void CFluidPlaneCPU::UpdatePatchNoNormals(CFluidPlaneRender::SHFieldSample (&hei
}
}
void CFluidPlaneCPU::UpdatePatchWithNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46],
const u8 (&flags)[9][9], const CFluidPlaneRender::SPatchInfo& info) {
void CFluidPlaneCPU::UpdatePatchWithNormals(Heights& heights, const Flags& flags,
const CFluidPlaneRender::SPatchInfo& info) {
float normalScale = -(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;
@ -696,11 +697,9 @@ void CFluidPlaneCPU::UpdatePatchWithNormals(CFluidPlaneRender::SHFieldSample (&h
}
}
bool CFluidPlaneCPU::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 {
bool CFluidPlaneCPU::UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info, Heights& heights, Flags& flags,
const zeus::CVector3f& areaCenter, const std::optional<CRippleManager>& rippleManager,
int fromX, int toX, int fromY, int toY) const {
rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32> rippleInfos;
if (rippleManager) {
for (const CRipple& ripple : rippleManager->GetRipples()) {
@ -730,10 +729,10 @@ bool CFluidPlaneCPU::UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo
return false;
}
/* Used to be part of locked cache
* These are too big for stack allocation */
static CFluidPlaneRender::SHFieldSample lc_heights[46][46] = {};
static u8 lc_flags[9][9] = {};
// Used to be part of locked cache
// These are too big for stack allocation
static CFluidPlane::Heights lc_heights{};
static CFluidPlane::Flags lc_flags{};
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,

View File

@ -12,6 +12,9 @@ namespace urde {
class CFluidUVMotion;
class CFluidPlaneCPU : public CFluidPlane {
public:
using SineTable = std::array<float, 256>;
protected:
class CTurbulence {
float x0_speed;
@ -60,28 +63,22 @@ protected:
u32 m_maxVertCount;
bool m_tessellation = false;
bool m_cachedDoubleLightmapBlend;
bool m_cachedAdditive;
bool m_cachedDoubleLightmapBlend = false;
bool m_cachedAdditive = false;
static bool PrepareRipple(const CRipple& ripple, const CFluidPlaneRender::SPatchInfo& info,
CFluidPlaneRender::SRippleInfo& rippleOut);
void ApplyTurbulence(float t, CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9],
const float sineWave[256], const CFluidPlaneRender::SPatchInfo& info,
const zeus::CVector3f& areaCenter) const;
void ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const float sineWave[256],
const CFluidPlaneRender::SPatchInfo& info) const;
void ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos,
CFluidPlaneRender::SHFieldSample (&heights)[46][46], u8 (&flags)[9][9], const float sineWave[256],
const CFluidPlaneRender::SPatchInfo& info) const;
static void UpdatePatchNoNormals(CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9],
const CFluidPlaneRender::SPatchInfo& info);
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;
void ApplyTurbulence(float t, Heights& heights, const Flags& flags, const SineTable& sineWave,
const CFluidPlaneRender::SPatchInfo& info, const zeus::CVector3f& areaCenter) const;
void ApplyRipple(const CFluidPlaneRender::SRippleInfo& rippleInfo, Heights& heights, Flags& flags,
const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const;
void ApplyRipples(const rstl::reserved_vector<CFluidPlaneRender::SRippleInfo, 32>& rippleInfos, Heights& heights,
Flags& flags, const SineTable& sineWave, const CFluidPlaneRender::SPatchInfo& info) const;
static void UpdatePatchNoNormals(Heights& heights, const Flags& flags, const CFluidPlaneRender::SPatchInfo& info);
static void UpdatePatchWithNormals(Heights& heights, const Flags& flags, const CFluidPlaneRender::SPatchInfo& info);
bool UpdatePatch(float time, const CFluidPlaneRender::SPatchInfo& info, Heights& heights, Flags& flags,
const zeus::CVector3f& areaCenter, const std::optional<CRippleManager>& rippleManager, int fromX,
int toX, int fromY, int toY) const;
public:
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;
}
/* Used to be part of locked cache
* These are too big for stack allocation */
static CFluidPlaneRender::SHFieldSample lc_heights[46][46] = {};
static u8 lc_flags[9][9] = {};
// Used to be part of locked cache
// These are too big for stack allocation
static CFluidPlane::Heights lc_heights{};
static CFluidPlane::Flags lc_flags{};
void CFluidPlaneDoor::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb,
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;
}
void CFluidPlaneGPU::RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46],
const u8 (&flags)[9][9], int startYDiv,
void CFluidPlaneGPU::RenderStripWithRipples(float curY, const Heights& heights, const Flags& flags, int startYDiv,
const CFluidPlaneRender::SPatchInfo& info,
std::vector<CFluidPlaneShader::Vertex>& vOut,
std::vector<CFluidPlaneShader::PatchVertex>& pvOut) {

View File

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

View File

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

View File

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

View File

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

View File

@ -78,7 +78,7 @@ class CScriptSpindleCamera : public CGameCamera {
float x328_maxAzimuthInterpTimer = 0.f;
bool x32c_outsideClampedAzimuth = false;
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)]; }

View File

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

View File

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

View File

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

View File

@ -38,7 +38,7 @@ public:
CCollisionSurface x50_surface =
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);
float x78_health;
float x78_health = 0.f;
int x7c_framesNotOnSurface : 8;
int x7c_idx : 10;
int x7c_remainingLaunchNotOnSurfaceFrames : 8;
@ -53,6 +53,7 @@ public:
: x0_xf(xf)
, x7c_framesNotOnSurface(0)
, x7c_idx(idx)
, x7c_remainingLaunchNotOnSurfaceFrames(0)
, x80_24_active(false)
, x80_25_inFrustum(false)
, x80_26_launched(false)

View File

@ -1,5 +1,8 @@
#include "Runtime/World/CWorld.hpp"
#include <algorithm>
#include <iterator>
#include "Runtime/CGameState.hpp"
#include "Runtime/CInGameTweakManagerBase.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::IGetAreaId(CAssetId id) const {
int ret = 0;
if (!id.IsValid())
if (!id.IsValid()) {
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) {
@ -226,15 +231,17 @@ const IGameArea* CWorld::IGetAreaAlways(TAreaId id) const { return GetAreaAlways
TAreaId CWorld::IGetCurrentAreaId() const { return x68_curAreaId; }
TAreaId CWorld::IGetAreaId(CAssetId id) const {
int ret = 0;
if (!id.IsValid())
if (!id.IsValid()) {
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) {
@ -705,19 +712,20 @@ bool CWorld::AreSkyNeedsMet() const {
}
TAreaId CWorld::GetAreaIdForSaveId(s32 saveId) const {
if (saveId == -1)
if (saveId == -1) {
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

View File

@ -171,7 +171,7 @@ public:
void CycleLoadPauseState();
CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId);
~CWorld();
~CWorld() override;
bool DoesAreaExist(TAreaId area) const;
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