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">
<option name="myName" value="Project Default" />
<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 class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />

View File

@ -15,6 +15,9 @@ struct ITweakGame : ITweak
virtual float GetWavecapIntensityNormal() const = 0;
virtual float GetWavecapIntensityPoison() 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 GetHardModeDamageMultiplier() const = 0;
virtual float GetHardModeWeaponMultiplier() const = 0;

View File

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

View File

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

View File

@ -23,9 +23,9 @@ struct CTweakGame : ITweakGame
Value<float> x34_wavecapIntensityNormal;
Value<float> x38_wavecapIntensityPoison;
Value<float> x3c_wavecapIntensityLava;
Value<float> x40_unknown10;
Value<float> x44_unknown11;
Value<float> x48_unknown12;
Value<float> x40_rippleIntensityNormal;
Value<float> x44_rippleIntentityPoison;
Value<float> x48_rippleIntensityLava;
Value<float> x4c_fluidEnvBumpScale;
Value<float> x50_unknown14;
Value<float> x54_unknown15;
@ -41,6 +41,9 @@ struct CTweakGame : ITweakGame
float GetWavecapIntensityNormal() const { return x34_wavecapIntensityNormal; }
float GetWavecapIntensityPoison() const { return x38_wavecapIntensityPoison; }
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 GetHardModeDamageMultiplier() const { return x60_hardmodeDamageMult; }
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 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)
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
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;
}
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);
auto& slot = m_cache[key];
auto& slot = CacheSlot(info, key);
if (slot.second != nullptr)
return slot.second;
@ -116,6 +131,60 @@ boo::IShaderPipeline* CFluidPlaneShader::Cache::GetOrBuildShader(const SFluidPla
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,
const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
const std::experimental::optional<TLockedToken<CTexture>>& patternTex2,
@ -143,54 +212,37 @@ CFluidPlaneShader::CFluidPlaneShader(CFluidPlane::EFluidType type,
m_lightmap.operator bool(),
doubleLightmapBlend, additive);
boo::IShaderPipeline* pipeline = _cache.GetOrBuildShader(shaderInfo);
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;
});
PrepareBinding(pipeline, maxVertCount, false);
}
void CFluidPlaneShader::prepareDraw(const zeus::CMatrix4f* texMtxs, const zeus::CMatrix4f& normMtx, float indScale,
const std::vector<CLight>& lights, const zeus::CColor* kColors)
CFluidPlaneShader::CFluidPlaneShader(const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
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)));
uni.m_mv = CGraphics::g_GXModelView.toMatrix4f();
uni.m_mvNorm = normMtx;
uni.m_mvNorm = info.normMtx;
uni.m_proj = CGraphics::GetPerspectiveProjectionMatrix(true);
for (int i=0 ; i<6 ; ++i)
uni.m_texMtxs[i] = texMtxs[i];
uni.m_lighting.ActivateLights(lights);
uni.m_texMtxs[i] = info.texMtxs[i];
uni.m_lighting.ActivateLights(info.lights);
for (int i=0 ; i<3 ; ++i)
uni.m_lighting.colorRegs[i] = kColors[i];
uni.m_lighting.mulColor = kColors[3];
uni.m_lighting.fog.m_rangeScale = indScale;
uni.m_lighting.colorRegs[i] = info.kColors[i];
uni.m_lighting.mulColor = info.kColors[3];
uni.m_lighting.fog.m_rangeScale = info.indScale;
m_uniBuf->unmap();
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
{
public:
@ -59,13 +70,30 @@ public:
: 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:
class Cache
{
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 SFluidPlaneDoorShaderInfo& info);
public:
boo::IShaderPipeline* GetOrBuildShader(const SFluidPlaneShaderInfo& info);
template<class T>
boo::IShaderPipeline* GetOrBuildShader(const T& info);
void Clear();
};
static Cache _cache;
@ -91,20 +119,25 @@ private:
boo::IShaderDataBinding* m_dataBind;
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
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
#if BOO_HAS_METAL
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
#if BOO_HAS_VULKAN
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
void PrepareBinding(boo::IShaderPipeline* pipeline, u32 maxVertCount, bool door);
public:
CFluidPlaneShader(CFluidPlane::EFluidType type,
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>>& lightmap,
bool doubleLightmapBlend, bool additive, u32 maxVertCount);
void prepareDraw(const zeus::CMatrix4f* texMtxs, const zeus::CMatrix4f& normMtx, float indScale,
const std::vector<CLight>& lights, const zeus::CColor* kColors);
CFluidPlaneShader(const std::experimental::optional<TLockedToken<CTexture>>& patternTex1,
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);
static void Shutdown() { _cache.Clear(); }
};
}

