This commit is contained in:
Jack Andersen 2017-08-09 21:06:12 -10:00
commit 39fd2be286
19 changed files with 883 additions and 43 deletions

View File

@ -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<ViewManager>(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());

View File

@ -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);

View File

@ -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;}

View File

@ -406,6 +406,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; }
@ -428,6 +429,7 @@ public:
CActorModelParticles* GetActorModelParticles() const { return x884_actorModelParticles; }
const std::shared_ptr<CMapWorldInfo>& MapWorldInfo() const { return x8c0_mapWorldInfo; }
const std::shared_ptr<CWorldTransManager>& WorldTransManager() const { return x8c4_worldTransManager; }
const std::shared_ptr<CWorldLayerState>& LayerState() const { return x8c8_worldLayerState; }
CPlayer& GetPlayer() const { return *x84c_player; }

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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"

View File

@ -1,4 +1,5 @@
#include "CConsoleOutputWindow.hpp"
#include "Graphics/CGraphics.hpp"
namespace urde
{

View File

@ -41,6 +41,7 @@ public:
virtual bool Proc()=0;
virtual void Shutdown()=0;
virtual boo::IWindow* GetMainWindow() const=0;
virtual void SetFlowState(EFlowState) = 0;
};
}

View File

@ -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; }

View File

@ -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

View File

@ -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<CScriptSpiderBallWaypoint*>(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<CScriptSpiderBallWaypoint*>(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;
}
}

View File

@ -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<TUniqueId> xec_waypoints;
std::experimental::optional<zeus::CAABox> 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<zeus::CAABox> 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__

View File

@ -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<CWorldTransManager>& 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;
}
}
}
}

View File

@ -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&);
};
}

View File

@ -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);
}
}

View File

@ -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();
};

View File

@ -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"
@ -1848,9 +1849,50 @@ CEntity* ScriptLoader::LoadVisorFlare(CStateManager& mgr, CInputStream& in, int
CEntity* ScriptLoader::LoadWorldTeleporter(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
{
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)
{
return nullptr;