#pragma once #include "RetroTypes.hpp" #include "boo/graphicsdev/IGraphicsDataFactory.hpp" #include "CModelShaders.hpp" #include "World/CFluidPlaneManager.hpp" #include "Graphics/CTexture.hpp" #include "CToken.hpp" #include "zeus/CAABox.hpp" #include "Shaders/shader_CFluidPlaneShader.hpp" namespace urde { class CFluidPlaneShader { public: struct Vertex { zeus::CVector3f m_pos; zeus::CVector3f m_norm; zeus::CVector3f m_binorm; zeus::CVector3f m_tangent; zeus::CColor m_color; Vertex() = default; Vertex(const zeus::CVector3f& position) : m_pos(position) {} Vertex(const zeus::CVector3f& position, const zeus::CColor& color) : m_pos(position), m_color(color) {} Vertex(const zeus::CVector3f& position, const zeus::CVector3f& normal, const zeus::CColor& color) : m_pos(position), m_norm(normal), m_color(color) {} Vertex(const zeus::CVector3f& position, const zeus::CVector3f& normal, const zeus::CVector3f& binormal, const zeus::CVector3f& tangent, const zeus::CColor& color) : m_pos(position), m_norm(normal), m_binorm(binormal), m_tangent(tangent), m_color(color) {} }; struct PatchVertex { zeus::CVector4f m_pos; float m_outerLevels[4] = {}; float m_innerLevels[4] = {}; }; struct RenderSetupInfo { zeus::CMatrix4f texMtxs[6]; zeus::CMatrix4f normMtx; float indScale = 1.f; zeus::CColor kColors[4]; std::vector lights; }; private: struct ShaderPair { boo::ObjToken m_regular; boo::ObjToken m_tessellation; void reset() { m_regular.reset(); m_tessellation.reset(); } }; struct BindingPair { boo::ObjToken m_regular; boo::ObjToken m_tessellation; }; class Cache { ShaderPair m_cache[1024] = {}; ShaderPair m_doorCache[8] = {}; ShaderPair& CacheSlot(const SFluidPlaneShaderInfo& info, int i) { return m_cache[i]; } ShaderPair& CacheSlot(const SFluidPlaneDoorShaderInfo& info, int i) { return m_doorCache[i]; } static u16 MakeCacheKey(const SFluidPlaneShaderInfo& info); static u16 MakeCacheKey(const SFluidPlaneDoorShaderInfo& info); public: template ShaderPair GetOrBuildShader(const T& info); void Clear(); }; static Cache _cache; struct Ripple { zeus::CVector4f center; // time, distFalloff zeus::CVector4f params; // amplitude, lookupPhase, lookupTime }; struct Uniform { zeus::CMatrix4f m_mv; zeus::CMatrix4f m_mvNorm; zeus::CMatrix4f m_proj; zeus::CMatrix4f m_texMtxs[6]; Ripple m_ripple[20]; zeus::CVector4f m_colorMul; zeus::CVector4f m_pad[3]; // rippleNormResolution, Pad out to 1280 bytes CModelShaders::LightingUniform m_lighting; zeus::CVector3f m_pad2; // Pad out to 768 bytes, also holds ind scale }; TLockedToken m_patternTex1; TLockedToken m_patternTex2; TLockedToken m_colorTex; TLockedToken m_bumpMap; TLockedToken m_envMap; TLockedToken m_envBumpMap; TLockedToken m_lightmap; boo::ObjToken m_rippleMap; boo::ObjToken m_vbo; boo::ObjToken m_pvbo; boo::ObjToken m_uniBuf; ShaderPair m_pipelines; BindingPair m_dataBind; int m_lastBind = -1; #if BOO_HAS_GL static ShaderPair BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static ShaderPair BuildShader(boo::GLDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info); BindingPair BuildBinding(boo::GLDataFactory::Context& ctx, const ShaderPair& pipeline); #endif #if _WIN32 static ShaderPair BuildShader(boo::D3D11DataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static ShaderPair BuildShader(boo::D3D11DataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info); BindingPair BuildBinding(boo::D3D11DataFactory::Context& ctx, const ShaderPair& pipeline); #endif #if BOO_HAS_METAL static ShaderPair BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static ShaderPair BuildShader(boo::MetalDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info); BindingPair BuildBinding(boo::MetalDataFactory::Context& ctx, const ShaderPair& pipeline); #endif #if BOO_HAS_VULKAN static ShaderPair BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneShaderInfo& info); static ShaderPair BuildShader(boo::VulkanDataFactory::Context& ctx, const SFluidPlaneDoorShaderInfo& info); BindingPair BuildBinding(boo::VulkanDataFactory::Context& ctx, const ShaderPair& pipeline); #endif template static void _Shutdown(); void PrepareBinding(u32 maxVertCount); public: 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); CFluidPlaneShader(const TLockedToken& patternTex1, const TLockedToken& patternTex2, const TLockedToken& colorTex, u32 maxVertCount); void prepareDraw(const RenderSetupInfo& info); void prepareDraw(const RenderSetupInfo& info, const zeus::CVector3f& waterCenter, const CRippleManager& rippleManager, const zeus::CColor& colorMul, float rippleNormResolution); void bindRegular() { if (m_lastBind != 0) { CGraphics::SetShaderDataBinding(m_dataBind.m_regular); m_lastBind = 0; } } bool bindTessellation() { if (m_lastBind != 1) { CGraphics::SetShaderDataBinding(m_dataBind.m_tessellation); m_lastBind = 1; } return true; } void doneDrawing() { m_lastBind = -1; } void loadVerts(const std::vector& verts, const std::vector& pVerts); bool isReady() const { return m_pipelines.m_regular->isReady() && (!m_pipelines.m_tessellation || m_pipelines.m_tessellation->isReady()); } static void Shutdown(); }; } // namespace urde