View File

@ -115,6 +115,28 @@ BOO_GLSL_BINDING_HEAD
"%s" // Combiner expression here
"}\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],
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());
}
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*
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::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
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::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
boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::GLDataFactory::Context& ctx,
boo::IShaderPipeline* pipeline)
boo::IShaderPipeline* pipeline, bool door)
{
boo::VertexElementDescriptor elements[] =
{
@ -521,13 +628,13 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::GLDataFactory::Con
texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs,
ubufSizes, texCount, texs, nullptr, nullptr);
return ctx.newShaderDataBinding(pipeline, vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
}
#if BOO_HAS_VULKAN
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::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex,
@ -550,8 +657,8 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::VulkanDataFactory:
texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs,
ubufSizes, texCount, texs, nullptr, nullptr);
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
}
#endif

View File

@ -119,6 +119,27 @@ static const char* FS =
" return colorOut;\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*
CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info)
{
@ -198,12 +219,12 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
// Output reg 2
// KColor 3
// Tex * K2 + Lighting
combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n";
combiner += " lighting += mix(lightMapTexel * kColor2, lightMapTexel, kColor3);\n";
}
else
{
// 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_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";
else
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
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";
}
else if (info.m_hasEnvMap)
@ -253,8 +274,8 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasColorTex)
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"
" float2(lu.fog.indScale, -lu.fog.indScale);", envBumpMapUv);
combiner += hecl::Format(" colorOut = mix(colorOut, envMap.Sample(samp, indUvs + vtf.uvs[%d]), lu.kColor1);\n",
" float2(fog.indScale, -fog.indScale);", envBumpMapUv);
combiner += hecl::Format(" colorOut = mix(colorOut, envMap.Sample(samp, indUvs + vtf.uvs[%d]), kColor1);\n",
envMapUv);
}
else if (info.m_hasColorTex)
@ -279,12 +300,12 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
// Output reg 2
// KColor 3
// Tex * K2 + Lighting
combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n";
combiner += " lighting += mix(lightMapTexel * kColor2, lightMapTexel, kColor3);\n";
}
else
{
// 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_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";
else
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
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";
}
else
@ -350,7 +371,7 @@ CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidP
if (info.m_hasPatternTex2)
{
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";
else
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_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";
else
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::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::IShaderPipeline* pipeline)
boo::IShaderPipeline* pipeline, bool door)
{
boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf };
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();
if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs,
ubufSizes, texCount, texs, nullptr, nullptr);
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
}
}

View File

@ -125,6 +125,29 @@ static const char* FS =
" return colorOut;\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*
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::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::IShaderPipeline* pipeline)
boo::IShaderPipeline* pipeline, bool door)
{
boo::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf };
boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex,
@ -475,8 +553,8 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::MetalDataFactory::
texs[texCount++] = (*m_envBumpMap)->GetBooTexture();
if (m_lightmap)
texs[texCount++] = (*m_lightmap)->GetBooTexture();
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs,
ubufSizes, texCount, texs, nullptr, nullptr);
return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, door ? 1 : 3,
ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr);
}
}

View File

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

View File

