diff --git a/Runtime/Graphics/CBooRenderer.cpp b/Runtime/Graphics/CBooRenderer.cpp index db5631089..6022d9ed6 100644 --- a/Runtime/Graphics/CBooRenderer.cpp +++ b/Runtime/Graphics/CBooRenderer.cpp @@ -295,6 +295,14 @@ void CBooRenderer::LoadThermoPalette() x288_thermoPalette = thermoTexObj->GetPaletteTexture(); } +void CBooRenderer::LoadBallFade() +{ + m_ballFadeTex = xc_store.GetObj("TXTR_BallFade"); + CTexture* ballFadeTexObj = m_ballFadeTex.GetObj(); + if (ballFadeTexObj) + m_ballFade = ballFadeTexObj->GetBooTexture(); +} + CBooRenderer::CBooRenderer(IObjectStore& store, IFactory& resFac) : x8_factory(resFac), xc_store(store), x2a8_thermalRand(20) { @@ -305,9 +313,11 @@ CBooRenderer::CBooRenderer(IObjectStore& store, IFactory& resFac) { GenerateFogVolumeRampTex(ctx); GenerateSphereRampTex(ctx); + m_ballShadowId = ctx.newRenderTexture(m_ballShadowIdW, m_ballShadowIdH, true, false); return true; }); LoadThermoPalette(); + LoadBallFade(); m_thermHotFilter.emplace(); Buckets::Init(); @@ -732,4 +742,91 @@ void CBooRenderer::SetWorldLightFadeLevel(float level) x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); } +void CBooRenderer::FindOverlappingWorldModels(std::vector& modelBits, const zeus::CAABox& aabb) const +{ + u32 bitmapWords = 0; + for (const CAreaListItem& item : x1c_areaListItems) + if (item.x4_octTree) + bitmapWords += item.x4_octTree->x14_bitmapWordCount; + + if (!bitmapWords) + { + modelBits.clear(); + return; + } + + modelBits.clear(); + modelBits.resize(bitmapWords); + + u32 curWord = 0; + for (const CAreaListItem& item : x1c_areaListItems) + { + if (!item.x4_octTree) + continue; + + item.x4_octTree->FindOverlappingModels(modelBits.data() + curWord, aabb); + + u32 wordModel = 0; + for (int i=0 ; ix14_bitmapWordCount ; ++i, wordModel += 32) + { + u32& word = modelBits[i]; + if (!word) + continue; + for (int j=0 ; j<32 ; ++j) + { + if ((1 << j) & word) + { + const zeus::CAABox& modelAABB = item.x10_models[wordModel + j]->x20_aabb; + if (!modelAABB.intersects(aabb)) + word &= ~(1 << j); + } + } + } + + curWord += item.x4_octTree->x14_bitmapWordCount; + } +} + +int CBooRenderer::DrawOverlappingWorldModelIDs(int alphaVal, const std::vector& modelBits, + const zeus::CAABox& aabb) const +{ + CModelFlags flags(0, 0, 3, zeus::CColor{1.f, 1.f, 1.f, alphaVal / 255.f}); + flags.m_extendedShaderIdx = 5; // Do solid color draw + + u32 curWord = 0; + for (const CAreaListItem& item : x1c_areaListItems) + { + if (!item.x4_octTree) + continue; + + u32 wordModel = 0; + for (int i=0 ; ix14_bitmapWordCount ; ++i, wordModel += 32) + { + const u32& word = modelBits[i]; + if (!word) + continue; + for (int j=0 ; j<32 ; ++j) + { + if ((1 << j) & word) + { + if (alphaVal > 255) + return alphaVal; + + const CBooModel& model = *item.x10_models[wordModel + j]; + const_cast(model).VerifyCurrentShader(0); + for (const CBooSurface* surf = model.x38_firstUnsortedSurface; surf; surf = surf->m_next) + if (surf->GetBounds().intersects(aabb)) + model.DrawSurface(*surf, flags); + alphaVal += 4; + flags.color.a = alphaVal / 255.f; + } + } + } + + curWord += item.x4_octTree->x14_bitmapWordCount; + } + + return alphaVal; +} + } diff --git a/Runtime/Graphics/CBooRenderer.hpp b/Runtime/Graphics/CBooRenderer.hpp index 68c822b9f..e2730a6e3 100644 --- a/Runtime/Graphics/CBooRenderer.hpp +++ b/Runtime/Graphics/CBooRenderer.hpp @@ -99,6 +99,11 @@ class CBooRenderer : public IRenderer boo::ITextureS* x220_sphereRamp = nullptr; TLockedToken m_thermoPaletteTex; boo::ITexture* x288_thermoPalette = nullptr; + TLockedToken m_ballFadeTex; + boo::ITexture* m_ballFade = nullptr; + boo::ITextureR* m_ballShadowId = nullptr; + int m_ballShadowIdW = 64; + int m_ballShadowIdH = 64; CRandom16 x2a8_thermalRand; std::list x2b8_; @@ -136,6 +141,7 @@ class CBooRenderer : public IRenderer void GenerateFogVolumeRampTex(boo::IGraphicsDataFactory::Context& ctx); void GenerateSphereRampTex(boo::IGraphicsDataFactory::Context& ctx); void LoadThermoPalette(); + void LoadBallFade(); void ActivateLightsForModel(CAreaListItem* item, CBooModel& model); void RenderBucketItems(CAreaListItem* item); @@ -210,6 +216,23 @@ public: void BindMainDrawTarget() {CGraphics::g_BooMainCommandQueue->setRenderTarget(CGraphics::g_SpareTexture);} void BindReflectionDrawTarget() {CGraphics::g_BooMainCommandQueue->setRenderTarget(x14c_reflectionTex);} + void BindBallShadowIdTarget() + { + CGraphics::g_BooMainCommandQueue->setRenderTarget(m_ballShadowId); + SetViewport(0, 0, m_ballShadowIdW, m_ballShadowIdH); + } + void ResolveBallShadowIdTarget() + { + CGraphics::g_BooMainCommandQueue->resolveBindTexture(m_ballShadowId, + boo::SWindowRect(0, 0, + m_ballShadowIdW, + m_ballShadowIdH), + false, true, false); + } + + void FindOverlappingWorldModels(std::vector& modelBits, const zeus::CAABox& aabb) const; + int DrawOverlappingWorldModelIDs(int alphaVal, const std::vector& modelBits, + const zeus::CAABox& aabb) const; }; } diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 76930e192..c6e92fdc3 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -463,7 +463,7 @@ void CGraphics::SetViewportResolution(const zeus::CVector2i& res) } static boo::SWindowRect CachedVP; -static float CachedDepthRange[2] = {0.f, 1.f}; +zeus::CVector2f CGraphics::g_CachedDepthRange = {0.f, 1.f}; void CGraphics::SetViewport(int leftOff, int bottomOff, int width, int height) { @@ -471,7 +471,7 @@ void CGraphics::SetViewport(int leftOff, int bottomOff, int width, int height) CachedVP.location[1] = bottomOff; CachedVP.size[0] = width; CachedVP.size[1] = height; - g_BooMainCommandQueue->setViewport(CachedVP, CachedDepthRange[0], CachedDepthRange[1]); + g_BooMainCommandQueue->setViewport(CachedVP, g_CachedDepthRange[0], g_CachedDepthRange[1]); } void CGraphics::SetScissor(int leftOff, int bottomOff, int width, int height) @@ -482,9 +482,9 @@ void CGraphics::SetScissor(int leftOff, int bottomOff, int width, int height) void CGraphics::SetDepthRange(float znear, float zfar) { - CachedDepthRange[0] = znear; - CachedDepthRange[1] = zfar; - g_BooMainCommandQueue->setViewport(CachedVP, CachedDepthRange[0], CachedDepthRange[1]); + g_CachedDepthRange[0] = znear; + g_CachedDepthRange[1] = zfar; + g_BooMainCommandQueue->setViewport(CachedVP, g_CachedDepthRange[0], g_CachedDepthRange[1]); } CTimeProvider* CGraphics::g_ExternalTimeProvider = nullptr; diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index b28703fdb..5cf50e48a 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -220,6 +220,7 @@ public: }; static CProjectionState g_Proj; + static zeus::CVector2f g_CachedDepthRange; static CFogState g_Fog; static float g_ProjAspect; static u32 g_NumLightsActive; diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index b74d8dec9..9c168613e 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -126,8 +126,6 @@ private: void DrawSurfaces(const CModelFlags& flags) const; void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const; - void VerifyCurrentShader(int shaderIdx); - static zeus::CVector3f g_PlayerPosition; static float g_ModSeconds; static float g_TransformedTime; @@ -152,6 +150,7 @@ public: bool TryLockTextures() const; void UnlockTextures() const; void Touch(int shaderIdx) const; + void VerifyCurrentShader(int shaderIdx); void UpdateUniformData(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const; @@ -178,6 +177,7 @@ public: static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos); static void KillCachedViewDepState(); + }; class CModel diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index 5843fead9..7f33e2364 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -172,6 +172,10 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() newInst.m_shaderDataBindings.reserve(x0_surfaces->size()); std::vector texs; + texs.resize(8); + boo::ITexture* mbShadowTexs[] = {g_Renderer->m_ballShadowId, + g_Renderer->x220_sphereRamp, + g_Renderer->m_ballFade}; size_t thisOffs[3]; size_t thisSizes[3]; @@ -185,13 +189,11 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() const MaterialSet::Material& mat = x4_matSet->materials.at(surf.m_data.matIdx); texs.clear(); - texs.reserve(8); for (atUint32 idx : mat.textureIdxs) { TCachedToken& tex = x1c_textures[idx]; texs.push_back(tex.GetObj()->GetBooTexture()); } - texs.resize(8); texs[7] = g_Renderer->x220_sphereRamp; if (m_skinBankCount) @@ -220,11 +222,27 @@ CBooModel::ModelInstance* CBooModel::PushNewModelInstance() int idx = 0; for (boo::IShaderPipeline* pipeline : pipelines->m_pipelines) { + size_t texCount; + boo::ITexture** ltexs; + if (idx == 2) + { + texCount = 8; + ltexs = texs.data(); + } + else if (idx == 6) + { + texCount = 3; + ltexs = mbShadowTexs; + } + else + { + texCount = mat.textureIdxs.size(); + ltexs = texs.data(); + } extendeds.push_back( ctx.newShaderDataBinding(pipeline, m_vtxFmt, x8_vbo, nullptr, xc_ibo, 3, bufs, stages, - thisOffs, thisSizes, (idx == 2) ? 8 : mat.textureIdxs.size(), - texs.data())); + thisOffs, thisSizes, texCount, ltexs)); ++idx; } } @@ -630,6 +648,18 @@ void CBooModel::UpdateUniformData(const CModelFlags& flags, thermalOut.mulColor = flags.color; thermalOut.addColor = flags.addColor; } + else if (flags.m_extendedShaderIdx == 5) /* Solid color render */ + { + CModelShaders::SolidUniform& solidOut = *reinterpret_cast(dataCur); + solidOut.solidColor = flags.color; + } + else if (flags.m_extendedShaderIdx == 6) /* MorphBall shadow render */ + { + CModelShaders::MBShadowUniform& shadowOut = *reinterpret_cast(dataCur); + shadowOut.shadowUp = CGraphics::g_GXModelView * zeus::CVector3f::skUp; + shadowOut.shadowUp.w = flags.color.a; + shadowOut.shadowId = flags.color.r; + } else { CModelShaders::LightingUniform& lightingOut = *reinterpret_cast(dataCur); diff --git a/Runtime/Graphics/Shaders/CModelShaders.cpp b/Runtime/Graphics/Shaders/CModelShaders.cpp index 62612045a..8a6867b23 100644 --- a/Runtime/Graphics/Shaders/CModelShaders.cpp +++ b/Runtime/Graphics/Shaders/CModelShaders.cpp @@ -32,6 +32,13 @@ const hecl::Backend::TextureInfo CModelShaders::ThermalTextures[] = {hecl::Backend::TexGenSrc::Normal, 7, 0, 7, true} }; +const hecl::Backend::TextureInfo CModelShaders::BallFadeTextures[] = +{ + {hecl::Backend::TexGenSrc::Position, 0, 0, 0, false}, // ID tex + {hecl::Backend::TexGenSrc::Position, 1, 0, 0, false}, // Sphere ramp + {hecl::Backend::TexGenSrc::Position, 2, 0, 1, false} // TXTR_BallFade +}; + CModelShaders::CModelShaders(const hecl::Runtime::FileStoreManager& storeMgr, boo::IGraphicsDataFactory* gfxFactory) : m_shaderCache(storeMgr, gfxFactory, GetShaderExtensions(gfxFactory->platform())) {} diff --git a/Runtime/Graphics/Shaders/CModelShaders.hpp b/Runtime/Graphics/Shaders/CModelShaders.hpp index 52cd1c263..13a561f33 100644 --- a/Runtime/Graphics/Shaders/CModelShaders.hpp +++ b/Runtime/Graphics/Shaders/CModelShaders.hpp @@ -22,6 +22,7 @@ class CModelShaders static hecl::Runtime::ShaderCacheExtensions GetShaderExtensionsHLSL(boo::IGraphicsDataFactory::Platform plat); static hecl::Runtime::ShaderCacheExtensions GetShaderExtensionsMetal(boo::IGraphicsDataFactory::Platform plat); static const hecl::Backend::TextureInfo ThermalTextures[]; + static const hecl::Backend::TextureInfo BallFadeTextures[]; public: struct Light { @@ -47,6 +48,17 @@ public: zeus::CColor addColor; }; + struct SolidUniform + { + zeus::CColor solidColor; + }; + + struct MBShadowUniform + { + zeus::CVector4f shadowUp; + float shadowId; + }; + static void Initialize(const hecl::Runtime::FileStoreManager& storeMgr, boo::IGraphicsDataFactory* gfxFactory); diff --git a/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp b/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp index 0c4b98f07..48c653dcf 100644 --- a/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersGLSL.cpp @@ -72,6 +72,35 @@ static const char* ThermalPostGLSL = "}\n" "\n"; +static const char* SolidPostGLSL = +"UBINDING2 uniform SolidUniform\n" +"{\n" +" vec4 solidColor;\n" +"};\n" +"vec4 SolidPostFunc(vec4 colorIn)\n" +"{\n" +" return solidColor;\n" +"}\n" +"\n"; + +static const char* MBShadowPostGLSL = +"UBINDING2 uniform MBShadowUniform\n" +"{\n" +" vec4 shadowUp;\n" +" float shadowId;\n" +"};\n" +"vec4 MBShadowPostFunc(vec4 colorIn)\n" +"{\n" +" float idTexel = texture(tex0, vtf.extTcgs[0]).a;\n" +" float sphereTexel = texture(tex1, vtf.extTcgs[1]).a;\n" +" float fadeTexel = texture(tex2, vtf.extTcgs[2]).a;\n" +" float val = ((abs(idTexel - shadowId) < 0.001) ?\n" +" (dot(vtf.mvNorm.xyz, shadowUp.xyz) * shadowUp.w) : 0.0) *\n" +" sphereTexel * fadeTexel;\n" +" return vec4(0.0, 0.0, 0.0, val);\n" +"}\n" +"\n"; + static const char* BlockNames[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME, HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME, "LightingUniform"}; @@ -80,6 +109,14 @@ static const char* ThermalBlockNames[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME, HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME, "ThermalUniform"}; +static const char* SolidBlockNames[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME, + HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME, + "SolidUniform"}; + +static const char* MBShadowBlockNames[] = {HECL_GLSL_VERT_UNIFORM_BLOCK_NAME, + HECL_GLSL_TEXMTX_UNIFORM_BLOCK_NAME, + "MBShadowUniform"}; + hecl::Runtime::ShaderCacheExtensions CModelShaders::GetShaderExtensionsGLSL(boo::IGraphicsDataFactory::Platform plat) { @@ -105,6 +142,17 @@ CModelShaders::GetShaderExtensionsGLSL(boo::IGraphicsDataFactory::Platform plat) 3, BlockNames, 0, nullptr, hecl::Backend::BlendFactor::One, hecl::Backend::BlendFactor::One); + /* Solid shading */ + ext.registerExtensionSlot({}, {SolidPostGLSL, "SolidPostFunc"}, + 3, SolidBlockNames, 0, nullptr, hecl::Backend::BlendFactor::One, + hecl::Backend::BlendFactor::Zero); + + /* MorphBall shadow shading */ + ext.registerExtensionSlot({}, {MBShadowPostGLSL, "MBShadowPostFunc"}, + 3, MBShadowBlockNames, 3, BallFadeTextures, + hecl::Backend::BlendFactor::SrcAlpha, + hecl::Backend::BlendFactor::InvSrcAlpha); + return ext; } diff --git a/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp b/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp index 3ac9d15e6..44307d919 100644 --- a/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersHLSL.cpp @@ -71,6 +71,35 @@ static const char* ThermalPostHLSL = "}\n" "\n"; +static const char* SolidPostHLSL = +"cbuffer SolidUniform : register(b2)\n" +"{\n" +" float4 solidColor;\n" +"};\n" +"static float4 SolidPostFunc(float4 colorIn)\n" +"{\n" +" return solidColor;\n" +"}\n" +"\n"; + +static const char* MBShadowPostHLSL = +"cbuffer MBShadowUniform : register(b2)\n" +"{\n" +" float4 shadowUp;\n" +" float shadowId;\n" +"};\n" +"static float4 MBShadowPostFunc(float4 colorIn)\n" +"{\n" +" float idTexel = extTex0.Sample(samp, vtf.extTcgs[0]).a;\n" +" float sphereTexel = extTex1.Sample(samp, vtf.extTcgs[1]).a;\n" +" float fadeTexel = extTex2.Sample(samp, vtf.extTcgs[2]).a;\n" +" float val = ((abs(idTexel - shadowId) < 0.001) ?\n" +" (dot(vtf.mvNorm.xyz, shadowUp.xyz) * shadowUp.w) : 0.0) *\n" +" sphereTexel * fadeTexel;\n" +" return float4(0.0, 0.0, 0.0, val);\n" +"}\n" +"\n"; + hecl::Runtime::ShaderCacheExtensions CModelShaders::GetShaderExtensionsHLSL(boo::IGraphicsDataFactory::Platform plat) { @@ -96,6 +125,17 @@ CModelShaders::GetShaderExtensionsHLSL(boo::IGraphicsDataFactory::Platform plat) 0, nullptr, 0, nullptr, hecl::Backend::BlendFactor::One, hecl::Backend::BlendFactor::One); + /* Solid shading */ + ext.registerExtensionSlot({}, {SolidPostHLSL, "SolidPostFunc"}, + 0, nullptr, 0, nullptr, hecl::Backend::BlendFactor::One, + hecl::Backend::BlendFactor::Zero); + + /* Solid shading */ + ext.registerExtensionSlot({}, {MBShadowPostHLSL, "MBShadowPostFunc"}, + 0, nullptr, 3, BallFadeTextures, + hecl::Backend::BlendFactor::SrcAlpha, + hecl::Backend::BlendFactor::InvSrcAlpha); + return ext; } diff --git a/Runtime/Graphics/Shaders/CModelShadersMetal.cpp b/Runtime/Graphics/Shaders/CModelShadersMetal.cpp index c5e3c65dc..2086b607b 100644 --- a/Runtime/Graphics/Shaders/CModelShadersMetal.cpp +++ b/Runtime/Graphics/Shaders/CModelShadersMetal.cpp @@ -71,8 +71,40 @@ static const char* ThermalPostMetal = "}\n" "\n"; +static const char* SolidPostMetal = +"struct SolidUniform\n" +"{\n" +" float4 solidColor;\n" +"};\n" +"static float4 SolidPostFunc(thread VertToFrag& vtf, constant SolidUniform& lu, float4 colorIn)\n" +"{\n" +" return lu.solidColor;\n" +"}\n" +"\n"; + +static const char* MBShadowPostMetal = +"UBINDING2 uniform MBShadowUniform\n" +"{\n" +" vec4 shadowUp;\n" +" float shadowId;\n" +"};\n" +"static float4 MBShadowPostFunc(thread VertToFrag& vtf, constant MBShadowUniform& su,\n" +" texture2d tex0, texture2d tex1, texture2d tex2, float4 colorIn)\n" +"{\n" +" float idTexel = tex0.sample(samp, vtf.extTcgs0).a;\n" +" float sphereTexel = tex1.sample(samp, vtf.extTcgs1).a;\n" +" float fadeTexel = tex2.sample(samp, vtf.extTcgs2).a;\n" +" float val = ((fabs(idTexel - su.shadowId) < 0.001) ?\n" +" (dot(vtf.mvNorm.xyz, su.shadowUp.xyz) * su.shadowUp.w) : 0.0) *\n" +" sphereTexel * fadeTexel;\n" +" return float4(0.0, 0.0, 0.0, val);\n" +"}\n" +"\n"; + static const char* BlockNames[] = {"LightingUniform"}; static const char* ThermalBlockNames[] = {"ThermalUniform"}; +static const char* SolidBlockNames[] = {"SolidUniform"}; +static const char* MBShadowBlockNames[] = {"MBShadowUniform"}; hecl::Runtime::ShaderCacheExtensions CModelShaders::GetShaderExtensionsMetal(boo::IGraphicsDataFactory::Platform plat) @@ -99,6 +131,17 @@ CModelShaders::GetShaderExtensionsMetal(boo::IGraphicsDataFactory::Platform plat 1, BlockNames, 0, nullptr, hecl::Backend::BlendFactor::One, hecl::Backend::BlendFactor::One); + /* Solid shading */ + ext.registerExtensionSlot({}, {SolidPostMetal, "SolidPostFunc"}, + 1, SolidBlockNames, 0, nullptr, hecl::Backend::BlendFactor::One, + hecl::Backend::BlendFactor::Zero); + + /* MorphBall shadow shading */ + ext.registerExtensionSlot({}, {MBShadowPostMetal, "MBShadowPostFunc"}, + 1, MBShadowBlockNames, 3, BallFadeTextures, + hecl::Backend::BlendFactor::SrcAlpha, + hecl::Backend::BlendFactor::InvSrcAlpha); + return ext; } diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 49d26be07..d2dca9021 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -312,4 +312,15 @@ void CActor::SetActorLights(std::unique_ptr lights) x90_actorLights = std::move(lights); xe4_31_lightsDirty = true; } + +bool CActor::CanDrawStatic() const +{ + if (!x30_24_active) + return false; + + if (x64_modelData && x64_modelData->HasNormalModel()) + return xb4_ <= 4; + + return false; +} } diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 6be7395c1..eafd4ab0f 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -161,6 +161,7 @@ public: void EnsureRendered(const CStateManager&, const zeus::CVector3f&, const zeus::CVector3f&); SAdvancementDeltas UpdateAnimation(float, CStateManager&, bool); void SetActorLights(std::unique_ptr); + bool CanDrawStatic() const; bool GetE7_29() const { return xe7_29_; } }; } diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index efeea4d06..60ed98268 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -414,16 +414,6 @@ bool CGameArea::IGetScriptingMemoryAlways() const return false; } -TAreaId CGameArea::IGetAreaId() const -{ - return 0; -} - -ResId CGameArea::IGetAreaAssetId() const -{ - return 0; -} - bool CGameArea::IIsActive() const { return false; diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 885dfd254..62da725c4 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -266,8 +266,9 @@ public: void SetPauseState(bool paused); bool IGetScriptingMemoryAlways() const; - TAreaId IGetAreaId() const; - ResId IGetAreaAssetId() const; + TAreaId GetAreaId() const { return x4_selfIdx; } + TAreaId IGetAreaId() const { return x4_selfIdx; } + ResId IGetAreaAssetId() const { return x84_mrea; } bool IIsActive() const; TAreaId IGetAttachedAreaId(int) const; u32 IGetNumAttachedAreas() const; diff --git a/Runtime/World/CMakeLists.txt b/Runtime/World/CMakeLists.txt index ae8ed43bb..7d2f3e9fd 100644 --- a/Runtime/World/CMakeLists.txt +++ b/Runtime/World/CMakeLists.txt @@ -8,7 +8,7 @@ set(WORLD_SOURCES CEnergyDrainSource.hpp CEnergyDrainSource.cpp CPlayerCameraBob.hpp CPlayerCameraBob.cpp CMorphBall.hpp CMorphBall.cpp - CMorphBallTrail.hpp CMorphBallTrail.cpp + CMorphBallShadow.hpp CMorphBallShadow.cpp CActor.hpp CActor.cpp CAi.hpp CAi.cpp CAiFuncMap.hpp CAiFuncMap.cpp diff --git a/Runtime/World/CMorphBallShadow.cpp b/Runtime/World/CMorphBallShadow.cpp new file mode 100644 index 000000000..3a61a46f5 --- /dev/null +++ b/Runtime/World/CMorphBallShadow.cpp @@ -0,0 +1,143 @@ +#include "CMorphBallShadow.hpp" +#include "CStateManager.hpp" +#include "World/CWorld.hpp" +#include "GameGlobalObjects.hpp" +#include "Graphics/CBooRenderer.hpp" +#include "World/CPlayer.hpp" + +namespace urde +{ + +static union +{ + struct + { + bool x_24_ : 1; + bool x_25_ : 1; + bool x_26_ : 1; + bool x_27_ : 1; + }; + u16 _dummy = 0; +} s_flags; + +void CMorphBallShadow::GatherAreas(CStateManager& mgr) +{ + x18_areas.clear(); + for (CGameArea* area = mgr.WorldNC()->GetChainHead(EChain::Alive); + area != CWorld::GetAliveAreasEnd(); + area = area->GetNext()) + { + CGameArea::EOcclusionState occState = CGameArea::EOcclusionState::NotOccluded; + if (area->IsPostConstructed()) + occState = area->GetPostConstructed()->x10dc_occlusionState; + if (occState == CGameArea::EOcclusionState::Occluded) + x18_areas.push_back(area->GetAreaId()); + } +} + +void CMorphBallShadow::RenderIdBuffer(const zeus::CAABox& aabb, CStateManager& mgr, CPlayer& player) +{ + xb8_ = aabb; + x0_actors.clear(); + x18_areas.clear(); + x30_worldModelBits.clear(); + s_flags.x_26_ = true; + + if (!s_flags.x_27_) + { + xd0_hasIds = false; + return; + } + + GatherAreas(mgr); + + g_Renderer->BindBallShadowIdTarget(); + CGraphics::g_BooMainCommandQueue->clearTarget(); + + zeus::CTransform backupViewMtx = CGraphics::g_ViewMatrix; + CGraphics::CProjectionState backupProjection = CGraphics::g_Proj; + zeus::CVector2f backupDepth = CGraphics::g_CachedDepthRange; + zeus::CTransform viewMtx(zeus::CVector3f::skRight, zeus::CVector3f::skDown, zeus::CVector3f::skForward, + zeus::CVector3f((aabb.min.x + aabb.max.x) * 0.5f, + (aabb.min.y + aabb.max.y) * 0.5f, + aabb.max.z)); + + CGraphics::SetDepthRange(0.f, 1.f); + float vpX = (aabb.max.x - aabb.min.x) * 0.5f; + float vpY = (aabb.max.y - aabb.min.y) * 0.5f; + float vpZ = (aabb.max.z - aabb.min.z) + FLT_EPSILON; + CGraphics::SetOrtho(-vpX, vpX, vpY, -vpY, 0.f, vpZ); + + rstl::reserved_vector nearItems; + mgr.BuildNearList(nearItems, aabb, CMaterialFilter::skPassEverything, &player); + + CGraphics::SetViewPointMatrix(viewMtx); + + int alphaVal = 4; + for (TUniqueId id : nearItems) + { + if (alphaVal > 255) + break; + + const CActor* actor = static_cast(mgr.GetObjectById(id)); + if (!actor || !actor->CanDrawStatic()) + continue; + + x0_actors.push_back(actor); + + const CModelData* modelData = actor->GetModelData(); + zeus::CTransform modelXf = actor->GetTransform() * zeus::CTransform::Scale(modelData->GetScale()); + CGraphics::SetModelMatrix(modelXf); + + CModelFlags flags(0, 0, 3, zeus::CColor{1.f, 1.f, 1.f, alphaVal / 255.f}); + flags.m_extendedShaderIdx = 5; // Do solid color draw + const CBooModel& model = *modelData->PickStaticModel(CModelData::EWhichModel::Normal); + const_cast(model).VerifyCurrentShader(flags.m_matSetIdx); + model.DrawNormal(flags, nullptr, nullptr); + alphaVal += 4; + } + + CGraphics::SetModelMatrix(zeus::CTransform::Identity()); + + g_Renderer->FindOverlappingWorldModels(x30_worldModelBits, aabb); + alphaVal = g_Renderer->DrawOverlappingWorldModelIDs(alphaVal, x30_worldModelBits, aabb); + + g_Renderer->ResolveBallShadowIdTarget(); + + g_Renderer->BindMainDrawTarget(); + CGraphics::SetViewPointMatrix(backupViewMtx); + CGraphics::SetProjectionState(backupProjection); + CGraphics::SetDepthRange(backupDepth[0], backupDepth[1]); + + xd0_hasIds = alphaVal != 4; +} + +bool CMorphBallShadow::AreasValid(CStateManager& mgr) const +{ + auto it = x18_areas.begin(); + for (CGameArea* area = mgr.WorldNC()->GetChainHead(EChain::Alive); + area != CWorld::GetAliveAreasEnd(); + area = area->GetNext()) + { + CGameArea::EOcclusionState occState = CGameArea::EOcclusionState::NotOccluded; + if (area->IsPostConstructed()) + occState = area->GetPostConstructed()->x10dc_occlusionState; + if (occState != CGameArea::EOcclusionState::Occluded) + continue; + if (it == x18_areas.end()) + return false; + if (*it != area->GetAreaId()) + return false; + ++it; + } + return true; +} + +void CMorphBallShadow::Render(CStateManager& mgr, float alpha) +{ + if (!xd0_hasIds || !AreasValid(mgr)) + return; + +} + +} diff --git a/Runtime/World/CMorphBallShadow.hpp b/Runtime/World/CMorphBallShadow.hpp new file mode 100644 index 000000000..45922efa4 --- /dev/null +++ b/Runtime/World/CMorphBallShadow.hpp @@ -0,0 +1,35 @@ +#ifndef __URDE_CMORPHBALLSHADOW_HPP__ +#define __URDE_CMORPHBALLSHADOW_HPP__ + +#include "CToken.hpp" +#include "Graphics/CTexture.hpp" +#include "zeus/CAABox.hpp" + +namespace urde +{ +class CStateManager; +class CPlayer; +class CGameArea; +class CActor; + +class CMorphBallShadow +{ + std::list x0_actors; + std::list x18_areas; + std::vector x30_worldModelBits; + //CTexture x40_; + //TToken xa8_ballFade; + //int xb0_idW; + //int xb4_idH; + zeus::CAABox xb8_; + bool xd0_hasIds = false; + void GatherAreas(CStateManager& mgr); + bool AreasValid(CStateManager& mgr) const; +public: + void RenderIdBuffer(const zeus::CAABox& aabb, CStateManager& mgr, CPlayer& player); + void Render(CStateManager& mgr, float alpha); +}; + +} + +#endif // __URDE_CMORPHBALLSHADOW_HPP__ diff --git a/Runtime/World/CMorphBallTrail.cpp b/Runtime/World/CMorphBallTrail.cpp deleted file mode 100644 index a5e2874c2..000000000 --- a/Runtime/World/CMorphBallTrail.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "CMorphBallTrail.hpp" -#include "CStateManager.hpp" -#include "World/CWorld.hpp" - -namespace urde -{ - -static union -{ - struct - { - bool x_24_ : 1; - bool x_25_ : 1; - bool x_26_ : 1; - bool x_27_ : 1; - }; - u16 _dummy = 0; -} s_flags; - -CMorphBallTrail::CMorphBallTrail(int w, int h, const TToken& fadeTex) -: xb0_w(w), xb4_h(h), xa8_ballFade(fadeTex) -{ - m_gfxToken = CGraphics::CommitResources([this, w, h](boo::IGraphicsDataFactory::Context& ctx) - { - m_renderTex = ctx.newRenderTexture(w, h, true, false); - return true; - }); -} - -void CMorphBallTrail::GatherAreas(CStateManager& mgr) -{ - x18_areas.clear(); - for (CGameArea* area = mgr.WorldNC()->GetChainHead(EChain::Alive); - area != CWorld::GetAliveAreasEnd(); - area = area->GetNext()) - { - CGameArea::EOcclusionState occState = CGameArea::EOcclusionState::NotOccluded; - if (area->IsPostConstructed()) - occState = area->GetPostConstructed()->x10dc_occlusionState; - if (occState == CGameArea::EOcclusionState::Occluded) - x18_areas.push_back(area); - } -} - -void CMorphBallTrail::RenderToTex(const zeus::CAABox& aabb, CStateManager& mgr, CPlayer& player) -{ - xb8_ = aabb; - x0_.clear(); - x18_areas.clear(); - x30_.clear(); - s_flags.x_26_ = true; - - if (!s_flags.x_27_) - { - xd0_ = false; - return; - } - - GatherAreas(mgr); - - // TODO: finish -} - -void CMorphBallTrail::Render(CStateManager& mgr) -{ - -} - -} diff --git a/Runtime/World/CMorphBallTrail.hpp b/Runtime/World/CMorphBallTrail.hpp deleted file mode 100644 index 01608066e..000000000 --- a/Runtime/World/CMorphBallTrail.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __URDE_CMORPHBALLTRAIL_HPP__ -#define __URDE_CMORPHBALLTRAIL_HPP__ - -#include "CToken.hpp" -#include "Graphics/CTexture.hpp" -#include "zeus/CAABox.hpp" - -namespace urde -{ -class CStateManager; -class CPlayer; -class CGameArea; - -class CMorphBallTrail -{ - std::list x0_; - std::list x18_areas; - std::vector x30_; - //CTexture x40_; - boo::GraphicsDataToken m_gfxToken; - boo::ITextureR* m_renderTex; - TToken xa8_ballFade; - int xb0_w; - int xb4_h; - zeus::CAABox xb8_; - bool xd0_ = false; - void GatherAreas(CStateManager& mgr); -public: - CMorphBallTrail(int w, int h, const TToken& fadeTex); - void RenderToTex(const zeus::CAABox& aabb, CStateManager& mgr, CPlayer& player); - void Render(CStateManager& mgr); -}; - -} - -#endif // __URDE_CMORPHBALLTRAIL_HPP__ diff --git a/hecl b/hecl index c9948da59..b80547d01 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit c9948da598998fe630883639e63b4059adcd9cb3 +Subproject commit b80547d01fb70f349eb6128bd9c44921763f2821 diff --git a/specter b/specter index ccceebc33..717a6bbb1 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit ccceebc331453fd3f71440ab8f14511572e36918 +Subproject commit 717a6bbb1dd3a9dbe9ab85e58033c8ebca163a92 diff --git a/visigen/VISIBuilder.hpp b/visigen/VISIBuilder.hpp index 7a396c78a..0e0a50501 100644 --- a/visigen/VISIBuilder.hpp +++ b/visigen/VISIBuilder.hpp @@ -3,7 +3,7 @@ #include "VISIRenderer.hpp" #include "zeus/CAABox.hpp" -#include "hecl/extern/xxhash/xxhash.h" +#include "hecl/extern/boo/xxhash/xxhash.h" #include "athena/MemoryWriter.hpp" #include "hecl/hecl.hpp" #include