Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move init data logic to resource loader #790

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/graphic/Fast3D/gfx_pc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#endif
#include "graphic/Fast3D/debug/GfxDebugger.h"
#include "libultraship/libultra/types.h"
//#include "libultraship/libultra/gs2dex.h"
// #include "libultraship/libultra/gs2dex.h"
#include <string>

#include "gfx_pc.h"
Expand Down Expand Up @@ -879,6 +879,19 @@ static void import_texture_ci8(int tile, bool importReplacement) {
gfx_rapi->upload_texture(tex_upload_buffer, width, height);
}

static void import_texture_img(int tile, bool importReplacement) {
const RawTexMetadata* metadata = &g_rdp.loaded_texture[g_rdp.texture_tile[tile].tmem_index].raw_tex_metadata;
const uint8_t* addr =
importReplacement && (metadata->resource != nullptr)
? masked_textures.find(gfx_get_base_texture_path(metadata->resource->GetInitData()->Path))
->second.replacementData
: g_rdp.loaded_texture[g_rdp.texture_tile[tile].tmem_index].addr;

uint16_t width = metadata->width;
uint16_t height = metadata->height;
gfx_rapi->upload_texture(addr, width, height);
}

static void import_texture_raw(int tile, bool importReplacement) {
const RawTexMetadata* metadata = &g_rdp.loaded_texture[g_rdp.texture_tile[tile].tmem_index].raw_tex_metadata;
const uint8_t* addr =
Expand Down Expand Up @@ -982,6 +995,11 @@ static void import_texture(int i, int tile, bool importReplacement) {
return;
}

if ((texFlags & TEX_FLAG_LOAD_AS_IMG) != 0) {
import_texture_img(tile, importReplacement);
return;
}

// if load as raw is set then we load_raw();
if ((texFlags & TEX_FLAG_LOAD_AS_RAW) != 0) {
import_texture_raw(tile, importReplacement);
Expand Down
6 changes: 4 additions & 2 deletions src/resource/ResourceFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
namespace Ship {
class ResourceFactory {
public:
virtual std::shared_ptr<IResource> ReadResource(std::shared_ptr<File> file) = 0;
virtual std::shared_ptr<IResource> ReadResource(std::shared_ptr<File> file,
std::shared_ptr<ResourceInitData> initData) = 0;

protected:
virtual bool FileHasValidFormatAndReader(std::shared_ptr<File> file) = 0;
virtual bool FileHasValidFormatAndReader(std::shared_ptr<File> file,
std::shared_ptr<Ship::ResourceInitData> initData) = 0;
};
} // namespace Ship
7 changes: 4 additions & 3 deletions src/resource/ResourceFactoryBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
#include "spdlog/spdlog.h"

namespace Ship {
bool ResourceFactoryBinary::FileHasValidFormatAndReader(std::shared_ptr<File> file) {
if (file->InitData->Format != RESOURCE_FORMAT_BINARY) {
bool ResourceFactoryBinary::FileHasValidFormatAndReader(std::shared_ptr<File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (initData->Format != RESOURCE_FORMAT_BINARY) {
SPDLOG_ERROR("resource file format does not match factory format.");
return false;
}

if (!std::holds_alternative<std::shared_ptr<BinaryReader>>(file->Reader)) {
SPDLOG_ERROR("Failed to load resource: File has Reader ({} - {})", file->InitData->Type, file->InitData->Path);
SPDLOG_ERROR("Failed to load resource: File has Reader ({} - {})", initData->Type, initData->Path);
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion src/resource/ResourceFactoryBinary.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Ship {
class ResourceFactoryBinary : public ResourceFactory {
protected:
bool FileHasValidFormatAndReader(std::shared_ptr<File> file) override;
bool FileHasValidFormatAndReader(std::shared_ptr<File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
} // namespace Ship
8 changes: 4 additions & 4 deletions src/resource/ResourceFactoryXML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
#include "spdlog/spdlog.h"

namespace Ship {
bool ResourceFactoryXML::FileHasValidFormatAndReader(std::shared_ptr<File> file) {
if (file->InitData->Format != RESOURCE_FORMAT_XML) {
bool ResourceFactoryXML::FileHasValidFormatAndReader(std::shared_ptr<File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (initData->Format != RESOURCE_FORMAT_XML) {
SPDLOG_ERROR("resource file format does not match factory format.");
return false;
}

if (!std::holds_alternative<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)) {
SPDLOG_ERROR("Failed to load resource: File has no XML document ({} - {})", file->InitData->Type,
file->InitData->Path);
SPDLOG_ERROR("Failed to load resource: File has no XML document ({} - {})", initData->Type, initData->Path);
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion src/resource/ResourceFactoryXML.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Ship {
class ResourceFactoryXML : public ResourceFactory {
protected:
bool FileHasValidFormatAndReader(std::shared_ptr<File> file) override;
bool FileHasValidFormatAndReader(std::shared_ptr<File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
} // namespace Ship
202 changes: 195 additions & 7 deletions src/resource/ResourceLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,216 @@ std::shared_ptr<ResourceFactory> ResourceLoader::GetFactory(uint32_t format, std
return GetFactory(format, mResourceTypes[typeName], version);
}

std::shared_ptr<IResource> ResourceLoader::LoadResource(std::shared_ptr<File> fileToLoad) {
std::shared_ptr<ResourceInitData> ResourceLoader::ReadResourceInitDataLegacy(const std::string& filePath,
std::shared_ptr<File> fileToLoad) {
if (fileToLoad->Buffer->at(0) == '<') { // Determine if file is binary or XML...
// File is XML
// Read the xml document
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);

auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();

xmlReader->Parse(binaryReader->ReadCString().data());
if (xmlReader->Error()) {
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", filePath, xmlReader->ErrorStr());
return nullptr;
}
return ReadResourceInitDataXml(filePath, xmlReader);
} else {
auto headerBuffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(),
fileToLoad->Buffer->begin() + OTR_HEADER_SIZE);

if (headerBuffer->size() < OTR_HEADER_SIZE) {
SPDLOG_ERROR("Failed to parse ResourceInitData, buffer size too small. File: {}. Got {} bytes and "
"needed {} bytes.",
filePath, headerBuffer->size(), OTR_HEADER_SIZE);
return nullptr;
}

// Factories expect the buffer to not include the header,
// so we need to remove it from the buffer on the file
fileToLoad->Buffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE,
fileToLoad->Buffer->end());

// Create a reader for the header buffer
auto headerStream = std::make_shared<MemoryStream>(headerBuffer);
auto headerReader = std::make_shared<BinaryReader>(headerStream);
return ReadResourceInitDataBinary(filePath, headerReader);
}
}

std::shared_ptr<BinaryReader> ResourceLoader::CreateBinaryReader(std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData) {
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto reader = std::make_shared<BinaryReader>(stream);
reader->SetEndianness(initData->ByteOrder);
return reader;
}

std::shared_ptr<tinyxml2::XMLDocument> ResourceLoader::CreateXMLReader(std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData) {
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);

auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();

xmlReader->Parse(binaryReader->ReadCString().data());
if (xmlReader->Error()) {
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", initData->Path, xmlReader->ErrorStr());
return nullptr;
}

return xmlReader;
}

std::shared_ptr<ResourceInitData> ResourceLoader::CreateDefaultResourceInitData() {
auto resourceInitData = std::make_shared<ResourceInitData>();
resourceInitData->Id = 0xDEADBEEFDEADBEEF;
resourceInitData->Type = static_cast<uint32_t>(ResourceType::None);
resourceInitData->ResourceVersion = -1;
resourceInitData->IsCustom = false;
resourceInitData->Format = RESOURCE_FORMAT_BINARY;
resourceInitData->ByteOrder = Endianness::Native;
return resourceInitData;
}

std::shared_ptr<ResourceInitData> ResourceLoader::ReadResourceInitData(const std::string& filePath,
std::shared_ptr<File> metaFileToLoad) {
auto initData = CreateDefaultResourceInitData();

// just using metaFileToLoad->Buffer->data() leads to garbage at the end
// that causes nlohmann to fail parsing, following the pattern used for
// xml resolves that issue
auto stream = std::make_shared<MemoryStream>(metaFileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);
auto parsed = nlohmann::json::parse(binaryReader->ReadCString());

if (parsed.contains("path")) {
initData->Path = parsed["path"];
} else {
initData->Path = filePath;
}

auto formatString = parsed["format"];
if (formatString == "XML") {
initData->Format = RESOURCE_FORMAT_XML;
}

initData->Type = Context::GetInstance()->GetResourceManager()->GetResourceLoader()->GetResourceType(parsed["type"]);
initData->ResourceVersion = parsed["version"];

return initData;
}

std::shared_ptr<IResource> ResourceLoader::LoadResource(std::string filePath, std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData) {
if (fileToLoad == nullptr) {
SPDLOG_ERROR("Failed to load resource: File not loaded");
return nullptr;
}

if (fileToLoad->InitData == nullptr) {
SPDLOG_ERROR("Failed to load resource: ResourceInitData not loaded");
if (initData == nullptr) {
auto metaFilePath = filePath + ".meta";
auto metaFileToLoad = Context::GetInstance()->GetResourceManager()->LoadFileProcess(metaFilePath);

if (metaFileToLoad != nullptr) {
auto initDataFromMetaFile = ReadResourceInitData(filePath, metaFileToLoad);
fileToLoad = Context::GetInstance()->GetResourceManager()->LoadFileProcess(initDataFromMetaFile->Path);
initData = initDataFromMetaFile;
} else {
initData = ReadResourceInitDataLegacy(filePath, fileToLoad);
}
}

if (fileToLoad == nullptr) {
SPDLOG_ERROR("Failed to load file at path {}.", filePath);
return nullptr;
}

auto factory =
GetFactory(fileToLoad->InitData->Format, fileToLoad->InitData->Type, fileToLoad->InitData->ResourceVersion);
switch (initData->Format) {
case RESOURCE_FORMAT_BINARY:
fileToLoad->Reader = CreateBinaryReader(fileToLoad, initData);
break;
case RESOURCE_FORMAT_XML:
fileToLoad->Reader = CreateXMLReader(fileToLoad, initData);
break;
}

// initData->Parent = shared_from_this();

auto factory = GetFactory(initData->Format, initData->Type, initData->ResourceVersion);
if (factory == nullptr) {
SPDLOG_ERROR("LoadResource failed to find factory for the resource at path: {}", fileToLoad->InitData->Path);
SPDLOG_ERROR("LoadResource failed to find factory for the resource at path: {}", initData->Path);
return nullptr;
}

return factory->ReadResource(fileToLoad);
return factory->ReadResource(fileToLoad, initData);
}

uint32_t ResourceLoader::GetResourceType(const std::string& type) {
return mResourceTypes.contains(type) ? mResourceTypes[type] : static_cast<uint32_t>(ResourceType::None);
}

std::shared_ptr<ResourceInitData>
ResourceLoader::ReadResourceInitDataBinary(const std::string& filePath, std::shared_ptr<BinaryReader> headerReader) {
auto resourceInitData = CreateDefaultResourceInitData();
resourceInitData->Path = filePath;

if (headerReader == nullptr) {
SPDLOG_ERROR("Error reading OTR header from Binary: No header buffer document for file {}", filePath);
return resourceInitData;
}

// OTR HEADER BEGIN
// Byte Order
resourceInitData->ByteOrder = (Endianness)headerReader->ReadInt8();
headerReader->SetEndianness(resourceInitData->ByteOrder);
// Is this asset custom?
resourceInitData->IsCustom = (bool)headerReader->ReadInt8();
// Unused two bytes
for (int i = 0; i < 2; i++) {
headerReader->ReadInt8();
}
// The type of the resource
resourceInitData->Type = headerReader->ReadUInt32();
// Resource version
resourceInitData->ResourceVersion = headerReader->ReadUInt32();
// Unique asset ID
resourceInitData->Id = headerReader->ReadUInt64();
// Reserved
// reader->ReadUInt32();
// ROM CRC
// reader->ReadUInt64();
// ROM Enum
// reader->ReadUInt32();
// Reserved for future file format versions...
// reader->Seek(OTR_HEADER_SIZE, SeekOffsetType::Start);
// OTR HEADER END

headerReader->Seek(0, SeekOffsetType::Start);
return resourceInitData;
}

std::shared_ptr<ResourceInitData>
ResourceLoader::ReadResourceInitDataXml(const std::string& filePath, std::shared_ptr<tinyxml2::XMLDocument> document) {
auto resourceInitData = CreateDefaultResourceInitData();
resourceInitData->Path = filePath;

if (document == nullptr) {
SPDLOG_ERROR("Error reading OTR header from XML: No XML document for file {}", filePath);
return resourceInitData;
}

// XML
resourceInitData->IsCustom = true;
resourceInitData->Format = RESOURCE_FORMAT_XML;

auto root = document->FirstChildElement();
resourceInitData->Type =
Context::GetInstance()->GetResourceManager()->GetResourceLoader()->GetResourceType(root->Name());
resourceInitData->ResourceVersion = root->IntAttribute("Version");

return resourceInitData;
}
} // namespace Ship
18 changes: 17 additions & 1 deletion src/resource/ResourceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class ResourceLoader {
ResourceLoader();
~ResourceLoader();

std::shared_ptr<IResource> LoadResource(std::shared_ptr<File> fileToLoad);
std::shared_ptr<IResource> LoadResource(std::string filePath, std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData = nullptr);
bool RegisterResourceFactory(std::shared_ptr<ResourceFactory> factory, uint32_t format, std::string typeName,
uint32_t type, uint32_t version);

Expand All @@ -42,6 +43,21 @@ class ResourceLoader {
void RegisterGlobalResourceFactories();
std::shared_ptr<ResourceFactory> GetFactory(uint32_t format, uint32_t type, uint32_t version);
std::shared_ptr<ResourceFactory> GetFactory(uint32_t format, std::string typeName, uint32_t version);
std::shared_ptr<ResourceInitData> ReadResourceInitData(const std::string& filePath,
std::shared_ptr<File> metaFileToLoad);
static std::shared_ptr<ResourceInitData> CreateDefaultResourceInitData();
std::shared_ptr<ResourceInitData> ReadResourceInitDataLegacy(const std::string& filePath,
std::shared_ptr<File> fileToLoad);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataBinary(const std::string& filePath,
std::shared_ptr<BinaryReader> headerReader);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataXml(const std::string& filePath,
std::shared_ptr<tinyxml2::XMLDocument> document);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataPng(const std::string& filePath,
std::shared_ptr<BinaryReader> headerReader);
std::shared_ptr<BinaryReader> CreateBinaryReader(std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData);
std::shared_ptr<tinyxml2::XMLDocument> CreateXMLReader(std::shared_ptr<File> fileToLoad,
std::shared_ptr<ResourceInitData> initData);

private:
std::string DecodeASCII(uint32_t value);
Expand Down
Loading
Loading