Implement CFluidPlaneDoor and CScriptDamageableTrigger

This commit is contained in:
Jack Andersen 2017-08-13 17:55:06 -10:00
parent 02f8f77b57
commit 086ff76474
26 changed files with 1110 additions and 295 deletions

View File

@ -2,7 +2,7 @@
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true"> <inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="clangTidyChecks" value="*,-cert-env33-c,-cppcoreguidelines-no-malloc,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-union-access,-google-*,google-default-arguments,google-explicit-constructor,google-runtime-member-string-references,google-runtime-memset,google-runtime-operator,-llvm-*,-readability-simplify-boolean-expr,-readability-braces-around-statements,-readability-identifier-naming,-readability-function-size,-misc-bool-pointer-implicit-conversion,-misc-unused-parameters,-modernize-use-using,-safety-no-assembler,-clang-diagnostic-*,-clang-analyzer-*,-cert-flp30-c" /> <option name="clangTidyChecks" value="*,-cert-env33-c,-cppcoreguidelines-no-malloc,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-union-access,-google-*,google-default-arguments,google-explicit-constructor,google-runtime-member-string-references,google-runtime-memset,google-runtime-operator,-llvm-*,-readability-simplify-boolean-expr,-readability-braces-around-statements,-readability-identifier-naming,-readability-function-size,-misc-bool-pointer-implicit-conversion,-misc-unused-parameters,-modernize-use-using,-safety-no-assembler,-clang-diagnostic-*,-clang-analyzer-*,-cert-flp30-c,-cppcoreguidelines-pro-type-vararg" />
</inspection_tool> </inspection_tool>
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" /> <option name="processCode" value="true" />

View File

@ -15,6 +15,9 @@ struct ITweakGame : ITweak
virtual float GetWavecapIntensityNormal() const = 0; virtual float GetWavecapIntensityNormal() const = 0;
virtual float GetWavecapIntensityPoison() const = 0; virtual float GetWavecapIntensityPoison() const = 0;
virtual float GetWavecapIntensityLava() const = 0; virtual float GetWavecapIntensityLava() const = 0;
virtual float GetRippleIntensityNormal() const = 0;
virtual float GetRippleIntensityPoison() const = 0;
virtual float GetRippleIntensityLava() const = 0;
virtual float GetFluidEnvBumpScale() const = 0; virtual float GetFluidEnvBumpScale() const = 0;
virtual float GetHardModeDamageMultiplier() const = 0; virtual float GetHardModeDamageMultiplier() const = 0;
virtual float GetHardModeWeaponMultiplier() const = 0; virtual float GetHardModeWeaponMultiplier() const = 0;

View File

@ -17,38 +17,38 @@ struct DamageableTrigger : IScriptObject
Value<atVec3f> volume; Value<atVec3f> volume;
HealthInfo healthInfo; HealthInfo healthInfo;
DamageVulnerability damageVulnerabilty; DamageVulnerability damageVulnerabilty;
Value<atUint32> unknown1; Value<atUint32> faceFlag;
UniqueID32 texture1; UniqueID32 patternTex1;
UniqueID32 texture2; UniqueID32 patternTex2;
UniqueID32 texture3; UniqueID32 colorTex;
Value<bool> lockOn; Value<bool> lockOn;
Value<bool> active; Value<bool> active;
VisorParameters visorParameters; VisorParameters visorParameters;
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const void nameIDs(PAKRouter<PAKBridge>& pakRouter) const
{ {
if (texture1) if (patternTex1)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture1); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternTex1);
ent->name = name + "_texture1"; ent->name = name + "_patternTex1";
} }
if (texture2) if (patternTex2)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture2); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternTex2);
ent->name = name + "_texture2"; ent->name = name + "_patternTex2";
} }
if (texture3) if (colorTex)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture3); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(colorTex);
ent->name = name + "_texture3"; ent->name = name + "_colorTex";
} }
} }
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{ {
g_curSpec->flattenDependencies(texture1, pathsOut); g_curSpec->flattenDependencies(patternTex1, pathsOut);
g_curSpec->flattenDependencies(texture2, pathsOut); g_curSpec->flattenDependencies(patternTex2, pathsOut);
g_curSpec->flattenDependencies(texture3, pathsOut); g_curSpec->flattenDependencies(colorTex, pathsOut);
} }
zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const zeus::CAABox getVISIAABB(hecl::BlenderToken& btok) const

View File

@ -84,7 +84,7 @@ struct Water : IScriptObject
Value<float> fogBias; Value<float> fogBias;
Value<float> fogMagnitude; Value<float> fogMagnitude;
Value<float> fogSpeed; Value<float> fogSpeed;
Value<atVec4f> fogColor; // CColor Value<atVec4f> fogColor;
UniqueID32 lightmap; UniqueID32 lightmap;
Value<float> unitsPerLightmapTexel; Value<float> unitsPerLightmapTexel;
Value<float> alphaInTime; Value<float> alphaInTime;
@ -116,52 +116,52 @@ struct Water : IScriptObject
if (patternMap1) if (patternMap1)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternMap1); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternMap1);
ent->name = name + "_tex1"; ent->name = name + "_patternMap1";
} }
if (patternMap2) if (patternMap2)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternMap2); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(patternMap2);
ent->name = name + "_tex2"; ent->name = name + "_patternMap2";
} }
if (colorMap) if (colorMap)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(colorMap); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(colorMap);
ent->name = name + "_tex3"; ent->name = name + "_colorMap";
} }
if (bumpMap) if (bumpMap)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(bumpMap); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(bumpMap);
ent->name = name + "_tex4"; ent->name = name + "_bumpMap";
} }
if (envMap) if (envMap)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(envMap); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(envMap);
ent->name = name + "_tex5"; ent->name = name + "_envMap";
} }
if (envBumpMap) if (envBumpMap)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(envBumpMap); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(envBumpMap);
ent->name = name + "_tex6"; ent->name = name + "_envBumpMap";
} }
if (lightmap) if (lightmap)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(lightmap); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(lightmap);
ent->name = name + "_tex34"; ent->name = name + "_lightmap";
} }
if (splashParticle1) if (splashParticle1)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle1); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle1);
ent->name = name + "_part1"; ent->name = name + "_splashParticle1";
} }
if (splashParticle2) if (splashParticle2)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle2); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle2);
ent->name = name + "_part2"; ent->name = name + "_splashParticle2";
} }
if (splashParticle3) if (splashParticle3)
{ {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle3); PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(splashParticle3);
ent->name = name + "_part3"; ent->name = name + "_splashParticle3";
} }
if (particle4) if (particle4)
{ {

View File

@ -23,9 +23,9 @@ struct CTweakGame : ITweakGame
Value<float> x34_wavecapIntensityNormal; Value<float> x34_wavecapIntensityNormal;
Value<float> x38_wavecapIntensityPoison; Value<float> x38_wavecapIntensityPoison;
Value<float> x3c_wavecapIntensityLava; Value<float> x3c_wavecapIntensityLava;
Value<float> x40_unknown10; Value<float> x40_rippleIntensityNormal;
Value<float> x44_unknown11; Value<float> x44_rippleIntentityPoison;
Value<float> x48_unknown12; Value<float> x48_rippleIntensityLava;
Value<float> x4c_fluidEnvBumpScale; Value<float> x4c_fluidEnvBumpScale;
Value<float> x50_unknown14; Value<float> x50_unknown14;
Value<float> x54_unknown15; Value<float> x54_unknown15;
@ -41,6 +41,9 @@ struct CTweakGame : ITweakGame
float GetWavecapIntensityNormal() const { return x34_wavecapIntensityNormal; } float GetWavecapIntensityNormal() const { return x34_wavecapIntensityNormal; }
float GetWavecapIntensityPoison() const { return x38_wavecapIntensityPoison; } float GetWavecapIntensityPoison() const { return x38_wavecapIntensityPoison; }
float GetWavecapIntensityLava() const { return x3c_wavecapIntensityLava; } float GetWavecapIntensityLava() const { return x3c_wavecapIntensityLava; }
float GetRippleIntensityNormal() const { return x40_rippleIntensityNormal; }
float GetRippleIntensityPoison() const { return x44_rippleIntentityPoison; }
float GetRippleIntensityLava() const { return x48_rippleIntensityLava; }
float GetFluidEnvBumpScale() const { return x4c_fluidEnvBumpScale; } float GetFluidEnvBumpScale() const { return x4c_fluidEnvBumpScale; }
float GetHardModeDamageMultiplier() const { return x60_hardmodeDamageMult; } float GetHardModeDamageMultiplier() const { return x60_hardmodeDamageMult; }
float GetHardModeWeaponMultiplier() const { return x64_hardmodeWeaponMult; } float GetHardModeWeaponMultiplier() const { return x64_hardmodeWeaponMult; }

View File

@ -1576,7 +1576,7 @@ void CStateManager::TestBombHittingWater(const CActor& damager, const zeus::CVec
{ {
float bombMag = powerBomb ? 1.f : 0.75f; float bombMag = powerBomb ? 1.f : 0.75f;
float mag = 0.6f * bombMag + 0.4f * bombMag * std::sin(2.f * M_PIF * rippleFactor * 0.25f); float mag = 0.6f * bombMag + 0.4f * bombMag * std::sin(2.f * M_PIF * rippleFactor * 0.25f);
water->GetFluidPlane().Ripple(mag, damager.GetUniqueId(), hitPos, *water, *this); water->GetFluidPlane().AddRipple(mag, damager.GetUniqueId(), hitPos, *water, *this);
} }
if (!powerBomb) if (!powerBomb)
x87c_fluidPlaneManager->CreateSplash(damager.GetUniqueId(), *this, *water, hitPos, rippleFactor, true); x87c_fluidPlaneManager->CreateSplash(damager.GetUniqueId(), *this, *water, hitPos, rippleFactor, true);
@ -1594,7 +1594,7 @@ void CStateManager::TestBombHittingWater(const CActor& damager, const zeus::CVec
{ {
// Not blocked by static geometry // Not blocked by static geometry
float mag = 0.6f * bombMag + 0.4f * bombMag * std::sin(2.f * M_PIF * -delta / bombMag * 0.25f); float mag = 0.6f * bombMag + 0.4f * bombMag * std::sin(2.f * M_PIF * -delta / bombMag * 0.25f);
water->GetFluidPlane().Ripple(mag, damager.GetUniqueId(), hitPos, *water, *this); water->GetFluidPlane().AddRipple(mag, damager.GetUniqueId(), hitPos, *water, *this);
} }
} }
} }

View File

