From d68d3c26b185b1a3b67c7553a7f0eb9a89d06670 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 7 Aug 2017 20:43:27 -1000 Subject: [PATCH 1/2] Implement HLSL CFluidPlaneShader --- .../Shaders/CFluidPlaneShaderGLSL.cpp | 5 +- .../Shaders/CFluidPlaneShaderHLSL.cpp | 478 +++++++++++++++++- .../Shaders/CFluidPlaneShaderMetal.cpp | 6 +- 3 files changed, 481 insertions(+), 8 deletions(-) diff --git a/Runtime/Graphics/Shaders/CFluidPlaneShaderGLSL.cpp b/Runtime/Graphics/Shaders/CFluidPlaneShaderGLSL.cpp index 575bb6e39..fbb652f6a 100644 --- a/Runtime/Graphics/Shaders/CFluidPlaneShaderGLSL.cpp +++ b/Runtime/Graphics/Shaders/CFluidPlaneShaderGLSL.cpp @@ -480,8 +480,7 @@ CFluidPlaneShader::BuildShader(boo::VulkanDataFactory::Context& ctx, const SFlui const char* texNames[7] = {}; std::string finalVS, finalFS; _BuildShader(finalVS, finalFS, nextTex, texNames, info); - const char* uniNames[] = {"FluidPlaneUniform", "FluidPlaneUniform", "LightingUniform"}; - return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), size_t(nextTex), texNames, 3, uniNames, + return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), s_vtxFmt, info.m_additive ? boo::BlendFactor::One : boo::BlendFactor::SrcAlpha, info.m_additive ? boo::BlendFactor::One : boo::BlendFactor::InvSrcAlpha, boo::Primitive::TriStrips, boo::ZTest::LEqual, false, true, false, @@ -556,4 +555,4 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::VulkanDataFactory: } #endif -} \ No newline at end of file +} diff --git a/Runtime/Graphics/Shaders/CFluidPlaneShaderHLSL.cpp b/Runtime/Graphics/Shaders/CFluidPlaneShaderHLSL.cpp index df35c523d..f84010322 100644 --- a/Runtime/Graphics/Shaders/CFluidPlaneShaderHLSL.cpp +++ b/Runtime/Graphics/Shaders/CFluidPlaneShaderHLSL.cpp @@ -1,4 +1,476 @@ -// -// Created by Jack Andersen on 8/6/17. -// +#include "CFluidPlaneShader.hpp" +namespace urde +{ + +static boo::IVertexFormat* s_vtxFmt = nullptr; + +static const char* VS = +"struct VertData\n" +"{\n" +" float4 posIn : POSITION;\n" +" float4 normalIn : NORMAL0;\n" +" float4 binormalIn : NORMAL1;\n" +" float4 tangentIn : NORMAL2;\n" +" float4 colorIn : COLOR;\n" +"};\n" +"\n" +"cbuffer FluidPlaneUniform : register(b0)\n" +"{\n" +" float4x4 mv;\n" +" float4x4 mvNorm;\n" +" float4x4 proj;\n" +" float4x4 texMtxs[6];\n" +"};\n" +"\n" +"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" +"VertToFrag main(in VertData v)\n" +"{\n" +" VertToFrag vtf;\n" +" vtf.mvPos = mul(mv, float4(v.posIn.xyz, 1.0));\n" +" vtf.pos = mul(proj, vtf.mvPos);\n" +" vtf.mvNorm = mul(mvNorm, v.normalIn);\n" +" vtf.mvBinorm = mul(mvNorm, v.binormalIn);\n" +" vtf.mvTangent = mul(mvNorm, v.tangentIn);\n" +" vtf.color = v.colorIn;\n" +" vtf.uvs[0] = mul(texMtxs[0], v.posIn).xy;\n" +" vtf.uvs[1] = mul(texMtxs[1], v.posIn).xy;\n" +" vtf.uvs[2] = mul(texMtxs[2], v.posIn).xy;\n" +"%s" // Additional TCGs here +" return vtf;\n" +"}\n"; + +static const char* FS = +"struct Light\n" +"{\n" +" float4 pos;\n" +" float4 dir;\n" +" float4 color;\n" +" float4 linAtt;\n" +" float4 angAtt;\n" +"};\n" +"struct Fog\n" // Reappropriated for indirect texture scaling +"{\n" +" float4 color;\n" +" float indScale;\n" +" float start;\n" +"};\n" +"\n" +"struct LightingUniform\n" +"{\n" +" Light lights[" _XSTR(URDE_MAX_LIGHTS) "];\n" +" float4 ambient;\n" +" float4 kColor0;\n" +" float4 kColor1;\n" +" float4 kColor2;\n" +" float4 kColor3;\n" +" Fog fog;\n" +"};\n" +"\n" +"static float4 LightingFunc(float4 mvPosIn, float4 mvNormIn)\n" +"{\n" +" float4 ret = ambient;\n" +" \n" +" for (int i=0 ; i<" _XSTR(URDE_MAX_LIGHTS) " ; ++i)\n" +" {\n" +" float3 delta = mvPosIn.xyz - lights[i].pos.xyz;\n" +" float dist = length(delta);\n" +" float angDot = clamp(dot(normalize(delta), lights[i].dir.xyz), 0.0, 1.0);\n" +" float att = 1.0 / (lights[i].linAtt[2] * dist * dist +\n" +" lights[i].linAtt[1] * dist +\n" +" lights[i].linAtt[0]);\n" +" float angAtt = lights[i].angAtt[2] * angDot * angDot +\n" +" lights[i].angAtt[1] * angDot +\n" +" lights[i].angAtt[0];\n" +" ret += lights[i].color * clamp(angAtt, 0.0, 1.0) * att * clamp(dot(normalize(-delta), mvNormIn.xyz), 0.0, 1.0);\n" +" }\n" +" \n" +" return clamp(ret, float4(0.0,0.0,0.0,0.0), float4(1.0,1.0,1.0,1.0));\n" +"}\n" +"\n" +"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 lighting = LightingFunc(vtf.mvPos, normalize(vtf.mvNorm));\n" +" float4 colorOut;\n" +"%s" // Combiner expression here +" return colorOut;\n" +"}\n"; + +boo::IShaderPipeline* +CFluidPlaneShader::BuildShader(boo::ID3DDataFactory::Context& ctx, const SFluidPlaneShaderInfo& 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; + int nextTCG = 3; + int nextMtx = 4; + int bumpMapUv, envBumpMapUv, envMapUv, lightmapUv; + + 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++); + if (info.m_hasBumpMap) + textures += hecl::Format("Texture2D bumpMap : register(t%d)\n", nextTex++); + if (info.m_hasEnvMap) + textures += hecl::Format("Texture2D envMap : register(t%d)\n", nextTex++); + if (info.m_hasEnvBumpMap) + textures += hecl::Format("Texture2D envBumpMap : register(t%d)\n", nextTex++); + if (info.m_hasLightmap) + textures += hecl::Format("Texture2D lightMap : register(t%d)\n", nextTex++); + + if (info.m_hasBumpMap) + { + bumpMapUv = nextTCG; + additionalTCGs += hecl::Format(" vtf.uvs[%d] = mul(texMtxs[0], v.posIn).xy;\n", nextTCG++); + } + if (info.m_hasEnvBumpMap) + { + envBumpMapUv = nextTCG; + additionalTCGs += hecl::Format(" vtf.uvs[%d] = mul(texMtxs[3], v.posIn).xy;\n", nextTCG++); + } + if (info.m_hasEnvMap) + { + envMapUv = nextTCG; + additionalTCGs += hecl::Format(" vtf.uvs[%d] = mul(texMtxs[%d], v.posIn).xy;\n", nextTCG++, nextMtx++); + } + if (info.m_hasLightmap) + { + lightmapUv = nextTCG; + additionalTCGs += hecl::Format(" vtf.uvs[%d] = mul(texMtxs[%d], v.posIn).xy;\n", nextTCG++, nextMtx++); + } + + switch (info.m_type) + { + case CFluidPlane::EFluidType::NormalWater: + case CFluidPlane::EFluidType::Three: + case CFluidPlane::EFluidType::Four: + if (info.m_hasLightmap) + { + combiner += hecl::Format(" float4 lightMapTexel = lightMap.Sample(samp, vtf.uvs[%d]);\n", lightmapUv); + // 0: Tex4TCG, Tex4, doubleLightmapBlend ? NULL : GX_COLOR1A1 + // ZERO, TEX, KONST, doubleLightmapBlend ? ZERO : RAS + // Output reg 2 + // KColor 2 + if (info.m_doubleLightmapBlend) + { + // 1: Tex4TCG2, Tex4, GX_COLOR1A1 + // C2, TEX, KONST, RAS + // Output reg 2 + // KColor 3 + // Tex * K2 + Lighting + combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n"; + } + else + { + // mix(Tex * K2, Tex, K3) + Lighting + combiner += " lighting += lightMapTexel * lu.kColor2;\n"; + } + } + + // Next: Tex0TCG, Tex0, GX_COLOR1A1 + // ZERO, TEX, KONST, RAS + // Output reg prev + // KColor 0 + + // Next: Tex1TCG, Tex1, GX_COLOR0A0 + // ZERO, TEX, PREV, RAS + // Output reg prev + + // Next: Tex2TCG, Tex2, GX_COLOR1A1 + // ZERO, TEX, hasTex4 ? C2 : RAS, PREV + // Output reg prev + + // (Tex0 * kColor0 + Lighting) * Tex1 + VertColor + Tex2 * Lighting + if (info.m_hasPatternTex2) + { + if (info.m_hasPatternTex1) + combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.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"; + } + else + { + combiner += " colorOut = vtf.color;\n"; + } + + + if (info.m_hasColorTex && !info.m_hasEnvMap && info.m_hasEnvBumpMap) + { + // 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); + combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n"; + } + else if (info.m_hasEnvMap) + { + // Next: envTCG, envTex, NULL + // PREV, TEX, KONST, ZERO + // Output reg prev + // KColor 1 + + // Make previous stage indirect, mtx0 + 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", + envMapUv); + } + else if (info.m_hasColorTex) + { + combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]) * lighting;\n"; + } + + break; + + case CFluidPlane::EFluidType::PoisonWater: + if (info.m_hasLightmap) + { + combiner += hecl::Format(" float4 lightMapTexel = lightMap.Sample(samp, vtf.uvs[%d]);\n", lightmapUv); + // 0: Tex4TCG, Tex4, doubleLightmapBlend ? NULL : GX_COLOR1A1 + // ZERO, TEX, KONST, doubleLightmapBlend ? ZERO : RAS + // Output reg 2 + // KColor 2 + if (info.m_doubleLightmapBlend) + { + // 1: Tex4TCG2, Tex4, GX_COLOR1A1 + // C2, TEX, KONST, RAS + // Output reg 2 + // KColor 3 + // Tex * K2 + Lighting + combiner += " lighting += mix(lightMapTexel * lu.kColor2, lightMapTexel, lu.kColor3);\n"; + } + else + { + // mix(Tex * K2, Tex, K3) + Lighting + combiner += " lighting += lightMapTexel * lu.kColor2;\n"; + } + } + + // Next: Tex0TCG, Tex0, GX_COLOR1A1 + // ZERO, TEX, KONST, RAS + // Output reg prev + // KColor 0 + + // Next: Tex1TCG, Tex1, GX_COLOR0A0 + // ZERO, TEX, PREV, RAS + // Output reg prev + + // Next: Tex2TCG, Tex2, GX_COLOR1A1 + // ZERO, TEX, hasTex4 ? C2 : RAS, PREV + // Output reg prev + + // (Tex0 * kColor0 + Lighting) * Tex1 + VertColor + Tex2 * Lighting + if (info.m_hasPatternTex2) + { + if (info.m_hasPatternTex1) + combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.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"; + } + else + { + combiner += " colorOut = vtf.color;\n"; + } + + if (info.m_hasColorTex) + { + if (info.m_hasEnvBumpMap) + { + // 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); + combiner += " colorOut += colorTex.Sample(samp, indUvs + vtf.uvs[2]) * lighting;\n"; + } + else + { + combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]) * lighting;\n"; + } + } + + break; + + case CFluidPlane::EFluidType::Lava: + // 0: Tex0TCG, Tex0, GX_COLOR0A0 + // ZERO, TEX, KONST, RAS + // Output reg prev + // KColor 0 + + // 1: Tex1TCG, Tex1, GX_COLOR0A0 + // ZERO, TEX, PREV, RAS + // Output reg prev + + // 2: Tex2TCG, Tex2, NULL + // ZERO, TEX, ONE, PREV + // Output reg prev + + // (Tex0 * kColor0 + VertColor) * Tex1 + VertColor + Tex2 + if (info.m_hasPatternTex2) + { + if (info.m_hasPatternTex1) + combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.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"; + } + else + { + combiner += " colorOut = vtf.color;\n"; + } + + if (info.m_hasColorTex) + combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]);\n"; + + if (info.m_hasBumpMap) + { + // 3: bumpMapTCG, bumpMap, NULL + // ZERO, TEX, ONE, HALF + // Output reg 0, no clamp, no bias + + // 4: bumpMapTCG2, bumpMap, NULL + // ZERO, TEX, ONE, C0 + // Output reg 0, subtract, clamp, no bias + + combiner += " float3 lightVec = lights[3].pos.xyz - vtf.mvPos.xyz;\n" + " float lx = dot(vtf.mvTangent.xyz, lightVec);\n" + " float ly = dot(vtf.mvBinorm.xyz, lightVec);\n"; + combiner += hecl::Format(" float4 emboss1 = bumpMap.Sample(samp, vtf.uvs[%d]) + float4(0.5);\n" + " float4 emboss2 = bumpMap.Sample(samp, vtf.uvs[%d] + float2(lx, ly));\n", + bumpMapUv, bumpMapUv); + + // 5: NULL, NULL, NULL + // ZERO, PREV, C0, ZERO + // Output reg prev, scale 2, clamp + + // colorOut * clamp(emboss1 + 0.5 - emboss2, 0.0, 1.0) * 2.0 + combiner += "colorOut *= clamp((emboss1 + float4(0.5) - emboss2) * float4(2.0), float4(0.0), float4(1.0));\n"; + } + + break; + + case CFluidPlane::EFluidType::Five: + // 0: Tex0TCG, Tex0, GX_COLOR0A0 + // ZERO, TEX, KONST, RAS + // Output reg prev + // KColor 0 + + // 1: Tex1TCG, Tex1, GX_COLOR0A0 + // ZERO, TEX, PREV, RAS + // Output reg prev + + // 2: Tex2TCG, Tex2, NULL + // ZERO, TEX, ONE, PREV + // Output reg prev + + // (Tex0 * kColor0 + VertColor) * Tex1 + VertColor + Tex2 + if (info.m_hasPatternTex2) + { + if (info.m_hasPatternTex1) + combiner += " colorOut = (patternTex1.Sample(samp, vtf.uvs[0]) * lu.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"; + } + else + { + combiner += " colorOut = vtf.color;\n"; + } + + if (info.m_hasColorTex) + combiner += " colorOut += colorTex.Sample(samp, vtf.uvs[2]);\n"; + + if (info.m_hasBumpMap) + { + // 3: bumpMapTCG, bumpMap, NULL + // ZERO, TEX, PREV, ZERO + // Output reg prev, scale 2 + combiner += hecl::Format(" float4 emboss1 = bumpMap.Sample(samp, vtf.uvs[%d]) + float4(0.5);\n", bumpMapUv); + combiner += "colorOut *= emboss1 * float4(2.0);\n"; + } + + break; + } + + combiner += " colorOut.a = kColor0.a;\n"; + + std::string finalVS = hecl::Format(VS, additionalTCGs.c_str()); + std::string finalFS = hecl::Format(FS, textures.c_str(), combiner.c_str()); + + return ctx.newShaderPipeline(finalVS.c_str(), finalFS.c_str(), nullptr, nullptr, nullptr, s_vtxFmt, + info.m_additive ? boo::BlendFactor::One : boo::BlendFactor::SrcAlpha, + info.m_additive ? boo::BlendFactor::One : 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::IGraphicsBuffer* ubufs[] = { m_uniBuf, m_uniBuf, m_uniBuf }; + boo::PipelineStage ubufStages[] = { boo::PipelineStage::Vertex, boo::PipelineStage::Vertex, + boo::PipelineStage::Fragment }; + size_t ubufOffs[] = {0, 0, 768}; + size_t ubufSizes[] = {768, 768, 256}; + size_t texCount = 0; + boo::ITexture* texs[7] = {}; + 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(); + return ctx.newShaderDataBinding(pipeline, s_vtxFmt, m_vbo, nullptr, nullptr, 1, ubufs, ubufStages, ubufOffs, + ubufSizes, texCount, texs, nullptr, nullptr); +} + +} diff --git a/Runtime/Graphics/Shaders/CFluidPlaneShaderMetal.cpp b/Runtime/Graphics/Shaders/CFluidPlaneShaderMetal.cpp index e4610184f..78708bf9d 100644 --- a/Runtime/Graphics/Shaders/CFluidPlaneShaderMetal.cpp +++ b/Runtime/Graphics/Shaders/CFluidPlaneShaderMetal.cpp @@ -27,6 +27,7 @@ static const char* VS = "\n" "struct VertToFrag\n" "{\n" +" float4 pos : [[ position ]];\n" " float4 mvPos;\n" " float4 mvNorm;\n" " float4 mvBinorm;\n" @@ -40,7 +41,7 @@ static const char* VS = "{\n" " VertToFrag vtf;\n" " vtf.mvPos = fu.mv * float4(v.posIn.xyz, 1.0);\n" -" gl_Position = fu.proj * vtf.mvPos;\n" +" vtf.pos = fu.proj * vtf.mvPos;\n" " vtf.mvNorm = fu.mvNorm * v.normalIn;\n" " vtf.mvBinorm = fu.mvNorm * v.binormalIn;\n" " vtf.mvTangent = fu.mvNorm * v.tangentIn;\n" @@ -106,6 +107,7 @@ static const char* FS = "\n" "struct VertToFrag\n" "{\n" +" float4 pos : [[ position ]];\n" " float4 mvPos;\n" " float4 mvNorm;\n" " float4 mvBinorm;\n" @@ -477,4 +479,4 @@ boo::IShaderDataBinding* CFluidPlaneShader::BuildBinding(boo::MetalDataFactory:: ubufSizes, texCount, texs, nullptr, nullptr); } -} \ No newline at end of file +} From ecff2b7f8dfb90a15322eb761ad026e6898bcaad Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 8 Aug 2017 15:12:14 -0700 Subject: [PATCH 2/2] Implement WorldTeleporter and SpiderBallWaypoint --- Editor/main.cpp | 4 +- Runtime/CObjectList.hpp | 14 ++ Runtime/CRandom16.hpp | 6 +- Runtime/CStateManager.hpp | 2 + Runtime/GuiSys/CConsoleOutputWindow.cpp | 1 + Runtime/IMain.hpp | 1 + Runtime/World/CAnimationParameters.hpp | 2 +- Runtime/World/CFluidUVMotion.cpp | 2 +- Runtime/World/CMakeLists.txt | 1 + Runtime/World/CScriptSpiderBallWaypoint.cpp | 94 +++++++++++++ Runtime/World/CScriptSpiderBallWaypoint.hpp | 32 +++++ Runtime/World/CScriptWorldTeleporter.cpp | 143 +++++++++++++++++++- Runtime/World/CScriptWorldTeleporter.hpp | 59 +++++--- Runtime/World/CWorldTransManager.cpp | 15 ++ Runtime/World/CWorldTransManager.hpp | 17 ++- Runtime/World/ScriptLoader.cpp | 44 +++++- 16 files changed, 402 insertions(+), 35 deletions(-) diff --git a/Editor/main.cpp b/Editor/main.cpp index 8ed560e4d..d6070480d 100644 --- a/Editor/main.cpp +++ b/Editor/main.cpp @@ -32,7 +32,7 @@ struct Application : boo::IApplicationCallback m_fileMgr(_S("urde")), m_cvarManager(m_fileMgr) { - m_viewManager.reset(new ViewManager(m_fileMgr, m_cvarManager)); + m_viewManager = std::make_unique(m_fileMgr, m_cvarManager); } virtual ~Application() = default; @@ -74,7 +74,7 @@ struct Application : boo::IApplicationCallback zeus::detectCPU(); for (const boo::SystemString& arg : app->getArgs()) { - if (arg.find(_S("--verbosity=")) == 0) + if (arg.find(_S("--verbosity=")) == 0 || arg.find(_S("-v=")) == 0) { hecl::SystemUTF8View utf8Arg(arg.substr(arg.find_last_of('=') + 1)); hecl::VerbosityLevel = atoi(utf8Arg.c_str()); diff --git a/Runtime/CObjectList.hpp b/Runtime/CObjectList.hpp index 8678469bb..ea424a96d 100644 --- a/Runtime/CObjectList.hpp +++ b/Runtime/CObjectList.hpp @@ -49,6 +49,20 @@ public: iterator begin() { return iterator(*this, x2008_firstId); } iterator end() { return iterator(*this, kInvalidUniqueId); } + class const_iterator + { + friend class CObjectList; + const CObjectList& m_list; + TUniqueId m_id; + const_iterator(const CObjectList& list, TUniqueId id) : m_list(list), m_id(id) {} + public: + const_iterator& operator++() { m_id = m_list.GetNextObjectIndex(m_id); return *this; } + bool operator!=(const iterator& other) const { return m_id != other.m_id; } + const CEntity* operator*() const { return m_list.GetObjectById(m_id); } + }; + const_iterator cbegin() const { return const_iterator(*this, x2008_firstId); } + const_iterator cend() const { return const_iterator(*this, kInvalidUniqueId); } + CObjectList(EGameObjectList listEnum); void AddObject(CEntity& entity); diff --git a/Runtime/CRandom16.hpp b/Runtime/CRandom16.hpp index aa055ac38..e14558f91 100644 --- a/Runtime/CRandom16.hpp +++ b/Runtime/CRandom16.hpp @@ -33,7 +33,7 @@ public: inline float Float() { - return Next() * 0.000015259022; + return Next() * 0.000015259022f; } inline float Range(float min, float max) @@ -43,9 +43,7 @@ public: inline s32 Range(s32 min, s32 max) { - s32 rnd = Next(); - s32 diff = (max - min) + 1; - return min + (rnd - ((rnd / diff) * diff)); + return min + (Next() % ((max - min) + 1)); } static CRandom16* GetRandomNumber() {return g_randomNumber;} diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index c3d67d658..873f36d60 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -405,6 +405,7 @@ public: ResId GetPauseHUDMessage() const { return xf08_pauseHudMessage; } void IncrementHUDMessageFrameCounter() { ++xf80_hudMessageFrameCount; } bool ShouldQuitGame() const { return xf94_25_quitGame; } + void SetShouldQuitGame(bool should) { xf94_25_quitGame = should; } void SetInSaveUI(bool b) { xf94_28_inSaveUI = b; } void SetInMapScreen(bool b) { xf94_27_inMapScreen = b; } bool GetInMapScreen() const { return xf94_27_inMapScreen; } @@ -427,6 +428,7 @@ public: CActorModelParticles* GetActorModelParticles() const { return x884_actorModelParticles; } const std::shared_ptr& MapWorldInfo() const { return x8c0_mapWorldInfo; } + const std::shared_ptr& WorldTransManager() const { return x8c4_worldTransManager; } const std::shared_ptr& LayerState() const { return x8c8_worldLayerState; } CPlayer& GetPlayer() const { return *x84c_player; } diff --git a/Runtime/GuiSys/CConsoleOutputWindow.cpp b/Runtime/GuiSys/CConsoleOutputWindow.cpp index b86f5c10b..f547af5c3 100644 --- a/Runtime/GuiSys/CConsoleOutputWindow.cpp +++ b/Runtime/GuiSys/CConsoleOutputWindow.cpp @@ -1,4 +1,5 @@ #include "CConsoleOutputWindow.hpp" +#include "Graphics/CGraphics.hpp" namespace urde { diff --git a/Runtime/IMain.hpp b/Runtime/IMain.hpp index c31eb75ca..98ad3e246 100644 --- a/Runtime/IMain.hpp +++ b/Runtime/IMain.hpp @@ -41,6 +41,7 @@ public: virtual bool Proc()=0; virtual void Shutdown()=0; virtual boo::IWindow* GetMainWindow() const=0; + virtual void SetFlowState(EFlowState) = 0; }; } diff --git a/Runtime/World/CAnimationParameters.hpp b/Runtime/World/CAnimationParameters.hpp index d0a3748e9..1802ba2c8 100644 --- a/Runtime/World/CAnimationParameters.hpp +++ b/Runtime/World/CAnimationParameters.hpp @@ -20,7 +20,7 @@ public: x4_charIdx(in.readUint32Big()), x8_defaultAnim(in.readUint32Big()) {} - u32 GetACSFile() const { return x0_ancs; } + ResId GetACSFile() const { return x0_ancs; } u32 GetCharacter() const { return x4_charIdx; } u32 GetInitialAnimation() const { return x8_defaultAnim; } void SetCharacter(u32 charIdx) { x4_charIdx = charIdx; } diff --git a/Runtime/World/CFluidUVMotion.cpp b/Runtime/World/CFluidUVMotion.cpp index 3d824f70a..a5fd37711 100644 --- a/Runtime/World/CFluidUVMotion.cpp +++ b/Runtime/World/CFluidUVMotion.cpp @@ -55,7 +55,7 @@ void CFluidUVMotion::CalculateFluidTextureOffset(float f31, float offsets[3][2]) float y = f27 * zeus::fastSinF(layer.x8_b) + (f26 * zeus::fastCosF(layer.x8_b) + f28); offsets[i][0] = float(x - floor(x)); - offsets[i][1] = float(y - floor(y)); + offsets[i][1] = float(y - floor(y)); } } } diff --git a/Runtime/World/CMakeLists.txt b/Runtime/World/CMakeLists.txt index a89ca2eba..467864175 100644 --- a/Runtime/World/CMakeLists.txt +++ b/Runtime/World/CMakeLists.txt @@ -53,6 +53,7 @@ set(WORLD_SOURCES CScriptWorldTeleporter.hpp CScriptWorldTeleporter.cpp CScriptCameraWaypoint.hpp CScriptCameraWaypoint.cpp CScriptCoverPoint.hpp CScriptCoverPoint.cpp + CScriptSpiderBallWaypoint.hpp CScriptSpiderBallWaypoint.cpp CScriptSpawnPoint.hpp CScriptSpawnPoint.cpp CScriptCameraHint.hpp CScriptCameraHint.cpp CScriptPickup.hpp CScriptPickup.cpp diff --git a/Runtime/World/CScriptSpiderBallWaypoint.cpp b/Runtime/World/CScriptSpiderBallWaypoint.cpp index e69de29bb..63b6c0282 100644 --- a/Runtime/World/CScriptSpiderBallWaypoint.cpp +++ b/Runtime/World/CScriptSpiderBallWaypoint.cpp @@ -0,0 +1,94 @@ +#include "CScriptSpiderBallWaypoint.hpp" +#include "CActorParameters.hpp" +#include "CStateManager.hpp" +#include "TCastTo.hpp" + +namespace urde +{ +CScriptSpiderBallWaypoint::CScriptSpiderBallWaypoint(TUniqueId uid, const std::string& name, const CEntityInfo& info, + const zeus::CTransform& xf, bool active, u32 w1) +: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::Unknown), + CActorParameters::None(), kInvalidUniqueId) +, xe8_(w1) +{ + +} + +void CScriptSpiderBallWaypoint::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptSpiderBallWaypoint::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) +{ + CActor::AcceptScriptMsg(msg, uid, mgr); + + if (msg == EScriptObjectMessage::InitializedInArea) + BuildWaypointListAndBounds(mgr); + else if (msg == EScriptObjectMessage::UNKM2) + SendScriptMsgs(EScriptObjectState::Arrived, mgr, EScriptObjectMessage::None); +} + +void CScriptSpiderBallWaypoint::AccumulateBounds(const zeus::CVector3f& v) +{ + if (!xfc_aabox) + xfc_aabox.emplace(v, v); + xfc_aabox->accumulateBounds(v); +} + +void CScriptSpiderBallWaypoint::BuildWaypointListAndBounds(CStateManager& mgr) +{ + u32 validConnections = 0; + for (const SConnection& conn : x20_conns) + { + if (conn.x0_state == EScriptObjectState::Arrived && conn.x4_msg == EScriptObjectMessage::Next) + { + TUniqueId uid = mgr.GetIdForScript(conn.x8_objId); + if (uid != kInvalidUniqueId) + { + static_cast(mgr.ObjectById(uid))->AddPreviousWaypoint(GetUniqueId()); + ++validConnections; + } + } + } + + if (validConnections == 0) + AccumulateBounds(x34_transform.origin); + else + { + CScriptSpiderBallWaypoint* curWaypoint = this; + TUniqueId uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); + while (uid != kInvalidUniqueId) + { + curWaypoint = static_cast(mgr.ObjectById(uid)); + uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); + } + + curWaypoint->AccumulateBounds(x34_transform.origin); + } +} + +void CScriptSpiderBallWaypoint::AddPreviousWaypoint(TUniqueId uid) +{ + xec_waypoints.push_back(uid); +} + +TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) +{ + for (const SConnection& conn : x20_conns) + { + if (conn.x0_state == EScriptObjectState::Arrived && conn.x4_msg == EScriptObjectMessage::Next) + { + TUniqueId uid = mgr.GetIdForScript(conn.x8_objId); + if (uid != kInvalidUniqueId) + { + const CEntity* ent = mgr.GetObjectById(uid); + if (ent && checkActive == ECheckActiveWaypoint::Yes && ent->GetActive()) + return ent->GetUniqueId(); + } + } + } + + return kInvalidUniqueId; +} +} diff --git a/Runtime/World/CScriptSpiderBallWaypoint.hpp b/Runtime/World/CScriptSpiderBallWaypoint.hpp index e69de29bb..de49a15bf 100644 --- a/Runtime/World/CScriptSpiderBallWaypoint.hpp +++ b/Runtime/World/CScriptSpiderBallWaypoint.hpp @@ -0,0 +1,32 @@ +#ifndef __URDE_CSCRIPTSPIDERBALLWAYPOINT_HPP__ +#define __URDE_CSCRIPTSPIDERBALLWAYPOINT_HPP__ + +#include "CActor.hpp" + +namespace urde +{ +class CScriptSpiderBallWaypoint : public CActor +{ + enum class ECheckActiveWaypoint + { + No, + Yes + }; + u32 xe8_; + std::vector xec_waypoints; + std::experimental::optional xfc_aabox; +public: + CScriptSpiderBallWaypoint(TUniqueId, const std::string&, const CEntityInfo&, const zeus::CTransform&, bool, u32); + void Accept(IVisitor&); + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); + void Render(const CStateManager& mgr) const { CActor::Render(mgr); } + void AddToRenderer(const zeus::CFrustum&, const CStateManager&) {} + std::experimental::optional GetTouchBounds() const { return xfc_aabox; } + void AccumulateBounds(const zeus::CVector3f&); + void BuildWaypointListAndBounds(CStateManager&); + void AddPreviousWaypoint(TUniqueId); + TUniqueId NextWaypoint(const CStateManager&, ECheckActiveWaypoint); +}; +} + +#endif // __URDE_CSCRIPTSPIDERBALLWAYPOINT_HPP__ \ No newline at end of file diff --git a/Runtime/World/CScriptWorldTeleporter.cpp b/Runtime/World/CScriptWorldTeleporter.cpp index dfeaa9d24..d5a505862 100644 --- a/Runtime/World/CScriptWorldTeleporter.cpp +++ b/Runtime/World/CScriptWorldTeleporter.cpp @@ -1,10 +1,151 @@ #include "CScriptWorldTeleporter.hpp" +#include "CStateManager.hpp" +#include "CWorldTransManager.hpp" +#include "CWorld.hpp" +#include "CGameState.hpp" +#include "IMain.hpp" +#include "TCastTo.hpp" namespace urde { CScriptWorldTeleporter::CScriptWorldTeleporter(TUniqueId uid, const std::string& name, const CEntityInfo& info, - bool active, u32, u32) + bool active, ResId worldId, ResId areaId) : CEntity(uid, info, active, name) +, x34_worldId(worldId) +, x38_areaId(areaId) +, x3c_type(ETeleporterType::NoTransition) +, x40_24_upElevator(false) +, x40_25_inTransition(false) +, x40_27_fadeWhite(false) { } + +CScriptWorldTeleporter::CScriptWorldTeleporter(TUniqueId uid, const std::string& name, const CEntityInfo& info, + bool active, ResId worldId, ResId areaId, + ResId playerAncs, u32 charIdx, u32 defaultAnim, + const zeus::CVector3f& playerScale, ResId platformModel, + const zeus::CVector3f& platformScale, ResId backgroundModel, + const zeus::CVector3f& backgroundScale, bool upElevator, u16 soundId, + u8 volume, u8 panning) +: CEntity(uid, info, active, name) +, x34_worldId(worldId) +, x38_areaId(areaId) +, x3c_type(ETeleporterType::Elevator) +, x40_24_upElevator(upElevator) +, x40_25_inTransition(false) +, x40_27_fadeWhite(false) +, x50_playerAnim(playerAncs, charIdx, defaultAnim) +, x5c_playerScale(playerScale) +, x68_platformModel(platformModel) +, x6c_platformScale(platformScale) +, x78_backgroundModel(backgroundModel) +, x7c_backgroundScale(backgroundScale) +, x88_soundId(CSfxManager::TranslateSFXID(soundId)) +, x8a_volume(volume) +, x8b_panning(panning) +{ +} + +CScriptWorldTeleporter::CScriptWorldTeleporter(TUniqueId uid, const std::string& name, const CEntityInfo& info, + bool active, ResId worldId, ResId areaId, u16 soundId, u8 volume, + u8 panning, ResId fontId, ResId stringId, bool fadeWhite, + float charFadeIn, float charsPerSecond, float showDelay) +: CEntity(uid, info, active, name) +, x34_worldId(worldId) +, x38_areaId(areaId) +, x3c_type(ETeleporterType::Text) +, x40_24_upElevator(false) +, x40_25_inTransition(false) +, x40_27_fadeWhite(fadeWhite) +, x44_charFadeIn(charFadeIn) +, x48_charsPerSecond(charsPerSecond) +, x4c_showDelay(showDelay) +, x88_soundId(CSfxManager::TranslateSFXID(soundId)) +, x8a_volume(volume) +, x8b_panning(panning) +, x8c_fontId(fontId) +, x90_stringId(stringId) +{ +} + +void CScriptWorldTeleporter::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptWorldTeleporter::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) +{ + if (GetActive()) + { + const std::shared_ptr& transMgr = mgr.WorldTransManager(); + switch(msg) + { + case EScriptObjectMessage::Stop: + x40_25_inTransition = false; + transMgr->DisableTransition(); + transMgr->SfxStop(); + break; + case EScriptObjectMessage::Play: + StartTransition(mgr); + transMgr->SetSfx(x88_soundId, x8a_volume, x8b_panning); + transMgr->SfxStart(); + break; + case EScriptObjectMessage::SetToZero: + { + const auto& world = mgr.WorldNC(); + world->SetPauseState(true); + ResId currentWorld = g_GameState->CurrentWorldAssetId(); + + if (g_ResFactory->GetResourceTypeById(currentWorld) == SBIG('MLVL')) + { + StartTransition(mgr); + g_GameState->SetCurrentWorldId(x34_worldId); + g_GameState->CurrentWorldState().SetDesiredAreaAssetId(x38_areaId); + g_Main->SetFlowState(EFlowState::None); + mgr.SetShouldQuitGame(true); + } + else + { + x40_25_inTransition = false; + transMgr->DisableTransition(); + g_GameState->SetCurrentWorldId(currentWorld); + } + break; + } + default: + break; + } + } + CEntity::AcceptScriptMsg(msg, uid, mgr); +} + +void CScriptWorldTeleporter::StartTransition(CStateManager& mgr) +{ + if (!x40_25_inTransition) + { + const auto& transMgr = mgr.WorldTransManager(); + switch(x3c_type) + { + case ETeleporterType::NoTransition: + transMgr->DisableTransition(); + break; + case ETeleporterType::Elevator: + if (x50_playerAnim.GetACSFile() != kInvalidResId && x50_playerAnim.GetCharacter() != -1) + { + transMgr->EnableTransition(CAnimRes(x50_playerAnim.GetACSFile(), x50_playerAnim.GetCharacter(), + x5c_playerScale, x50_playerAnim.GetInitialAnimation(),true), + x68_platformModel, x6c_platformScale, x78_backgroundModel, + x7c_backgroundScale, x40_24_upElevator); + x40_25_inTransition = true; + } + break; + case ETeleporterType::Text: + transMgr->EnableTransition(x8c_fontId, x90_stringId, 0, x40_27_fadeWhite, x44_charFadeIn, x48_charsPerSecond, + x4c_showDelay); + x40_25_inTransition = true; + break; + } + } +} + } diff --git a/Runtime/World/CScriptWorldTeleporter.hpp b/Runtime/World/CScriptWorldTeleporter.hpp index 43e91b774..d275fc61b 100644 --- a/Runtime/World/CScriptWorldTeleporter.hpp +++ b/Runtime/World/CScriptWorldTeleporter.hpp @@ -2,6 +2,7 @@ #define __CSCRIPTWORLDTELEPORTER_HPP__ #include "CEntity.hpp" +#include "CAnimationParameters.hpp" #include "zeus/CVector3f.hpp" namespace urde @@ -9,36 +10,52 @@ namespace urde class CScriptWorldTeleporter : public CEntity { - u32 x34_; - u32 x38_; - u32 x3c_ = 0; + enum class ETeleporterType + { + NoTransition, + Elevator, + Text + }; + + ResId x34_worldId; + ResId x38_areaId; + ETeleporterType x3c_type = ETeleporterType::NoTransition; union { struct { - bool x40_24_ : 1; - bool x40_25_ : 1; - bool x40_26_ : 1; - bool x40_27_ : 1; + bool x40_24_upElevator : 1; + bool x40_25_inTransition : 1; + bool x40_27_fadeWhite : 1; }; u8 _dummy = 0; }; - float x44_ = 0.1f; - float x48_ = 8.0f; - float x4c_ = 0.0f; - u32 x50_ = -1; - u32 x54_ = -1; - u32 x58_ = 0; - zeus::CVector3f x5c_; - u32 x68_ = -1; - zeus::CVector3f x6c_; - u32 x78_ = -1; - zeus::CVector3f x7c_; - u32 x88_ = -1; - + float x44_charFadeIn = 0.1f; + float x48_charsPerSecond = 8.0f; + float x4c_showDelay = 0.0f; + CAnimationParameters x50_playerAnim; + zeus::CVector3f x5c_playerScale; + ResId x68_platformModel = kInvalidResId; + zeus::CVector3f x6c_platformScale; + ResId x78_backgroundModel = kInvalidResId; + zeus::CVector3f x7c_backgroundScale; + u16 x88_soundId = -1; + u8 x8a_volume = 0; + u8 x8b_panning = 0; + ResId x8c_fontId; + ResId x90_stringId; public: - CScriptWorldTeleporter(TUniqueId, const std::string&, const CEntityInfo&, bool, u32, u32); + CScriptWorldTeleporter(TUniqueId, const std::string&, const CEntityInfo&, bool, ResId, ResId); + CScriptWorldTeleporter(TUniqueId, const std::string&, const CEntityInfo&, bool, ResId, ResId, u16, u8, u8, ResId, + ResId, bool, float, float, float); + CScriptWorldTeleporter(TUniqueId, const std::string&, const CEntityInfo&, bool, ResId, ResId, ResId, u32, u32, + const zeus::CVector3f&, ResId, const zeus::CVector3f&, ResId, const zeus::CVector3f&, bool, + u16, u8, u8); + + void Accept(IVisitor&); + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr); + void StartTransition(CStateManager&); }; } diff --git a/Runtime/World/CWorldTransManager.cpp b/Runtime/World/CWorldTransManager.cpp index bb1528366..eafb98213 100644 --- a/Runtime/World/CWorldTransManager.cpp +++ b/Runtime/World/CWorldTransManager.cpp @@ -487,4 +487,19 @@ bool CWorldTransManager::WaitForModelsAndTextures() return true; } +void CWorldTransManager::SfxStop() +{ + if (x28_sfxHandle) + { + CSfxManager::SfxStop(x28_sfxHandle); + x28_sfxHandle.reset(); + } +} + +void CWorldTransManager::SfxStart() +{ + if (!x28_sfxHandle && x24_sfx != 0xFFFF) + x28_sfxHandle = CSfxManager::SfxStart(x24_sfx, x2c_volume, x2d_panning, false, 127, true, -1); +} + } diff --git a/Runtime/World/CWorldTransManager.hpp b/Runtime/World/CWorldTransManager.hpp index e50100c1c..daa3b4655 100644 --- a/Runtime/World/CWorldTransManager.hpp +++ b/Runtime/World/CWorldTransManager.hpp @@ -9,6 +9,7 @@ #include "Graphics/Shaders/CColoredQuadFilter.hpp" #include "Graphics/Shaders/CTexturedQuadFilter.hpp" #include "Graphics/Shaders/CCameraBlurFilter.hpp" +#include "Audio/CSfxManager.hpp" namespace urde { @@ -60,10 +61,10 @@ private: float x18_bgOffset; float x1c_bgHeight; CRandom16 x20_random = CRandom16(99); - u16 x24_ = 1189; - u32 x28_ = 0; - u8 x2c_ = 127; - u8 x2d_ = 64; + u16 x24_sfx = 1189; + CSfxHandle x28_sfxHandle; + u8 x2c_volume = 127; + u8 x2d_panning = 64; ETransType x30_type = ETransType::Disabled; float x34_stopTime; float x38_textStartTime = 0.f; @@ -121,6 +122,14 @@ public: void DisableTransition(); void TouchModels(); ETransType GetTransType() { return x30_type; } + void SetSfx(u16 sfx, u8 volume, u8 panning) + { + x24_sfx = sfx; + x2c_volume = volume; + x2d_panning = panning; + } + void SfxStart(); + void SfxStop(); static bool WaitForModelsAndTextures(); }; diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index a02b01834..c87084a2f 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -59,6 +59,7 @@ #include "CScriptCameraPitchVolume.hpp" #include "CScriptCameraHintTrigger.hpp" #include "CScriptVisorFlare.hpp" +#include "CScriptWorldTeleporter.hpp" #include "CScriptBeam.hpp" #include "CScriptMazeNode.hpp" #include "Camera/CCinematicCamera.hpp" @@ -1847,7 +1848,48 @@ CEntity* ScriptLoader::LoadVisorFlare(CStateManager& mgr, CInputStream& in, int CEntity* ScriptLoader::LoadWorldTeleporter(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (propCount < 4 || propCount > 21) + { + Log.report(logvisor::Warning, "Incorrect number of props for WorldTeleporter"); + return nullptr; + } + + std::string name = mgr.HashInstanceName(in); + bool active = in.readBool(); + ResId worldId = in.readUint32Big(); + ResId areaId = in.readUint32Big(); + + if (propCount == 4) + return new CScriptWorldTeleporter(mgr.AllocateUniqueId(), name, info, active, worldId, areaId); + + CAnimationParameters animParms = LoadAnimationParameters(in); + zeus::CVector3f playerScale = zeus::CVector3f::ReadBig(in); + ResId platformModel = in.readUint32Big(); + zeus::CVector3f platformScale = zeus::CVector3f::ReadBig(in); + ResId backgroundModel = in.readUint32Big(); + zeus::CVector3f backgroundScale = zeus::CVector3f::ReadBig(in); + bool upElevator = in.readBool(); + + s16 elevatorSound = (propCount < 12 ? s16(-1) : s16(in.readUint32Big())); + u8 volume = (propCount < 13 ? u8(127) : u8(in.readUint32Big())); + u8 panning = (propCount < 14 ? u8(64) : u8(in.readUint32Big())); + bool showText = (propCount < 15 ? false : in.readBool()); + ResId fontId = (propCount < 16 ? kInvalidResId : in.readUint32Big()); + ResId stringId = (propCount < 17 ? kInvalidResId : in.readUint32Big()); + bool fadeWhite = (propCount < 18 ? false : in.readBool()); + float charFadeInTime = (propCount < 19 ? 0.1f : in.readFloatBig()); + float charsPerSecond = (propCount < 20 ? 16.f : in.readFloatBig()); + float showDelay = (propCount < 21 ? 0.f : in.readFloatBig()); + + if (showText) + return new CScriptWorldTeleporter(mgr.AllocateUniqueId(), name, info, active, worldId, areaId, elevatorSound, + volume, panning, fontId, stringId, fadeWhite, charFadeInTime, charsPerSecond, + showDelay); + + return new CScriptWorldTeleporter(mgr.AllocateUniqueId(), name, info, active, worldId, areaId, + animParms.GetACSFile(), animParms.GetCharacter(), + animParms.GetInitialAnimation(), playerScale, platformModel, platformScale, + backgroundModel, backgroundScale, upElevator, elevatorSound, volume, panning); } CEntity* ScriptLoader::LoadVisorGoo(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)