#include "CFluidPlaneShader.hpp" #include "World/CRipple.hpp" #include "World/CRippleManager.hpp" #include "hecl/Pipeline.hpp" namespace urde { CFluidPlaneShader::Cache CFluidPlaneShader::_cache = {}; u16 CFluidPlaneShader::Cache::MakeCacheKey(const SFluidPlaneShaderInfo& info) { u16 ret = 0; switch (info.m_type) { case EFluidType::NormalWater: case EFluidType::PhazonFluid: case EFluidType::Four: if (info.m_hasLightmap) { ret |= 1 << 2; if (info.m_doubleLightmapBlend) ret |= 1 << 3; } if (!info.m_hasEnvMap && info.m_hasEnvBumpMap) ret |= 1 << 4; if (info.m_hasEnvMap) ret |= 1 << 5; break; case EFluidType::PoisonWater: ret |= 1; if (info.m_hasLightmap) { ret |= 1 << 2; if (info.m_doubleLightmapBlend) ret |= 1 << 3; } if (info.m_hasEnvBumpMap) ret |= 1 << 4; break; case EFluidType::Lava: ret |= 2; if (info.m_hasBumpMap) ret |= 1 << 2; break; case EFluidType::ThickLava: ret |= 3; if (info.m_hasBumpMap) ret |= 1 << 2; break; } if (info.m_hasPatternTex1) ret |= 1 << 6; if (info.m_hasPatternTex2) ret |= 1 << 7; if (info.m_hasColorTex) ret |= 1 << 8; if (info.m_additive) ret |= 1 << 9; return ret; } 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 <> CFluidPlaneShader::ShaderPair CFluidPlaneShader::Cache::GetOrBuildShader(const SFluidPlaneShaderInfo& info) { u16 key = MakeCacheKey(info); auto& slot = CacheSlot(info, key); if (slot.m_regular) return slot; slot.m_regular = hecl::conv->convert(Shader_CFluidPlaneShader{info, false}); if (info.m_tessellation) slot.m_tessellation = hecl::conv->convert(Shader_CFluidPlaneShader{info, true}); return slot; } template <> CFluidPlaneShader::ShaderPair CFluidPlaneShader::Cache::GetOrBuildShader(const SFluidPlaneDoorShaderInfo& info) { u16 key = MakeCacheKey(info); auto& slot = CacheSlot(info, key); if (slot.m_regular) return slot; slot.m_regular = hecl::conv->convert(Shader_CFluidPlaneDoorShader{info}); return slot; } void CFluidPlaneShader::Cache::Clear() { for (auto& p : m_cache) p.reset(); for (auto& p : m_doorCache) p.reset(); } void CFluidPlaneShader::PrepareBinding(const ShaderPair& pipeline, u32 maxVertCount) { CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(Vertex), maxVertCount); if (pipeline.m_tessellation) m_pvbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(PatchVertex), maxVertCount); m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(Uniform), 1); boo::ObjToken ubufs[] = {m_uniBuf.get(), m_uniBuf.get(), m_uniBuf.get()}; boo::PipelineStage ubufStages[] = {boo::PipelineStage::Vertex, boo::PipelineStage::Vertex, boo::PipelineStage::Fragment}; size_t ubufOffs[] = {0, 0, 1280}; size_t ubufSizes[] = {1280, 1280, sizeof(CModelShaders::LightingUniform)}; size_t texCount = 0; boo::ObjToken texs[8]; if (m_patternTex1) texs[texCount++] = m_patternTex1->GetBooTexture(); if (m_patternTex2) texs[texCount++] = m_patternTex2->GetBooTexture(); if (m_colorTex) texs[texCount++] = m_colorTex->GetBooTexture(); if (m_bumpMap) texs[texCount++] = m_bumpMap->GetBooTexture(); if (m_envMap) texs[texCount++] = m_envMap->GetBooTexture(); if (m_envBumpMap) texs[texCount++] = m_envBumpMap->GetBooTexture(); if (m_lightmap) texs[texCount++] = m_lightmap->GetBooTexture(); auto regular = ctx.newShaderDataBinding(pipeline.m_regular, m_vbo.get(), nullptr, nullptr, 3, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr); boo::ObjToken tessellation; if (pipeline.m_tessellation) { texs[texCount++] = m_rippleMap.get(); tessellation = ctx.newShaderDataBinding(pipeline.m_tessellation, m_pvbo.get(), nullptr, nullptr, 3, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs, nullptr, nullptr); } m_dataBind = {regular, tessellation}; return true; } BooTrace); } void CFluidPlaneShader::Shutdown() { _cache.Clear(); } CFluidPlaneShader::CFluidPlaneShader(EFluidType type, const TLockedToken& patternTex1, const TLockedToken& patternTex2, const TLockedToken& colorTex, const TLockedToken& bumpMap, const TLockedToken& envMap, const TLockedToken& envBumpMap, const TLockedToken& lightmap, const boo::ObjToken& rippleMap, bool doubleLightmapBlend, bool additive, u32 maxVertCount) : m_patternTex1(patternTex1) , m_patternTex2(patternTex2) , m_colorTex(colorTex) , m_bumpMap(bumpMap) , m_envMap(envMap) , m_envBumpMap(envBumpMap) , m_lightmap(lightmap) , m_rippleMap(rippleMap) { SFluidPlaneShaderInfo shaderInfo(type, m_patternTex1.operator bool(), m_patternTex2.operator bool(), m_colorTex.operator bool(), m_bumpMap.operator bool(), m_envMap.operator bool(), m_envBumpMap.operator bool(), m_lightmap.operator bool(), m_rippleMap.operator bool(), doubleLightmapBlend, additive); ShaderPair pipeline = _cache.GetOrBuildShader(shaderInfo); PrepareBinding(pipeline, maxVertCount); } CFluidPlaneShader::CFluidPlaneShader(const TLockedToken& patternTex1, const TLockedToken& patternTex2, const TLockedToken& 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()); ShaderPair pipeline = _cache.GetOrBuildShader(shaderInfo); PrepareBinding(pipeline, maxVertCount); } void CFluidPlaneShader::prepareDraw(const RenderSetupInfo& info) { Uniform& uni = *reinterpret_cast(m_uniBuf->map(sizeof(Uniform))); uni.m_mv = CGraphics::g_GXModelView.toMatrix4f(); uni.m_mvNorm = info.normMtx; uni.m_proj = CGraphics::GetPerspectiveProjectionMatrix(true); for (int i = 0; i < 6; ++i) 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] = info.kColors[i]; uni.m_lighting.mulColor = info.kColors[3]; uni.m_lighting.fog = CGraphics::g_Fog; uni.m_pad2.x() = info.indScale; m_uniBuf->unmap(); } void CFluidPlaneShader::prepareDraw(const RenderSetupInfo& info, const zeus::CVector3f& waterCenter, const CRippleManager& rippleManager, const zeus::CColor& colorMul, float rippleNormResolution) { Uniform& uni = *reinterpret_cast(m_uniBuf->map(sizeof(Uniform))); uni.m_mv = CGraphics::g_GXModelView.toMatrix4f(); uni.m_mvNorm = info.normMtx; uni.m_proj = CGraphics::GetPerspectiveProjectionMatrix(true); for (int i = 0; i < 6; ++i) uni.m_texMtxs[i] = info.texMtxs[i]; int i = 0; for (const CRipple& ripple : rippleManager.GetRipples()) { assert(i < 20 && "Too many ripples"); Ripple& rOut = uni.m_ripple[i++]; if (ripple.GetTime() >= ripple.GetTimeFalloff()) { rOut.center.zeroOut(); rOut.params.zeroOut(); continue; } zeus::CVector3f localPos = ripple.GetCenter() - waterCenter; rOut.center.x() = float(localPos.x()); rOut.center.y() = float(localPos.y()); rOut.center.z() = ripple.GetTime() * ripple.GetOOTimeFalloff(); rOut.center.w() = ripple.GetOODistanceFalloff(); rOut.params.x() = ripple.GetAmplitude(); rOut.params.y() = ripple.GetPhase(); rOut.params.z() = (1.f - ripple.GetTime() * ripple.GetOOTimeFalloff() * ripple.GetOOTimeFalloff()) * ripple.GetFrequency(); } uni.m_colorMul = colorMul; uni.m_pad[0].x() = rippleNormResolution; uni.m_lighting.ActivateLights(info.lights); for (i = 0; i < 3; ++i) uni.m_lighting.colorRegs[i] = info.kColors[i]; uni.m_lighting.mulColor = info.kColors[3]; uni.m_lighting.fog = CGraphics::g_Fog; uni.m_pad2.x() = info.indScale; m_uniBuf->unmap(); } void CFluidPlaneShader::loadVerts(const std::vector& verts, const std::vector& pVerts) { m_vbo->load(verts.data(), verts.size() * sizeof(Vertex)); if (m_pvbo) m_pvbo->load(pVerts.data(), pVerts.size() * sizeof(PatchVertex)); } } // namespace urde