@ -74,10 +74,25 @@ u16 CFluidPlaneShader::Cache::MakeCacheKey(const SFluidPlaneShaderInfo& info)
return ret; return ret;
} }
boo::IShaderPipeline* CFluidPlaneShader::Cache::GetOrBuildShader(const SFluidPlaneShaderInfo& info) u16 CFluidPlaneShader::Cache::MakeCacheKey(const SFluidPlaneDoorShaderInfo& info)
{
u16 ret = 0;
if (info.m_hasPatternTex1)
ret |= 1 << 0;
if (info.m_hasPatternTex2)
ret |= 1 << 1;
if (info.m_hasColorTex)
ret |= 1 << 2;
return ret;
}
template<class T>
boo::IShaderPipeline* CFluidPlaneShader::Cache::GetOrBuildShader(const T& info)
{ {
u16 key = MakeCacheKey(info); u16 key = MakeCacheKey(info);
auto& slot = m_cache[key]; auto& slot = CacheSlot(info, key);
if (slot.second != nullptr) if (slot.second != nullptr)
return slot.second; return slot.second;
@ -116,6 +131,60 @@ boo::IShaderPipeline* CFluidPlaneShader::Cache::GetOrBuildShader(const SFluidPla
return slot.second; return slot.second;
} }
template boo::IShaderPipeline*
CFluidPlaneShader::Cache::GetOrBuildShader<SFluidPlaneShaderInfo>(const SFluidPlaneShaderInfo& info);
template boo::IShaderPipeline*
CFluidPlaneShader::Cache::GetOrBuildShader<SFluidPlaneDoorShaderInfo>(const SFluidPlaneDoorShaderInfo& info);
void CFluidPlaneShader::Cache::Clear()
{
for (auto& p : m_cache)
{
p.first.doDestroy();
p.second = nullptr;
}
for (auto& p : m_doorCache)
{
p.first.doDestroy();
p.second = nullptr;
}
}
void CFluidPlaneShader::PrepareBinding(boo::IShaderPipeline* pipeline, u32 maxVertCount, bool door)
{
m_gfxTok = CGraphics::CommitResources(
[&](boo::IGraphicsDataFactory::Context& ctx)
{
m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(Vertex), maxVertCount);
m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, 1024, 1);
switch (ctx.platform())
{
case boo::IGraphicsDataFactory::Platform::OpenGL:
m_dataBind = BuildBinding(static_cast<boo::GLDataFactory::Context&>(ctx), pipeline, door);
break;
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
case boo::IGraphicsDataFactory::Platform::D3D12:
m_dataBind = BuildBinding(static_cast<boo::ID3DDataFactory::Context&>(ctx), pipeline, door);
break;
#endif
#if BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
m_dataBind = BuildBinding(static_cast<boo::MetalDataFactory::Context&>(ctx), pipeline, door);
break;
#endif
#if BOO_HAS_VULKAN
case boo::IGraphicsDataFactory::Platform::Vulkan:
m_dataBind = BuildBinding(static_cast<boo::VulkanDataFactory::Context&>(ctx), pipeline, door);
break;
#endif
default: break;
}
return true;
});
}
CFluidPlaneShader::CFluidPlaneShader(CFluidPlane::EFluidType type, CFluidPlaneShader::CFluidPlaneShader(CFluidPlane::EFluidType type,
const std::experimental::optional<TLockedToken<CTexture>>& patternTex1, const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
const std::experimental::optional<TLockedToken<CTexture>>& patternTex2, const std::experimental::optional<TLockedToken<CTexture>>& patternTex2,
@ -143,54 +212,37 @@ CFluidPlaneShader::CFluidPlaneShader(CFluidPlane::EFluidType type,
m_lightmap.operator bool(), m_lightmap.operator bool(),
doubleLightmapBlend, additive); doubleLightmapBlend, additive);
boo::IShaderPipeline* pipeline = _cache.GetOrBuildShader(shaderInfo); boo::IShaderPipeline* pipeline = _cache.GetOrBuildShader(shaderInfo);
PrepareBinding(pipeline, maxVertCount, false);
m_gfxTok = CGraphics::CommitResources(
[&](boo::IGraphicsDataFactory::Context& ctx)
{
m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(Vertex), maxVertCount);
m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, 1024, 1);
switch (ctx.platform())
{
case boo::IGraphicsDataFactory::Platform::OpenGL:
m_dataBind = BuildBinding(static_cast<boo::GLDataFactory::Context&>(ctx), pipeline);
break;
#if _WIN32
case boo::IGraphicsDataFactory::Platform::D3D11:
case boo::IGraphicsDataFactory::Platform::D3D12:
m_dataBind = BuildBinding(static_cast<boo::ID3DDataFactory::Context&>(ctx), pipeline);
break;
#endif
#if BOO_HAS_METAL
case boo::IGraphicsDataFactory::Platform::Metal:
m_dataBind = BuildBinding(static_cast<boo::MetalDataFactory::Context&>(ctx), pipeline);
break;
#endif
#if BOO_HAS_VULKAN
case boo::IGraphicsDataFactory::Platform::Vulkan:
m_dataBind = BuildBinding(static_cast<boo::VulkanDataFactory::Context&>(ctx), pipeline);
break;
#endif
default: break;
}
return true;
});
} }
void CFluidPlaneShader::prepareDraw(const zeus::CMatrix4f* texMtxs, const zeus::CMatrix4f& normMtx, float indScale, CFluidPlaneShader::CFluidPlaneShader(const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
const std::vector<CLight>& lights, const zeus::CColor* kColors) const std::experimental::optional<TLockedToken<CTexture>>& patternTex2,
const std::experimental::optional<TLockedToken<CTexture>>& colorTex,
u32 maxVertCount)
: m_patternTex1(patternTex1),
m_patternTex2(patternTex2),
m_colorTex(colorTex)
{
SFluidPlaneDoorShaderInfo shaderInfo(m_patternTex1.operator bool(),
m_patternTex2.operator bool(),
m_colorTex.operator bool());
boo::IShaderPipeline* pipeline = _cache.GetOrBuildShader(shaderInfo);
PrepareBinding(pipeline, maxVertCount, true);
}
void CFluidPlaneShader::prepareDraw(const RenderSetupInfo& info)
{ {
Uniform& uni = *reinterpret_cast<Uniform*>(m_uniBuf->map(sizeof(Uniform))); Uniform& uni = *reinterpret_cast<Uniform*>(m_uniBuf->map(sizeof(Uniform)));
uni.m_mv = CGraphics::g_GXModelView.toMatrix4f(); uni.m_mv = CGraphics::g_GXModelView.toMatrix4f();
uni.m_mvNorm = normMtx; uni.m_mvNorm = info.normMtx;
uni.m_proj = CGraphics::GetPerspectiveProjectionMatrix(true); uni.m_proj = CGraphics::GetPerspectiveProjectionMatrix(true);
for (int i=0 ; i<6 ; ++i) for (int i=0 ; i<6 ; ++i)
uni.m_texMtxs[i] = texMtxs[i]; uni.m_texMtxs[i] = info.texMtxs[i];
uni.m_lighting.ActivateLights(lights); uni.m_lighting.ActivateLights(info.lights);
for (int i=0 ; i<3 ; ++i) for (int i=0 ; i<3 ; ++i)
uni.m_lighting.colorRegs[i] = kColors[i]; uni.m_lighting.colorRegs[i] = info.kColors[i];
uni.m_lighting.mulColor = kColors[3]; uni.m_lighting.mulColor = info.kColors[3];
uni.m_lighting.fog.m_rangeScale = indScale; uni.m_lighting.fog.m_rangeScale = info.indScale;
m_uniBuf->unmap(); m_uniBuf->unmap();
CGraphics::SetShaderDataBinding(m_dataBind); CGraphics::SetShaderDataBinding(m_dataBind);
} }

View File

@ -35,6 +35,17 @@ struct SFluidPlaneShaderInfo
{} {}
}; };
struct SFluidPlaneDoorShaderInfo
{
bool m_hasPatternTex1;
bool m_hasPatternTex2;
bool m_hasColorTex;
SFluidPlaneDoorShaderInfo(bool hasPatternTex1, bool hasPatternTex2, bool hasColorTex)
: m_hasPatternTex1(hasPatternTex1), m_hasPatternTex2(hasPatternTex2), m_hasColorTex(hasColorTex)
{}
};
class CFluidPlaneShader class CFluidPlaneShader
{ {
public: public:
@ -59,13 +70,30 @@ public:
: m_pos(position), m_norm(normal), m_binorm(binormal), m_tangent(tangent), m_color(color) {} : m_pos(position), m_norm(normal), m_binorm(binormal), m_tangent(tangent), m_color(color) {}
}; };
struct RenderSetupInfo
{
zeus::CMatrix4f texMtxs[6];
zeus::CMatrix4f normMtx;
float indScale = 1.f;
zeus::CColor kColors[4];
std::vector<CLight> lights;
};
private: private:
class Cache class Cache
{ {
std::pair<boo::GraphicsDataToken, boo::IShaderPipeline*> m_cache[1024] = {}; std::pair<boo::GraphicsDataToken, boo::IShaderPipeline*> m_cache[1024] = {};
std::pair<boo::GraphicsDataToken, boo::IShaderPipeline*> m_doorCache[8] = {};
std::pair<boo::GraphicsDataToken, boo::IShaderPipeline*>&
CacheSlot(const SFluidPlaneShaderInfo& info, int i) { return m_cache[i]; }
std::pair<boo::GraphicsDataToken, boo::IShaderPipeline*>&
CacheSlot(const SFluidPlaneDoorShaderInfo& info, int i) { return m_doorCache[i]; }
static u16 MakeCacheKey(const SFluidPlaneShaderInfo& info); static u16 MakeCacheKey(const SFluidPlaneShaderInfo& info);
static u16 MakeCacheKey(const SFluidPlaneDoorShaderInfo& info);
public: public:
boo::IShaderPipeline* GetOrBuildShader(const SFluidPlaneShaderInfo& info); template<class T>
boo::IShaderPipeline* GetOrBuildShader(const T& info);
void Clear();
}; };
static Cache _cache; static Cache _cache;
@ -91,20 +119,25 @@ private:
boo::IShaderDataBinding* m_dataBind; boo::IShaderDataBinding* m_dataBind;
static boo::IShaderPipeline* BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static boo::IShaderPipeline* BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::GLDataFactory::Context& ctx, boo::IShaderPipeline* pipeline); static boo::IShaderPipeline* BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::GLDataFactory::Context& ctx, boo::IShaderPipeline* pipeline, bool door);
#if _WIN32 #if _WIN32
static boo::IShaderPipeline* BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static boo::IShaderPipeline* BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::ID3DDataFactory::Context& ctx, boo::IShaderPipeline* pipeline); static boo::IShaderPipeline* BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::ID3DDataFactory::Context& ctx, boo::IShaderPipeline* pipeline, bool door);
#endif #endif
#if BOO_HAS_METAL #if BOO_HAS_METAL
static boo::IShaderPipeline* BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static boo::IShaderPipeline* BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::MetalDataFactory::Context& ctx, boo::IShaderPipeline* pipeline); static boo::IShaderPipeline* BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::MetalDataFactory::Context& ctx, boo::IShaderPipeline* pipeline, bool door);
#endif #endif
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
static boo::IShaderPipeline* BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static boo::IShaderPipeline* BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::VulkanDataFactory::Context& ctx, boo::IShaderPipeline* pipeline); static boo::IShaderPipeline* BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info);
boo::IShaderDataBinding* BuildBinding(boo::VulkanDataFactory::Context& ctx, boo::IShaderPipeline* pipeline, bool door);
#endif #endif
void PrepareBinding(boo::IShaderPipeline* pipeline, u32 maxVertCount, bool door);
public: public:
CFluidPlaneShader(CFluidPlane::EFluidType type, CFluidPlaneShader(CFluidPlane::EFluidType type,
const std::experimental::optional<TLockedToken<CTexture>>& patternTex1, const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
@ -115,9 +148,14 @@ public:
const std::experimental::optional<TLockedToken<CTexture>>& envBumpMap, const std::experimental::optional<TLockedToken<CTexture>>& envBumpMap,
const std::experimental::optional<TLockedToken<CTexture>>& lightmap, const std::experimental::optional<TLockedToken<CTexture>>& lightmap,
bool doubleLightmapBlend, bool additive, u32 maxVertCount); bool doubleLightmapBlend, bool additive, u32 maxVertCount);
void prepareDraw(const zeus::CMatrix4f* texMtxs, const zeus::CMatrix4f& normMtx, float indScale, CFluidPlaneShader(const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
const std::vector<CLight>& lights, const zeus::CColor* kColors); const std::experimental::optional<TLockedToken<CTexture>>& patternTex2,
const std::experimental::optional<TLockedToken<CTexture>>& colorTex,
u32 maxVertCount);
void prepareDraw(const RenderSetupInfo& info);
void loadVerts(const std::vector<Vertex>& verts); void loadVerts(const std::vector<Vertex>& verts);
static void Shutdown() { _cache.Clear(); }
}; };
} }

View File

