mirror of https://github.com/AxioDL/metaforce.git
Initially working CEnvFxManager
This commit is contained in:
parent
93e9e2f6f1
commit
98c7525176
|
@ -33,6 +33,7 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn,
|
|||
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
|
||||
if (force || cmdlPath.isNone())
|
||||
{
|
||||
cmdlPath.makeDirChain(false);
|
||||
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
|
||||
return false;
|
||||
|
||||
|
@ -70,6 +71,7 @@ bool ReadANCSToBlender(hecl::blender::Connection& conn,
|
|||
hecl::ProjectPath cmdlPath = pakRouter.getWorking(cmdlE);
|
||||
if (force || cmdlPath.isNone())
|
||||
{
|
||||
cmdlPath.makeDirChain(false);
|
||||
if (!conn.createBlend(cmdlPath, hecl::blender::BlendType::Mesh))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -652,6 +652,7 @@ atUint32 ReadGeomSectionsToBlender(hecl::blender::PyOutStream& os,
|
|||
{
|
||||
MaterialSet matSet;
|
||||
matSet.read(reader);
|
||||
matSet.ensureTexturesExtracted(pakRouter);
|
||||
GetVertexAttributes(matSet, vertAttribs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,25 @@ struct MaterialSet : BigDNA
|
|||
|
||||
void addTexture(const UniqueID32& id) {textureIDs.push_back(id); ++textureCount;}
|
||||
void addMaterialEndOff(atUint32 off) {materialEndOffs.push_back(off); ++materialCount;}
|
||||
|
||||
template <class PAKBRIDGE>
|
||||
void ensureTexturesExtracted(PAKRouter<PAKBRIDGE>& pakRouter) const
|
||||
{
|
||||
for (const auto& id : textureIDs)
|
||||
{
|
||||
const nod::Node* node;
|
||||
const PAK::Entry* texEntry = pakRouter.lookupEntry(id, &node);
|
||||
if (!texEntry)
|
||||
continue;
|
||||
hecl::ProjectPath txtrPath = pakRouter.getWorking(texEntry);
|
||||
if (txtrPath.isNone())
|
||||
{
|
||||
txtrPath.makeDirChain(false);
|
||||
PAKEntryReadStream rs = texEntry->beginReadStream(*node);
|
||||
TXTR::Extract(rs, txtrPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} head;
|
||||
|
||||
struct Material : BigDNA
|
||||
|
@ -352,6 +371,10 @@ struct MaterialSet : BigDNA
|
|||
}
|
||||
}
|
||||
|
||||
void ensureTexturesExtracted(PAKRouter<PAKBridge>& pakRouter) const
|
||||
{
|
||||
head.ensureTexturesExtracted(pakRouter);
|
||||
}
|
||||
};
|
||||
|
||||
struct HMDLMaterialSet : BigDNA
|
||||
|
|
|
@ -71,6 +71,11 @@ struct MaterialSet : BigDNA
|
|||
{
|
||||
DNACMDL::ReadMaterialSetToBlender_1_2(os, *this, pakRouter, entry, setIdx);
|
||||
}
|
||||
|
||||
void ensureTexturesExtracted(PAKRouter<PAKBridge>& pakRouter) const
|
||||
{
|
||||
head.ensureTexturesExtracted(pakRouter);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -198,6 +198,8 @@ struct MaterialSet : BigDNA
|
|||
{
|
||||
DNACMDL::ReadMaterialSetToBlender_3(os, *this, pakRouter, entry, setIdx);
|
||||
}
|
||||
|
||||
void ensureTexturesExtracted(PAKRouter<PAKBridge>& pakRouter) const {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
namespace urde
|
||||
{
|
||||
static TLockedToken<std::vector<s16>> mpSfxTranslationTableTok;
|
||||
std::vector<s16>* CSfxManager::mpSfxTranslationTable = nullptr;
|
||||
static TLockedToken<std::vector<u16>> mpSfxTranslationTableTok;
|
||||
std::vector<u16>* CSfxManager::mpSfxTranslationTable = nullptr;
|
||||
|
||||
static amuse::EffectReverbHiInfo s_ReverbHiQueued;
|
||||
static amuse::EffectChorusInfo s_ChorusQueued;
|
||||
|
@ -20,12 +20,12 @@ CFactoryFnReturn FAudioTranslationTableFactory(const SObjectTag& tag, CInputStre
|
|||
const CVParamTransfer& vparms,
|
||||
CObjectReference* selfRef)
|
||||
{
|
||||
std::unique_ptr<std::vector<s16>> obj = std::make_unique<std::vector<s16>>();
|
||||
std::unique_ptr<std::vector<u16>> obj = std::make_unique<std::vector<u16>>();
|
||||
u32 count = in.readUint32Big();
|
||||
obj->reserve(count);
|
||||
for (u32 i=0 ; i<count ; ++i)
|
||||
obj->push_back(in.readUint16Big());
|
||||
return TToken<std::vector<s16>>::GetIObjObjectFor(std::move(obj));
|
||||
return TToken<std::vector<u16>>::GetIObjObjectFor(std::move(obj));
|
||||
}
|
||||
|
||||
CSfxManager::CSfxChannel CSfxManager::m_channels[4];
|
||||
|
@ -379,8 +379,8 @@ u16 CSfxManager::TranslateSFXID(u16 id)
|
|||
if (index >= mpSfxTranslationTable->size())
|
||||
return 0;
|
||||
|
||||
s16 ret = mpSfxTranslationTable->at(index);
|
||||
if (ret == -1)
|
||||
u16 ret = (*mpSfxTranslationTable)[index];
|
||||
if (ret == 0xffff)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
@ -747,7 +747,7 @@ void CSfxManager::Update(float dt)
|
|||
void CSfxManager::Shutdown()
|
||||
{
|
||||
mpSfxTranslationTable = nullptr;
|
||||
mpSfxTranslationTableTok = TLockedToken<std::vector<s16>>{};
|
||||
mpSfxTranslationTableTok = TLockedToken<std::vector<u16>>{};
|
||||
StopAndRemoveAllEmitters();
|
||||
DisableAuxCallback();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace urde
|
|||
|
||||
class CSfxManager
|
||||
{
|
||||
static std::vector<s16>* mpSfxTranslationTable;
|
||||
static std::vector<u16>* mpSfxTranslationTable;
|
||||
public:
|
||||
|
||||
enum class ESfxChannels
|
||||
|
|
|
@ -2434,9 +2434,6 @@ void CStateManager::SetCurrentAreaId(TAreaId aid)
|
|||
x850_world->GetMapWorld()->RecalculateWorldSphere(*x8c0_mapWorldInfo, *x850_world);
|
||||
}
|
||||
|
||||
CEntity* CStateManager::ObjectById(TUniqueId uid) { return GetAllObjectList().GetObjectById(uid); }
|
||||
const CEntity* CStateManager::GetObjectById(TUniqueId uid) const { return GetAllObjectList().GetObjectById(uid); }
|
||||
|
||||
void CStateManager::AreaUnloaded(TAreaId)
|
||||
{
|
||||
// Intentionally empty
|
||||
|
|
|
@ -361,8 +361,8 @@ public:
|
|||
void UpdateRoomAcoustics(TAreaId);
|
||||
TAreaId GetNextAreaId() const { return x8cc_nextAreaId; }
|
||||
void SetCurrentAreaId(TAreaId);
|
||||
CEntity* ObjectById(TUniqueId uid);
|
||||
const CEntity* GetObjectById(TUniqueId uid) const;
|
||||
CEntity* ObjectById(TUniqueId uid) const { return GetAllObjectList().GetObjectById(uid); }
|
||||
const CEntity* GetObjectById(TUniqueId uid) const { return GetAllObjectList().GetObjectById(uid); }
|
||||
void AreaUnloaded(TAreaId);
|
||||
void PrepareAreaUnload(TAreaId);
|
||||
void AreaLoaded(TAreaId);
|
||||
|
|
|
@ -1067,7 +1067,7 @@ void CBooRenderer::AddPlaneObject(const void* obj, const zeus::CAABox& aabb, con
|
|||
float farDist = xb0_viewPlane.pointToPlaneDist(farPoint);
|
||||
if (closeDist >= 0.f || farDist >= 0.f)
|
||||
{
|
||||
bool zOnly = plane.normal().isZero();
|
||||
bool zOnly = plane.normal() == zeus::CVector3f::skUp;
|
||||
bool invert;
|
||||
if (zOnly)
|
||||
invert = CGraphics::g_ViewMatrix.origin.z >= plane.d;
|
||||
|
|
|
@ -9,8 +9,8 @@ enum class EDrawableType : u16
|
|||
{
|
||||
WorldSurface,
|
||||
Particle,
|
||||
UnsortedCallback,
|
||||
SortedCallback,
|
||||
Actor,
|
||||
SimpleShadow,
|
||||
Decal
|
||||
};
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ set(GRAPHICS_SOURCES
|
|||
Shaders/CParticleSwooshShaders.hpp Shaders/CParticleSwooshShaders.cpp
|
||||
Shaders/CFluidPlaneShader.hpp Shaders/CFluidPlaneShader.cpp
|
||||
Shaders/CAABoxShader.hpp Shaders/CAABoxShader.cpp
|
||||
Shaders/CWorldShadowShader.hpp Shaders/CWorldShadowShader.cpp)
|
||||
Shaders/CWorldShadowShader.hpp Shaders/CWorldShadowShader.cpp
|
||||
Shaders/CEnvFxShaders.hpp Shaders/CEnvFxShaders.cpp)
|
||||
|
||||
runtime_add_list(Graphics GRAPHICS_SOURCES)
|
||||
|
|
|
@ -170,7 +170,7 @@ void CRainSplashGenerator::Update(float dt, CStateManager& mgr)
|
|||
EEnvFxType neededFx = mgr.GetWorld()->GetNeededEnvFx();
|
||||
x28_dt = dt;
|
||||
x48_25_raining = false;
|
||||
if (neededFx != EEnvFxType::None && mgr.GetEnvFxManager()->GetX24() &&
|
||||
if (neededFx != EEnvFxType::None && mgr.GetEnvFxManager()->IsSplashActive() &&
|
||||
mgr.GetEnvFxManager()->GetRainMagnitude() != 0.f && neededFx == EEnvFxType::Rain)
|
||||
{
|
||||
UpdateRainSplashes(mgr, mgr.GetEnvFxManager()->GetRainMagnitude(), dt);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#include "CEnvFxShaders.hpp"
|
||||
#include "hecl/Pipeline.hpp"
|
||||
#include "World/CEnvFxManager.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
boo::ObjToken<boo::IShaderPipeline> CEnvFxShaders::m_snowPipeline;
|
||||
boo::ObjToken<boo::IShaderPipeline> CEnvFxShaders::m_underwaterPipeline;
|
||||
|
||||
void CEnvFxShaders::Initialize()
|
||||
{
|
||||
m_snowPipeline = hecl::conv->convert(Shader_CEnvFxSnowShader{});
|
||||
m_underwaterPipeline = hecl::conv->convert(Shader_CEnvFxUnderwaterShader{});
|
||||
}
|
||||
|
||||
void CEnvFxShaders::Shutdown()
|
||||
{
|
||||
m_snowPipeline.reset();
|
||||
m_underwaterPipeline.reset();
|
||||
}
|
||||
|
||||
void CEnvFxShaders::BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||
CEnvFxManager& fxMgr, CEnvFxManagerGrid& grid)
|
||||
{
|
||||
auto uBufInfo = grid.m_uniformBuf.getBufferInfo();
|
||||
auto iBufInfo = grid.m_instBuf.getBufferInfo();
|
||||
boo::ObjToken<boo::IGraphicsBuffer> uniforms[] = {uBufInfo.first.get(),
|
||||
fxMgr.m_fogUniformBuf.get()};
|
||||
size_t ubufOffsets[] = {uBufInfo.second, 0};
|
||||
size_t ubufSizes[] = {256, 256};
|
||||
boo::PipelineStage uniformStages[] = {boo::PipelineStage::Vertex, boo::PipelineStage::Fragment};
|
||||
boo::ObjToken<boo::ITexture> textures[] = {fxMgr.xb74_txtrSnowFlake->GetBooTexture(),
|
||||
fxMgr.x40_txtrEnvGradient->GetBooTexture()};
|
||||
grid.m_snowBinding = ctx.newShaderDataBinding(m_snowPipeline, nullptr,
|
||||
iBufInfo.first.get(), nullptr, 2, uniforms,
|
||||
uniformStages, ubufOffsets, ubufSizes,
|
||||
2, textures, nullptr, nullptr, 0, iBufInfo.second);
|
||||
textures[0] = fxMgr.xc48_underwaterFlake->GetBooTexture();
|
||||
grid.m_underwaterBinding = ctx.newShaderDataBinding(m_underwaterPipeline, nullptr,
|
||||
iBufInfo.first.get(), nullptr, 2, uniforms,
|
||||
uniformStages, ubufOffsets, ubufSizes,
|
||||
2, textures, nullptr, nullptr, 0, iBufInfo.second);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "Graphics/CGraphics.hpp"
|
||||
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
class CEnvFxManager;
|
||||
class CEnvFxManagerGrid;
|
||||
|
||||
class CEnvFxShaders
|
||||
{
|
||||
public:
|
||||
struct Instance
|
||||
{
|
||||
zeus::CVector3f positions[4];
|
||||
zeus::CColor color;
|
||||
zeus::CVector2f uvs[4];
|
||||
};
|
||||
struct Uniform
|
||||
{
|
||||
zeus::CMatrix4f mvp;
|
||||
zeus::CMatrix4f envMtx;
|
||||
zeus::CColor moduColor;
|
||||
};
|
||||
|
||||
private:
|
||||
static boo::ObjToken<boo::IShaderPipeline> m_snowPipeline;
|
||||
static boo::ObjToken<boo::IShaderPipeline> m_underwaterPipeline;
|
||||
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
static void BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx,
|
||||
CEnvFxManager& fxMgr, CEnvFxManagerGrid& grid);
|
||||
};
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
#include "Graphics/Shaders/CAABoxShader.hpp"
|
||||
#include "Graphics/Shaders/CWorldShadowShader.hpp"
|
||||
#include "Graphics/Shaders/CParticleSwooshShaders.hpp"
|
||||
#include "Graphics/Shaders/CEnvFxShaders.hpp"
|
||||
#include "NESEmulator/CNESShader.hpp"
|
||||
#include "Audio/CStreamAudioManager.hpp"
|
||||
#include "CGBASupport.hpp"
|
||||
|
@ -286,6 +287,7 @@ CMain::BooSetter::BooSetter(boo::IGraphicsDataFactory* factory,
|
|||
CTextSupportShader::Initialize();
|
||||
CScanLinesFilter::Initialize();
|
||||
CRandomStaticFilter::Initialize();
|
||||
CEnvFxShaders::Initialize();
|
||||
CNESShader::Initialize();
|
||||
}
|
||||
|
||||
|
@ -942,6 +944,7 @@ void CMain::Shutdown()
|
|||
CTextSupportShader::Shutdown();
|
||||
CScanLinesFilter::Shutdown();
|
||||
CRandomStaticFilter::Shutdown();
|
||||
CEnvFxShaders::Shutdown();
|
||||
CFluidPlaneShader::Shutdown();
|
||||
CFluidPlaneManager::RippleMapTex.reset();
|
||||
CNESShader::Shutdown();
|
||||
|
|
|
@ -110,6 +110,7 @@ public:
|
|||
x4_resFactory->LoadOriginalIDs(*xcc_simplePool);
|
||||
LoadStringTable();
|
||||
m_renderer.reset(AllocateRenderer(*xcc_simplePool, *x4_resFactory));
|
||||
CEnvFxManager::Initialize();
|
||||
CScriptMazeNode::LoadMazeSeeds();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +1,656 @@
|
|||
#include "CEnvFxManager.hpp"
|
||||
#include "Graphics/CTexture.hpp"
|
||||
#include "CActor.hpp"
|
||||
#include "GameGlobalObjects.hpp"
|
||||
#include "CSimplePool.hpp"
|
||||
#include "CRandom16.hpp"
|
||||
#include "CStateManager.hpp"
|
||||
#include "TCastTo.hpp"
|
||||
#include "CHUDBillboardEffect.hpp"
|
||||
#include "World/CWorld.hpp"
|
||||
#include "World/CPlayer.hpp"
|
||||
#include "Collision/CGameCollision.hpp"
|
||||
#include "Collision/CInternalRayCastStructure.hpp"
|
||||
#include "World/CScriptTrigger.hpp"
|
||||
#include "World/CScriptWater.hpp"
|
||||
#include "Graphics/CBooRenderer.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
||||
static rstl::reserved_vector<zeus::CVector2f, 256> g_SnowForces;
|
||||
|
||||
CEnvFxManagerGrid::CEnvFxManagerGrid(const zeus::CVector2i& position, const zeus::CVector2i& extent,
|
||||
const std::vector<CVectorFixed8_8>& initialParticles, int reserve,
|
||||
CEnvFxManager& parent, boo::IGraphicsDataFactory::Context& ctx)
|
||||
: x4_position(position), xc_extent(extent), x1c_particles(initialParticles),
|
||||
m_instBuf(parent.m_instPool.allocateBlock(CGraphics::g_BooFactory, reserve)),
|
||||
m_uniformBuf(parent.m_uniformPool.allocateBlock(CGraphics::g_BooFactory)),
|
||||
m_lineRenderer(ctx, CLineRenderer::EPrimitiveMode::Lines, reserve * 2,
|
||||
parent.x40_txtrEnvGradient->GetBooTexture(), true, true)
|
||||
{
|
||||
x1c_particles.reserve(reserve);
|
||||
CEnvFxShaders::BuildShaderDataBinding(ctx, parent, *this);
|
||||
}
|
||||
|
||||
CEnvFxManager::CEnvFxManager()
|
||||
{
|
||||
|
||||
x40_txtrEnvGradient = g_SimplePool->GetObj("TXTR_EnvGradient");
|
||||
x40_txtrEnvGradient->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge);
|
||||
xb58_envRainSplash = g_SimplePool->GetObj("PART_EnvRainSplash");
|
||||
xb74_txtrSnowFlake = g_SimplePool->GetObj("TXTR_SnowFlake");
|
||||
xc48_underwaterFlake = g_SimplePool->GetObj("TXTR_UnderwaterFlake");
|
||||
CRandom16 random(0);
|
||||
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx)
|
||||
{
|
||||
m_fogUniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(CGraphics::g_Fog), 1);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
for (int j = 0; j < 8; ++j)
|
||||
x50_grids.emplace_back(zeus::CVector2i{j * 2048, i * 2048}, zeus::CVector2i{2048, 2048},
|
||||
std::vector<CVectorFixed8_8>{}, 171, *this, ctx);
|
||||
return true;
|
||||
} BooTrace);
|
||||
for (int i = 0; i < 16; ++i)
|
||||
xb84_snowZDeltas.emplace_back(0.f, 0.f, random.Range(-2.f, -4.f));
|
||||
}
|
||||
|
||||
void CEnvFxManager::Update(float, const CStateManager&)
|
||||
void CEnvFxManager::SetSplashEffectRate(float rate, const CStateManager& mgr)
|
||||
{
|
||||
if (TCastToPtr<CHUDBillboardEffect> splashEffect = mgr.ObjectById(xb68_envRainSplashId))
|
||||
if (splashEffect->GetX104_26())
|
||||
splashEffect->GetParticleGen()->SetGeneratorRate(rate);
|
||||
}
|
||||
|
||||
/* Used to be MIDI scale */
|
||||
static float CalcRainVolume(float f)
|
||||
{
|
||||
if (f < 0.1f)
|
||||
return (f / 0.1f * 74.f) / 127.f;
|
||||
else
|
||||
return (f / 0.9f * 21.f + 74.f) / 127.f;
|
||||
}
|
||||
|
||||
/* Used to be MIDI scale */
|
||||
static float CalcRainPitch(float f)
|
||||
{
|
||||
return f - 1.f;
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateRainSounds(const CStateManager& mgr)
|
||||
{
|
||||
if (mgr.GetWorld()->GetNeededEnvFx() == EEnvFxType::Rain)
|
||||
{
|
||||
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
|
||||
float rainVol = CalcRainVolume(x30_fxDensity);
|
||||
if (!xb6a_rainSoundActive)
|
||||
{
|
||||
xb6c_leftRainSound = CSfxManager::AddEmitter(SFXsfx09F0,
|
||||
zeus::CVector3f::skZero, zeus::CVector3f::skZero,
|
||||
false, true, 0xff, kInvalidAreaId);
|
||||
xb70_rightRainSound = CSfxManager::AddEmitter(SFXsfx09F1,
|
||||
zeus::CVector3f::skZero, zeus::CVector3f::skZero,
|
||||
false, true, 0xff, kInvalidAreaId);
|
||||
xb6a_rainSoundActive = true;
|
||||
}
|
||||
CSfxManager::UpdateEmitter(xb6c_leftRainSound, camXf.origin - camXf.basis[0], camXf.basis[0], rainVol);
|
||||
CSfxManager::UpdateEmitter(xb70_rightRainSound, camXf.origin + camXf.basis[0], -camXf.basis[0], rainVol);
|
||||
float rainPitch = CalcRainPitch(x30_fxDensity);
|
||||
CSfxManager::PitchBend(xb6c_leftRainSound, rainPitch);
|
||||
CSfxManager::PitchBend(xb70_rightRainSound, rainPitch);
|
||||
}
|
||||
else if (xb6a_rainSoundActive)
|
||||
{
|
||||
CSfxManager::RemoveEmitter(xb6c_leftRainSound);
|
||||
CSfxManager::RemoveEmitter(xb70_rightRainSound);
|
||||
xb6a_rainSoundActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
zeus::CVector3f CEnvFxManager::GetParticleBoundsToWorldScale() const
|
||||
{
|
||||
return (x0_particleBounds.max - x0_particleBounds.min) / 127.f;
|
||||
}
|
||||
|
||||
zeus::CTransform CEnvFxManager::GetParticleBoundsToWorldTransform() const
|
||||
{
|
||||
return zeus::CTransform::Translate(x18_focusCellPosition)
|
||||
* zeus::CTransform::Translate(zeus::CVector3f(-31.75f))
|
||||
* zeus::CTransform::Scale(GetParticleBoundsToWorldScale());
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateVisorSplash(CStateManager& mgr, float dt, const zeus::CTransform& camXf)
|
||||
{
|
||||
EEnvFxType fxType = mgr.GetWorld()->GetNeededEnvFx();
|
||||
if (xb68_envRainSplashId != kInvalidUniqueId)
|
||||
if (TCastToPtr<CHUDBillboardEffect> splashEffect = mgr.ObjectById(xb68_envRainSplashId))
|
||||
mgr.SetActorAreaId(*splashEffect, mgr.GetNextAreaId());
|
||||
float camUpness = camXf.basis[1].dot(zeus::CVector3f::skUp);
|
||||
float splashRateFactor;
|
||||
if (x24_enableSplash)
|
||||
splashRateFactor = std::max(0.f, camUpness) * x30_fxDensity;
|
||||
else
|
||||
splashRateFactor = 0.f;
|
||||
float forwardRateFactor = 0.f;
|
||||
if (x24_enableSplash && camUpness >= -0.1f)
|
||||
{
|
||||
zeus::CVector3f pRelVel = mgr.GetPlayer().GetTransform().transposeRotate(mgr.GetPlayer().GetVelocity());
|
||||
if (pRelVel.canBeNormalized())
|
||||
{
|
||||
float velMag = pRelVel.magnitude();
|
||||
zeus::CVector3f normRelVel = pRelVel * (1.f / velMag);
|
||||
forwardRateFactor = std::min(velMag / 60.f, 1.f) * normRelVel.dot(zeus::CVector3f::skForward);
|
||||
}
|
||||
}
|
||||
float additionalFactor;
|
||||
if (fxType == EEnvFxType::Rain)
|
||||
additionalFactor = splashRateFactor + forwardRateFactor;
|
||||
else
|
||||
additionalFactor = 0.f;
|
||||
SetSplashEffectRate(xb54_baseSplashRate + additionalFactor, mgr);
|
||||
xb54_baseSplashRate = 0.f;
|
||||
}
|
||||
|
||||
void CEnvFxManager::MoveWrapCells(s32 moveX, s32 moveY)
|
||||
{
|
||||
if (moveX == 0 && moveY == 0)
|
||||
return;
|
||||
bool r5 = std::fabs(moveX) >= 1.f || std::fabs(moveY) >= 1.f;
|
||||
s32 moveXMaj = moveX << 11;
|
||||
s32 moveYMaj = moveY << 11;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
s32 r28 = i - moveY;
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
CEnvFxManagerGrid& grid = x50_grids[i * 8 + j];
|
||||
s32 r3 = j - moveX;
|
||||
if (!r5)
|
||||
{
|
||||
CEnvFxManagerGrid& otherGrid = x50_grids[r28 * 8 + r3];
|
||||
grid.x14_block = otherGrid.x14_block;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.x0_24_blockDirty = true;
|
||||
}
|
||||
grid.x4_position = zeus::CVector2i((moveXMaj + grid.x4_position.x) & 0x3fff,
|
||||
(moveYMaj + grid.x4_position.y) & 0x3fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::CalculateSnowForces(const CVectorFixed8_8& zVec,
|
||||
rstl::reserved_vector<CVectorFixed8_8, 256>& snowForces,
|
||||
EEnvFxType type, const zeus::CVector3f& oopbtws, float dt)
|
||||
{
|
||||
if (type == EEnvFxType::Snow)
|
||||
{
|
||||
CVectorFixed8_8 vecf;
|
||||
zeus::CVector3f vec;
|
||||
for (int i = 255; i >= 0; ++i)
|
||||
{
|
||||
const zeus::CVector2f& force = g_SnowForces[i];
|
||||
zeus::CVector3f delta = zeus::CVector3f(force * dt) * oopbtws;
|
||||
vec += delta;
|
||||
CVectorFixed8_8 vecf2(vec);
|
||||
snowForces.push_back(vecf2 - vecf);
|
||||
vecf = vecf2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < snowForces.size(); ++i)
|
||||
snowForces[i] = snowForces[i] + zVec + CVectorFixed8_8(xb84_snowZDeltas[i & 0xf] * dt * oopbtws);
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::BuildBlockObjectList(rstl::reserved_vector<TUniqueId, 1024>& list, CStateManager& mgr)
|
||||
{
|
||||
for (CEntity* ent : mgr.GetAllObjectList())
|
||||
{
|
||||
if (TCastToPtr<CScriptTrigger> trig = ent)
|
||||
{
|
||||
if ((trig->GetTriggerFlags() & ETriggerFlags::BlockEnvironmentalEffects) != ETriggerFlags::None)
|
||||
list.push_back(ent->GetUniqueId());
|
||||
}
|
||||
else if (TCastToPtr<CScriptWater> water = ent)
|
||||
{
|
||||
list.push_back(ent->GetUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateBlockedGrids(CStateManager& mgr, EEnvFxType type, const zeus::CTransform& camXf,
|
||||
const zeus::CTransform& xf, const zeus::CTransform& invXf)
|
||||
{
|
||||
zeus::CVector3f playerPos;
|
||||
if (mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed)
|
||||
playerPos = camXf.origin;
|
||||
else
|
||||
playerPos = mgr.GetPlayer().GetBallPosition();
|
||||
zeus::CVector2i localPlayerPos((invXf * playerPos * 256.f).toVec2f());
|
||||
x2c_lastBlockedGridIdx = -1;
|
||||
x24_enableSplash = false;
|
||||
rstl::reserved_vector<TUniqueId, 1024> blockList;
|
||||
bool blockListBuilt = false;
|
||||
int blockedGrids = 0;
|
||||
for (int i = 0; i < x50_grids.size(); ++i)
|
||||
{
|
||||
CEnvFxManagerGrid& grid = x50_grids[i];
|
||||
if (blockedGrids < 8 && grid.x0_24_blockDirty)
|
||||
{
|
||||
if (type == EEnvFxType::UnderwaterFlake)
|
||||
{
|
||||
grid.x14_block = std::make_pair(true, float(-FLT_MAX));
|
||||
}
|
||||
else
|
||||
{
|
||||
CMaterialFilter filter =
|
||||
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid, EMaterialTypes::Trigger},
|
||||
{EMaterialTypes::ProjectilePassthrough, EMaterialTypes::SeeThrough});
|
||||
zeus::CVector3f pos = xf * zeus::CVector3f((grid.x4_position + grid.xc_extent * 0).toVec2f() / 256.f) +
|
||||
zeus::CVector3f::skUp * 500.f;
|
||||
CRayCastResult result =
|
||||
CGameCollision::RayStaticIntersection(mgr, pos, zeus::CVector3f::skDown, 1000.f, filter);
|
||||
if (result.IsValid())
|
||||
{
|
||||
if (!blockListBuilt)
|
||||
{
|
||||
BuildBlockObjectList(blockList, mgr);
|
||||
blockListBuilt = true;
|
||||
}
|
||||
for (TUniqueId id : blockList)
|
||||
{
|
||||
if (TCastToConstPtr<CScriptTrigger> trig = mgr.GetObjectById(id))
|
||||
{
|
||||
if (auto tb = trig->GetTouchBounds())
|
||||
{
|
||||
CCollidableAABox caabb(*tb, {EMaterialTypes::Trigger});
|
||||
CRayCastResult result2 =
|
||||
caabb.CastRayInternal({pos, zeus::CVector3f::skDown, 1000.f, {}, filter});
|
||||
if (result2.IsValid() && result2.GetT() < result.GetT())
|
||||
result = result2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++blockedGrids;
|
||||
grid.x14_block = std::make_pair(result.IsValid(), result.GetPoint().z);
|
||||
}
|
||||
grid.x0_24_blockDirty = false;
|
||||
}
|
||||
zeus::CVector2i gridEnd = grid.x4_position + grid.xc_extent;
|
||||
if (localPlayerPos.x >= grid.x4_position.x && localPlayerPos.y >= grid.x4_position.y &&
|
||||
localPlayerPos.x < gridEnd.x && localPlayerPos.y < gridEnd.y && grid.x14_block.first &&
|
||||
grid.x14_block.second <= playerPos.z)
|
||||
{
|
||||
x24_enableSplash = true;
|
||||
x2c_lastBlockedGridIdx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::CreateNewParticles(EEnvFxType type)
|
||||
{
|
||||
int maxCellParticleCount;
|
||||
if (type == EEnvFxType::Snow)
|
||||
maxCellParticleCount = 0x1c98;
|
||||
else if (type == EEnvFxType::Rain)
|
||||
maxCellParticleCount = 0x2af8;
|
||||
else if (type == EEnvFxType::UnderwaterFlake)
|
||||
maxCellParticleCount = 0x1fd6;
|
||||
else
|
||||
maxCellParticleCount = 0;
|
||||
maxCellParticleCount >>= 6;
|
||||
int cellParticleCount = maxCellParticleCount * x30_fxDensity;
|
||||
static u32 seedStash = 0;
|
||||
CRandom16 random(seedStash);
|
||||
for (auto it = x50_grids.rbegin(); it != x50_grids.rend(); ++it)
|
||||
{
|
||||
if (it->x14_block.first)
|
||||
{
|
||||
if (cellParticleCount > it->x1c_particles.size())
|
||||
{
|
||||
if (cellParticleCount > it->x1c_particles.capacity())
|
||||
it->x1c_particles.reserve(maxCellParticleCount);
|
||||
int remCellParticleCount = cellParticleCount - it->x1c_particles.size();
|
||||
for (int i = 0; i < remCellParticleCount; ++i)
|
||||
{
|
||||
int x = random.Range(0.f, float(it->xc_extent.x));
|
||||
int y = random.Range(0.f, float(it->xc_extent.y));
|
||||
int z = 256.f * random.Range(0.f, 63.f);
|
||||
it->x1c_particles.emplace_back(x, y, z);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
it->x1c_particles.resize(cellParticleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
seedStash = random.GetSeed();
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateSnowParticles(const rstl::reserved_vector<CVectorFixed8_8, 256>& snowForces)
|
||||
{
|
||||
for (auto it = x50_grids.rbegin(); it != x50_grids.rend(); ++it)
|
||||
{
|
||||
int forceIt = int(x28_firstSnowForce);
|
||||
if (it->x14_block.first)
|
||||
{
|
||||
for (auto pit = it->x1c_particles.rbegin(); pit != it->x1c_particles.rend(); ++pit)
|
||||
{
|
||||
const CVectorFixed8_8& force = snowForces[forceIt];
|
||||
forceIt = (forceIt + 1) & 0xff;
|
||||
*pit = *pit + force;
|
||||
pit->z = s16(pit->z & 0x3fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateRainParticles(const CVectorFixed8_8& zVec, const zeus::CVector3f& oopbtws, float dt)
|
||||
{
|
||||
s16 deltaZ = zVec.z + s16(-40.f * dt * oopbtws.z * 256.f);
|
||||
for (auto it = x50_grids.rbegin(); it != x50_grids.rend(); ++it)
|
||||
for (auto pit = it->x1c_particles.rbegin(); pit != it->x1c_particles.rend(); ++pit)
|
||||
pit->z = s16((pit->z + deltaZ) & 0x3fff);
|
||||
}
|
||||
|
||||
void CEnvFxManager::UpdateUnderwaterParticles(const CVectorFixed8_8& zVec)
|
||||
{
|
||||
for (auto it = x50_grids.rbegin(); it != x50_grids.rend(); ++it)
|
||||
for (auto pit = it->x1c_particles.rbegin(); pit != it->x1c_particles.rend(); ++pit)
|
||||
pit->z = s16((pit->z + zVec.z) & 0x3fff);
|
||||
}
|
||||
|
||||
void CEnvFxManager::Update(float dt, CStateManager& mgr)
|
||||
{
|
||||
EEnvFxType fxType = mgr.GetWorld()->GetNeededEnvFx();
|
||||
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
|
||||
if (mgr.GetCameraManager()->GetFluidCounter() != 0)
|
||||
{
|
||||
x2c_lastBlockedGridIdx = -1;
|
||||
x24_enableSplash = false;
|
||||
SetSplashEffectRate(0.f, mgr);
|
||||
}
|
||||
UpdateRainSounds(mgr);
|
||||
UpdateVisorSplash(mgr, dt, camXf);
|
||||
if (fxType == EEnvFxType::None)
|
||||
{
|
||||
for (auto it = x50_grids.rbegin(); it != x50_grids.rend(); ++it)
|
||||
if (it->x14_block.first)
|
||||
it->x1c_particles = std::vector<CVectorFixed8_8>();
|
||||
}
|
||||
else
|
||||
{
|
||||
float densityDelta = x34_targetFxDensity - x30_fxDensity;
|
||||
float densityDeltaDamper = std::min(std::fabs(densityDelta) / 0.15f, 1.f);
|
||||
float maxDensityDelta = x38_maxDensityDeltaSpeed / 11000.f * dt;
|
||||
if (std::fabs(densityDelta) > maxDensityDelta)
|
||||
densityDelta = (densityDelta > 0.f ? 1.f : -1.f) * maxDensityDelta;
|
||||
x30_fxDensity += densityDeltaDamper * densityDelta;
|
||||
zeus::CVector3f pbtws = GetParticleBoundsToWorldScale();
|
||||
zeus::CVector3f oopbtws = 1.f / pbtws;
|
||||
zeus::CVector3f forwardPoint = camXf.basis[1] * 23.8125f + camXf.origin;
|
||||
float modX = std::fmod(forwardPoint.x, 7.9375f);
|
||||
float modY = std::fmod(forwardPoint.x, 7.9375f);
|
||||
s32 moveX = (x18_focusCellPosition.x - (forwardPoint.x - modX)) / 7.9375f;
|
||||
x18_focusCellPosition.x = forwardPoint.x - modX;
|
||||
s32 moveY = (x18_focusCellPosition.y - (forwardPoint.y - modY)) / 7.9375f;
|
||||
x18_focusCellPosition.y = forwardPoint.y - modY;
|
||||
float deltaZ = x18_focusCellPosition.z - forwardPoint.z;
|
||||
x18_focusCellPosition.z = forwardPoint.z;
|
||||
MoveWrapCells(moveX, moveY);
|
||||
CVectorFixed8_8 zVec(oopbtws * zeus::CVector3f(0.f, 0.f, deltaZ));
|
||||
if (fxType == EEnvFxType::UnderwaterFlake)
|
||||
zVec.z += s16(256.f * 0.5f * dt);
|
||||
rstl::reserved_vector<CVectorFixed8_8, 256> snowForces;
|
||||
CalculateSnowForces(zVec, snowForces, fxType, oopbtws, dt);
|
||||
zeus::CTransform xf = GetParticleBoundsToWorldTransform();
|
||||
zeus::CTransform invXf = xf.inverse();
|
||||
UpdateBlockedGrids(mgr, fxType, camXf, xf, invXf);
|
||||
CreateNewParticles(fxType);
|
||||
switch (fxType)
|
||||
{
|
||||
case EEnvFxType::Snow:
|
||||
UpdateSnowParticles(snowForces);
|
||||
break;
|
||||
case EEnvFxType::Rain:
|
||||
UpdateRainParticles(zVec, oopbtws, dt);
|
||||
break;
|
||||
case EEnvFxType::UnderwaterFlake:
|
||||
UpdateUnderwaterParticles(zVec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (fxType == EEnvFxType::Snow)
|
||||
x28_firstSnowForce = std::fmod(1.f + x28_firstSnowForce, 256.f);
|
||||
else
|
||||
x28_firstSnowForce = std::fmod(0.125f + x28_firstSnowForce, 256.f);
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManagerGrid::RenderSnowParticles(const zeus::CTransform& camXf) const
|
||||
{
|
||||
zeus::CVector3f xVec = 0.2f * camXf.basis[0];
|
||||
zeus::CVector3f zVec = 0.2f * camXf.basis[2];
|
||||
}
|
||||
|
||||
void CEnvFxManagerGrid::RenderRainParticles(const zeus::CTransform& camXf) const
|
||||
{
|
||||
m_lineRenderer.Reset();
|
||||
float zOffset = 2.f * (1.f - std::fabs(camXf.basis[2].dot(zeus::CVector3f::skUp))) + 1.f;
|
||||
zeus::CColor color0(1.f, 10.f / 15.f);
|
||||
for (const auto& particle : x1c_particles)
|
||||
{
|
||||
zeus::CVector3f pos0 = particle.toVec3f();
|
||||
zeus::CVector3f pos1 = pos0;
|
||||
pos1.z += zOffset;
|
||||
float uvy0 = pos0.z * 10.f + m_uvyOffset;
|
||||
float uvy1 = pos1.z * 10.f + m_uvyOffset;
|
||||
m_lineRenderer.AddVertex(pos0, zeus::CColor::skWhite, 1.f, {0.f, uvy0});
|
||||
m_lineRenderer.AddVertex(pos1, zeus::CColor::skClear, 1.f, {0.f, uvy1});
|
||||
}
|
||||
m_lineRenderer.Render(zeus::CColor(1.f, 0.15f));
|
||||
}
|
||||
|
||||
void CEnvFxManagerGrid::RenderUnderwaterParticles(const zeus::CTransform& camXf) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CEnvFxManager::Render(const CStateManager& mgr)
|
||||
void CEnvFxManagerGrid::Render(const zeus::CTransform& xf, const zeus::CTransform& invXf,
|
||||
const zeus::CTransform& camXf, float fxDensity, EEnvFxType fxType,
|
||||
const CEnvFxManager& parent) const
|
||||
{
|
||||
if (!x1c_particles.empty() && x14_block.first)
|
||||
{
|
||||
CGraphics::SetModelMatrix(xf * zeus::CTransform::Translate(x4_position.toVec2f() / 256.f));
|
||||
parent.m_uniformData.mvp =
|
||||
CGraphics::GetPerspectiveProjectionMatrix(true) *
|
||||
CGraphics::g_GXModelView.toMatrix4f();
|
||||
switch (fxType)
|
||||
{
|
||||
case EEnvFxType::Snow:
|
||||
case EEnvFxType::Rain:
|
||||
{
|
||||
zeus::CMatrix4f envTexMtx(true);
|
||||
envTexMtx[2][1] = 10.f;
|
||||
envTexMtx[3][1] = 0.5f - (invXf * (zeus::CVector3f::skUp * x14_block.second)).z * 10.f;
|
||||
m_uvyOffset = envTexMtx[3][1];
|
||||
parent.m_uniformData.envMtx = envTexMtx;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_uniformBuf.access() = parent.m_uniformData;
|
||||
switch (fxType)
|
||||
{
|
||||
case EEnvFxType::Snow:
|
||||
RenderSnowParticles(camXf);
|
||||
break;
|
||||
case EEnvFxType::Rain:
|
||||
RenderRainParticles(camXf);
|
||||
break;
|
||||
case EEnvFxType::UnderwaterFlake:
|
||||
RenderUnderwaterParticles(camXf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::SetupSnowTevs(const CStateManager& mgr) const
|
||||
{
|
||||
mgr.GetCameraManager()->GetCurrentCamera(mgr);
|
||||
if (mgr.GetCameraManager()->GetFluidCounter() != 0)
|
||||
{
|
||||
g_Renderer->SetWorldFog(ERglFogMode::PerspExp, 0.f, 35.f, zeus::CColor::skBlack);
|
||||
m_uniformData.moduColor = zeus::CColor(1.f, 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Renderer->SetWorldFog(ERglFogMode::PerspLin, 52.f, 57.f, zeus::CColor::skBlack);
|
||||
}
|
||||
|
||||
// Blend One One
|
||||
// 2 stages
|
||||
|
||||
// xb74_txtrSnowFlake
|
||||
// Texcoord0: 2x4, TEX0, GX_IDENTITY, no norm, GX_PTTIDENTITY
|
||||
// 0: Standard alpha, map0, tcg0
|
||||
// Color: Zero, Konst, TexC, Zero
|
||||
// Alpha: Zero, Konst, TexA, Zero
|
||||
|
||||
// x40_txtrEnvGradient
|
||||
// Texcoord1: 2x4, POS, GX_TEXMTX5, no norm, GX_PTTIDENTITY
|
||||
// 0: Standard alpha, map0, tcg0
|
||||
// Color: Zero, TexC, CPrev, Zero
|
||||
// Alpha: Zero, Zero, Zero, TexA
|
||||
}
|
||||
|
||||
void CEnvFxManager::SetupRainTevs() const
|
||||
{
|
||||
// Line-width 1px
|
||||
// Blend SrcAlpha One
|
||||
|
||||
// x40_txtrEnvGradient
|
||||
// Texcoord0: 2x4, POS, GX_TEXMTX5, no norm, GX_PTTIDENTITY
|
||||
// 0: Standard alpha, map0, tcg0
|
||||
// Color: Zero, Zero, Zero, TexC
|
||||
// Alpha: Zero, RasA, Konst, Zero
|
||||
// Ras vertex color
|
||||
// KAlpha 0.15
|
||||
}
|
||||
|
||||
void CEnvFxManager::SetupUnderwaterTevs(const zeus::CTransform& invXf, const CStateManager& mgr) const
|
||||
{
|
||||
// Blend SrcAlpha InvSrcAlpha
|
||||
|
||||
// xc48_underwaterFlake
|
||||
// Texcoord0: 2x4, TEX0, GX_IDENTITY, no norm, GX_PTTIDENTITY
|
||||
// Color: Zero, Zero, Zero, TexC
|
||||
// Alpha: Zero, Zero, Zero, TexA
|
||||
|
||||
float waterTop = FLT_MAX;
|
||||
for (CEntity* ent : mgr.GetAllObjectList())
|
||||
if (TCastToPtr<CScriptWater> water = ent)
|
||||
if (auto tb = water->GetTouchBounds())
|
||||
waterTop = std::min(waterTop, tb->max.z);
|
||||
zeus::CVector3f localWaterTop = invXf * (zeus::CVector3f::skUp * waterTop);
|
||||
zeus::CMatrix4f envTexMtx(true);
|
||||
envTexMtx[2][1] = -10.f;
|
||||
envTexMtx[3][1] = localWaterTop.z * -10.f + 0.5f;
|
||||
// Load into texmtx5
|
||||
|
||||
// x40_txtrEnvGradient
|
||||
// Texcoord1: 2x4, POS, GX_TEXMTX5, no norm, GX_PTTIDENTITY
|
||||
// MTX: y-scale -10.0 of Z, y-trans -10.0 * ()
|
||||
// 1: Standard alpha, map1, tcg1
|
||||
// Color: Zero, One, CPrev, Zero
|
||||
// Alpha: Zero, TexA, APrev, Zero
|
||||
// Swap: RGBR
|
||||
}
|
||||
|
||||
void CEnvFxManager::Render(const CStateManager& mgr) const
|
||||
{
|
||||
EEnvFxType fxType = mgr.GetWorld()->GetNeededEnvFx();
|
||||
if (fxType != EEnvFxType::None)
|
||||
{
|
||||
if (mgr.GetPlayer().GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphed ||
|
||||
(mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::Thermal &&
|
||||
(fxType != EEnvFxType::Snow ||
|
||||
mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay)))
|
||||
{
|
||||
// No Cull
|
||||
// ZTest, No ZWrite
|
||||
zeus::CTransform xf = GetParticleBoundsToWorldTransform();
|
||||
zeus::CTransform invXf = xf.inverse();
|
||||
zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
|
||||
m_uniformData.moduColor = zeus::CColor::skWhite;
|
||||
switch (fxType)
|
||||
{
|
||||
case EEnvFxType::Snow:
|
||||
SetupSnowTevs(mgr);
|
||||
break;
|
||||
case EEnvFxType::Rain:
|
||||
SetupRainTevs();
|
||||
break;
|
||||
case EEnvFxType::UnderwaterFlake:
|
||||
SetupUnderwaterTevs(invXf, mgr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_fogUniformBuf->load(&CGraphics::g_Fog, sizeof(CGraphics::g_Fog));
|
||||
for (const auto& grid : x50_grids)
|
||||
grid.Render(xf, invXf, camXf, x30_fxDensity, fxType, *this);
|
||||
// Backface cull
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEnvFxManager::AsyncLoadResources(CStateManager& mgr)
|
||||
{
|
||||
xb68_envRainSplashId = mgr.AllocateUniqueId();
|
||||
CHUDBillboardEffect* effect =
|
||||
new CHUDBillboardEffect(xb58_envRainSplash, {}, xb68_envRainSplashId, true, "VisorRainSplashes",
|
||||
CHUDBillboardEffect::GetNearClipDistance(mgr),
|
||||
CHUDBillboardEffect::GetScaleForPOV(mgr), zeus::CColor::skWhite,
|
||||
zeus::CVector3f::skOne, zeus::CVector3f::skZero);
|
||||
effect->SetX104_27(true);
|
||||
mgr.AddObject(effect);
|
||||
}
|
||||
|
||||
void CEnvFxManager::SetFxDensity(s32 val, float density)
|
||||
{
|
||||
x34_fxDensity = density;
|
||||
x38_ = val;
|
||||
x34_targetFxDensity = density;
|
||||
x38_maxDensityDeltaSpeed = val;
|
||||
}
|
||||
|
||||
void CEnvFxManager::AreaLoaded()
|
||||
{
|
||||
for (CEnvFxManagerGrid& grid : x50_grids)
|
||||
grid.x0_24_ = true;
|
||||
grid.x0_24_blockDirty = true;
|
||||
}
|
||||
|
||||
void CEnvFxManager::Cleanup()
|
||||
{
|
||||
xb68_envRainSplashId = kInvalidUniqueId;
|
||||
xb6a_ = false;
|
||||
xb6c_ = 0;
|
||||
xb70_ = 0;
|
||||
xb6a_rainSoundActive = false;
|
||||
xb6c_leftRainSound.reset();
|
||||
xb70_rightRainSound.reset();
|
||||
}
|
||||
|
||||
void CEnvFxManager::Initialize()
|
||||
{
|
||||
const SObjectTag* tag = g_ResFactory->GetResourceIdByName("DUMB_SnowForces");
|
||||
std::unique_ptr<u8[]> data = g_ResFactory->LoadResourceSync(*tag);
|
||||
athena::io::MemoryReader r(data.get(), 2048);
|
||||
for (int i = 0; i < 256; ++i)
|
||||
g_SnowForces.push_back(r.readVec2fBig());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
#include "CToken.hpp"
|
||||
#include "zeus/CAABox.hpp"
|
||||
#include "Particle/CGenDescription.hpp"
|
||||
#include "Audio/CSfxManager.hpp"
|
||||
#include "Graphics/Shaders/CEnvFxShaders.hpp"
|
||||
#include "Graphics/CLineRenderer.hpp"
|
||||
#include "hecl/VertexBufferPool.hpp"
|
||||
#include "hecl/UniformBufferPool.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
|
@ -15,7 +20,8 @@ enum class EEnvFxType
|
|||
{
|
||||
None,
|
||||
Snow,
|
||||
Rain
|
||||
Rain,
|
||||
UnderwaterFlake
|
||||
};
|
||||
|
||||
enum class EPhazonType
|
||||
|
@ -27,64 +33,132 @@ enum class EPhazonType
|
|||
|
||||
class CVectorFixed8_8
|
||||
{
|
||||
//u16 x0_[3];
|
||||
public:
|
||||
union {
|
||||
struct
|
||||
{
|
||||
s16 x, y, z;
|
||||
};
|
||||
s16 v[3];
|
||||
};
|
||||
CVectorFixed8_8() { x = y = z = 0; }
|
||||
CVectorFixed8_8(s16 xi, s16 yi, s16 zi) { x = xi; y = yi; z = zi; }
|
||||
CVectorFixed8_8(const zeus::CVector3f& vec)
|
||||
{
|
||||
x = s16(vec.x * 256.f);
|
||||
y = s16(vec.y * 256.f);
|
||||
z = s16(vec.z * 256.f);
|
||||
}
|
||||
CVectorFixed8_8 operator+(const CVectorFixed8_8& other) const
|
||||
{
|
||||
return {s16(x + other.x), s16(y + other.y), s16(z + other.z)};
|
||||
}
|
||||
CVectorFixed8_8 operator-(const CVectorFixed8_8& other) const
|
||||
{
|
||||
return {s16(x - other.x), s16(y - other.y), s16(z - other.z)};
|
||||
}
|
||||
zeus::CVector3f toVec3f() const
|
||||
{
|
||||
return {x / 256.f, y / 256.f, z / 256.f};
|
||||
}
|
||||
};
|
||||
|
||||
class CEnvFxManagerGrid
|
||||
{
|
||||
friend class CEnvFxManager;
|
||||
bool x0_24_ = true;
|
||||
zeus::CVector2i x4_;
|
||||
zeus::CVector2i xc_;
|
||||
std::pair<bool, float> x14_ = {false, FLT_MAX};
|
||||
std::vector<CVectorFixed8_8> x1c_;
|
||||
friend class CEnvFxShaders;
|
||||
bool x0_24_blockDirty = true;
|
||||
zeus::CVector2i x4_position; /* 8.8 fixed point */
|
||||
zeus::CVector2i xc_extent; /* 8.8 fixed point */
|
||||
std::pair<bool, float> x14_block = {false, FLT_MAX}; /* Blocked-bool, Z-coordinate */
|
||||
std::vector<CVectorFixed8_8> x1c_particles;
|
||||
|
||||
mutable hecl::VertexBufferPool<CEnvFxShaders::Instance>::Token m_instBuf;
|
||||
mutable hecl::UniformBufferPool<CEnvFxShaders::Uniform>::Token m_uniformBuf;
|
||||
mutable CLineRenderer m_lineRenderer;
|
||||
|
||||
boo::ObjToken<boo::IShaderDataBinding> m_snowBinding;
|
||||
boo::ObjToken<boo::IShaderDataBinding> m_underwaterBinding;
|
||||
|
||||
mutable float m_uvyOffset = 0.f;
|
||||
|
||||
void RenderSnowParticles(const zeus::CTransform& camXf) const;
|
||||
void RenderRainParticles(const zeus::CTransform& camXf) const;
|
||||
void RenderUnderwaterParticles(const zeus::CTransform& camXf) const;
|
||||
public:
|
||||
CEnvFxManagerGrid(const zeus::CVector2i& a, const zeus::CVector2i& b,
|
||||
const std::vector<CVectorFixed8_8>& vec, int reserve)
|
||||
: x4_(a), xc_(b), x1c_(vec)
|
||||
{
|
||||
x1c_.reserve(reserve);
|
||||
}
|
||||
CEnvFxManagerGrid(const zeus::CVector2i& position, const zeus::CVector2i& extent,
|
||||
const std::vector<CVectorFixed8_8>& initialParticles, int reserve,
|
||||
CEnvFxManager& parent, boo::IGraphicsDataFactory::Context& ctx);
|
||||
void Render(const zeus::CTransform& xf, const zeus::CTransform& invXf,
|
||||
const zeus::CTransform& camXf, float fxDensity, EEnvFxType fxType,
|
||||
const CEnvFxManager& parent) const;
|
||||
};
|
||||
|
||||
class CEnvFxManager
|
||||
{
|
||||
zeus::CAABox x0_ = zeus::CAABox(-63.5, 63.5);
|
||||
zeus::CVector3f x18_ = zeus::CVector3f::skZero;
|
||||
bool x24_ = false;
|
||||
float x28_ = 0.f;
|
||||
u32 x2c_ = -1;
|
||||
float x30_rainMagnitude = 0.f;
|
||||
float x34_fxDensity = 0.f;
|
||||
float x38_ = 0.f;
|
||||
u8 x3c = 0;
|
||||
|
||||
friend class CEnvFxManagerGrid;
|
||||
friend class CEnvFxShaders;
|
||||
zeus::CAABox x0_particleBounds = zeus::CAABox(-63.5f, 63.5f);
|
||||
zeus::CVector3f x18_focusCellPosition = zeus::CVector3f::skZero;
|
||||
bool x24_enableSplash = false;
|
||||
float x28_firstSnowForce = 0.f;
|
||||
s32 x2c_lastBlockedGridIdx = -1;
|
||||
float x30_fxDensity = 0.f;
|
||||
float x34_targetFxDensity = 0.f;
|
||||
float x38_maxDensityDeltaSpeed = 0.f;
|
||||
//bool x3c_snowflakeTextureMipBlanked = false; /* Shader simulates this texture mod */
|
||||
TLockedToken<CTexture> x40_txtrEnvGradient;
|
||||
rstl::reserved_vector<CEnvFxManagerGrid, 64> x50_grids;
|
||||
|
||||
float xb54_;
|
||||
float xb54_baseSplashRate;
|
||||
TLockedToken<CGenDescription> xb58_envRainSplash;
|
||||
bool xb64_ = true;
|
||||
TUniqueId xb68_envRainSplashId = kInvalidUniqueId;
|
||||
bool xb6a_ = false;
|
||||
u32 xb6c_ = 0;
|
||||
u32 xb70_ = 0;
|
||||
bool xb6a_rainSoundActive = false;
|
||||
CSfxHandle xb6c_leftRainSound;
|
||||
CSfxHandle xb70_rightRainSound;
|
||||
TLockedToken<CTexture> xb74_txtrSnowFlake;
|
||||
bool xb80_ = true;
|
||||
rstl::reserved_vector<zeus::CVector3f, 16> xb84_snowZDeltas;
|
||||
TLockedToken<CTexture> xc48_underwaterFlake;
|
||||
bool xc54_ = true;
|
||||
|
||||
void SetupSnowTevs();
|
||||
void SetupRainTevs();
|
||||
hecl::VertexBufferPool<CEnvFxShaders::Instance> m_instPool;
|
||||
hecl::UniformBufferPool<CEnvFxShaders::Uniform> m_uniformPool;
|
||||
mutable CEnvFxShaders::Uniform m_uniformData;
|
||||
boo::ObjToken<boo::IGraphicsBufferD> m_fogUniformBuf;
|
||||
|
||||
void SetSplashEffectRate(float f, const CStateManager& mgr);
|
||||
void UpdateRainSounds(const CStateManager& mgr);
|
||||
zeus::CVector3f GetParticleBoundsToWorldScale() const;
|
||||
zeus::CTransform GetParticleBoundsToWorldTransform() const;
|
||||
void UpdateVisorSplash(CStateManager& mgr, float dt, const zeus::CTransform& camXf);
|
||||
void MoveWrapCells(s32, s32);
|
||||
void CalculateSnowForces(const CVectorFixed8_8& zVec, rstl::reserved_vector<CVectorFixed8_8, 256>& snowForces,
|
||||
EEnvFxType type, const zeus::CVector3f& oopbtws, float dt);
|
||||
static void BuildBlockObjectList(rstl::reserved_vector<TUniqueId, 1024>& list, CStateManager& mgr);
|
||||
void UpdateBlockedGrids(CStateManager& mgr, EEnvFxType type, const zeus::CTransform& camXf,
|
||||
const zeus::CTransform& xf, const zeus::CTransform& invXf);
|
||||
void CreateNewParticles(EEnvFxType type);
|
||||
void UpdateSnowParticles(const rstl::reserved_vector<CVectorFixed8_8, 256>& snowForces);
|
||||
void UpdateRainParticles(const CVectorFixed8_8& zVec, const zeus::CVector3f& oopbtws, float dt);
|
||||
void UpdateUnderwaterParticles(const CVectorFixed8_8& zVec);
|
||||
void SetupSnowTevs(const CStateManager& mgr) const;
|
||||
void SetupRainTevs() const;
|
||||
void SetupUnderwaterTevs(const zeus::CTransform& invXf, const CStateManager& mgr) const;
|
||||
public:
|
||||
CEnvFxManager();
|
||||
void AsyncLoadResources(CStateManager& mgr);
|
||||
|
||||
void Update(float, const CStateManager&);
|
||||
void Render(const CStateManager& mgr);
|
||||
void Update(float, CStateManager& mgr);
|
||||
void Render(const CStateManager& mgr) const;
|
||||
void SetFxDensity(s32, float);
|
||||
void MoveWrapCells(s32, s32);
|
||||
void GetParticleBoundsToWorldScale() const;
|
||||
void AreaLoaded();
|
||||
void SetXB54(float f) { xb54_ = f; }
|
||||
bool GetX24() const { return x24_; }
|
||||
float GetRainMagnitude() const { return x30_rainMagnitude; }
|
||||
void SetSplashRate(float f) { xb54_baseSplashRate = f; }
|
||||
bool IsSplashActive() const { return x24_enableSplash; }
|
||||
float GetRainMagnitude() const { return x30_fxDensity; }
|
||||
void Cleanup();
|
||||
|
||||
static void Initialize();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
const zeus::CColor& color, const zeus::CVector3f& v1, const zeus::CVector3f& v2);
|
||||
~CHUDBillboardEffect();
|
||||
void Accept(IVisitor& visitor);
|
||||
bool GetX104_26() const { return x104_26_; }
|
||||
void SetX104_27(bool b) { x104_27_ = b; }
|
||||
CParticleGen* GetParticleGen() const { return xe8_generator.get(); }
|
||||
|
||||
static float GetNearClipDistance(CStateManager& mgr);
|
||||
static zeus::CVector3f GetScaleForPOV(CStateManager& mgr);
|
||||
|
|
|
@ -1258,7 +1258,7 @@ void CMorphBall::UpdateEffects(float dt, CStateManager& mgr)
|
|||
bool emitRainWake = (x0_player.GetPlayerMovementState() == CPlayer::EPlayerMovementState::OnGround &&
|
||||
mgr.GetWorld()->GetNeededEnvFx() == EEnvFxType::Rain &&
|
||||
mgr.GetEnvFxManager()->GetRainMagnitude() > 0.f &&
|
||||
mgr.GetEnvFxManager()->GetX24());
|
||||
mgr.GetEnvFxManager()->IsSplashActive());
|
||||
x1bc8_wakeEffectGens[7]->SetParticleEmission(emitRainWake);
|
||||
float rainGenRate = std::min(mgr.GetEnvFxManager()->GetRainMagnitude() * 2.f *
|
||||
x0_player.x4fc_flatMoveSpeed / x0_player.GetBallMaxVelocity(), 1.f);
|
||||
|
|
|
@ -933,7 +933,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
|
|||
if (water.GetFluidPlane().GetFluidType() == EFluidType::NormalWater)
|
||||
{
|
||||
float velMag = mgr.GetPlayer().GetVelocity().magnitude() / 10.f;
|
||||
mgr.GetEnvFxManager()->SetXB54(10.f * std::max(1.f, velMag));
|
||||
mgr.GetEnvFxManager()->SetSplashRate(10.f * std::max(1.f, velMag));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -147,15 +147,15 @@ void CScriptEffect::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt
|
|||
case EScriptObjectMessage::InitializedInArea:
|
||||
for (const SConnection& conn : x20_conns)
|
||||
{
|
||||
if (!(conn.x0_state == EScriptObjectState::Active && conn.x4_msg == EScriptObjectMessage::Deactivate) &&
|
||||
!(conn.x0_state == EScriptObjectState::Modify && conn.x4_msg == EScriptObjectMessage::Activate))
|
||||
continue;
|
||||
|
||||
auto search = mgr.GetIdListForScript(conn.x8_objId);
|
||||
for (auto it = search.first; it != search.second; ++it)
|
||||
if ((conn.x0_state == EScriptObjectState::Modify && conn.x4_msg == EScriptObjectMessage::Follow) ||
|
||||
(conn.x0_state == EScriptObjectState::InheritBounds && conn.x4_msg == EScriptObjectMessage::Activate))
|
||||
{
|
||||
if (TCastToConstPtr<CScriptTrigger>(mgr.GetObjectById(it->second)))
|
||||
x13c_triggerId = it->second;
|
||||
auto search = mgr.GetIdListForScript(conn.x8_objId);
|
||||
for (auto it = search.first; it != search.second; ++it)
|
||||
{
|
||||
if (TCastToConstPtr<CScriptTrigger>(mgr.GetObjectById(it->second)))
|
||||
x13c_triggerId = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -55,7 +55,7 @@ void CScriptSteam::Think(float dt, CStateManager& mgr)
|
|||
float distance = (mag >= x164_ ? 0.f : std::cos((1.5707964f * mag) * x168_) * x158_);
|
||||
mgr.Player()->SetVisorSteam(distance, x15c_alphaInDur, x160_alphaOutDur, x154_texture, x150_);
|
||||
if (x150_)
|
||||
mgr.GetEnvFxManager()->SetXB54(2.f * distance);
|
||||
mgr.GetEnvFxManager()->SetSplashRate(2.f * distance);
|
||||
}
|
||||
else
|
||||
mgr.Player()->SetVisorSteam(0.f, x15c_alphaInDur, x160_alphaOutDur, CAssetId(), x150_);
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
#shader CEnvFxSnowShader
|
||||
#instattribute position4 0
|
||||
#instattribute position4 1
|
||||
#instattribute position4 2
|
||||
#instattribute position4 3
|
||||
#instattribute color
|
||||
#instattribute uv4 0
|
||||
#instattribute uv4 1
|
||||
#instattribute uv4 2
|
||||
#instattribute uv4 3
|
||||
#srcfac one
|
||||
#dstfac one
|
||||
#primitive tristrips
|
||||
#depthtest lequal
|
||||
#depthwrite false
|
||||
#alphawrite false
|
||||
#culling none
|
||||
|
||||
#vertex glsl
|
||||
layout(location=0) in vec4 posIn[4];
|
||||
layout(location=4) in vec4 colorIn;
|
||||
layout(location=5) in vec4 uvsIn[4];
|
||||
|
||||
UBINDING0 uniform EnvFxUniform
|
||||
{
|
||||
mat4 mv;
|
||||
mat4 proj;
|
||||
mat4 envMtx;
|
||||
vec4 moduColor;
|
||||
};
|
||||
|
||||
struct VertToFrag
|
||||
{
|
||||
vec4 mvPos;
|
||||
vec4 color;
|
||||
vec2 uvFlake;
|
||||
vec2 uvEnv;
|
||||
};
|
||||
|
||||
SBINDING(0) out VertToFrag vtf;
|
||||
void main()
|
||||
{
|
||||
vec4 pos = posIn[gl_VertexID];
|
||||
vtf.color = colorIn * moduColor;
|
||||
vtf.uvFlake = uvsIn[gl_VertexID].xy;
|
||||
vtf.uvEnv = (envMtx * pos).xy;
|
||||
vtf.mvPos = mv * pos;
|
||||
gl_Position = proj * vtf.mvPos;
|
||||
}
|
||||
|
||||
#fragment glsl
|
||||
struct VertToFrag
|
||||
{
|
||||
vec4 mvPos;
|
||||
vec4 color;
|
||||
vec2 uvFlake;
|
||||
vec2 uvEnv;
|
||||
};
|
||||
|
||||
SBINDING(0) in VertToFrag vtf;
|
||||
layout(location=0) out vec4 colorOut;
|
||||
TBINDING0 uniform sampler2D texFlake;
|
||||
TBINDING1 uniform sampler2D texEnv;
|
||||
|
||||
UBINDING1 uniform FogUniform
|
||||
{
|
||||
int mode;
|
||||
vec4 color;
|
||||
float rangeScale;
|
||||
float start;
|
||||
};
|
||||
|
||||
vec4 MainPostFunc(vec4 colorIn)
|
||||
{
|
||||
float fogZ, temp;
|
||||
switch (mode)
|
||||
{
|
||||
case 2:
|
||||
fogZ = (-vtf.mvPos.z - start) * rangeScale;
|
||||
break;
|
||||
case 4:
|
||||
fogZ = 1.0 - exp2(-8.0 * (-vtf.mvPos.z - start) * rangeScale);
|
||||
break;
|
||||
case 5:
|
||||
temp = (-vtf.mvPos.z - start) * rangeScale;
|
||||
fogZ = 1.0 - exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
case 6:
|
||||
fogZ = exp2(-8.0 * (start + vtf.mvPos.z) * rangeScale);
|
||||
break;
|
||||
case 7:
|
||||
temp = (start + vtf.mvPos.z) * rangeScale;
|
||||
fogZ = exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
default:
|
||||
fogZ = 0.0;
|
||||
break;
|
||||
}
|
||||
return vec4(mix(colorIn, color, clamp(fogZ, 0.0, 1.0)).rgb, colorIn.a);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
colorOut = MainPostFunc(vtf.color * texture(texFlake, vtf.uvFlake) * texture(texEnv, vtf.uvEnv));
|
||||
}
|
||||
|
||||
#vertex hlsl
|
||||
struct VertData
|
||||
{
|
||||
float4 posIn[4] : POSITION;
|
||||
float4 colorIn : COLOR;
|
||||
float4 uvsIn[4] : UV;
|
||||
};
|
||||
|
||||
cbuffer EnvFxUniform : register(b0)
|
||||
{
|
||||
float4x4 mv;
|
||||
float4x4 proj;
|
||||
float4x4 envMtx;
|
||||
float4 moduColor;
|
||||
};
|
||||
|
||||
struct VertToFrag
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float4 mvPos : POSITION;
|
||||
float4 color : COLOR;
|
||||
float2 uvFlake : UV0;
|
||||
float2 uvEnv : UV1;
|
||||
};
|
||||
|
||||
VertToFrag main(in VertData v, in uint vertId : SV_VertexID)
|
||||
{
|
||||
VertToFrag vtf;
|
||||
vtf.color = v.colorIn * moduColor;
|
||||
vtf.uvFlake = v.uvsIn[vertId].xy;
|
||||
vtf.uvEnv = mul(envMtx, v.posIn[vertId]).xy;
|
||||
vtf.mvPos = mul(mv, v.posIn[vertId]);
|
||||
vtf.position = mul(proj, vtf.mvPos);
|
||||
return vtf;
|
||||
}
|
||||
|
||||
#fragment hlsl
|
||||
SamplerState samp : register(s0);
|
||||
SamplerState sampClamp : register(s3);
|
||||
Texture2D texFlake : register(t0);
|
||||
Texture2D texEnv : register(t1);
|
||||
struct VertToFrag
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float4 mvPos : POSITION;
|
||||
float4 color : COLOR;
|
||||
float2 uvFlake : UV0;
|
||||
float2 uvEnv : UV1;
|
||||
};
|
||||
|
||||
cbuffer FogUniform : register(b1)
|
||||
{
|
||||
int mode;
|
||||
float4 color;
|
||||
float rangeScale;
|
||||
float start;
|
||||
};
|
||||
|
||||
static float4 MainPostFunc(in VertToFrag vtf, float4 colorIn)
|
||||
{
|
||||
float fogZ, temp;
|
||||
switch (mode)
|
||||
{
|
||||
case 2:
|
||||
fogZ = (-vtf.mvPos.z - start) * rangeScale;
|
||||
break;
|
||||
case 4:
|
||||
fogZ = 1.0 - exp2(-8.0 * (-vtf.mvPos.z - start) * rangeScale);
|
||||
break;
|
||||
case 5:
|
||||
temp = (-vtf.mvPos.z - start) * rangeScale;
|
||||
fogZ = 1.0 - exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
case 6:
|
||||
fogZ = exp2(-8.0 * (start + vtf.mvPos.z) * rangeScale);
|
||||
break;
|
||||
case 7:
|
||||
temp = (start + vtf.mvPos.z) * rangeScale;
|
||||
fogZ = exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
default:
|
||||
fogZ = 0.0;
|
||||
break;
|
||||
}
|
||||
return float4(lerp(colorIn, color, saturate(fogZ)).rgb, colorIn.a);
|
||||
}
|
||||
|
||||
float4 main(in VertToFrag vtf) : SV_Target0
|
||||
{
|
||||
return MainPostFunc(vtf, vtf.color * texFlake.Sample(samp, vtf.uvFlake) * texEnv.Sample(sampClamp, vtf.uvEnv));
|
||||
}
|
||||
|
||||
#vertex metal
|
||||
struct VertData
|
||||
{
|
||||
float4 posIn[4];
|
||||
float4 colorIn;
|
||||
float4 uvsIn[4];
|
||||
};
|
||||
|
||||
struct EnvFxUniform
|
||||
{
|
||||
float4x4 mv;
|
||||
float4x4 proj;
|
||||
float4x4 envMtx;
|
||||
float4 moduColor;
|
||||
};
|
||||
|
||||
struct VertToFrag
|
||||
{
|
||||
float4 position [[ position ]];
|
||||
float4 mvPos;
|
||||
float4 color;
|
||||
float2 uvFlake;
|
||||
float2 uvEnv;
|
||||
};
|
||||
|
||||
vertex VertToFrag vmain(constant VertData* va [[ buffer(1) ]],
|
||||
uint vertId [[ vertex_id ]], uint instId [[ instance_id ]],
|
||||
constant EnvFxUniform& particle [[ buffer(2) ]])
|
||||
{
|
||||
VertToFrag vtf;
|
||||
constant VertData& v = va[instId];
|
||||
vtf.color = v.colorIn * particle.moduColor;
|
||||
vtf.uvFlake = v.uvsIn[vertId].xy;
|
||||
vtf.uvEnv = (envMtx * v.posIn[vertId]).xy;
|
||||
vtf.mvPos = particle.mv * v.posIn[vertId];
|
||||
vtf.position = particle.proj * vtf.mvPos;
|
||||
return vtf;
|
||||
}
|
||||
|
||||
#fragment metal
|
||||
struct VertToFrag
|
||||
{
|
||||
float4 position [[ position ]];
|
||||
float4 mvPos;
|
||||
float4 color;
|
||||
float2 uvFlake;
|
||||
float2 uvEnv;
|
||||
};
|
||||
|
||||
struct FogUniform
|
||||
{
|
||||
int mode;
|
||||
float4 color;
|
||||
float rangeScale;
|
||||
float start;
|
||||
};
|
||||
|
||||
float4 MainPostFunc(thread VertToFrag& vtf, constant FogUniform& fu, float4 colorIn)
|
||||
{
|
||||
float fogZ, temp;
|
||||
switch (lu.mode)
|
||||
{
|
||||
case 2:
|
||||
fogZ = (-vtf.mvPos.z - fu.start) * fu.rangeScale;
|
||||
break;
|
||||
case 4:
|
||||
fogZ = 1.0 - exp2(-8.0 * (-vtf.mvPos.z - fu.start) * fu.rangeScale);
|
||||
break;
|
||||
case 5:
|
||||
temp = (-vtf.mvPos.z - fu.start) * fu.rangeScale;
|
||||
fogZ = 1.0 - exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
case 6:
|
||||
fogZ = exp2(-8.0 * (fu.start + vtf.mvPos.z) * fu.rangeScale);
|
||||
break;
|
||||
case 7:
|
||||
temp = (fu.start + vtf.mvPos.z) * fu.rangeScale;
|
||||
fogZ = exp2(-8.0 * temp * temp);
|
||||
break;
|
||||
default:
|
||||
fogZ = 0.0;
|
||||
break;
|
||||
}
|
||||
return float4(mix(colorIn, fu.color, saturate(fogZ)).rgb, colorIn.a);
|
||||
}
|
||||
|
||||
fragment float4 fmain(VertToFrag vtf [[ stage_in ]],
|
||||
sampler samp [[ sampler(0) ]],
|
||||
sampler sampClamp [[ sampler(3) ]],
|
||||
constant FogUniform& fu [[ buffer(3) ]],
|
||||
texture2d<float> texFlake [[ texture(0) ]],
|
||||
texture2d<float> texEnv [[ texture(1) ]])
|
||||
{
|
||||
return MainPostFunc(vtf, fu, vtf.color * texFlake.sample(samp, vtf.uvFlake) * texEnv.sample(sampClamp, vtf.uvEnv));
|
||||
}
|
||||
|
||||
#shader CEnvFxUnderwaterShader : CEnvFxSnowShader
|
||||
#srcfac srcalpha
|
||||
#dstfac invsrcalpha
|
|
@ -10,6 +10,7 @@ add_shader(CColoredQuadFilter)
|
|||
add_shader(CDecalShaders)
|
||||
add_shader(CElementGenShaders)
|
||||
add_shader(CEnergyBarShader)
|
||||
add_shader(CEnvFxShaders)
|
||||
add_shader(CFogVolumeFilter)
|
||||
add_shader(CFogVolumePlaneShader)
|
||||
add_shader(CLineRendererShaders)
|
||||
|
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
|||
Subproject commit 7561dd66e6ab5f5b7d4f94fc7bf732653ce104fb
|
||||
Subproject commit 26541cd2b460592049b75b9612562fa6b7d01cc5
|
2
specter
2
specter
|
@ -1 +1 @@
|
|||
Subproject commit 8d29c1449c4e661449c6b666c2fe17ce35dff023
|
||||
Subproject commit 6475d4ad284a6106f55313f86d8fdc2ac13a381b
|
Loading…
Reference in New Issue