@ -79,9 +79,9 @@ protected:
public:
enum class EFluidState
{
Zero,
One,
Two
EnteredFluid,
InFluid,
LeftFluid
};
enum class EScanState
@ -180,6 +180,7 @@ public:
float GetAverageAnimVelocity(int anim) const;
u8 GetTargetableVisorFlags() const { return xe6_31_targetableVisorFlags; }
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 "CFluidPlane.hpp"
#include "CSimplePool.hpp"
#include "CRipple.hpp"
#include "CScriptWater.hpp"
#include "CStateManager.hpp"
namespace urde
{
@ -18,14 +21,67 @@ CFluidPlane::CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId te
x30_texColor.emplace(g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texColor}));
}
void CFluidPlane::Ripple(float mag, TUniqueId rippler, const zeus::CVector3f& pos,
CScriptWater& water, CStateManager& mgr)
float CFluidPlane::ProjectRippleVelocity(float baseI, float velDot) const
{
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 CScriptWater;
class CStateManager;
class CRipple;
class CFluidPlane
{
public:
@ -38,17 +39,28 @@ protected:
EFluidType x44_fluidType;
float x48_rippleIntensity;
CFluidUVMotion x4c_uvMotion;
float ProjectRippleVelocity(float baseI, float velDot) const;
float CalculateRippleIntensity(float baseI) const;
public:
CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, float alpha,
EFluidType fluidType, float rippleIntensity, const CFluidUVMotion& motion);
virtual void Ripple(float mag, TUniqueId rippler, const zeus::CVector3f& pos,
CScriptWater& water, CStateManager& mgr);
virtual void Update();
// Called by CPlayer, CMorphBall, CWeapon, CPuddleSpore, CMagdolite
virtual void AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center,
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,
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 {}
float GetAlpha() const { return x40_alpha; }
EFluidType GetFluidType() const { return x44_fluidType; }
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,
CAssetId envBumpMap, CAssetId lightMap, float unitsPerLightmapTexel, float tileSize,
u32 tileSubdivisions, EFluidType fluidType, float alpha,
CFluidPlaneCPU::CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap,
CAssetId envMap, CAssetId envBumpMap, CAssetId lightMap, float unitsPerLightmapTexel,
float tileSize, u32 tileSubdivisions, EFluidType fluidType, float alpha,
const zeus::CVector3f& bumpLightDir, float bumpScale, const CFluidUVMotion& mot,
float turbSpeed, float turbDistance, float turbFreqMax, float turbFreqMin,
float turbPhaseMax, float turbPhaseMin, float turbAmplitudeMax, float turbAmplitudeMin,
@ -114,11 +114,11 @@ static const float* InitializeSineWave()
#define kEnableWaterBumpMaps true
CFluidPlaneCPU::RenderSetupInfo
CFluidPlaneShader::RenderSetupInfo
CFluidPlaneCPU::RenderSetup(const CStateManager& mgr, float alpha, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, const zeus::CAABox& aabb, const CScriptWater* water) const
{
RenderSetupInfo out;
CFluidPlaneShader::RenderSetupInfo out;
float uvT = mgr.GetFluidPlaneManager()->GetUVT();
bool hasBumpMap = HasBumpMap() && kEnableWaterBumpMaps;
@ -283,110 +283,6 @@ CFluidPlaneCPU::RenderSetup(const CStateManager& mgr, float alpha, const zeus::C
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::numSubdivisionsInTile;
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]);
curTileX += info.x18_rippleResolution;
}
CGraphics::DrawArray(start, 4);
CGraphics::DrawArray(start, vOut.size() - start);
}
}
else
@ -1040,7 +936,7 @@ static void RenderStripWithRipples(float curY, const CFluidPlaneCPURender::SHFie
default:
break;
}
CGraphics::DrawArray(start, 4);
CGraphics::DrawArray(start, vOut.size() - start);
}
else
{
@ -1145,10 +1041,10 @@ static void RenderStripWithRipples(float curY, const CFluidPlaneCPURender::SHFie
}
}
static 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)
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)
{
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
{
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;
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;
m_verts.clear();
m_shader->prepareDraw(setupInfo.texMtxs, setupInfo.normMtx, setupInfo.indScale,
setupInfo.lights, setupInfo.kColors);
m_shader->prepareDraw(setupInfo);
u32 tileY = 0;
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);
}
void CFluidPlaneCPU::RenderCleanup() const
{
}
}

View File