@ -115,6 +115,28 @@ BOO_GLSL_BINDING_HEAD
"%s" // Combiner expression here "%s" // Combiner expression here
"}\n"; "}\n";
static const char* FSDoor =
"#version 330\n"
BOO_GLSL_BINDING_HEAD
"\n"
"struct VertToFrag\n"
"{\n"
" vec4 mvPos;\n"
" vec4 mvNorm;\n"
" vec4 mvBinorm;\n"
" vec4 mvTangent;\n"
" vec4 color;\n"
" vec2 uvs[7];\n"
"};\n"
"\n"
"SBINDING(0) in VertToFrag vtf;\n"
"layout(location=0) out vec4 colorOut;\n"
"%s" // Textures here
"void main()\n"
"{\n"
"%s" // Combiner expression here
"}\n";
static void _BuildShader(std::string& finalVS, std::string& finalFS, int& nextTex, const char* texNames[7], static void _BuildShader(std::string& finalVS, std::string& finalFS, int& nextTex, const char* texNames[7],
const SFluidPlaneShaderInfo& info) const SFluidPlaneShaderInfo& info)
{ {
@ -442,6 +464,51 @@ static void _BuildShader(std::string& finalVS, std::string& finalFS, int& nextTe
finalFS = hecl::Format(FS, textures.c_str(), combiner.c_str()); finalFS = hecl::Format(FS, textures.c_str(), combiner.c_str());
} }
static void _BuildShader(std::string& finalVS, std::string& finalFS, int& nextTex, const char* texNames[3],
const SFluidPlaneDoorShaderInfo& info)
{
std::string additionalTCGs;
std::string textures;
std::string combiner;
if (info.m_hasPatternTex1)
{
texNames[nextTex] = "patternTex1";
textures += hecl::Format("TBINDING%d uniform sampler2D patternTex1;\n", nextTex++);
}
if (info.m_hasPatternTex2)
{
texNames[nextTex] = "patternTex2";
textures += hecl::Format("TBINDING%d uniform sampler2D patternTex2;\n", nextTex++);
}
if (info.m_hasColorTex)
{
texNames[nextTex] = "colorTex";
textures += hecl::Format("TBINDING%d uniform sampler2D colorTex;\n", nextTex++);
}
// Tex0 * kColor0 * Tex1 + Tex2
if (info.m_hasPatternTex1 && info.m_hasPatternTex2)
{
combiner += " colorOut = texture(patternTex1, vtf.uvs[0]) * kColor0 *\n"
" texture(patternTex2, vtf.uvs[1]);\n";
}
else
{
combiner += " colorOut = vec4(0.0);\n";
}
if (info.m_hasColorTex)
{
combiner += " colorOut += texture(colorTex, vtf.uvs[2]);\n";
}
combiner += " colorOut.a = kColor0.a;\n";
finalVS = hecl::Format(VS, additionalTCGs.c_str());
finalFS = hecl::Format(FSDoor, textures.c_str(), combiner.c_str());
}
boo::IShaderPipeline* boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info) CFluidPlaneShader::BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info)
{ {
@ -457,6 +524,20 @@ CFluidPlaneShader::BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPla
boo::CullMode::None); boo::CullMode::None);
} }
boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info)
{
int nextTex = 0;
const char* texNames[3] = {};
std::string finalVS, finalFS;
_BuildShader(finalVS, finalFS, nextTex, texNames, info);
const char* uniNames[] = {"FluidPlaneUniform"};
return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), size_t(nextTex), texNames, 1, uniNames,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false,
boo::CullMode::None);
}
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
static boo::IVertexFormat* s_vtxFmt = nullptr; static boo::IVertexFormat* s_vtxFmt = nullptr;
@ -486,10 +567,36 @@ CFluidPlaneShader::BuildShader(boo::VulkanDataFactory::Context& ctx, const SFlui
boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false, boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false,
boo::CullMode::None); boo::CullMode::None);
} }
boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info)
{
if (s_vtxFmt == nullptr)
{
boo::VertexElementDescriptor elements[] =
{
{nullptr, nullptr, boo::VertexSemantic::Position4},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 0},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 1},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 2},
{nullptr, nullptr, boo::VertexSemantic::Color}
};
s_vtxFmt = ctx.newVertexFormat(5, elements);
}
int nextTex = 0;
const char* texNames[3] = {};
std::string finalVS, finalFS;
_BuildShader(finalVS, finalFS, nextTex, texNames, info);
return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), s_vtxFmt,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false,
boo::CullMode::None);
}
#endif #endif
boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::GLDataFactory::Context& ctx, boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::GLDataFactory::Context& ctx,
boo::IShaderPipeline* pipeline) boo::IShaderPipeline* pipeline, bool door)
{ {
boo::VertexElementDescriptor elements[] = boo::VertexElementDescriptor elements[] =
{ {
@ -521,13 +628,13 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::GLDataFactory::Con
texs[texCount++] = (*m_envBumpMap)->GetBooTexture(); texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap) if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture(); texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs, return ctx.newShaderDataBinding(pipeline, vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufSizes, texCount, texs, nullptr, nullptr); ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
} }
#if BOO_HAS_VULKAN #if BOO_HAS_VULKAN
boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::VulkanDataFactory::Context& ctx, boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::VulkanDataFactory::Context& ctx,
boo::IShaderPipeline* pipeline) boo::IShaderPipeline* pipeline, bool door)
{ {
boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf }; boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf };
boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex, boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex,
@ -550,8 +657,8 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::VulkanDataFactory:
texs[texCount++] = (*m_envBumpMap)->GetBooTexture(); texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap) if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture(); texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs, return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufSizes, texCount, texs, nullptr, nullptr); ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
} }
#endif #endif

View File

@ -119,6 +119,27 @@ static const char* FS =
" return colorOut;\n" " return colorOut;\n"
"}\n"; "}\n";
static const char* FSDoor =
"struct VertToFrag\n"
"{\n"
" float4 pos : SV_Position;\n"
" float4 mvPos : POSITION;\n"
" float4 mvNorm : NORMAL;\n"
" float4 mvBinorm : BINORMAL;\n"
" float4 mvTangent : TANGENT;\n"
" float4 color : COLOR;\n"
" float2 uvs[7] : UV;\n"
"};\n"
"\n"
"SamplerState samp : register(s0);\n"
"%s" // Textures here
"float4 main(in VertToFrag vtf)\n"
"{\n"
" float4 colorOut;\n"
"%s" // Combiner expression here
" return colorOut;\n"
"}\n";
boo::IShaderPipeline* boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info) CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info)
{ {
@ -198,12 +219,12 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
// Output reg 2 // Output reg 2
// KColor 3 // KColor 3
// Tex * K2 + Lighting // Tex * K2 + Lighting
combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n"; combiner += " lighting += mix(lightMapTexel * kColor2, lightMapTexel, kColor3);\n";
} }
else else
{ {
// mix(Tex * K2, Tex, K3) + Lighting // mix(Tex * K2, Tex, K3) + Lighting
combiner += " lighting += lightMapTexel * lu.kColor2;\n"; combiner += " lighting += lightMapTexel * kColor2;\n";
} }
} }
@ -224,7 +245,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasPatternTex2) if (info.m_hasPatternTex2)
{ {
if (info.m_hasPatternTex1) if (info.m_hasPatternTex1)
combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.kColor0 + lighting) *\n" combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * kColor0 + lighting) *\n"
" patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; " patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
else else
combiner += " colorOut = lighting * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; combiner += " colorOut = lighting * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
@ -239,7 +260,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
{ {
// Make previous stage indirect, mtx0 // Make previous stage indirect, mtx0
combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n" combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n"
" float2(lu.fog.indScale, -lu.fog.indScale);", envBumpMapUv); " float2(fog.indScale, -fog.indScale);", envBumpMapUv);
combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n"; combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n";
} }
else if (info.m_hasEnvMap) else if (info.m_hasEnvMap)
@ -253,8 +274,8 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasColorTex) if (info.m_hasColorTex)
combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]) * lighting;\n"; combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]) * lighting;\n";
combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n" combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n"
" float2(lu.fog.indScale, -lu.fog.indScale);", envBumpMapUv); " float2(fog.indScale, -fog.indScale);", envBumpMapUv);
combiner += hecl::Format(" colorOut = mix(colorOut, envMap.Sample(samp, indUvs + vtf.uvs[%d]), lu.kColor1);\n", combiner += hecl::Format(" colorOut = mix(colorOut, envMap.Sample(samp, indUvs + vtf.uvs[%d]), kColor1);\n",
envMapUv); envMapUv);
} }
else if (info.m_hasColorTex) else if (info.m_hasColorTex)
@ -279,12 +300,12 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
// Output reg 2 // Output reg 2
// KColor 3 // KColor 3
// Tex * K2 + Lighting // Tex * K2 + Lighting
combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n"; combiner += " lighting += mix(lightMapTexel * kColor2, lightMapTexel, kColor3);\n";
} }
else else
{ {
// mix(Tex * K2, Tex, K3) + Lighting // mix(Tex * K2, Tex, K3) + Lighting
combiner += " lighting += lightMapTexel * lu.kColor2;\n"; combiner += " lighting += lightMapTexel * kColor2;\n";
} }
} }
@ -305,7 +326,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasPatternTex2) if (info.m_hasPatternTex2)
{ {
if (info.m_hasPatternTex1) if (info.m_hasPatternTex1)
combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.kColor0 + lighting) *\n" combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * kColor0 + lighting) *\n"
" patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; " patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
else else
combiner += " colorOut = lighting * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; combiner += " colorOut = lighting * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
@ -321,7 +342,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
{ {
// Make previous stage indirect, mtx0 // Make previous stage indirect, mtx0
combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n" combiner += hecl::Format(" float2 indUvs = (envBumpMap.Sample(samp, vtf.uvs[%d]).ra - float2(0.5, 0.5)) *\n"
" float2(lu.fog.indScale, -lu.fog.indScale);", envBumpMapUv); " float2(fog.indScale, -fog.indScale);", envBumpMapUv);
combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n"; combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n";
} }
else else
@ -350,7 +371,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasPatternTex2) if (info.m_hasPatternTex2)
{ {
if (info.m_hasPatternTex1) if (info.m_hasPatternTex1)
combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.kColor0 + vtf.color) *\n" combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * kColor0 + vtf.color) *\n"
" patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; " patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
else else
combiner += " colorOut = vtf.color * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; combiner += " colorOut = vtf.color * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
@ -408,7 +429,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasPatternTex2) if (info.m_hasPatternTex2)
{ {
if (info.m_hasPatternTex1) if (info.m_hasPatternTex1)
combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.kColor0 + vtf.color) *\n" combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * kColor0 + vtf.color) *\n"
" patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; " patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
else else
combiner += " colorOut = vtf.color * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n"; combiner += " colorOut = vtf.color * patternTex2.Sample(samp, vtf.uvs[1]) + vtf.color;\n";
@ -445,8 +466,63 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
boo::CullMode::None); boo::CullMode::None);
} }
boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info)
{
if (s_vtxFmt == nullptr)
{
boo::VertexElementDescriptor elements[] =
{
{nullptr, nullptr, boo::VertexSemantic::Position4},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 0},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 1},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 2},
{nullptr, nullptr, boo::VertexSemantic::Color}
};
s_vtxFmt = ctx.newVertexFormat(5, elements);
}
std::string additionalTCGs;
std::string textures;
std::string combiner;
int nextTex = 0;
if (info.m_hasPatternTex1)
textures += hecl::Format("Texture2D patternTex1 : register(t%d)\n", nextTex++);
if (info.m_hasPatternTex2)
textures += hecl::Format("Texture2D patternTex2 : register(t%d)\n", nextTex++);
if (info.m_hasColorTex)
textures += hecl::Format("Texture2D colorTex : register(t%d)\n", nextTex++);
// Tex0 * kColor0 * Tex1 + Tex2
if (info.m_hasPatternTex1 && info.m_hasPatternTex2)
{
combiner += " colorOut = patternTex1.Sample(samp, vtf.uvs[0]) * kColor0 *\n"
" patternTex2.Sample(samp, vtf.uvs[1]);\n";
}
else
{
combiner += " colorOut = float4(0.0);\n";
}
if (info.m_hasColorTex)
{
combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]);\n";
}
combiner += " colorOut.a = kColor0.a;\n";
std::string finalVS = hecl::Format(VS, additionalTCGs.c_str());
std::string finalFS = hecl::Format(FSDoor, textures.c_str(), combiner.c_str());
return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), nullptr, nullptr, nullptr, s_vtxFmt,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false,
boo::CullMode::None);
}
boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::ID3DDataFactory::Context& ctx, boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::ID3DDataFactory::Context& ctx,
boo::IShaderPipeline* pipeline) boo::IShaderPipeline* pipeline, bool door)
{ {
boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf }; boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf };
boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex, boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex,
@ -469,8 +545,8 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::ID3DDataFactory::C
texs[texCount++] = (*m_envBumpMap)->GetBooTexture(); texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap) if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture(); texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs, return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufSizes, texCount, texs, nullptr, nullptr); ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
} }
} }

