From b6781313290a5c0f4ebb5756d103ef02ffe2fd6b Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Sat, 7 Nov 2026 16:19:02 +0000 Subject: [PATCH] Maintenance: Restore original C3dGround/C3dGround15 hierarchy as GroundBase/GroundGeometry with 20 virtual slots, base size0x64 and d Batch #14713 by ragnarok-clanker: forced by an admin (7 lower score(s), 49 changed function(s)); checked with 27 compiled unit(s), including every includer of Source/Contents/Ground/GroundGeometry.h, Source/Contents/Ground/GroundWaterState.h, Source/Contents/World/WorldGroundImport.h. --- Source/Client/Mode/GameMode.cpp | 6 +- Source/Contents/Actors/GraffiSkill.cpp | 2 +- Source/Contents/Actors/GroundScope.cpp | 2 +- Source/Contents/Actors/Player.cpp | 2 +- .../Effects/EffectPrimitiveRendering.cpp | 4 +- Source/Contents/Ground/GroundDecals.cpp | 32 ++-- Source/Contents/Ground/GroundGeometry.cpp | 58 ++++-- Source/Contents/Ground/GroundGeometry.h | 177 ++++++++++++------ Source/Contents/Ground/GroundLighting.cpp | 2 +- .../Ground/GroundLightingInitialization.cpp | 10 +- Source/Contents/Ground/GroundLightmaps.cpp | 18 +- Source/Contents/Ground/GroundPicking.cpp | 14 +- Source/Contents/Ground/GroundRendering.cpp | 2 +- Source/Contents/Ground/GroundSamples.cpp | 19 +- Source/Contents/Ground/GroundSpatial.cpp | 2 +- .../Contents/Ground/GroundWaterRendering.cpp | 14 +- Source/Contents/Ground/GroundWaterState.cpp | 79 ++++---- Source/Contents/Ground/GroundWaterState.h | 23 --- Source/Contents/NavigationRoute.cpp | 4 +- Source/Contents/Sound/SoundMaker.cpp | 2 +- Source/Contents/World/WorldGroundImport.h | 9 +- Source/Contents/World/WorldModelLoading.cpp | 7 +- Source/Contents/World/WorldModelView.cpp | 6 +- 23 files changed, 287 insertions(+), 207 deletions(-) diff --git a/Source/Client/Mode/GameMode.cpp b/Source/Client/Mode/GameMode.cpp index a41320532..f07882216 100644 --- a/Source/Client/Mode/GameMode.cpp +++ b/Source/Client/Mode/GameMode.cpp @@ -8435,8 +8435,8 @@ void __stdcall SendMacroUserInfoPacket(std::uint16_t first, std::uint16_t second // OFFSET: 0x00CE0210 // FUNCTION: fn_21329 int CGameMode::ProcessGroundClick(int result) { - const auto drawCell = [this](GroundGeometry* ground, const float* matrix, int column, int row, std::uint32_t color) { - ground->DrawGrid(*this->scene->terrain, matrix, column, row, color); + const auto drawCell = [](GroundGeometry* ground, const float* matrix, int column, int row, std::uint32_t color) { + ground->DrawGrid(matrix, column, row, color); }; UIWindow* macroArea = g_windowMgr.LookupWindow(0x11E); @@ -8839,7 +8839,7 @@ void CGameMode::Update() { for (int frame = frames; frame != 0; --frame) { g_effectMgr->Update(); this->scene->OnProcess(); - this->scene->ground->Slot19(); + this->scene->ground->UpdateWater(); this->camera->Update(); } } else if (frames == 0) { diff --git a/Source/Contents/Actors/GraffiSkill.cpp b/Source/Contents/Actors/GraffiSkill.cpp index bf6b93d68..b82b1de53 100644 --- a/Source/Contents/Actors/GraffiSkill.cpp +++ b/Source/Contents/Actors/GraffiSkill.cpp @@ -129,7 +129,7 @@ void CGraffiSkill::Render(int argument) { uv[6] = 1.0f - (row1 * sine + column1 * cosine + 9.0f) / 18.0f; uv[7] = (row1 * cosine - column1 * sine + 9.0f) / 18.0f; ground->DrawGridDecal( - *mode->scene->terrain, reinterpret_cast(argument), cellX - 9 + column, cellY - 9 + row, 0xFFFFFFFF, *this->m_canvas, uv); + reinterpret_cast(argument), cellX - 9 + column, cellY - 9 + row, 0xFFFFFFFF, *this->m_canvas, uv); } } } diff --git a/Source/Contents/Actors/GroundScope.cpp b/Source/Contents/Actors/GroundScope.cpp index 06cf7ae70..5c1495c92 100644 --- a/Source/Contents/Actors/GroundScope.cpp +++ b/Source/Contents/Actors/GroundScope.cpp @@ -171,7 +171,7 @@ void CGroundScope::Render(int argument) { } CTexture* texture = g_texMgr.Load(name, 0, false, true, false); - ground->DrawGridDecal(*mode->scene->terrain, reinterpret_cast(argument), left + column, top + row, tint, *texture, uv); + ground->DrawGridDecal(reinterpret_cast(argument), left + column, top + row, tint, *texture, uv); } } diff --git a/Source/Contents/Actors/Player.cpp b/Source/Contents/Actors/Player.cpp index e7b60e434..4c6923e81 100644 --- a/Source/Contents/Actors/Player.cpp +++ b/Source/Contents/Actors/Player.cpp @@ -4686,7 +4686,7 @@ void CGrannyPc::RenderShadow(int argument, vector3d lightDirection, bool cached) uv[6] = (row1 * groundSine + column1 * groundCosine + 2.5f) / 5.0f; uv[7] = (row1 * groundCosine - column1 * groundSine + 2.5f) / 5.0f; ground->DrawGridDecal( - *mode->scene->terrain, reinterpret_cast(argument), column + j, row + i, 0x70FFFFFF, *this->unknown_2554, uv); + reinterpret_cast(argument), column + j, row + i, 0x70FFFFFF, *this->unknown_2554, uv); } } } diff --git a/Source/Contents/Effects/EffectPrimitiveRendering.cpp b/Source/Contents/Effects/EffectPrimitiveRendering.cpp index 808dd60e8..27913ad8a 100644 --- a/Source/Contents/Effects/EffectPrimitiveRendering.cpp +++ b/Source/Contents/Effects/EffectPrimitiveRendering.cpp @@ -6589,7 +6589,7 @@ void CEffectPrim::RenderMagicTarget(matrix& wtm) { (u01 * scale + 3.5f) / 7.0f, (v01 * scale + 3.5f) / 7.0f, (u11 * scale + 3.5f) / 7.0f, (v11 * scale + 3.5f) / 7.0f, }; ground->DrawGridDecal( - *gameMode->scene->terrain, wtm.values, column + x, row + z, 0xAA9999FF, *g_texMgr.Load("effect\\magic_target.tga", 0, false, true, false), uv); + wtm.values, column + x, row + z, 0xAA9999FF, *g_texMgr.Load("effect\\magic_target.tga", 0, false, true, false), uv); scale = slot.maxHeight + 0.1f; uv[0] = (scale * u00 + 3.5f) / 7.0f; @@ -6601,7 +6601,7 @@ void CEffectPrim::RenderMagicTarget(matrix& wtm) { uv[6] = (scale * u11 + 3.5f) / 7.0f; uv[7] = (scale * v11 + 3.5f) / 7.0f; ground->DrawGridDecal( - *gameMode->scene->terrain, wtm.values, column + x, row + z, 0x559999FF, *g_texMgr.Load("effect\\magic_target.tga", 0, false, true, false), uv); + wtm.values, column + x, row + z, 0x559999FF, *g_texMgr.Load("effect\\magic_target.tga", 0, false, true, false), uv); } } } diff --git a/Source/Contents/Ground/GroundDecals.cpp b/Source/Contents/Ground/GroundDecals.cpp index d6c308186..dc15d7fb0 100644 --- a/Source/Contents/Ground/GroundDecals.cpp +++ b/Source/Contents/Ground/GroundDecals.cpp @@ -32,7 +32,17 @@ bool GroundGeometry::CellRectangle(const C3dAttr& terrain, int column, int row, vertices[9] = static_cast(cellColumn - this->width / 2 + 1) * this->cellSize; vertices[11] = static_cast(cellRow - this->height / 2 + 1) * this->cellSize; - return this->OverlayHeights(terrain, vertices, column, row); + const TerrainHeightCell* cell = terrain.CellAt(column, row); + + if (!cell) { + return false; + } + + for (unsigned corner = 0; corner < 4; ++corner) { + vertices[corner * 3 + 1] = cell->heights[corner]; + } + + return true; } namespace { @@ -101,45 +111,45 @@ namespace { // OFFSET: 0x00AC3380 // FUNCTION: fn_17602 void GroundGeometry::DrawCellDecal( - const C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv + const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv ) const { - DrawDecal(*this, terrain, matrix, column, row, color, texture, uv, 0.10003052f); + DrawDecal(*this, *this->terrain, matrix, column, row, color, texture, uv, 0.10003052f); } // OFFSET: 0x00AC1710 // FUNCTION: fn_17588 -void GroundGeometry::Slot14(int, int, int, int) { +void GroundBase::DrawGrid(const float*, int, int, std::uint32_t) const { } // OFFSET: 0x00AC1720 // FUNCTION: fn_17589 __declspec(noinline) void GroundGeometry::DrawGridDecal( - const C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv + const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv ) const { - DrawDecal(*this, terrain, matrix, column, row, color, texture, uv, 3.0517578e-05f); + DrawDecal(*this, *this->terrain, matrix, column, row, color, texture, uv, 3.0517578e-05f); } // OFFSET: 0x00AC16D0 // FUNCTION: fn_17587 void GroundGeometry::DrawGrid( - const C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color + const float* matrix, int column, int row, std::uint32_t color ) const { CTexture* texture = g_texMgr.Load("grid.tga", 0, false, true, false); // STATIC: 0x01347EB0 // GLOBAL: gl_25477 static const float uv[8] = {0, 0, 1, 0, 0, 1, 1, 1}; - this->DrawGridDecal(terrain, matrix, column, row, color, *texture, uv); + this->DrawGridDecal(matrix, column, row, color, *texture, uv); } // OFFSET: 0x00AC3600 // FUNCTION: fn_17603 -void GroundGeometry::Slot16(int, int, int, int, int, int) { +void GroundBase::DrawCellDecal(const float*, int, int, std::uint32_t, CTexture&, const float*) const { } // OFFSET: 0x00AC3610 // FUNCTION: fn_17604 void GroundGeometry::DrawTerrainOverlay( - const C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture* texture + const float* matrix, int column, int row, std::uint32_t color, CTexture* texture ) const { const int cellColumn = static_cast(static_cast(column) * 0.5f); const int cellRow = static_cast(static_cast(row) * 0.5f); @@ -152,7 +162,7 @@ void GroundGeometry::DrawTerrainOverlay( return; } - const TerrainHeightCell* cell = terrain.CellAt(column, row); + const TerrainHeightCell* cell = this->terrain->CellAt(column, row); if (!cell) { return; diff --git a/Source/Contents/Ground/GroundGeometry.cpp b/Source/Contents/Ground/GroundGeometry.cpp index 4a07de931..17053552a 100644 --- a/Source/Contents/Ground/GroundGeometry.cpp +++ b/Source/Contents/Ground/GroundGeometry.cpp @@ -46,7 +46,7 @@ namespace { } // INLINED - std::uint32_t + __forceinline std::uint32_t LitColor(const float* normal, bool normalize, bool side, const float* direction, const float* diffuse, const float* ambient, const GroundQuad* source) { float vector[3] = {normal[0], normal[1], normal[2]}; @@ -73,16 +73,23 @@ namespace { } } -// OFFSET: 0x00ABD640 -// FUNCTION: fn_17546 -GroundGeometry::GroundGeometry() : cellSize(10.0f), loaded(0) { +// INLINED +GroundBase::GroundBase() + : terrain(nullptr), cellSize(10.0f), waterLevel(0.0f), waterAnimation(3), waterPitch(50), waterPhase(2), waterType(0), waterHeight(1.0f), + unknown_0050(0), unknown_0054(0), loaded(0) { } // INLINED -GroundGeometry::~GroundGeometry() { - this->ClearLightmaps(); +GroundBase::~GroundBase() = default; + +// OFFSET: 0x00ABD640 +// FUNCTION: fn_17546 +GroundGeometry::GroundGeometry() : waterColumns(1), waterRows(1), waterPartitioned(false) { } +// INLINED +GroundGeometry::~GroundGeometry() = default; + // OFFSET: 0x00AC3010 // FUNCTION: fn_17595 void GroundGeometry::ClearGeometry() { @@ -105,7 +112,7 @@ void GroundGeometry::Reset(int columns, int rows) { // OFFSET: 0x00AC0350 // FUNCTION: fn_17564 -void GroundGeometry::Slot01(int, int) { +void GroundBase::Reset(int, int) { } // OFFSET: 0x00ABDEF0 @@ -115,7 +122,7 @@ void GroundGeometry::Build(CGndRes& resource, const float* lightDirection, const this->Reset(resource.width, resource.height); CellNormals* normals = new CellNormals[resource.width * resource.height]; this->cellSize = resource.cellSize; - this->BuildLightmaps(resource); + this->lightmapSet.Build(resource); this->tiles.clear(); this->tiles.resize(static_cast(resource.tileCount)); @@ -175,9 +182,9 @@ void GroundGeometry::Build(CGndRes& resource, const float* lightDirection, const normals[index].side1.values[0] = next[0] <= cell.heights[2] ? 1.0f : -1.0f; } - const float scaleU = static_cast(tile.texture->Width()) / static_cast(tile.texture->TextureWidth()); - const float scaleV = static_cast(tile.texture->Height()) / static_cast(tile.texture->TextureHeight()); - GroundLightmap& lightmap = this->lightmaps[lightmapIndex]; + const float scaleU = static_cast(tile.texture->ImageWidth()) / static_cast(tile.texture->TextureWidth()); + const float scaleV = static_cast(tile.texture->ImageHeight()) / static_cast(tile.texture->TextureHeight()); + GroundLightmap& lightmap = this->lightmapSet.lightmaps[lightmapIndex]; tile.lightmap = &lightmap; tile.lightmapTexture = lightmap.texture; @@ -344,37 +351,52 @@ void GroundGeometry::Build(CGndRes& resource, const float* lightDirection, const // OFFSET: 0x00ABFB00 // FUNCTION: fn_17557 -void GroundGeometry::Slot02(int, int, int, int) { +void GroundBase::Build(CGndRes&, const float*, const float*, const float*) { } // OFFSET: 0x00AC0990 // FUNCTION: fn_17566 -void GroundGeometry::Ground15Slot04(int) { +void GroundGeometry::Slot04(int) { } // OFFSET: 0x00AC09A0 // FUNCTION: fn_17567 -void GroundGeometry::Slot04(int) { +void GroundBase::Slot04(int) { } // OFFSET: 0x00AC1510 // FUNCTION: fn_17582 -void GroundGeometry::Slot19() { +void GroundBase::UpdateWater() { } // OFFSET: 0x00AC1520 // FUNCTION: fn_17583 -bool GroundGeometry::Ground15Slot10() { +bool GroundGeometry::Slot10() { return true; } // OFFSET: 0x00AC3080 // FUNCTION: fn_17598 -void GroundGeometry::Ground15Slot15(float, int, int) { +void GroundBase::Slot15(float, int, int) { } // OFFSET: 0x00AC1530 // FUNCTION: fn_17584 -bool GroundGeometry::Slot10() { +bool GroundBase::Slot10() { return false; } + +// OFFSET: 0x00AC3030 +// FUNCTION: fn_17596 +void GroundBase::ClearGeometry() { +} + +// OFFSET: 0x00AC3370 +// FUNCTION: fn_17601 +void GroundBase::ImportWater(const CGndRes&) { +} + +// OFFSET: 0x00AC38A0 +// FUNCTION: fn_17605 +void GroundBase::DrawTerrainOverlay(const float*, int, int, std::uint32_t, CTexture*) const { +} diff --git a/Source/Contents/Ground/GroundGeometry.h b/Source/Contents/Ground/GroundGeometry.h index 35ef06c88..5eba48d93 100644 --- a/Source/Contents/Ground/GroundGeometry.h +++ b/Source/Contents/Ground/GroundGeometry.h @@ -17,74 +17,107 @@ struct GroundLightmap { /* 0028 */ std::uint32_t unknown_0028[4]; }; -class GroundGeometry { +class GroundLightmapSet { +public: + ~GroundLightmapSet(); + void Build(CGndRes& resource); + void Clear(); + + /* 0000 */ std::vector lightmaps; + /* 000C */ std::vector lightmapTextures; + /* 0018 */ int lightmapCount; + /* 001C */ int atlasCount; +}; + +class GroundBase { +public: + GroundBase(); + GroundBase(const GroundBase&) = delete; + GroundBase& operator=(const GroundBase&) = delete; + virtual ~GroundBase(); + virtual void Reset(int columns, int rows); + virtual void Build(CGndRes& resource, const float* lightDirection, const float* diffuse, const float* ambient); + virtual void ClearGeometry(); + virtual void Slot04(int first); + virtual void Draw(const float* matrix, const int* rectangle, bool clip); + virtual void DrawLit(const float* matrix, const int* rectangle, bool clip); + virtual void CellBounds(int column, int row, float& minimum, float& maximum) const; + virtual void HeightBounds(const int* rectangle, float& minimum, float& maximum) const; + virtual void MarkRay(const float* ray, int column, int row, float limit); + virtual bool Slot10(); + virtual void InitializeLighting(); + virtual int Lighting(int column, int row, float& red, float& green, float& blue) const; + virtual void ImportWater(const CGndRes& resource); + virtual void DrawGrid(const float* matrix, int column, int row, std::uint32_t color) const; + virtual void Slot15(float alpha, int x, int y); + virtual void DrawCellDecal(const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv) const; + virtual void DrawTerrainOverlay(const float* matrix, int column, int row, std::uint32_t color, CTexture* texture) const; + virtual bool CellVertices(float* vertices, int column, int row) const; + virtual void UpdateWater(); + + void SpatialCell(float x, float z, int& column, int& row) const; + void SetWater(float level, int type, int animation, int pitch, int phase, float height); + + /* 0004 */ class C3dAttr* terrain; + /* 0008 */ int width; + /* 000C */ int height; + /* 0010 */ float cellSize; + /* 0014 */ GroundLightmapSet lightmapSet; + /* 0034 */ std::uint32_t unknown_0034; + /* 0038 */ float waterLevel; + /* 003C */ int waterAnimation; + /* 0040 */ int waterPitch; + /* 0044 */ int waterPhase; + /* 0048 */ int waterType; + /* 004C */ float waterHeight; + /* 0050 */ std::uint32_t unknown_0050; + /* 0054 */ std::uint32_t unknown_0054; + /* 0058 */ std::uint32_t unknown_0058; + /* 005C */ std::uint32_t unknown_005C; + /* 0060 */ int loaded; +}; + +class GroundGeometry : public GroundBase { public: GroundGeometry(); - ~GroundGeometry(); - GroundGeometry(const GroundGeometry&) = delete; - GroundGeometry& operator=(const GroundGeometry&) = delete; - void Build(CGndRes& resource, const float* lightDirection, const float* diffuse, const float* ambient); - void ClearGeometry(); - void Reset(int columns, int rows); - void SpatialCell(float x, float z, int& column, int& row) const; - void HeightBounds(const int* rectangle, float& minimum, float& maximum) const; - void Draw(const float* matrix, const int* rectangle, bool clip); - void CellBounds(int column, int row, float& minimum, float& maximum) const; - bool OverlayHeights(const class C3dAttr& terrain, float* vertices, int column, int row) const; - bool CellVertices(const class C3dAttr& terrain, float* vertices, int column, int row) const; - void MarkRay(const float* ray, int column, int row, float limit); - bool CellRectangle(const class C3dAttr& terrain, int column, int row, float* vertices) const; - void DrawCellDecal( - const class C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv - ) const; - void DrawGridDecal( - const class C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv - ) const; - void DrawGrid(const class C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color) const; - void DrawTerrainOverlay(const class C3dAttr& terrain, const float* matrix, int column, int row, std::uint32_t color, CTexture* texture) const; + ~GroundGeometry() override; + void Reset(int columns, int rows) override; + void Build(CGndRes& resource, const float* lightDirection, const float* diffuse, const float* ambient) override; + void ClearGeometry() override; + void Slot04(int first) override; + void Draw(const float* matrix, const int* rectangle, bool clip) override; + void DrawLit(const float* matrix, const int* rectangle, bool clip) override; + void CellBounds(int column, int row, float& minimum, float& maximum) const override; + void HeightBounds(const int* rectangle, float& minimum, float& maximum) const override; + void MarkRay(const float* ray, int column, int row, float limit) override; + bool Slot10() override; + void InitializeLighting() override; + int Lighting(int column, int row, float& red, float& green, float& blue) const override; + void ImportWater(const CGndRes& resource) override; + void DrawGrid(const float* matrix, int column, int row, std::uint32_t color) const override; + void DrawCellDecal(const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv) const override; + void DrawTerrainOverlay(const float* matrix, int column, int row, std::uint32_t color, CTexture* texture) const override; + bool CellVertices(float* vertices, int column, int row) const override; + void UpdateWater() override; + + bool CellRectangle(const C3dAttr& terrain, int column, int row, float* vertices) const; + void DrawGridDecal(const float* matrix, int column, int row, std::uint32_t color, CTexture& texture, const float* uv) const; void DrawWaterCell(int column, int row, GroundCell& cell, const float* matrix, const float* ambient); - void DrawLit(const float* matrix, const int* rectangle, bool clip); - __declspec(noinline) void DrawLightmapped(const float* matrix, const struct GroundQuad& quad, bool clip); - __declspec(noinline) void DrawSide(const float* matrix, const struct GroundQuad& quad, bool clip); + __declspec(noinline) void DrawLightmapped(const float* matrix, const GroundQuad& quad, bool clip); + __declspec(noinline) void DrawSide(const float* matrix, const GroundQuad& quad, bool clip); void WorldColor(float x, float unusedY, float z, std::uint32_t* output) const; - void Lighting(int column, int row, float& red, float& green, float& blue) const; - void Slot01(int first, int second); - void Slot02(int first, int second, int third, int fourth); - void Slot04(int first); - void Ground15Slot04(int first); - void Slot05(int first, int second, int third); - void Slot06(int first, int second, int third); - void Slot07(int first, int second, int third, int fourth) const; - void Slot08(int first, int second, int third) const; - void Slot09(int first, int second, int third, int fourth); - bool Slot10(); - bool Ground15Slot10(); - void Ground15Slot15(float alpha, int x, int y); - void Slot11(); - int Slot12(int first, int second, int third, int fourth, int fifth) const; - void Slot14(int first, int second, int third, int fourth); - void Slot16(int first, int second, int third, int fourth, int fifth, int sixth); - void Slot19(); void LightmapSample(int column, int row, unsigned char& alpha, unsigned char& red, unsigned char& green, unsigned char& blue) const; - bool TerrainCellCorners(const class C3dAttr& terrain, int column, int row, float* vertices) const; - void InitializeLighting(const class C3dAttr& terrain); + bool TerrainCellCorners(const C3dAttr& terrain, int column, int row, float* vertices) const; + float WaterLevel(int column, int row) const; - int width; - int height; - float cellSize; - int loaded; - std::vector lightmaps; - std::vector lightmapTextures; - std::vector tiles; - std::vector> lighting; - std::vector cells; - std::uint32_t unknown_0058; - std::uint32_t unknown_005C; - GroundWaterState water; - -private: - void BuildLightmaps(CGndRes& resource); - void ClearLightmaps(); + /* 0064 */ std::vector tiles; + /* 0070 */ std::vector> lighting; + /* 007C */ std::vector cells; + /* 0088 */ int waterColumns; + /* 008C */ int waterRows; + /* 0090 */ std::vector waterLevels; + /* 009C */ std::vector waterSurfaces; + /* 00A8 */ bool waterPartitioned; }; #if defined(_WIN32) && !defined(_WIN64) @@ -92,6 +125,26 @@ static_assert(sizeof(GroundLightmap) == 56); static_assert(offsetof(GroundLightmap, texture) == 0x04); static_assert(offsetof(GroundLightmap, uv) == 0x08); static_assert(offsetof(GroundLightmap, unknown_0028) == 0x28); +static_assert(sizeof(GroundLightmapSet) == 0x20); +static_assert(offsetof(GroundLightmapSet, lightmapCount) == 0x18); +static_assert(offsetof(GroundLightmapSet, atlasCount) == 0x1C); +static_assert(sizeof(GroundBase) == 0x64); +static_assert(offsetof(GroundBase, terrain) == 0x04); +static_assert(offsetof(GroundBase, width) == 0x08); +static_assert(offsetof(GroundBase, height) == 0x0C); +static_assert(offsetof(GroundBase, cellSize) == 0x10); +static_assert(offsetof(GroundBase, lightmapSet) == 0x14); +static_assert(offsetof(GroundBase, waterLevel) == 0x38); +static_assert(offsetof(GroundBase, loaded) == 0x60); +static_assert(sizeof(GroundGeometry) == 0xAC); +static_assert(offsetof(GroundGeometry, tiles) == 0x64); +static_assert(offsetof(GroundGeometry, lighting) == 0x70); +static_assert(offsetof(GroundGeometry, cells) == 0x7C); +static_assert(offsetof(GroundGeometry, waterColumns) == 0x88); +static_assert(offsetof(GroundGeometry, waterRows) == 0x8C); +static_assert(offsetof(GroundGeometry, waterLevels) == 0x90); +static_assert(offsetof(GroundGeometry, waterSurfaces) == 0x9C); +static_assert(offsetof(GroundGeometry, waterPartitioned) == 0xA8); #endif #endif diff --git a/Source/Contents/Ground/GroundLighting.cpp b/Source/Contents/Ground/GroundLighting.cpp index 2f684d1a6..403573a9f 100644 --- a/Source/Contents/Ground/GroundLighting.cpp +++ b/Source/Contents/Ground/GroundLighting.cpp @@ -136,5 +136,5 @@ void GroundGeometry::DrawLit(const float* matrix, const int* rectangle, bool cli // OFFSET: 0x00AC16C0 // FUNCTION: fn_17586 -void GroundGeometry::Slot06(int, int, int) { +void GroundBase::DrawLit(const float*, const int*, bool) { } diff --git a/Source/Contents/Ground/GroundLightingInitialization.cpp b/Source/Contents/Ground/GroundLightingInitialization.cpp index ce2c76bac..e91653eec 100644 --- a/Source/Contents/Ground/GroundLightingInitialization.cpp +++ b/Source/Contents/Ground/GroundLightingInitialization.cpp @@ -3,7 +3,11 @@ // OFFSET: 0x00ABFB10 // FUNCTION: fn_17558 -void GroundGeometry::InitializeLighting(const C3dAttr& terrain) { +void GroundGeometry::InitializeLighting() { + if (!this->Slot10()) { + return; + } + // STATIC: 0x01348128 constexpr int offsets[5][2] = {{0, 0}, {0, -1}, {0, 1}, {1, 0}, {-1, 0}}; const int columns = 2 * this->width; @@ -12,7 +16,7 @@ void GroundGeometry::InitializeLighting(const C3dAttr& terrain) { for (int row = 0; row < rows; ++row) { for (int column = 0; column < columns; ++column) { float average = 0.0f; - const TerrainHeightCell* cell = terrain.CellAt(column, row); + const TerrainHeightCell* cell = this->terrain->CellAt(column, row); if (cell) { average = ((cell->heights[1] + cell->heights[0]) + cell->heights[2] + cell->heights[3]) * 0.25f; @@ -64,5 +68,5 @@ void GroundGeometry::InitializeLighting(const C3dAttr& terrain) { // OFFSET: 0x00ABFD50 // FUNCTION: fn_17559 -void GroundGeometry::Slot11() { +void GroundBase::InitializeLighting() { } diff --git a/Source/Contents/Ground/GroundLightmaps.cpp b/Source/Contents/Ground/GroundLightmaps.cpp index fddf806ad..d8b39e138 100644 --- a/Source/Contents/Ground/GroundLightmaps.cpp +++ b/Source/Contents/Ground/GroundLightmaps.cpp @@ -6,9 +6,14 @@ #include #include +// INLINED +GroundLightmapSet::~GroundLightmapSet() { + this->Clear(); +} + // OFFSET: 0x00AC3040 // FUNCTION: fn_17597 -void GroundGeometry::ClearLightmaps() { +void GroundLightmapSet::Clear() { this->lightmaps.clear(); while (!this->lightmapTextures.empty()) { @@ -19,11 +24,12 @@ void GroundGeometry::ClearLightmaps() { // OFFSET: 0x00AC0360 // FUNCTION: fn_17565 -void GroundGeometry::BuildLightmaps(CGndRes& resource) { - this->ClearLightmaps(); - this->lightmaps.resize(static_cast(resource.lightmapCount)); - const unsigned atlasCount = (static_cast(resource.lightmapCount) + 1023u) / 1024u; - this->lightmapTextures.reserve(atlasCount); +void GroundLightmapSet::Build(CGndRes& resource) { + this->Clear(); + this->lightmapCount = resource.lightmapCount; + this->lightmaps.resize(static_cast(this->lightmapCount)); + this->atlasCount = (static_cast(this->lightmapCount) + 1023u) / 1024u; + this->lightmapTextures.reserve(this->atlasCount); std::array pixels; for (int first = 0; first < resource.lightmapCount; first += 1024) { diff --git a/Source/Contents/Ground/GroundPicking.cpp b/Source/Contents/Ground/GroundPicking.cpp index 80c0be42d..3a0445e62 100644 --- a/Source/Contents/Ground/GroundPicking.cpp +++ b/Source/Contents/Ground/GroundPicking.cpp @@ -41,18 +41,18 @@ void GroundGeometry::CellBounds(int column, int row, float& minimum, float& maxi // OFFSET: 0x00AC1110 // FUNCTION: fn_17575 -void GroundGeometry::Slot08(int, int, int) const { +void GroundBase::HeightBounds(const int*, float&, float&) const { } // OFFSET: 0x00AC1120 // FUNCTION: fn_17576 -void GroundGeometry::Slot07(int, int, int, int) const { +void GroundBase::CellBounds(int, int, float&, float&) const { } // OFFSET: 0x00AC0E30 // FUNCTION: fn_17572 -bool GroundGeometry::OverlayHeights(const C3dAttr& terrain, float* vertices, int column, int row) const { - const TerrainHeightCell* cell = terrain.CellAt(column, row); +bool GroundBase::CellVertices(float* vertices, int column, int row) const { + const TerrainHeightCell* cell = this->terrain->CellAt(column, row); if (!cell) { return false; @@ -67,7 +67,7 @@ bool GroundGeometry::OverlayHeights(const C3dAttr& terrain, float* vertices, int // OFFSET: 0x00AC0D40 // FUNCTION: fn_17571 -bool GroundGeometry::CellVertices(const C3dAttr& terrain, float* vertices, int column, int row) const { +bool GroundGeometry::CellVertices(float* vertices, int column, int row) const { if (column < 0 || (column >> 1) >= this->width || row < 0 || (row >> 1) >= this->height) { return false; } @@ -84,7 +84,7 @@ bool GroundGeometry::CellVertices(const C3dAttr& terrain, float* vertices, int c } } - this->OverlayHeights(terrain, vertices, column, row); + GroundBase::CellVertices(vertices, column, row); return true; } @@ -130,5 +130,5 @@ void GroundGeometry::MarkRay(const float* ray, int column, int row, float limit) // OFFSET: 0x00AC0170 // FUNCTION: fn_17561 -void GroundGeometry::Slot09(int, int, int, int) { +void GroundBase::MarkRay(const float*, int, int, float) { } diff --git a/Source/Contents/Ground/GroundRendering.cpp b/Source/Contents/Ground/GroundRendering.cpp index 6ea1946a3..b76342c09 100644 --- a/Source/Contents/Ground/GroundRendering.cpp +++ b/Source/Contents/Ground/GroundRendering.cpp @@ -81,5 +81,5 @@ void GroundGeometry::Draw(const float* matrix, const int* rectangle, bool clip) // OFFSET: 0x00AC1D20 // FUNCTION: fn_17591 -void GroundGeometry::Slot05(int, int, int) { +void GroundBase::Draw(const float*, const int*, bool) { } diff --git a/Source/Contents/Ground/GroundSamples.cpp b/Source/Contents/Ground/GroundSamples.cpp index 0aeca87c8..c0fa7c6d5 100644 --- a/Source/Contents/Ground/GroundSamples.cpp +++ b/Source/Contents/Ground/GroundSamples.cpp @@ -24,24 +24,25 @@ void GroundGeometry::WorldColor(float x, float, float z, std::uint32_t* output) // OFFSET: 0x00AC1130 // FUNCTION: fn_17577 -void GroundGeometry::Lighting(int column, int row, float& red, float& green, float& blue) const { +int GroundGeometry::Lighting(int column, int row, float& red, float& green, float& blue) const { if (column < 0 || (column >> 1) >= this->width || row < 0 || (row >> 1) >= this->height || this->lighting.empty()) { red = 1.0f; green = 1.0f; blue = 1.0f; - return; + return 1; } const unsigned index = static_cast(column) + 2u * static_cast(row) * static_cast(this->width); red = this->lighting[index][0]; green = this->lighting[index][1]; blue = this->lighting[index][2]; + return 1; } // OFFSET: 0x00AC11C0 // FUNCTION: fn_17578 -int GroundGeometry::Slot12(int, int, int, int, int) const { +int GroundBase::Lighting(int, int, float&, float&, float&) const { return 0; } @@ -116,5 +117,15 @@ bool GroundGeometry::TerrainCellCorners(const C3dAttr& terrain, int column, int vertices[9] = right; vertices[11] = bottom; - return this->OverlayHeights(terrain, vertices, column, row); + const TerrainHeightCell* cell = terrain.CellAt(column, row); + + if (!cell) { + return false; + } + + for (unsigned corner = 0; corner < 4; ++corner) { + vertices[corner * 3 + 1] = cell->heights[corner]; + } + + return true; } diff --git a/Source/Contents/Ground/GroundSpatial.cpp b/Source/Contents/Ground/GroundSpatial.cpp index d252e6e3d..df600eb62 100644 --- a/Source/Contents/Ground/GroundSpatial.cpp +++ b/Source/Contents/Ground/GroundSpatial.cpp @@ -32,7 +32,7 @@ GroundCell::GroundCell() { // OFFSET: 0x00AC0180 // FUNCTION: fn_17562 -void GroundGeometry::SpatialCell(float x, float z, int& column, int& row) const { +void GroundBase::SpatialCell(float x, float z, int& column, int& row) const { column = static_cast(std::floor(x / this->cellSize)) + this->width / 2; row = static_cast(std::floor(z / this->cellSize)) + this->height / 2; } diff --git a/Source/Contents/Ground/GroundWaterRendering.cpp b/Source/Contents/Ground/GroundWaterRendering.cpp index b38004bcc..4843d9749 100644 --- a/Source/Contents/Ground/GroundWaterRendering.cpp +++ b/Source/Contents/Ground/GroundWaterRendering.cpp @@ -16,16 +16,16 @@ void GroundGeometry::DrawWaterCell( int column, int row, GroundCell& cell, const float* matrix, const float* ambient ) { - const float level = this->water.Level(this->width, this->height, column, row); + const float level = this->WaterLevel(column, row); unsigned partition = 0; - if (this->water.partitioned) { - const int x = std::min(column / (this->width / this->water.columns), this->water.columns - 1); - const int z = std::min(row / (this->height / this->water.rows), this->water.rows - 1); - partition = static_cast(x) + static_cast(z) * static_cast(this->water.columns); + if (this->waterPartitioned) { + const int x = std::min(column / (this->width / this->waterColumns), this->waterColumns - 1); + const int z = std::min(row / (this->height / this->waterRows), this->waterRows - 1); + partition = static_cast(x) + static_cast(z) * static_cast(this->waterColumns); } - GroundWaterSurface& surface = this->water.surfaces[partition]; + GroundWaterSurface& surface = this->waterSurfaces[partition]; float middle = level; float first = level; float last = level; @@ -79,7 +79,7 @@ void GroundGeometry::DrawWaterCell( primitive->SetPosition(2, &vertices[2].x); primitive->SetPosition(3, &vertices[3].x); - if (!g_overrideColor && this->water.type == 4) { + if (!g_overrideColor && this->waterType == 4) { const std::uint8_t red = static_cast(ambient[0] * 255.0f); const std::uint8_t green = static_cast(ambient[1] * 255.0f); const std::uint8_t blue = static_cast(ambient[2] * 255.0f); diff --git a/Source/Contents/Ground/GroundWaterState.cpp b/Source/Contents/Ground/GroundWaterState.cpp index 62df72322..9e0525cfb 100644 --- a/Source/Contents/Ground/GroundWaterState.cpp +++ b/Source/Contents/Ground/GroundWaterState.cpp @@ -1,79 +1,74 @@ -#include "Contents/Ground/GroundWaterState.h" +#include "Contents/Ground/GroundGeometry.h" #include "Render/Textures/TextureCache.h" #include "Resource/World/GroundResource.h" -#include "Utility/Math/ScalarConversion.h" #include "Utility/Text/FormatString.h" #include - -// INLINED -GroundWaterState::GroundWaterState() : level(0.0f), animation(3), pitch(50), phase(2), type(0), height(1.0f), columns(1), rows(1), partitioned(false) { -} +#include // OFFSET: 0x00AC3320 // FUNCTION: fn_17600 -void GroundWaterState::Set(float newLevel, int newType, int newAnimation, int newPitch, int newPhase, float newHeight) { - this->animation = newAnimation; - this->pitch = newPitch; - this->level = newLevel; - this->height = newHeight; - this->phase = newPhase % 360; - this->type = newType; +void GroundBase::SetWater(float newLevel, int newType, int newAnimation, int newPitch, int newPhase, float newHeight) { + this->waterAnimation = newAnimation; + this->waterPitch = newPitch; + this->waterLevel = newLevel; + this->waterHeight = newHeight; + this->waterPhase = newPhase % 360; + this->waterType = newType; } // OFFSET: 0x00AC30D0 // FUNCTION: fn_17599 -bool GroundWaterState::Import(const CGndRes& resource) { +void GroundGeometry::ImportWater(const CGndRes& resource) { if (resource.major == 1 && resource.minor >= 8) { - this->columns = resource.waterWidth; - this->rows = resource.waterHeight; - this->levels = resource.waterHeights; - this->surfaces.resize(resource.water.size()); + this->waterColumns = resource.waterWidth; + this->waterRows = resource.waterHeight; + this->waterLevels = resource.waterHeights; + this->waterSurfaces.resize(resource.water.size()); - for (std::size_t index = 0; index < resource.water.size(); ++index) { - const GroundWaterParameters& parameters = resource.water[index].parameters; - this->surfaces[index] = {parameters.level, parameters.type, parameters.height, parameters.speed, parameters.pitch, parameters.animation, 0, 0.0f, - nullptr}; + static_assert(sizeof(GroundWaterSurface) == sizeof(GroundWater)); + if (!resource.water.empty()) { + std::memcpy(this->waterSurfaces.data(), resource.water.data(), resource.water.size() * sizeof(GroundWater)); } - this->animation = resource.waterDefault.animation; - this->pitch = static_cast(resource.waterDefault.pitch); - this->phase = static_cast(resource.waterDefault.speed) % 360; - this->type = resource.waterDefault.type; - this->height = resource.waterDefault.height; + this->waterAnimation = resource.waterDefault.animation; + this->waterPitch = static_cast(resource.waterDefault.pitch); + this->waterPhase = static_cast(resource.waterDefault.speed) % 360; + this->waterType = resource.waterDefault.type; + this->waterHeight = resource.waterDefault.height; } else { - this->surfaces.push_back( - {this->level, this->type, this->height, static_cast(this->phase), static_cast(this->pitch), this->animation, 0, 0.0f, nullptr} + this->waterSurfaces.push_back( + {this->waterLevel, this->waterType, this->waterHeight, static_cast(this->waterPhase), static_cast(this->waterPitch), + this->waterAnimation, 0, 0.0f, nullptr} ); - this->levels.push_back(this->level); + this->waterLevels.push_back(this->waterLevel); } - this->Update(); - this->partitioned = this->levels.size() > 1; - return this->partitioned; + this->UpdateWater(); + this->waterPartitioned = this->waterLevels.size() > 1; } // OFFSET: 0x00AC1390 // FUNCTION: fn_17580 -float GroundWaterState::Level(int width, int height, int column, int row) const { - const int cellWidth = width / this->columns; - const int cellHeight = height / this->rows; - const int x = std::min(column / cellWidth, this->columns - 1); - const int z = std::min(row / cellHeight, this->rows - 1); - const unsigned index = static_cast(x) + static_cast(z) * static_cast(this->columns); +float GroundGeometry::WaterLevel(int column, int row) const { + const int cellWidth = this->width / this->waterColumns; + const int cellHeight = this->height / this->waterRows; + const int x = std::min(column / cellWidth, this->waterColumns - 1); + const int z = std::min(row / cellHeight, this->waterRows - 1); + const unsigned index = static_cast(x) + static_cast(z) * static_cast(this->waterColumns); - return index < this->levels.size() ? this->levels[index] : 0.0f; + return index < this->waterLevels.size() ? this->waterLevels[index] : 0.0f; } // OFFSET: 0x00AC1430 // FUNCTION: fn_17581 -void GroundWaterState::Update() { +void GroundGeometry::UpdateWater() { // STATIC: 0x01159248 // STRING: st_16830 static constexpr char format[] = "워터\\water%d%02d.jpg"; char name[32]{}; - for (GroundWaterSurface& surface : this->surfaces) { + for (GroundWaterSurface& surface : this->waterSurfaces) { ++surface.frame; const int end = surface.animation * 32; diff --git a/Source/Contents/Ground/GroundWaterState.h b/Source/Contents/Ground/GroundWaterState.h index 34b1a97cd..4e18d6917 100644 --- a/Source/Contents/Ground/GroundWaterState.h +++ b/Source/Contents/Ground/GroundWaterState.h @@ -2,11 +2,8 @@ #define RAGNAROK_SOURCE_CONTENTS_GROUND_GROUNDWATERSTATE_H #include -#include -class CGndRes; class CTexture; -class TextureCache; struct GroundWaterSurface { /* 0000 */ float level; @@ -20,26 +17,6 @@ struct GroundWaterSurface { /* 0020 */ CTexture* texture; }; -struct GroundWaterState { - GroundWaterState(); - void Set(float level, int type, int animation, int pitch, int phase, float height); - bool Import(const CGndRes& resource); - void Update(); - float Level(int width, int height, int column, int row) const; - - float level; - int animation; - int pitch; - int phase; - int type; - float height; - int columns; - int rows; - std::vector levels; - std::vector surfaces; - bool partitioned; -}; - #if defined(_WIN32) && !defined(_WIN64) static_assert(sizeof(GroundWaterSurface) == 36); static_assert(offsetof(GroundWaterSurface, texture) == 0x20); diff --git a/Source/Contents/NavigationRoute.cpp b/Source/Contents/NavigationRoute.cpp index 7913f56ce..c92aa18fb 100644 --- a/Source/Contents/NavigationRoute.cpp +++ b/Source/Contents/NavigationRoute.cpp @@ -86,7 +86,7 @@ void CNavigationManager::DrawRoute(const float* matrix) { GroundGeometry* ground = mode->scene->ground; const std::string name = FormatOwnedString("유저인터페이스\\navigation_interface3\\location%d.tga", g_locationFrame); CTexture* texture = g_texMgr.Load(name.c_str(), 0, false, true, false); - ground->DrawTerrainOverlay(*mode->scene->terrain, matrix, lastX, lastY, color, texture); + ground->DrawTerrainOverlay(matrix, lastX, lastY, color, texture); } } @@ -104,7 +104,7 @@ void CNavigationManager::DrawRoute(const float* matrix) { CTexture* texture = g_texMgr.Load(this->labels[points[index + 1].metadata].c_str(), 0, false, true, false); constexpr float uv[8] = {0, 0, 1, 0, 0, 1, 1, 1}; const std::uint32_t color = blink == static_cast(index) % 10 ? 0xEEFFFFFF : 0x99FFFFFF; - this->ground->DrawGridDecal(*mode->scene->terrain, matrix, x, y, color, *texture, uv); + this->ground->DrawGridDecal(matrix, x, y, color, *texture, uv); } } } diff --git a/Source/Contents/Sound/SoundMaker.cpp b/Source/Contents/Sound/SoundMaker.cpp index a7824d573..ab696faea 100644 --- a/Source/Contents/Sound/SoundMaker.cpp +++ b/Source/Contents/Sound/SoundMaker.cpp @@ -510,7 +510,7 @@ bool CGndRiser::OnProcess() { alpha = -(frame * frame) / 25.0f; } - mode->scene->ground->Ground15Slot15(alpha, this->screenX, this->screenY); + mode->scene->ground->Slot15(alpha, this->screenX, this->screenY); } return true; diff --git a/Source/Contents/World/WorldGroundImport.h b/Source/Contents/World/WorldGroundImport.h index fbfa9c835..d74995adf 100644 --- a/Source/Contents/World/WorldGroundImport.h +++ b/Source/Contents/World/WorldGroundImport.h @@ -48,10 +48,11 @@ inline bool ImportWorldGround( ground = new GroundGeometry; ground->Build(*resource, lightDirection, diffuse, ambient); - const int pitch = TruncateToInt(world.waveSpeed); - const int phase = TruncateToInt(world.wavePitch); - ground->water.Set(world.waterLevel, world.waterType, world.waterAnimation, pitch, phase, world.waveHeight); - ground->water.Import(*resource); + ground->terrain = terrain; + const int pitch = TruncateToInt(world.wavePitch); + const int phase = TruncateToInt(world.waveSpeed); + ground->SetWater(world.waterLevel, world.waterType, world.waterAnimation, pitch, phase, world.waveHeight); + ground->ImportWater(*resource); resources.Remove(resource); return true; diff --git a/Source/Contents/World/WorldModelLoading.cpp b/Source/Contents/World/WorldModelLoading.cpp index 48aa9affa..d9a2a776e 100644 --- a/Source/Contents/World/WorldModelLoading.cpp +++ b/Source/Contents/World/WorldModelLoading.cpp @@ -206,8 +206,9 @@ void CWorld::InitWorld() { this->ground = new GroundGeometry(); this->ground->Build(*groundRes, g_worldLightDirection, g_worldDiffuse, g_worldAmbient); + this->ground->terrain = this->terrain; - this->ground->water.Set( + this->ground->SetWater( worldRes->waterLevel, worldRes->waterType, worldRes->waterAnimation, @@ -216,7 +217,7 @@ void CWorld::InitWorld() { worldRes->waveHeight ); - this->ground->water.Import(*groundRes); + this->ground->ImportWater(*groundRes); ResourceMgr::Instance().Remove(groundRes); @@ -270,7 +271,7 @@ void CWorld::InitWorld() { this->InitializeSpatial(); this->LoadMapEffects(); - this->ground->InitializeLighting(*this->terrain); + this->ground->InitializeLighting(); this->published = static_cast(this->models.size()); diff --git a/Source/Contents/World/WorldModelView.cpp b/Source/Contents/World/WorldModelView.cpp index ff49db9f9..a81fd4675 100644 --- a/Source/Contents/World/WorldModelView.cpp +++ b/Source/Contents/World/WorldModelView.cpp @@ -249,11 +249,11 @@ void CView::Render() { g_navigationManager.DrawRoute(matrix); if (g_groundOverlaySkip == 0) { - this->scene->ground->DrawGrid(*this->scene->terrain, matrix, g_groundOverlayA, g_groundOverlayB, g_groundOverlayC); + this->scene->ground->DrawGrid(matrix, g_groundOverlayA, g_groundOverlayB, g_groundOverlayC); } if (g_session.unknown_5614 != 0 && g_session.unknown_5600 != 0 && g_session.unknown_5604 != 0) { - this->scene->ground->DrawGrid(*this->scene->terrain, matrix, g_session.unknown_5600, g_session.unknown_5604, 0xfeff0000); + this->scene->ground->DrawGrid(matrix, g_session.unknown_5600, g_session.unknown_5604, 0xfeff0000); } for (auto it = this->scene->objects.begin(); it != this->scene->objects.end(); ++it) { @@ -276,5 +276,5 @@ void CView::Render() { this->spatial.inside.clear(); this->spatial.clipped.clear(); - this->scene->ground->Ground15Slot04(reinterpret_cast(matrix)); + this->scene->ground->Slot04(reinterpret_cast(matrix)); }