@ -61,15 +61,6 @@ class CFluidPlaneCPU : public CFluidPlane
mutable std::experimental::optional<CFluidPlaneShader> m_shader;
mutable bool m_cachedDoubleLightmapBlend;
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:
CFluidPlaneCPU(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, CAssetId bumpMap, CAssetId envMap, CAssetId envBumpMap,
CAssetId lightMap, float unitsPerLightmapTexel, float tileSize, u32 tileSubdivisions,
@ -81,14 +72,13 @@ public:
void CreateRipple(const CRipple& ripple, CStateManager& mgr);
void CalculateLightmapMatrix(const zeus::CTransform& areaXf, const zeus::CTransform& xf,
const zeus::CAABox& aabb, zeus::CMatrix4f& mtxOut) const;
RenderSetupInfo RenderSetup(const CStateManager& mgr, float, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, const zeus::CAABox& aabb,
const CScriptWater* water) const;
CFluidPlaneShader::RenderSetupInfo RenderSetup(const CStateManager& mgr, float, const zeus::CTransform& xf,
const zeus::CTransform& areaXf, const zeus::CAABox& aabb,
const CScriptWater* water) const;
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;
void RenderCleanup() const;
float GetReflectionBlend() const { return x114_reflectionBlend; }
float GetSpecularMax() const { return x110_specularMax; }
float GetSpecularMin() const { return x10c_specularMin; }
@ -111,6 +101,116 @@ public:
float GetOOTurbulenceSpeed() const { return x120_turbulence.GetOOSpeed(); }
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__

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__
#define __URDE_CFLUIDPLANEDOOR_HPP__
#include "CFluidPlane.hpp
#include "CFluidPlane.hpp"
#include "Graphics/Shaders/CFluidPlaneShader.hpp"
namespace urde
{
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);
rstl::reserved_vector<CSplashRecord, 32>& SplashRecords() { return x18_splashes; }
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)
{
x768_morphball->FluidFXThink(state, water, mgr);
if (state == EFluidState::One)
if (state == EFluidState::InFluid)
x9c5_30_ = true;
}
else if (x2f8_morphTransState != EPlayerMorphBallState::Unmorphed)
@ -224,7 +224,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
zeus::CVector3f position(x34_transform.origin);
position.z = water.GetTriggerBoundsWR().max.z;
mgr.GetFluidPlaneManager()->CreateSplash(x8_uid, mgr, water, position, 0.1f,
state == EFluidState::Zero);
state == EFluidState::EnteredFluid);
}
}
else
@ -236,7 +236,7 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
posOffset = posOffset.normalized() * zeus::CVector3f(1.2f, 1.2f, 0.f);
switch (state)
{
case EFluidState::Zero:
case EFluidState::EnteredFluid:
{
bool doSplash = true;
if (x4fc_ > 12.5f)
@ -260,18 +260,18 @@ void CPlayer::FluidFXThink(EFluidState state, CScriptWater& water, CStateManager
}
break;
}
case EFluidState::One:
case EFluidState::InFluid:
{
if (x138_velocity.magnitude() > 1.f &&
mgr.GetFluidPlaneManager()->GetLastRippleDeltaTime(x8_uid) >= 0.2f)
{
zeus::CVector3f position(x34_transform.origin);
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;
}
case EFluidState::Two:
case EFluidState::LeftFluid:
{
zeus::CVector3f position = x34_transform.origin + posOffset;
position.z = water.GetTriggerBoundsWR().max.z;

View File

@ -1,6 +1,9 @@
#include "CScriptDamageableTrigger.hpp"
#include "CActorParameters.hpp"
#include "TCastTo.hpp"
#include "CStateManager.hpp"
#include "CWorld.hpp"
#include "CScriptActor.hpp"
namespace urde
{
@ -22,14 +25,52 @@ CMaterialList MakeDamageableTriggerMaterial(CScriptDamageableTrigger::ECanOrbit
CScriptDamageableTrigger::CScriptDamageableTrigger(TUniqueId uid, const std::string& name, const CEntityInfo& info,
const zeus::CVector3f& position, const zeus::CVector3f& extent, const CHealthInfo&,
const CDamageVulnerability&, u32, CAssetId, CAssetId, CAssetId,
CScriptDamageableTrigger::ECanOrbit canOrbit, bool active, const CVisorParameters& vParams)
: CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(),
MakeDamageableTriggerMaterial(canOrbit), MakeDamageableTriggerActorParms(CActorParameters::None(), vParams),
kInvalidUniqueId),
x14c_bounds(-extent * 0.5f, extent * 0.5f)
const zeus::CVector3f& position, const zeus::CVector3f& extent,
const CHealthInfo& hInfo, const CDamageVulnerability& dVuln,
u32 faceFlag, CAssetId patternTex1, CAssetId patternTex2,
CAssetId colorTex, ECanOrbit canOrbit, bool active,
const CVisorParameters& vParams)
: CActor(uid, active, name, info, zeus::CTransform::Translate(position), CModelData::CModelDataNull(),
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)
@ -37,4 +78,160 @@ void CScriptDamageableTrigger::Accept(IVisitor& visitor)
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
#include "CActor.hpp"
#include "CFluidPlaneDoor.hpp"
#include "CHealthInfo.hpp"
#include "CDamageVulnerability.hpp"
namespace urde
{
@ -15,13 +18,51 @@ public:
Orbit,
};
zeus::CFrustum xe8_frustum;
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:
CScriptDamageableTrigger(TUniqueId, const std::string&, const CEntityInfo&, const zeus::CVector3f&, const zeus::CVector3f&,
const CHealthInfo&, const CDamageVulnerability&, u32, CAssetId, CAssetId, CAssetId, ECanOrbit, bool,
const CVisorParameters&);
CScriptDamageableTrigger(TUniqueId uid, const std::string& name, const CEntityInfo& info,
const zeus::CVector3f& position, const zeus::CVector3f& extent,
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 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)
{
// 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)
@ -486,7 +520,7 @@ void CScriptWater::Touch(CActor& otherAct, CStateManager& mgr)
x1fc_waterInhabitants.emplace_back(otherAct.GetUniqueId(), true);
float triggerMaxZ = GetTriggerBoundsWR().max.z;
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);
}
@ -510,11 +544,7 @@ zeus::CAABox CScriptWater::GetSortingBounds(const CStateManager& mgr) const
}
EWeaponCollisionResponseTypes CScriptWater::GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
<<<<<<< HEAD
CWeaponMode&, int)
=======
const CWeaponMode&, int) const
>>>>>>> 11d4aad746973443508adbff80b9da9eb0b4c60c
{
return EWeaponCollisionResponseTypes::Water;
}
@ -566,4 +596,20 @@ const CScriptWater* CScriptWater::GetNextConnectedWater(const CStateManager& mgr
}
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 x1f8_morphFactor = 0.f;
std::list<std::pair<TUniqueId, bool>> x1fc_waterInhabitants;
<<<<<<< HEAD
float x214_fogBias;
float x218_fogMagnitude;
float x21c_origFogBias;
float x220_origFogMagnitude;
float x224_fogSpeed;
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 x230_splashParticle2Id;
CAssetId x234_splashParticle3Id;
CAssetId x238_particle4Id;
>>>>>>> 11d4aad746973443508adbff80b9da9eb0b4c60c
std::experimental::optional<TLockedToken<CGenDescription>> x23c_;
CAssetId x24c_particle5Id;
std::experimental::optional<TLockedToken<CGenDescription>> x250_visorRunoffEffect;
@ -117,8 +103,8 @@ public:
void Touch(CActor &, CStateManager &);
void CalculateRenderBounds();
zeus::CAABox GetSortingBounds(const CStateManager&) const;
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&, CWeaponMode&,
int);
EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
const CWeaponMode&, int) const;
s16 GetSplashSound(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]; }
int GetPatchDimensionX() const { return x2d0_patchDimX; }
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);
u32 triggerFlags = in.readUint32Big();
triggerFlags = TransformDamagableTriggerFlags(mgr, info.GetAreaId(), triggerFlags);
CAssetId w1 = in.readUint32Big();
CAssetId w2 = in.readUint32Big();
CAssetId w3 = in.readUint32Big();
CAssetId patternTex1 = in.readUint32Big();
CAssetId patternTex2 = in.readUint32Big();
CAssetId colorTex = in.readUint32Big();
CScriptDamageableTrigger::ECanOrbit canOrbit = CScriptDamageableTrigger::ECanOrbit(in.readBool());
bool active = in.readBool();
CVisorParameters vParms = LoadVisorParameters(in);
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)