View File

@ -125,6 +125,29 @@ static const char* FS =
" return colorOut;\n" " return colorOut;\n"
"}\n"; "}\n";
static const char* FSDoor =
"#include <metal_stdlib>\n"
"using namespace metal;\n"
"constexpr sampler samp(address::repeat, filter::linear);\n"
"\n"
"struct VertToFrag\n"
"{\n"
" float4 pos : [[ position ]];\n"
" float4 mvPos;\n"
" float4 mvNorm;\n"
" float4 mvBinorm;\n"
" float4 mvTangent;\n"
" float4 color;\n"
" float2 uvs[7];\n"
"};\n"
"\n"
"fragment float4 fmain(VertToFrag vtf [[ stage_in ]]%s)\n" // Textures here
"{\n"
" float4 colorOut;\n"
"%s" // Combiner expression here
" return colorOut;\n"
"}\n";
boo::IShaderPipeline* boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info) CFluidPlaneShader::BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info)
{ {
@ -451,8 +474,63 @@ CFluidPlaneShader::BuildShader(boo::MetalDataFactory::Context& ctx, const SFluid
boo::CullMode::None); boo::CullMode::None);
} }
boo::IShaderPipeline*
CFluidPlaneShader::BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info)
{
if (s_vtxFmt == nullptr)
{
boo::VertexElementDescriptor elements[] =
{
{nullptr, nullptr, boo::VertexSemantic::Position4},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 0},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 1},
{nullptr, nullptr, boo::VertexSemantic::Normal4, 2},
{nullptr, nullptr, boo::VertexSemantic::Color}
};
s_vtxFmt = ctx.newVertexFormat(5, elements);
}
std::string additionalTCGs;
std::string textures;
std::string combiner;
int nextTex = 0;
if (info.m_hasPatternTex1)
textures += hecl::Format(",\ntexture2d<float> patternTex1 [[ texture(%d) ]]", nextTex++);
if (info.m_hasPatternTex2)
textures += hecl::Format(",\ntexture2d<float> patternTex2 [[ texture(%d) ]]", nextTex++);
if (info.m_hasColorTex)
textures += hecl::Format(",\ntexture2d<float> colorTex [[ texture(%d) ]]", nextTex++);
// Tex0 * kColor0 * Tex1 + Tex2
if (info.m_hasPatternTex1 && info.m_hasPatternTex2)
{
combiner += " colorOut = patternTex1.sample(samp, vtf.uvs[0]) * lu.kColor0 *\n"
" patternTex2.sample(samp, vtf.uvs[1]);\n";
}
else
{
combiner += " colorOut = float4(0.0);\n";
}
if (info.m_hasColorTex)
{
combiner += " colorOut += colorTex.sample(samp, vtf.uvs[2]);\n";
}
combiner += " colorOut.a = kColor0.a;\n";
std::string finalVS = hecl::Format(VS, additionalTCGs.c_str());
std::string finalFS = hecl::Format(FSDoor, textures.c_str(), combiner.c_str());
return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), s_vtxFmt, CGraphics::g_ViewportSamples,
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false,
boo::CullMode::None);
}
boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::MetalDataFactory::Context& ctx, boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::MetalDataFactory::Context& ctx,
boo::IShaderPipeline* pipeline) boo::IShaderPipeline* pipeline, bool door)
{ {
boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf }; boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf };
boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex, boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex,
@ -475,8 +553,8 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::MetalDataFactory::
texs[texCount++] = (*m_envBumpMap)->GetBooTexture(); texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap) if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture(); texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs, return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufSizes, texCount, texs, nullptr, nullptr); ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
} }
} }

View File

@ -14,6 +14,7 @@
#include "Graphics/Shaders/CPhazonSuitFilter.hpp" #include "Graphics/Shaders/CPhazonSuitFilter.hpp"
#include "Graphics/Shaders/CScanLinesFilter.hpp" #include "Graphics/Shaders/CScanLinesFilter.hpp"
#include "Graphics/Shaders/CRandomStaticFilter.hpp" #include "Graphics/Shaders/CRandomStaticFilter.hpp"
#include "Graphics/Shaders/CFluidPlaneShader.hpp"
#include "Character/CCharLayoutInfo.hpp" #include "Character/CCharLayoutInfo.hpp"
#include "Audio/CStreamAudioManager.hpp" #include "Audio/CStreamAudioManager.hpp"
#include "CGBASupport.hpp" #include "CGBASupport.hpp"
@ -369,6 +370,7 @@ void CMain::Shutdown()
TMultiBlendShader<CTextSupportShader>::Shutdown(); TMultiBlendShader<CTextSupportShader>::Shutdown();
TMultiBlendShader<CScanLinesFilter>::Shutdown(); TMultiBlendShader<CScanLinesFilter>::Shutdown();
TMultiBlendShader<CRandomStaticFilter>::Shutdown(); TMultiBlendShader<CRandomStaticFilter>::Shutdown();
CFluidPlaneShader::Shutdown();
} }
boo::IWindow* CMain::GetMainWindow() const boo::IWindow* CMain::GetMainWindow() const

View File

@ -79,9 +79,9 @@ protected:
public: public:
enum class EFluidState enum class EFluidState
{ {
Zero, EnteredFluid,
One, InFluid,
Two LeftFluid
}; };
enum class EScanState enum class EScanState
@ -180,6 +180,7 @@ public:
float GetAverageAnimVelocity(int anim) const; float GetAverageAnimVelocity(int anim) const;
u8 GetTargetableVisorFlags() const { return xe6_31_targetableVisorFlags; } u8 GetTargetableVisorFlags() const { return xe6_31_targetableVisorFlags; }
bool GetIsTargetable() const { return xe7_31_targetable; } bool GetIsTargetable() const { return xe7_31_targetable; }
void SetDrawFlags(const CModelFlags& flags) { xb4_drawFlags = flags; }
}; };
} }

View File

@ -1,6 +1,9 @@
#include <Runtime/GameGlobalObjects.hpp> #include <Runtime/GameGlobalObjects.hpp>
#include "CFluidPlane.hpp" #include "CFluidPlane.hpp"
#include "CSimplePool.hpp" #include "CSimplePool.hpp"
#include "CRipple.hpp"
#include "CScriptWater.hpp"
#include "CStateManager.hpp"
namespace urde namespace urde
{ {
@ -18,14 +21,67 @@ CFluidPlane::CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId te
x30_texColor.emplace(g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texColor})); x30_texColor.emplace(g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texColor}));
} }
void CFluidPlane::Ripple(float mag, TUniqueId rippler, const zeus::CVector3f& pos, float CFluidPlane::ProjectRippleVelocity(float baseI, float velDot) const
CScriptWater& water, CStateManager& mgr)
{ {
float tmp = 0.5f * baseI * velDot * velDot;
if (tmp != 0.f)
tmp = std::sqrt(tmp);
if (tmp >= 160.f)
return 1.f;
return tmp / 160.f;
} }
void CFluidPlane::Update() float CFluidPlane::CalculateRippleIntensity(float baseI) const
{ {
float mul;
switch (x44_fluidType)
{
case EFluidType::NormalWater:
mul = g_tweakGame->GetRippleIntensityNormal();
break;
case EFluidType::PoisonWater:
mul = g_tweakGame->GetRippleIntensityPoison();
break;
case EFluidType::Lava:
mul = g_tweakGame->GetRippleIntensityLava();
break;
case EFluidType::Three:
case EFluidType::Four:
mul = 0.8f;
break;
case EFluidType::Five:
mul = 1.f;
break;
}
return zeus::clamp(0.f, baseI * mul * (1.f - x48_rippleIntensity + 0.5f), 1.f);
}
void CFluidPlane::AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center,
CScriptWater& water, CStateManager& mgr)
{
if (!water.CanRippleAtPoint(center))
return;
mag = CalculateRippleIntensity(mag);
mgr.GetFluidPlaneManager()->RippleManager().AddRipple(CRipple(rippler, center, mag));
}
void CFluidPlane::AddRipple(float intensity, TUniqueId rippler, const zeus::CVector3f& center,
const zeus::CVector3f& velocity, const CScriptWater& water, CStateManager& mgr,
const zeus::CVector3f& upVec)
{
if (!water.CanRippleAtPoint(center))
return;
intensity = CalculateRippleIntensity(ProjectRippleVelocity(intensity, upVec.dot(velocity)));
mgr.GetFluidPlaneManager()->RippleManager().AddRipple(CRipple(rippler, center, intensity));
}
void CFluidPlane::AddRipple(const CRipple& ripple, const CScriptWater& water, CStateManager& mgr)
{
if (!water.CanRippleAtPoint(ripple.GetCenter()))
return;
mgr.GetFluidPlaneManager()->RippleManager().AddRipple(ripple);
} }
} }

View File

@ -14,6 +14,7 @@ class CFluidUVMotion;
class CRippleManager; class CRippleManager;
class CScriptWater; class CScriptWater;
class CStateManager; class CStateManager;
class CRipple;
class CFluidPlane class CFluidPlane
{ {
public: public:
@ -38,17 +39,28 @@ protected:
EFluidType x44_fluidType; EFluidType x44_fluidType;
float x48_rippleIntensity; float x48_rippleIntensity;
CFluidUVMotion x4c_uvMotion; CFluidUVMotion x4c_uvMotion;
float ProjectRippleVelocity(float baseI, float velDot) const;
float CalculateRippleIntensity(float baseI) const;
public: public:
CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, float alpha, CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, float alpha,
EFluidType fluidType, float rippleIntensity, const CFluidUVMotion& motion); EFluidType fluidType, float rippleIntensity, const CFluidUVMotion& motion);
virtual void Ripple(float mag, TUniqueId rippler, const zeus::CVector3f& pos, // Called by CPlayer, CMorphBall, CWeapon, CPuddleSpore, CMagdolite
CScriptWater& water, CStateManager& mgr); virtual void AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center,
virtual void Update(); CScriptWater& water, CStateManager& mgr);
// Called by CAi
virtual void AddRipple(float intensity, TUniqueId rippler, const zeus::CVector3f& center,
const zeus::CVector3f& velocity, const CScriptWater& water, CStateManager& mgr,
const zeus::CVector3f& upVec);
virtual void AddRipple(const CRipple& ripple, const CScriptWater& water, CStateManager& mgr);
virtual void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf, virtual void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum, const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum,
const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId, const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId,
const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const {} const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const {}
float GetAlpha() const { return x40_alpha; } float GetAlpha() const { return x40_alpha; }
EFluidType GetFluidType() const { return x44_fluidType; } EFluidType GetFluidType() const { return x44_fluidType; }
const CFluidUVMotion& GetUVMotion() const { return x4c_uvMotion; } const CFluidUVMotion& GetUVMotion() const { return x4c_uvMotion; }

View File

