diff --git a/Source/Contents/World/WorldSpatialTree.cpp b/Source/Contents/World/WorldSpatialTree.cpp index d57eba3..6220b54 100644 --- a/Source/Contents/World/WorldSpatialTree.cpp +++ b/Source/Contents/World/WorldSpatialTree.cpp @@ -5,7 +5,7 @@ #include "Contents/Movies/BinkMovies.h" #include "Contents/World/WorldScene.h" #include "Contents/World/WorldSpatialTree.h" -#include "Resource/ResourceByteReader.h" +#include "File/File.h" #include "Resource/World/TerrainResource.h" // OFFSET: 0x00AC64F0 @@ -105,7 +105,7 @@ void WorldSpatialTree::Subdivide(int depth) { // OFFSET: 0x00AC8F60 // FUNCTION: fn_17681 -void WorldSpatialTree::ReadBounds(ResourceByteReader& input, int depth) { +void WorldSpatialTree::ReadBounds(CFile& input, int depth) { for (float& value : this->maximum) { input.Read(&value, sizeof(value)); } diff --git a/Source/Contents/World/WorldSpatialTree.h b/Source/Contents/World/WorldSpatialTree.h index 69374fd..ffc81d7 100644 --- a/Source/Contents/World/WorldSpatialTree.h +++ b/Source/Contents/World/WorldSpatialTree.h @@ -4,7 +4,7 @@ #include #include -struct ResourceByteReader; +class CFile; class C3dAttr; struct GroundSpatial; class C3dActor; @@ -15,7 +15,7 @@ struct WorldSpatialTree { WorldSpatialTree(const WorldSpatialTree&) = delete; WorldSpatialTree& operator=(const WorldSpatialTree&) = delete; void Subdivide(int depth); - void ReadBounds(ResourceByteReader& input, int depth); + void ReadBounds(CFile& input, int depth); void ClearChildren(); void BindTerrain(C3dAttr& resource, int depth); void BindGround(GroundSpatial& resource, int depth); diff --git a/Source/Resource/World/WorldResource.cpp b/Source/Resource/World/WorldResource.cpp index 64d8421..8713b96 100644 --- a/Source/Resource/World/WorldResource.cpp +++ b/Source/Resource/World/WorldResource.cpp @@ -1,11 +1,9 @@ #include "Client/Application/ErrorDialog.h" -#include "Resource/Bitmap/BitmapResource.h" -#include "Resource/ResourceByteReader.h" +#include "File/File.h" +#include "Render/DeviceContext/DCSurface.h" #include "Resource/World/WorldResource.h" #include "Utility/Math/AffineMatrix.h" -#include -#include #include #include @@ -15,6 +13,34 @@ WorldLighting g_worldLighting{}; namespace { + struct WorldModelFileRecord { + /* 0000 */ char model[80]; + /* 0050 */ char node[80]; + /* 00A0 */ float position[3]{}; + /* 00AC */ float rotation[3]{}; + /* 00B8 */ float scale[3]{}; + }; + + struct WorldLightFileRecord { + /* 0000 */ char name[80]; + /* 0050 */ float position[3]{}; + /* 005C */ unsigned char unknown_005C[16]; + }; + + struct WorldLegacySoundFileRecord { + /* 0000 */ char name[80]; + /* 0050 */ char file[80]; + /* 00A0 */ float position[3]{}; + /* 00AC */ float volume; + /* 00B0 */ int width; + /* 00B4 */ int height; + /* 00B8 */ float range; + }; + + static_assert(sizeof(WorldModelFileRecord) == 0xC4); + static_assert(sizeof(WorldLightFileRecord) == 0x6C); + static_assert(sizeof(WorldLegacySoundFileRecord) == 0xBC); + // OFFSET: 0x00763010 // FUNCTION: fn_08075 signed char CompareWorldVersion(const int targetVersion[2], const unsigned char* const fileVersion[2]) { @@ -34,22 +60,27 @@ namespace { return 0; } + + // OFFSET: 0x00763740 + // FUNCTION: fn_08079 + unsigned char IsUnsupportedWorldVersion(unsigned major, unsigned minor, unsigned build, char* message, unsigned capacity) { + return 0; + } } // OFFSET: 0x00763060 // FUNCTION: fn_08076 -C3dWorldRes::C3dWorldRes(WorldResourceContext& context) : spatial(nullptr), lightDirection{}, diffuse{}, ambient{}, flag(0), m_context(&context) { +C3dWorldRes::C3dWorldRes() : spatial(nullptr), lightDirection{}, diffuse{}, ambient{}, flag(0) { } // OFFSET: 0x00763550 -// OFFSET: 0x00762FE0 // FUNCTION: fn_08077 C3dWorldRes::~C3dWorldRes() = default; // OFFSET: 0x00761940 // FUNCTION: fn_08071 C3dWorldRes* C3dWorldRes::Create() { - return new C3dWorldRes(*this->m_context); + return new C3dWorldRes; } // OFFSET: 0x00761B40 @@ -77,7 +108,7 @@ void C3dWorldRes::Unload() { } // INLINED -inline void C3dWorldRes::ReadEnvironment(ResourceByteReader& input, unsigned version) { +inline void C3dWorldRes::ReadEnvironment(CFile& input, unsigned version) { if (version < 0x206u) { if (version >= 0x103u) { input.Read(&this->waterLevel, sizeof(this->waterLevel)); @@ -148,7 +179,7 @@ inline void C3dWorldRes::ReadEnvironment(ResourceByteReader& input, unsigned ver } // INLINED -inline void C3dWorldRes::ReadObjects(ResourceByteReader& input, unsigned version, unsigned build, char* lastName) { +inline void C3dWorldRes::ReadObjects(CFile& input, unsigned version, unsigned build, char* lastName) { int count; input.Read(&count, sizeof(count)); @@ -178,54 +209,55 @@ inline void C3dWorldRes::ReadObjects(ResourceByteReader& input, unsigned version input.Read(&modelIndex, sizeof(modelIndex)); } - if (speed > 100.0f || !(0.0f < speed)) { + if (speed > 100.0f || speed <= 0.0f) { speed = 1.0f; } } - std::array wire; - std::memset(wire.data() + 160, 0, 36); - input.Read(wire.data(), static_cast(wire.size())); + WorldModelFileRecord wire; + input.Read(&wire, sizeof(wire)); auto* record = new WorldModelRecord; - std::strcpy(record->name, lastName); - std::strcpy(record->model, reinterpret_cast(wire.data())); - std::strcpy(record->node, reinterpret_cast(wire.data() + 80)); - std::memcpy(record->position, wire.data() + 160, 12); - std::memcpy(record->rotation, wire.data() + 172, 12); - std::memcpy(record->scale, wire.data() + 184, 12); - record->animationSpeed = speed; - record->animation = animation; - record->unknown_00F0 = unknown; - record->flag = flag != 0; - record->index = modelIndex; - this->models.push_back(record); + + if (record) { + std::strcpy(record->name, lastName); + std::strcpy(record->model, wire.model); + std::strcpy(record->node, wire.node); + std::memcpy(record->position, wire.position, sizeof(record->position)); + std::memcpy(record->rotation, wire.rotation, sizeof(record->rotation)); + std::memcpy(record->scale, wire.scale, sizeof(record->scale)); + record->animationSpeed = speed; + record->animation = animation; + record->unknown_00F0 = unknown; + record->flag = flag != 0; + record->index = modelIndex; + this->models.push_back(record); + } break; } case 2: { - unsigned char light[108]; - std::memset(light + 72, 0, 12); - input.Read(light, sizeof(light)); + WorldLightFileRecord light; + input.Read(&light, sizeof(light)); break; } case 3: { - auto* record = new WorldSoundRecord; - std::memset(record->position, 0, sizeof(record->position)); + WorldSoundRecord* record; if (version < 0x200u) { - unsigned char wire[188]; - std::memset(wire + 160, 0, 12); - input.Read(wire, sizeof(wire)); - std::strncpy(record->name, reinterpret_cast(wire), 79); - std::strncpy(record->file, reinterpret_cast(wire + 80), 79); - std::memcpy(record->position, wire + 160, 12); - std::memcpy(&record->volume, wire + 172, 4); - std::memcpy(&record->width, wire + 176, 4); - std::memcpy(&record->height, wire + 180, 4); - std::memcpy(&record->range, wire + 184, 4); + WorldLegacySoundFileRecord wire; + input.Read(&wire, sizeof(wire)); + record = new WorldSoundRecord; + std::strncpy(record->name, wire.name, 79); + std::strncpy(record->file, wire.file, 79); + std::memcpy(record->position, wire.position, sizeof(record->position)); + record->volume = wire.volume; + record->width = wire.width; + record->height = wire.height; + record->range = wire.range; record->cycle = 4.0f; } else { + record = new WorldSoundRecord; input.Read(record, sizeof(*record)); } @@ -235,7 +267,6 @@ inline void C3dWorldRes::ReadObjects(ResourceByteReader& input, unsigned version case 4: { auto* record = new WorldEffectRecord; - std::memset(record->position, 0, sizeof(record->position)); input.Read(record, sizeof(*record)); this->effects.push_back(record); break; @@ -251,26 +282,18 @@ inline void C3dWorldRes::ReadObjects(ResourceByteReader& input, unsigned version // FUNCTION: fn_08073 bool C3dWorldRes::Load(const char* name) { this->Unload(); - auto& file = this->m_context->file; - struct CloseFile { - ResourceBytes& file; + CFile input; - ~CloseFile() { - file.Close(); - } - } close{file}; - - if (!file.Open(name)) { + if (!input.Open(name, 0, true, false)) { return false; } - ResourceByteReader input{static_cast(file.Data()), static_cast(file.Size())}; char magic[5]; input.Read(magic, 4); magic[4] = 0; if (std::strcmp(magic, "GRSW") != 0) { - ShowErrorDialog(this->m_context->renderSystem, "Invalid Format", 0); + ShowErrorDialog(GetRenderSystemHolder()->system, "Invalid Format", 0); return false; } @@ -280,10 +303,11 @@ bool C3dWorldRes::Load(const char* name) { input.Read(&minor, 1); const unsigned version = static_cast(major) * 256u + minor; + char message[256]; + if (version > 0x207u) { - char message[256]; std::snprintf(message, sizeof(message), "Unsupported Version\n current version: %d.%d < %d.%d", 2, 7, major, minor); - ShowErrorDialog(this->m_context->renderSystem, message, 0); + ShowErrorDialog(GetRenderSystemHolder()->system, message, 0); return false; } @@ -296,6 +320,11 @@ bool C3dWorldRes::Load(const char* name) { input.Read(&build, sizeof(build)); } + if (IsUnsupportedWorldVersion(major, minor, build, message, sizeof(message)) == 1) { + ShowErrorDialog(GetRenderSystemHolder()->system, message, 0); + return false; + } + if (major == 2 && minor >= 2) { input.Read(&this->flag, 1); } @@ -321,8 +350,7 @@ bool C3dWorldRes::Load(const char* name) { unsigned count; input.Read(&count, sizeof(count)); - const unsigned position = input.position + 4u * count; - input.position = position <= input.size ? position : input.size; + input.Seek(4u * count, FILE_CURRENT); } this->ReadObjects(input, version, build, lastName); @@ -333,10 +361,10 @@ bool C3dWorldRes::Load(const char* name) { this->spatial->ReadBounds(input, 0); } - file.Close(); - std::memcpy(this->m_context->lighting.ambient, this->ambient, sizeof(this->ambient)); - std::memcpy(this->m_context->lighting.diffuse, this->diffuse, sizeof(this->diffuse)); - std::memcpy(this->m_context->lighting.secondaryDiffuse, this->diffuse, sizeof(this->diffuse)); + input.Close(); + std::memcpy(g_worldLighting.ambient, this->ambient, sizeof(this->ambient)); + std::memcpy(g_worldLighting.diffuse, this->diffuse, sizeof(this->diffuse)); + std::memcpy(g_worldLighting.secondaryDiffuse, this->diffuse, sizeof(this->diffuse)); return true; } diff --git a/Source/Resource/World/WorldResource.h b/Source/Resource/World/WorldResource.h index 031d654..6511c95 100644 --- a/Source/Resource/World/WorldResource.h +++ b/Source/Resource/World/WorldResource.h @@ -8,16 +8,15 @@ #include #include -class ResourceBytes; -struct ResourceByteReader; +class CFile; struct WorldModelRecord { /* 0000 */ char name[40]; /* 0028 */ char model[80]; /* 0078 */ char node[80]; - /* 00C8 */ float position[3]; - /* 00D4 */ float rotation[3]; - /* 00E0 */ float scale[3]; + /* 00C8 */ float position[3]{}; + /* 00D4 */ float rotation[3]{}; + /* 00E0 */ float scale[3]{}; /* 00EC */ int animation; /* 00F0 */ int unknown_00F0; /* 00F4 */ float animationSpeed; @@ -30,7 +29,7 @@ struct WorldModelRecord { struct WorldSoundRecord { /* 0000 */ char name[80]; /* 0050 */ char file[80]; - /* 00A0 */ float position[3]; + /* 00A0 */ float position[3]{}; /* 00AC */ float volume; /* 00B0 */ int width; /* 00B4 */ int height; @@ -40,28 +39,22 @@ struct WorldSoundRecord { struct WorldEffectRecord { /* 0000 */ char name[80]; - /* 0050 */ float position[3]; + /* 0050 */ float position[3]{}; /* 005C */ int id; /* 0060 */ float delay; /* 0064 */ float parameters[4]; }; struct WorldLighting { - float diffuse[3]; - float secondaryDiffuse[3]; - float ambient[3]; + /* 0000 */ float diffuse[3]; + /* 000C */ float secondaryDiffuse[3]; + /* 0018 */ float ambient[3]; }; extern WorldLighting g_worldLighting; -struct WorldResourceContext { - ResourceBytes& file; - CRenderSystemBase*& renderSystem; - WorldLighting& lighting; -}; - class C3dWorldRes : public CRes { public: - explicit C3dWorldRes(WorldResourceContext& context); + C3dWorldRes(); ~C3dWorldRes() override; C3dWorldRes* Create() override; bool Load(const char* name) override; @@ -93,9 +86,8 @@ public: /* 01CD */ unsigned char unknown_01CD[3]; private: - void ReadEnvironment(ResourceByteReader& input, unsigned version); - void ReadObjects(ResourceByteReader& input, unsigned version, unsigned build, char* lastName); - WorldResourceContext* m_context; + void ReadEnvironment(CFile& input, unsigned version); + void ReadObjects(CFile& input, unsigned version, unsigned build, char* lastName); }; static_assert(sizeof(WorldModelRecord) == 268); @@ -112,7 +104,19 @@ static_assert(offsetof(WorldEffectRecord, position) == 0x0050); static_assert(offsetof(WorldEffectRecord, id) == 0x005C); static_assert(offsetof(WorldEffectRecord, delay) == 0x0060); static_assert(offsetof(WorldEffectRecord, parameters) == 0x0064); -static_assert(sizeof(C3dWorldRes) == 468); +static_assert(offsetof(C3dWorldRes, models) == 0x0110); +static_assert(offsetof(C3dWorldRes, effects) == 0x0118); +static_assert(offsetof(C3dWorldRes, sounds) == 0x0120); +static_assert(offsetof(C3dWorldRes, spatial) == 0x0128); +static_assert(offsetof(C3dWorldRes, groundName) == 0x012C); +static_assert(offsetof(C3dWorldRes, terrainName) == 0x0144); +static_assert(offsetof(C3dWorldRes, sourceName) == 0x015C); +static_assert(offsetof(C3dWorldRes, lightDirection) == 0x0194); +static_assert(offsetof(C3dWorldRes, diffuse) == 0x01A0); +static_assert(offsetof(C3dWorldRes, ambient) == 0x01AC); +static_assert(offsetof(C3dWorldRes, flag) == 0x01CC); +static_assert(sizeof(C3dWorldRes) == 0x01D0); +static_assert(sizeof(WorldLighting) == 0x24); #endif #endif