@ -43,9 +43,9 @@ CFluidPlaneCPU::CTurbulence::CTurbulence(float speed, float distance, float freq
} }
} }
CFluidPlaneCPU::CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap, CFluidPlaneCPU::CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap,
CAssetId envBumpMap, CAssetId lightMap, float unitsPerLightmapTexel, float tileSize, CAssetId envMap, CAssetId envBumpMap, CAssetId lightMap, float unitsPerLightmapTexel,
u32 tileSubdivisions, EFluidType fluidType, float alpha, float tileSize, u32 tileSubdivisions, EFluidType fluidType, float alpha,
const zeus::CVector3f& bumpLightDir, float bumpScale, const CFluidUVMotion& mot, const zeus::CVector3f& bumpLightDir, float bumpScale, const CFluidUVMotion& mot,
float turbSpeed, float turbDistance, float turbFreqMax, float turbFreqMin, float turbSpeed, float turbDistance, float turbFreqMax, float turbFreqMin,
float turbPhaseMax, float turbPhaseMin, float turbAmplitudeMax, float turbAmplitudeMin, float turbPhaseMax, float turbPhaseMin, float turbAmplitudeMax, float turbAmplitudeMin,
@ -114,11 +114,11 @@ static const float* InitializeSineWave()
#define kEnableWaterBumpMaps true #define kEnableWaterBumpMaps true
CFluidPlaneCPU::RenderSetupInfo CFluidPlaneShader::RenderSetupInfo
CFluidPlaneCPU::RenderSetup(const CStateManager& mgr, float alpha, const zeus::CTransform& xf, CFluidPlaneCPU::RenderSetup(const CStateManager& mgr, float alpha, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, const zeus::CAABox& aabb, const CScriptWater* water) const const zeus::CTransform& areaXf, const zeus::CAABox& aabb, const CScriptWater* water) const
{ {
RenderSetupInfo out; CFluidPlaneShader::RenderSetupInfo out;
float uvT = mgr.GetFluidPlaneManager()->GetUVT(); float uvT = mgr.GetFluidPlaneManager()->GetUVT();
bool hasBumpMap = HasBumpMap() && kEnableWaterBumpMaps; bool hasBumpMap = HasBumpMap() && kEnableWaterBumpMaps;
@ -283,110 +283,6 @@ CFluidPlaneCPU::RenderSetup(const CStateManager& mgr, float alpha, const zeus::C
return out; return out;
} }
class CFluidPlaneCPURender
{
public:
enum class NormalMode
{
None,
NoNormals,
Normals,
NBT
};
static int numTilesInHField;
static int numSubdivisionsInTile;
static int numSubdivisionsInHField;
struct SPatchInfo
{
u8 x0_xSubdivs, x1_ySubdivs;
zeus::CVector2f x4_localMin, xc_globalMin;
float x14_tileSize;
float x18_rippleResolution;
float x1c_tileHypRadius;
float x20_ooTileSize;
float x24_ooRippleResolution;
u16 x28_tileX;
u16 x2a_gridDimX;
u16 x2c_gridDimY;
u16 x2e_tileY;
const bool* x30_gridFlags;
u8 x34_redShift;
u8 x35_greenShift;
u8 x36_blueShift;
NormalMode x37_normalMode;
float x38_wavecapIntensityScale;
public:
SPatchInfo(const zeus::CVector3f& localMin, const zeus::CVector3f& localMax, const zeus::CVector3f& pos,
float rippleResolution, float tileSize, float wavecapIntensityScale, int numSubdivisionsInHField,
NormalMode normalMode, int redShift, int greenShift, int blueShift, u32 tileX, u32 gridDimX,
u32 gridDimY, u32 tileY, const bool* gridFlags)
{
x0_xSubdivs = std::min(s16((localMax.x - localMin.x) / rippleResolution + 1.f - FLT_EPSILON) + 2,
numSubdivisionsInHField + 2);
x1_ySubdivs = std::min(s16((localMax.y - localMin.y) / rippleResolution + 1.f - FLT_EPSILON) + 2,
numSubdivisionsInHField + 2);
float tileHypRadius = tileSize * tileSize * 2 * 0.25f;
x4_localMin.x = localMin.x;
x4_localMin.y = localMin.y;
xc_globalMin = x4_localMin + zeus::CVector2f(pos.x, pos.y);
x14_tileSize = tileSize;
x18_rippleResolution = rippleResolution;
if (tileHypRadius != 0.f)
tileHypRadius = std::sqrt(tileHypRadius);
x1c_tileHypRadius = tileHypRadius;
x20_ooTileSize = 1.f / x14_tileSize;
x24_ooRippleResolution = 1.f / x18_rippleResolution;
x28_tileX = u16(tileX);
x2a_gridDimX = u16(gridDimX);
x2c_gridDimY = u16(gridDimY);
x2e_tileY = u16(tileY);
x30_gridFlags = gridFlags;
x34_redShift = u8(redShift);
x35_greenShift = u8(greenShift);
x36_blueShift = u8(blueShift);
x37_normalMode = normalMode;
x38_wavecapIntensityScale = wavecapIntensityScale;
}
};
struct SRippleInfo
{
const CRipple& x0_ripple;
int x4_fromX;
int x8_toX;
int xc_fromY;
int x10_toY;
int x14_gfromX;
int x18_gtoX;
int x1c_gfromY;
int x20_gtoY;
public:
SRippleInfo(const CRipple& ripple, int fromX, int toX, int fromY, int toY)
: x0_ripple(ripple), x14_gfromX(fromX), x18_gtoX(toX), x1c_gfromY(fromY), x20_gtoY(toY) {}
};
struct SHFieldSample
{
float height;
s8 nx;
s8 ny;
s8 nz;
u8 wavecapIntensity;
zeus::CVector3f MakeNormal() const { return {nx / 63.f, ny / 63.f, nz / 63.f}; }
zeus::CVector3f MakeBinormal() const { return {nx / 63.f, nz / 63.f, -ny / 63.f}; }
zeus::CVector3f MakeTangent() const { return {nz / 63.f, ny / 63.f, -nx / 63.f}; }
zeus::CColor MakeColor(const CFluidPlaneCPURender::SPatchInfo& info) const
{
return {(wavecapIntensity >> info.x34_redShift) / 255.f,
(wavecapIntensity >> info.x35_greenShift) / 255.f,
(wavecapIntensity >> info.x36_blueShift) / 255.f};
}
};
};
int CFluidPlaneCPURender::numTilesInHField; int CFluidPlaneCPURender::numTilesInHField;
int CFluidPlaneCPURender::numSubdivisionsInTile; int CFluidPlaneCPURender::numSubdivisionsInTile;
int CFluidPlaneCPURender::numSubdivisionsInHField; int CFluidPlaneCPURender::numSubdivisionsInHField;
@ -963,7 +859,7 @@ static void RenderStripWithRipples(float curY, const CFluidPlaneCPURender::SHFie
func(curTileX, curTileY + info.x18_rippleResolution, heights[curYDiv+1][i+v]); func(curTileX, curTileY + info.x18_rippleResolution, heights[curYDiv+1][i+v]);
curTileX += info.x18_rippleResolution; curTileX += info.x18_rippleResolution;
} }
CGraphics::DrawArray(start, 4); CGraphics::DrawArray(start, vOut.size() - start);
} }
} }
else else
@ -1040,7 +936,7 @@ static void RenderStripWithRipples(float curY, const CFluidPlaneCPURender::SHFie
default: default:
break; break;
} }
CGraphics::DrawArray(start, 4); CGraphics::DrawArray(start, vOut.size() - start);
} }
else else
{ {
@ -1145,10 +1041,10 @@ static void RenderStripWithRipples(float curY, const CFluidPlaneCPURender::SHFie
} }
} }
static void RenderPatch(const CFluidPlaneCPURender::SPatchInfo& info, void RenderPatch(const CFluidPlaneCPURender::SPatchInfo& info,
const CFluidPlaneCPURender::SHFieldSample (&heights)[45][45], const CFluidPlaneCPURender::SHFieldSample (&heights)[45][45],
const u8 (&flags)[9][9], bool noRipples, bool flagIs1, const u8 (&flags)[9][9], bool noRipples, bool flagIs1,
std::vector<CFluidPlaneShader::Vertex>& vOut) std::vector<CFluidPlaneShader::Vertex>& vOut)
{ {
if (noRipples) if (noRipples)
{ {
@ -1367,7 +1263,7 @@ void CFluidPlaneCPU::Render(const CStateManager& mgr, float alpha, const zeus::C
const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const
{ {
TCastToConstPtr<CScriptWater> water = mgr.GetObjectById(waterId); TCastToConstPtr<CScriptWater> water = mgr.GetObjectById(waterId);
RenderSetupInfo setupInfo = RenderSetup(mgr, alpha, xf, areaXf, aabb, water.GetPtr()); CFluidPlaneShader::RenderSetupInfo setupInfo = RenderSetup(mgr, alpha, xf, areaXf, aabb, water.GetPtr());
CFluidPlaneCPURender::NormalMode normalMode; CFluidPlaneCPURender::NormalMode normalMode;
if (xb0_bumpMap && kEnableWaterBumpMaps) if (xb0_bumpMap && kEnableWaterBumpMaps)
@ -1435,8 +1331,7 @@ void CFluidPlaneCPU::Render(const CStateManager& mgr, float alpha, const zeus::C
u32 patchDimY = (water && water->GetPatchDimensionY()) ? water->GetPatchDimensionY() : 128; u32 patchDimY = (water && water->GetPatchDimensionY()) ? water->GetPatchDimensionY() : 128;
m_verts.clear(); m_verts.clear();
m_shader->prepareDraw(setupInfo.texMtxs, setupInfo.normMtx, setupInfo.indScale, m_shader->prepareDraw(setupInfo);
setupInfo.lights, setupInfo.kColors);
u32 tileY = 0; u32 tileY = 0;
float curY = aabb.min.y; float curY = aabb.min.y;
@ -1496,9 +1391,4 @@ void CFluidPlaneCPU::Render(const CStateManager& mgr, float alpha, const zeus::C
m_shader->loadVerts(m_verts); m_shader->loadVerts(m_verts);
} }
void CFluidPlaneCPU::RenderCleanup() const
{
}
} }

View File

@ -61,15 +61,6 @@ class CFluidPlaneCPU : public CFluidPlane
mutable std::experimental::optional<CFluidPlaneShader> m_shader; mutable std::experimental::optional<CFluidPlaneShader> m_shader;
mutable bool m_cachedDoubleLightmapBlend; mutable bool m_cachedDoubleLightmapBlend;
mutable bool m_cachedAdditive; mutable bool m_cachedAdditive;
struct RenderSetupInfo
{
zeus::CMatrix4f texMtxs[6];
zeus::CMatrix4f normMtx;
float indScale = 1.f;
zeus::CColor kColors[4];
std::vector<CLight> lights;
};
public: public:
CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap, CAssetId envBumpMap, CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap, CAssetId envBumpMap,
CAssetId lightMap, float unitsPerLightmapTexel, float tileSize, u32 tileSubdivisions, CAssetId lightMap, float unitsPerLightmapTexel, float tileSize, u32 tileSubdivisions,
@ -81,14 +72,13 @@ public:
void CreateRipple(const CRipple& ripple, CStateManager& mgr); void CreateRipple(const CRipple& ripple, CStateManager& mgr);
void CalculateLightmapMatrix(const zeus::CTransform& areaXf, const zeus::CTransform& xf, void CalculateLightmapMatrix(const zeus::CTransform& areaXf, const zeus::CTransform& xf,
const zeus::CAABox& aabb, zeus::CMatrix4f& mtxOut) const; const zeus::CAABox& aabb, zeus::CMatrix4f& mtxOut) const;
RenderSetupInfo RenderSetup(const CStateManager& mgr, float, const zeus::CTransform& xf, CFluidPlaneShader::RenderSetupInfo RenderSetup(const CStateManager& mgr, float, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, const zeus::CAABox& aabb, const zeus::CTransform& areaXf, const zeus::CAABox& aabb,
const CScriptWater* water) const; const CScriptWater* water) const;
void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf, void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum, const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum,
const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId, const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId,
const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const; const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const;
void RenderCleanup() const;
float GetReflectionBlend() const { return x114_reflectionBlend; } float GetReflectionBlend() const { return x114_reflectionBlend; }
float GetSpecularMax() const { return x110_specularMax; } float GetSpecularMax() const { return x110_specularMax; }
float GetSpecularMin() const { return x10c_specularMin; } float GetSpecularMin() const { return x10c_specularMin; }
@ -111,6 +101,116 @@ public:
float GetOOTurbulenceSpeed() const { return x120_turbulence.GetOOSpeed(); } float GetOOTurbulenceSpeed() const { return x120_turbulence.GetOOSpeed(); }
bool HasTurbulence() const { return x120_turbulence.HasTurbulence(); } bool HasTurbulence() const { return x120_turbulence.HasTurbulence(); }
}; };
class CFluidPlaneCPURender
{
public:
enum class NormalMode
{
None,
NoNormals,
Normals,
NBT
};
static int numTilesInHField;
static int numSubdivisionsInTile;
static int numSubdivisionsInHField;
struct SPatchInfo
{
u8 x0_xSubdivs, x1_ySubdivs;
zeus::CVector2f x4_localMin, xc_globalMin;
float x14_tileSize;
float x18_rippleResolution;
float x1c_tileHypRadius;
float x20_ooTileSize;
float x24_ooRippleResolution;
u16 x28_tileX;
u16 x2a_gridDimX;
u16 x2c_gridDimY;
u16 x2e_tileY;
const bool* x30_gridFlags;
u8 x34_redShift;
u8 x35_greenShift;
u8 x36_blueShift;
NormalMode x37_normalMode;
float x38_wavecapIntensityScale;
public:
SPatchInfo(const zeus::CVector3f& localMin, const zeus::CVector3f& localMax, const zeus::CVector3f& pos,
float rippleResolution, float tileSize, float wavecapIntensityScale, int numSubdivisionsInHField,
NormalMode normalMode, int redShift, int greenShift, int blueShift, u32 tileX, u32 gridDimX,
u32 gridDimY, u32 tileY, const bool* gridFlags)
{
x0_xSubdivs = std::min(s16((localMax.x - localMin.x) / rippleResolution + 1.f - FLT_EPSILON) + 2,
numSubdivisionsInHField + 2);
x1_ySubdivs = std::min(s16((localMax.y - localMin.y) / rippleResolution + 1.f - FLT_EPSILON) + 2,
numSubdivisionsInHField + 2);
float tileHypRadius = tileSize * tileSize * 2 * 0.25f;
x4_localMin.x = localMin.x;
x4_localMin.y = localMin.y;
xc_globalMin = x4_localMin + zeus::CVector2f(pos.x, pos.y);
x14_tileSize = tileSize;
x18_rippleResolution = rippleResolution;
if (tileHypRadius != 0.f)
tileHypRadius = std::sqrt(tileHypRadius);
x1c_tileHypRadius = tileHypRadius;
x20_ooTileSize = 1.f / x14_tileSize;
x24_ooRippleResolution = 1.f / x18_rippleResolution;
x28_tileX = u16(tileX);
x2a_gridDimX = u16(gridDimX);
x2c_gridDimY = u16(gridDimY);
x2e_tileY = u16(tileY);
x30_gridFlags = gridFlags;
x34_redShift = u8(redShift);
x35_greenShift = u8(greenShift);
x36_blueShift = u8(blueShift);
x37_normalMode = normalMode;
x38_wavecapIntensityScale = wavecapIntensityScale;
}
};
struct SRippleInfo
{
const CRipple& x0_ripple;
int x4_fromX;
int x8_toX;
int xc_fromY;
int x10_toY;
int x14_gfromX;
int x18_gtoX;
int x1c_gfromY;
int x20_gtoY;
public:
SRippleInfo(const CRipple& ripple, int fromX, int toX, int fromY, int toY)
: x0_ripple(ripple), x14_gfromX(fromX), x18_gtoX(toX), x1c_gfromY(fromY), x20_gtoY(toY) {}
};
struct SHFieldSample
{
float height;
s8 nx;
s8 ny;
s8 nz;
u8 wavecapIntensity;
zeus::CVector3f MakeNormal() const { return {nx / 63.f, ny / 63.f, nz / 63.f}; }
zeus::CVector3f MakeBinormal() const { return {nx / 63.f, nz / 63.f, -ny / 63.f}; }
zeus::CVector3f MakeTangent() const { return {nz / 63.f, ny / 63.f, -nx / 63.f}; }
zeus::CColor MakeColor(const CFluidPlaneCPURender::SPatchInfo& info) const
{
return {(wavecapIntensity >> info.x34_redShift) / 255.f,
(wavecapIntensity >> info.x35_greenShift) / 255.f,
(wavecapIntensity >> info.x36_blueShift) / 255.f};
}
};
};
void RenderPatch(const CFluidPlaneCPURender::SPatchInfo& info,
const CFluidPlaneCPURender::SHFieldSample (&heights)[45][45],
const u8 (&flags)[9][9], bool noRipples, bool flagIs1,
std::vector<CFluidPlaneShader::Vertex>& vOut);
} }
#endif // __URDE_CFLUIDPLANECPU_HPP__ #endif // __URDE_CFLUIDPLANECPU_HPP__

View File

@ -0,0 +1,100 @@
#include "CFluidPlaneDoor.hpp"
#include "CFluidPlaneCPU.hpp"
#include "CStateManager.hpp"
namespace urde
{
CFluidPlaneDoor::CFluidPlaneDoor(CAssetId patternTex1, CAssetId patternTex2, CAssetId colorTex, float tileSize,
u32 tileSubdivisions, EFluidType fluidType, float alpha,
const CFluidUVMotion& uvMotion)
: CFluidPlane(patternTex1, patternTex2, colorTex, alpha, fluidType, 0.5f, uvMotion), xa0_tileSize(tileSize),
xa4_tileSubdivisions(tileSubdivisions & ~0x1), xa8_rippleResolution(xa0_tileSize / float(xa4_tileSubdivisions))
{}
CFluidPlaneShader::RenderSetupInfo
CFluidPlaneDoor::RenderSetup(const CStateManager& mgr, float alpha, const zeus::CTransform& xf,
const zeus::CAABox& aabb, bool noNormals) const
{
CFluidPlaneShader::RenderSetupInfo out;
float uvT = mgr.GetFluidPlaneManager()->GetUVT();
CGraphics::SetModelMatrix(xf);
float fluidUVs[3][2];
x4c_uvMotion.CalculateFluidTextureOffset(uvT, fluidUVs);
out.texMtxs[0][0][0] = out.texMtxs[0][1][1] = x4c_uvMotion.GetFluidLayers()[1].GetUVScale();
out.texMtxs[0][3][0] = fluidUVs[1][0];
out.texMtxs[0][3][1] = fluidUVs[1][1];
out.texMtxs[1][0][0] = out.texMtxs[1][1][1] = x4c_uvMotion.GetFluidLayers()[2].GetUVScale();
out.texMtxs[1][3][0] = fluidUVs[2][0];
out.texMtxs[1][3][1] = fluidUVs[2][1];
out.texMtxs[2][0][0] = out.texMtxs[2][1][1] = x4c_uvMotion.GetFluidLayers()[0].GetUVScale();
out.texMtxs[2][3][0] = fluidUVs[0][0];
out.texMtxs[2][3][1] = fluidUVs[0][1];
out.kColors[0] = zeus::CColor(1.f, alpha);
if (!m_shader)
{
auto gridDimX = u32((xa0_tileSize + aabb.max.x - aabb.min.x - 0.01f) / xa0_tileSize);
auto gridDimY = u32((xa0_tileSize + aabb.max.y - aabb.min.y - 0.01f) / xa0_tileSize);
u32 gridCellCount = (gridDimX + 1) * (gridDimY + 1);
u32 maxVerts = gridCellCount * ((std::max(2, xa4_tileSubdivisions) * 4 + 2) * 4);
m_shader.emplace(x10_texPattern1, x20_texPattern2, x30_texColor, maxVerts);
}
return out;
}
void CFluidPlaneDoor::Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum,
const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId,
const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const
{
CFluidPlaneShader::RenderSetupInfo setupInfo = RenderSetup(mgr, alpha, xf, aabb, noNormals);
CFluidPlaneCPURender::numSubdivisionsInTile = xa4_tileSubdivisions;
CFluidPlaneCPURender::numTilesInHField = 42 / xa4_tileSubdivisions;
CFluidPlaneCPURender::numSubdivisionsInHField = CFluidPlaneCPURender::numTilesInHField * xa4_tileSubdivisions;
zeus::CVector2f centerPlane(aabb.center().x, aabb.center().y);
float patchSize = xa8_rippleResolution * CFluidPlaneCPURender::numSubdivisionsInHField;
float ooSubdivSize = 1.f / xa8_rippleResolution;
m_verts.clear();
m_shader->prepareDraw(setupInfo);
for (float curX = aabb.min.x ; curX < aabb.max.x ; curX += patchSize)
{
float remSubdivsX = (aabb.max.x - curX) * ooSubdivSize;
for (float curY = aabb.min.y ; curY < aabb.max.y ; curY += patchSize)
{
float remSubdivsY = (aabb.max.y - curY) * ooSubdivSize;
int remSubdivsXi = std::min(CFluidPlaneCPURender::numSubdivisionsInHField, int(remSubdivsX));
int remSubdivsYi = std::min(CFluidPlaneCPURender::numSubdivisionsInHField, int(remSubdivsY));
zeus::CAABox aabb2(aabb.min, zeus::CVector3f(xa8_rippleResolution * remSubdivsXi + curX,
xa8_rippleResolution * remSubdivsYi + curY,
aabb.max.z));
if (frustum.aabbFrustumTest(aabb2.getTransformedAABox(xf)))
{
CFluidPlaneCPURender::SPatchInfo patchInfo(zeus::CVector3f(curX, curY, aabb.min.z),
aabb2.max, xf.origin, xa8_rippleResolution,
xa0_tileSize, 0.f,
CFluidPlaneCPURender::numSubdivisionsInHField,
CFluidPlaneCPURender::NormalMode::None,
0, 0, 0, 0, 0, 0, 0, nullptr);
CFluidPlaneCPURender::SHFieldSample heights[45][45];
u8 flags[9][9] = {};
RenderPatch(patchInfo, heights, flags, true, true, m_verts);
}
}
}
m_shader->loadVerts(m_verts);
}
}

View File

@ -1,12 +1,37 @@
#ifndef __URDE_CFLUIDPLANEDOOR_HPP__ #ifndef __URDE_CFLUIDPLANEDOOR_HPP__
#define __URDE_CFLUIDPLANEDOOR_HPP__ #define __URDE_CFLUIDPLANEDOOR_HPP__
#include "CFluidPlane.hpp #include "CFluidPlane.hpp"
#include "Graphics/Shaders/CFluidPlaneShader.hpp"
namespace urde namespace urde
{ {
class CFluidPlaneDoor : public CFluidPlane class CFluidPlaneDoor : public CFluidPlane
{ {
float xa0_tileSize;
int xa4_tileSubdivisions;
float xa8_rippleResolution;
mutable std::vector<CFluidPlaneShader::Vertex> m_verts;
mutable std::experimental::optional<CFluidPlaneShader> m_shader;
CFluidPlaneShader::RenderSetupInfo
RenderSetup(const CStateManager& mgr, float alpha, const zeus::CTransform& xf,
const zeus::CAABox& aabb, bool noNormals) const;
public:
CFluidPlaneDoor(CAssetId patternTex1, CAssetId patternTex2, CAssetId colorTex, float tileSize, u32 tileSubdivisions,
EFluidType fluidType, float alpha, const CFluidUVMotion& uvMotion);
void AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center,
CScriptWater& water, CStateManager& mgr) {}
void AddRipple(float intensity, TUniqueId rippler, const zeus::CVector3f& center,
const zeus::CVector3f& velocity, const CScriptWater& water, CStateManager& mgr,
const zeus::CVector3f& upVec) {}
void AddRipple(const CRipple& ripple, const CScriptWater& water, CStateManager& mgr) {}
void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum,
const std::experimental::optional<CRippleManager>& rippleManager, TUniqueId waterId,
const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) const;
}; };
} }

View File

@ -49,6 +49,7 @@ public:
const zeus::CVector3f& pos, float factor, bool); const zeus::CVector3f& pos, float factor, bool);
rstl::reserved_vector<CSplashRecord, 32>& SplashRecords() { return x18_splashes; } rstl::reserved_vector<CSplashRecord, 32>& SplashRecords() { return x18_splashes; }
const CRippleManager& GetRippleManager() const { return x0_rippleManager; } const CRippleManager& GetRippleManager() const { return x0_rippleManager; }
CRippleManager& RippleManager() { return x0_rippleManager; }
}; };
} }

View File

@ -214,7 +214,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
if (x2f8_morphTransState == EPlayerMorphBallState::Morphed) if (x2f8_morphTransState == EPlayerMorphBallState::Morphed)
{ {
x768_morphball->FluidFXThink(state, water, mgr); x768_morphball->FluidFXThink(state, water, mgr);
if (state == EFluidState::One) if (state == EFluidState::InFluid)
x9c5_30_ = true; x9c5_30_ = true;
} }
else if (x2f8_morphTransState != EPlayerMorphBallState::Unmorphed) else if (x2f8_morphTransState != EPlayerMorphBallState::Unmorphed)
@ -224,7 +224,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
zeus::CVector3f position(x34_transform.origin); zeus::CVector3f position(x34_transform.origin);
position.z = water.GetTriggerBoundsWR().max.z; position.z = water.GetTriggerBoundsWR().max.z;
mgr.GetFluidPlaneManager()->CreateSplash(x8_uid, mgr, water, position, 0.1f, mgr.GetFluidPlaneManager()->CreateSplash(x8_uid, mgr, water, position, 0.1f,
state == EFluidState::Zero); state == EFluidState::EnteredFluid);
} }
} }
else else
@ -236,7 +236,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
posOffset = posOffset.normalized() * zeus::CVector3f(1.2f, 1.2f, 0.f); posOffset = posOffset.normalized() * zeus::CVector3f(1.2f, 1.2f, 0.f);
switch (state) switch (state)
{ {
case EFluidState::Zero: case EFluidState::EnteredFluid:
{ {
bool doSplash = true; bool doSplash = true;
if (x4fc_ > 12.5f) if (x4fc_ > 12.5f)
@ -260,18 +260,18 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
} }
break; break;
} }
case EFluidState::One: case EFluidState::InFluid:
{ {
if (x138_velocity.magnitude() > 1.f && if (x138_velocity.magnitude() > 1.f &&
mgr.GetFluidPlaneManager()->GetLastRippleDeltaTime(x8_uid) >= 0.2f) mgr.GetFluidPlaneManager()->GetLastRippleDeltaTime(x8_uid) >= 0.2f)
{ {
zeus::CVector3f position(x34_transform.origin); zeus::CVector3f position(x34_transform.origin);
position.z = water.GetTriggerBoundsWR().max.z; position.z = water.GetTriggerBoundsWR().max.z;
water.GetFluidPlane().Ripple(0.5f, x8_uid, position, water, mgr); water.GetFluidPlane().AddRipple(0.5f, x8_uid, position, water, mgr);
} }
break; break;
} }
case EFluidState::Two: case EFluidState::LeftFluid:
{ {
zeus::CVector3f position = x34_transform.origin + posOffset; zeus::CVector3f position = x34_transform.origin + posOffset;
position.z = water.GetTriggerBoundsWR().max.z; position.z = water.GetTriggerBoundsWR().max.z;

View File

@ -1,6 +1,9 @@
#include "CScriptDamageableTrigger.hpp" #include "CScriptDamageableTrigger.hpp"
#include "CActorParameters.hpp" #include "CActorParameters.hpp"
#include "TCastTo.hpp" #include "TCastTo.hpp"
#include "CStateManager.hpp"
#include "CWorld.hpp"
#include "CScriptActor.hpp"
namespace urde namespace urde
{ {
@ -22,14 +25,52 @@ CMaterialList MakeDamageableTriggerMaterial(CScriptDamageableTrigger::ECanOrbit
CScriptDamageableTrigger::CScriptDamageableTrigger(TUniqueId uid, const std::string& name, const CEntityInfo& info, CScriptDamageableTrigger::CScriptDamageableTrigger(TUniqueId uid, const std::string& name, const CEntityInfo& info,
const zeus::CVector3f& position, const zeus::CVector3f& extent, const CHealthInfo&, const zeus::CVector3f& position, const zeus::CVector3f& extent,
const CDamageVulnerability&, u32, CAssetId, CAssetId, CAssetId, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
CScriptDamageableTrigger::ECanOrbit canOrbit, bool active, const CVisorParameters& vParams) u32 faceFlag, CAssetId patternTex1, CAssetId patternTex2,
: CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(), CAssetId colorTex, ECanOrbit canOrbit, bool active,
MakeDamageableTriggerMaterial(canOrbit), MakeDamageableTriggerActorParms(CActorParameters::None(), vParams), const CVisorParameters& vParams)
kInvalidUniqueId), : CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(),
x14c_bounds(-extent * 0.5f, extent * 0.5f) MakeDamageableTriggerMaterial(canOrbit), MakeDamageableTriggerActorParms(CActorParameters::None(), vParams),
kInvalidUniqueId),
x14c_bounds(-extent * 0.5f, extent * 0.5f),
x164_origHInfo(hInfo), x16c_hInfo(hInfo), x174_dVuln(dVuln), x1dc_faceFlag(faceFlag),
x254_fluidPlane(patternTex1, patternTex2, colorTex, 1.f, 2,
CFluidPlane::EFluidType::NormalWater, 1.f, CFluidUVMotion(6.f, 0.f))
{ {
x300_28_canOrbit = canOrbit == ECanOrbit::Orbit;
if (x1dc_faceFlag & 0x1)
{
x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.max.y, 0.f);
x1e4_faceDir = zeus::CTransform::RotateX(-M_PIF / 2.f);
}
else if (x1dc_faceFlag & 0x2)
{
x244_faceTranslate = zeus::CVector3f(0.f, x14c_bounds.min.y, 0.f);
x1e4_faceDir = zeus::CTransform::RotateX(M_PIF / 2.f);
}
else if (x1dc_faceFlag & 0x4)
{
x244_faceTranslate = zeus::CVector3f(x14c_bounds.min.x, 0.f, 0.f);
x1e4_faceDir = zeus::CTransform::RotateY(-M_PIF / 2.f);
}
else if (x1dc_faceFlag & 0x8)
{
x244_faceTranslate = zeus::CVector3f(x14c_bounds.max.x, 0.f, 0.f);
x1e4_faceDir = zeus::CTransform::RotateY(M_PIF / 2.f);
}
else if (x1dc_faceFlag & 0x10)
{
x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.max.z);
x1e4_faceDir = zeus::CTransform::Identity();
}
else if (x1dc_faceFlag & 0x20)
{
x244_faceTranslate = zeus::CVector3f(0.f, 0.f, x14c_bounds.min.z);
x1e4_faceDir = zeus::CTransform::RotateY(M_PIF);
}
x214_faceDirInv = x1e4_faceDir.inverse();
} }
void CScriptDamageableTrigger::Accept(IVisitor& visitor) void CScriptDamageableTrigger::Accept(IVisitor& visitor)
@ -37,4 +78,160 @@ void CScriptDamageableTrigger::Accept(IVisitor& visitor)
visitor.Visit(this); visitor.Visit(this);
} }
void CScriptDamageableTrigger::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr)
{
switch (msg)
{
case EScriptObjectMessage::Deactivate:
if (x30_24_active && x300_25_alphaOut)
return;
case EScriptObjectMessage::Activate:
if (!x30_24_active || x300_25_alphaOut)
{
x250_alphaTimer = 0.f;
x16c_hInfo = x164_origHInfo;
x300_25_alphaOut = false;
if (x300_28_canOrbit)
AddMaterial(EMaterialTypes::Orbit, mgr);
SetLinkedObjectAlpha(0.f, mgr);
x1e0_alpha = 0.f;
}
break;
case EScriptObjectMessage::Damage:
if (x300_27_invulnerable)
x16c_hInfo = x164_origHInfo;
break;
case EScriptObjectMessage::Increment:
x300_27_invulnerable = true;
break;
case EScriptObjectMessage::Decrement:
x300_27_invulnerable = false;
break;
default:
break;
}
CActor::AcceptScriptMsg(msg, sender, mgr);
}
EWeaponCollisionResponseTypes
CScriptDamageableTrigger::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
const CWeaponMode& weapMode, int) const
{
return x174_dVuln.WeaponHurts(weapMode, false) ? EWeaponCollisionResponseTypes::Unknown13 :
EWeaponCollisionResponseTypes::Unknown15;
}
void CScriptDamageableTrigger::Render(const CStateManager& mgr) const
{
if (x30_24_active && x1dc_faceFlag != 0 && std::fabs(x1e0_alpha) >= 0.00001f)
{
zeus::CAABox aabb = x14c_bounds.getTransformedAABox(x214_faceDirInv);
zeus::CTransform xf = x34_transform * zeus::CTransform::Translate(x244_faceTranslate) * x1e4_faceDir;
x254_fluidPlane.Render(mgr, x1e0_alpha, aabb, xf, zeus::CTransform::Identity(), false,
xe8_frustum, {}, kInvalidUniqueId, nullptr, 0, 0, zeus::CVector3f::skZero);
}
CActor::Render(mgr);
}
void CScriptDamageableTrigger::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const
{
if (x300_26_outOfFrustum)
return;
EnsureRendered(mgr, GetTranslation() - x244_faceTranslate, GetSortingBounds(mgr));
}
void CScriptDamageableTrigger::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum)
{
x300_26_outOfFrustum = !frustum.aabbFrustumTest(x14c_bounds.getTransformedAABox(x34_transform));
if (!x300_26_outOfFrustum)
{
xe8_frustum = frustum;
CActor::PreRender(mgr, frustum);
}
}
void CScriptDamageableTrigger::SetLinkedObjectAlpha(float a, CStateManager& mgr)
{
for (const SConnection& conn : x20_conns)
{
if (conn.x0_state != EScriptObjectState::MaxReached ||
conn.x4_msg != EScriptObjectMessage::Activate)
continue;
if (TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId)))
{
if (!act->GetActive())
act->SetActive(true);
act->SetDrawFlags(CModelFlags(5, 0, 3, zeus::CColor(1.f, a)));
}
}
}
float CScriptDamageableTrigger::GetPuddleAlphaScale() const
{
if (x250_alphaTimer <= 0.75f)
{
if (x300_25_alphaOut)
return 1.f - x250_alphaTimer / 0.75f;
return x250_alphaTimer / 0.75f;
}
if (x300_25_alphaOut)
return 0.f;
return 1.f;
}
void CScriptDamageableTrigger::Think(float dt, CStateManager& mgr)
{
if (!x30_24_active)
return;
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(x4_areaId);
CGameArea::EOcclusionState occState =
area->IsPostConstructed() ? area->GetOcclusionState() : CGameArea::EOcclusionState::Occluded;
x300_24_notOccluded = occState == CGameArea::EOcclusionState::Visible;
if (x300_25_alphaOut)
{
if (x250_alphaTimer >= 0.75f)
{
SetActive(false);
for (const SConnection& conn : x20_conns)
{
if (conn.x0_state != EScriptObjectState::MaxReached ||
conn.x4_msg != EScriptObjectMessage::Activate)
continue;
if (TCastToPtr<CScriptActor> act = mgr.ObjectById(mgr.GetIdForScript(conn.x8_objId)))
act->SetActive(false);
}
SetLinkedObjectAlpha(0.f, mgr);
x300_25_alphaOut = false;
}
}
else
{
if (x16c_hInfo.GetHP() <= 0.f && x30_24_active)
{
SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None);
RemoveMaterial(EMaterialTypes::Orbit, mgr);
x300_25_alphaOut = true;
x250_alphaTimer = 0.f;
}
if (x250_alphaTimer <= 0.75f)
x250_alphaTimer += dt;
float objAlpha = GetPuddleAlphaScale();
x1e0_alpha = 0.2f * objAlpha;
SetLinkedObjectAlpha(objAlpha, mgr);
}
}
rstl::optional_object<zeus::CAABox> CScriptDamageableTrigger::GetTouchBounds() const
{
if (!x30_24_active || !x300_24_notOccluded)
return {};
return {zeus::CAABox(x14c_bounds.min + GetTranslation(), x14c_bounds.max + GetTranslation())};
}
} }

View File

@ -2,6 +2,9 @@
#define CSCRIPTDAMAGEABLETRIGGER_HPP #define CSCRIPTDAMAGEABLETRIGGER_HPP
#include "CActor.hpp" #include "CActor.hpp"
#include "CFluidPlaneDoor.hpp"
#include "CHealthInfo.hpp"
#include "CDamageVulnerability.hpp"
namespace urde namespace urde
{ {
@ -15,13 +18,51 @@ public:
Orbit, Orbit,
}; };
zeus::CFrustum xe8_frustum;
zeus::CAABox x14c_bounds; zeus::CAABox x14c_bounds;
CHealthInfo x164_origHInfo;
CHealthInfo x16c_hInfo;
CDamageVulnerability x174_dVuln;
u32 x1dc_faceFlag;
float x1e0_alpha = 1.f;
zeus::CTransform x1e4_faceDir;
zeus::CTransform x214_faceDirInv;
zeus::CVector3f x244_faceTranslate;
float x250_alphaTimer = 0.f;
CFluidPlaneDoor x254_fluidPlane;
union
{
struct
{
bool x300_24_notOccluded : 1;
bool x300_25_alphaOut : 1;
bool x300_26_outOfFrustum : 1;
bool x300_27_invulnerable : 1;
bool x300_28_canOrbit : 1;
};
u32 _dummy = 0;
};
void SetLinkedObjectAlpha(float a, CStateManager& mgr);
float GetPuddleAlphaScale() const;
public: public:
CScriptDamageableTrigger(TUniqueId, const std::string&, const CEntityInfo&, const zeus::CVector3f&, const zeus::CVector3f&, CScriptDamageableTrigger(TUniqueId uid, const std::string& name, const CEntityInfo& info,
const CHealthInfo&, const CDamageVulnerability&, u32, CAssetId, CAssetId, CAssetId, ECanOrbit, bool, const zeus::CVector3f& position, const zeus::CVector3f& extent,
const CVisorParameters&); const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
u32 faceFlag, CAssetId patternTex1, CAssetId patternTex2,
CAssetId colorTex, ECanOrbit canOrbit, bool active,
const CVisorParameters& vParams);
void Accept(IVisitor& visitor); void Accept(IVisitor& visitor);
void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&);
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
const CWeaponMode&, int) const;
void Render(const CStateManager& mgr) const;
void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const;
void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum);
const CDamageVulnerability* GetDamageVulnerability() const { return &x174_dVuln; }
CHealthInfo* HealthInfo() { return &x16c_hInfo; }
void Think(float, CStateManager&);
rstl::optional_object<zeus::CAABox> GetTouchBounds() const;
}; };
} }

View File

@ -231,7 +231,41 @@ void CScriptWater::SetupGridClipping(CStateManager& mgr, int computeVerts)
void CScriptWater::UpdateSplashInhabitants(CStateManager& mgr) void CScriptWater::UpdateSplashInhabitants(CStateManager& mgr)
{ {
// TODO: Do for (auto it = x1fc_waterInhabitants.begin() ; it != x1fc_waterInhabitants.end() ;)
{
auto& inhab = *it;
TCastToPtr<CActor> act = mgr.ObjectById(inhab.first);
bool intersects = false;
if (act)
{
if (auto tb = act->GetTouchBounds())
{
zeus::CAABox thisTb = GetTriggerBoundsWR();
if (tb->min.z <= thisTb.max.z && tb->max.z >= thisTb.max.z)
intersects = true;
}
}
if (act && inhab.second)
{
if (intersects)
act->FluidFXThink(EFluidState::InFluid, *this, mgr);
mgr.SendScriptMsg(act.GetPtr(), GetUniqueId(), EScriptObjectMessage::UpdateSplashInhabitant);
inhab.second = false;
}
else
{
it = x1fc_waterInhabitants.erase(it);
if (act)
{
if (intersects)
act->FluidFXThink(EFluidState::LeftFluid, *this, mgr);
mgr.SendScriptMsg(act.GetPtr(), GetUniqueId(), EScriptObjectMessage::RemoveSplashInhabitant);
}
continue;
}
++it;
}
} }
void CScriptWater::Think(float dt, CStateManager& mgr) void CScriptWater::Think(float dt, CStateManager& mgr)
@ -486,7 +520,7 @@ void CScriptWater::Touch(CActor& otherAct, CStateManager& mgr)
x1fc_waterInhabitants.emplace_back(otherAct.GetUniqueId(), true); x1fc_waterInhabitants.emplace_back(otherAct.GetUniqueId(), true);
float triggerMaxZ = GetTriggerBoundsWR().max.z; float triggerMaxZ = GetTriggerBoundsWR().max.z;
if (touchBounds->min.z <= triggerMaxZ && touchBounds->max.z >= triggerMaxZ) if (touchBounds->min.z <= triggerMaxZ && touchBounds->max.z >= triggerMaxZ)
otherAct.FluidFXThink(EFluidState::Zero, *this, mgr); otherAct.FluidFXThink(EFluidState::EnteredFluid, *this, mgr);
mgr.SendScriptMsg(&otherAct, x8_uid, EScriptObjectMessage::AddSplashInhabitant); mgr.SendScriptMsg(&otherAct, x8_uid, EScriptObjectMessage::AddSplashInhabitant);
} }
@ -510,11 +544,7 @@ zeus::CAABox CScriptWater::GetSortingBounds(const CStateManager& mgr) const
} }
EWeaponCollisionResponseTypes CScriptWater::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&, EWeaponCollisionResponseTypes CScriptWater::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
<<<<<<< HEAD
CWeaponMode&, int)
=======
const CWeaponMode&, int) const const CWeaponMode&, int) const
>>>>>>> 11d4aad746973443508adbff80b9da9eb0b4c60c
{ {
return EWeaponCollisionResponseTypes::Water; return EWeaponCollisionResponseTypes::Water;
} }
@ -566,4 +596,20 @@ const CScriptWater* CScriptWater::GetNextConnectedWater(const CStateManager& mgr
} }
return nullptr; return nullptr;
} }
bool CScriptWater::CanRippleAtPoint(const zeus::CVector3f& point) const
{
if (!x2d8_tileIntersects)
return true;
auto xTile = int((point.x - GetTriggerBoundsOR().min.x) / x2c0_tileSize);
if (xTile < 0 || xTile >= x2c4_gridDimX)
return false;
auto yTile = int((point.y - GetTriggerBoundsOR().min.y) / x2c0_tileSize);
if (xTile < 0 || xTile >= x2c8_gridDimY)
return false;
return x2d8_tileIntersects[yTile * x2c4_gridDimX + xTile];
}
} }

View File

@ -25,30 +25,16 @@ private:
float x1f4_morphOutTime; float x1f4_morphOutTime;
float x1f8_morphFactor = 0.f; float x1f8_morphFactor = 0.f;
std::list<std::pair<TUniqueId, bool>> x1fc_waterInhabitants; std::list<std::pair<TUniqueId, bool>> x1fc_waterInhabitants;
<<<<<<< HEAD
float x214_fogBias; float x214_fogBias;
float x218_fogMagnitude; float x218_fogMagnitude;
float x21c_origFogBias; float x21c_origFogBias;
float x220_origFogMagnitude; float x220_origFogMagnitude;
float x224_fogSpeed; float x224_fogSpeed;
zeus::CColor x228_fogColor; zeus::CColor x228_fogColor;
ResId x22c_splashParticle1Id;
ResId x230_splashParticle2Id;
ResId x234_splashParticle3Id;
ResId x238_particle4Id;
=======
u32 x210_;
float x214_;
float x218_;
float x21c_;
float x220_;
float x224_;
zeus::CColor x228_;
CAssetId x22c_splashParticle1Id; CAssetId x22c_splashParticle1Id;
CAssetId x230_splashParticle2Id; CAssetId x230_splashParticle2Id;
CAssetId x234_splashParticle3Id; CAssetId x234_splashParticle3Id;
CAssetId x238_particle4Id; CAssetId x238_particle4Id;
>>>>>>> 11d4aad746973443508adbff80b9da9eb0b4c60c
std::experimental::optional<TLockedToken<CGenDescription>> x23c_; std::experimental::optional<TLockedToken<CGenDescription>> x23c_;
CAssetId x24c_particle5Id; CAssetId x24c_particle5Id;
std::experimental::optional<TLockedToken<CGenDescription>> x250_visorRunoffEffect; std::experimental::optional<TLockedToken<CGenDescription>> x250_visorRunoffEffect;
@ -117,8 +103,8 @@ public:
void Touch(CActor &, CStateManager &); void Touch(CActor &, CStateManager &);
void CalculateRenderBounds(); void CalculateRenderBounds();
zeus::CAABox GetSortingBounds(const CStateManager&) const; zeus::CAABox GetSortingBounds(const CStateManager&) const;
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&, CWeaponMode&, EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
int); const CWeaponMode&, int) const;
s16 GetSplashSound(float) const; s16 GetSplashSound(float) const;
const std::experimental::optional<TLockedToken<CGenDescription>>& GetSplashEffect(float) const; const std::experimental::optional<TLockedToken<CGenDescription>>& GetSplashEffect(float) const;
@ -141,6 +127,7 @@ public:
u8 GetPatchRenderFlags(int x, int y) const { return x2e0_patchIntersects[y * x2d0_patchDimX + x]; } u8 GetPatchRenderFlags(int x, int y) const { return x2e0_patchIntersects[y * x2d0_patchDimX + x]; }
int GetPatchDimensionX() const { return x2d0_patchDimX; } int GetPatchDimensionX() const { return x2d0_patchDimX; }
int GetPatchDimensionY() const { return x2d4_patchDimY; } int GetPatchDimensionY() const { return x2d4_patchDimY; }
bool CanRippleAtPoint(const zeus::CVector3f& point) const;
}; };
} }

View File

@ -1111,14 +1111,14 @@ CEntity* ScriptLoader::LoadDamageableTrigger(CStateManager& mgr, CInputStream& i
CDamageVulnerability dVuln(in); CDamageVulnerability dVuln(in);
u32 triggerFlags = in.readUint32Big(); u32 triggerFlags = in.readUint32Big();
triggerFlags = TransformDamagableTriggerFlags(mgr, info.GetAreaId(), triggerFlags); triggerFlags = TransformDamagableTriggerFlags(mgr, info.GetAreaId(), triggerFlags);
CAssetId w1 = in.readUint32Big(); CAssetId patternTex1 = in.readUint32Big();
CAssetId w2 = in.readUint32Big(); CAssetId patternTex2 = in.readUint32Big();
CAssetId w3 = in.readUint32Big(); CAssetId colorTex = in.readUint32Big();
CScriptDamageableTrigger::ECanOrbit canOrbit = CScriptDamageableTrigger::ECanOrbit(in.readBool()); CScriptDamageableTrigger::ECanOrbit canOrbit = CScriptDamageableTrigger::ECanOrbit(in.readBool());
bool active = in.readBool(); bool active = in.readBool();
CVisorParameters vParms = LoadVisorParameters(in); CVisorParameters vParms = LoadVisorParameters(in);
return new CScriptDamageableTrigger(mgr.AllocateUniqueId(), name, info, position, volume, hInfo, dVuln, return new CScriptDamageableTrigger(mgr.AllocateUniqueId(), name, info, position, volume, hInfo, dVuln,
triggerFlags, w1, w2, w3, canOrbit, active, vParms); triggerFlags, patternTex1, patternTex2, colorTex, canOrbit, active, vParms);
} }
CEntity* ScriptLoader::LoadDebris(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) CEntity* ScriptLoader::LoadDebris(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)