This commit is contained in:
2024-10-03 20:09:10 -05:00
parent 2ff1a159bc
commit ad317da97e
303 changed files with 1613 additions and 21403 deletions

View File

@ -1,200 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
#include "AssetDataLoader.hpp"
#include "util/Math.hpp"
using namespace Dawn;
ssize_t assetDataLoaderArchiveRead(
struct archive *archive,
void *d,
const void **buffer
) {
assertNotNull(archive, "Archive is NULL!");
assertNotNull(d, "Data is NULL!");
assertNotNull(buffer, "Buffer is NULL!");
AssetDataLoader *loader = (AssetDataLoader*)d;
*buffer = loader->buffer;
size_t read = fread(
loader->buffer, 1, ASSET_LOADER_BUFFER_SIZE, loader->assetArchiveFile
);
if(ferror(loader->assetArchiveFile)) return ARCHIVE_FATAL;
return read;
}
int64_t assetDataLoaderArchiveSeek(
struct archive *archive,
void *d,
int64_t offset,
int32_t whence
) {
assertNotNull(archive, "Archive is NULL!");
assertNotNull(d, "Data is NULL!");
assertTrue(offset > 0, "Offset must be greater than 0!");
AssetDataLoader *loader = (AssetDataLoader*)d;
int32_t ret = fseek(loader->assetArchiveFile, offset, whence);
assertTrue(ret == 0, "Failed to seek!");
return ftell(loader->assetArchiveFile);
}
int32_t assetDataLoaderArchiveOpen(struct archive *a, void *d) {
assertNotNull(a, "Archive is NULL!");
assertNotNull(d, "Data is NULL!");
AssetDataLoader *loader = (AssetDataLoader*)d;
int32_t ret = fseek(loader->assetArchiveFile, 0, SEEK_SET);
assertTrue(ret == 0, "Failed to seek to start of file!");
return ARCHIVE_OK;
}
int32_t assetDataLoaderArchiveClose(struct archive *a, void *d) {
assertNotNull(a, "Archive is NULL!");
assertNotNull(d, "Data is NULL!");
return assetDataLoaderArchiveOpen(a, d);
}
// // // // // // // // // // // // // // // // // // // // // // // // // // //
AssetDataLoader::AssetDataLoader(std::string fileName) : fileName(fileName) {
assertTrue(
fileName.size() > 0,
"IAssetDataLoader::IAssetDataLoader: fileName must be greater than 0"
);
}
void AssetDataLoader::open() {
assertNull(this->assetArchiveFile, "AssetDataLoader::open: File is already open");
assertNull(this->assetArchive, "AssetDataLoader::open: Archive is already open");
assertNull(this->assetArchiveEntry, "AssetDataLoader::open: Entry is already open");
this->assetArchiveFile = this->openAssetArchiveFile();
assertNotNull(this->assetArchiveFile, "AssetDataLoader::open: Failed to open archive file!");
// Open archive reader
assetArchive = archive_read_new();
assertNotNull(assetArchive, "AssetDataLoader::open: Failed to create archive reader");
// Set up the reader
archive_read_support_format_tar(assetArchive);
// Open reader
archive_read_set_open_callback(assetArchive, &assetDataLoaderArchiveOpen);
archive_read_set_read_callback(assetArchive, &assetDataLoaderArchiveRead);
archive_read_set_seek_callback(assetArchive, &assetDataLoaderArchiveSeek);
archive_read_set_close_callback(assetArchive, &assetDataLoaderArchiveClose);
archive_read_set_callback_data(assetArchive, this);
int32_t ret = archive_read_open1(assetArchive);
assertTrue(ret == ARCHIVE_OK, "AssetDataLoader::open: Failed to open archive!");
position = 0;
// Iterate over each file to find the one for this asset loader.
while(archive_read_next_header(assetArchive, &assetArchiveEntry) == ARCHIVE_OK) {
const char_t *headerFile = (char_t*)archive_entry_pathname(assetArchiveEntry);
if(std::string(headerFile) == this->fileName) return;
int32_t ret = archive_read_data_skip(assetArchive);
assertTrue(ret == ARCHIVE_OK, "AssetDataLoader::open: Failed to skip data!");
}
assertUnreachable("AssetDataLoader::open: Failed to find file!");
}
int32_t AssetDataLoader::close() {
assertNotNull(this->assetArchiveFile, "AssetDataLoader::close: File is NULL");
assertNotNull(this->assetArchive, "AssetDataLoader::close: Archive is NULL!");
assertNotNull(this->assetArchiveEntry, "AssetDataLoader::close: Entry is NULL!");
// Close the archive
int32_t ret = archive_read_free(this->assetArchive);
assertTrue(ret == ARCHIVE_OK, "AssetDataLoader::close: Failed to close archive!");
this->assetArchive = nullptr;
this->assetArchiveEntry = nullptr;
// Close the file
int32_t res = fclose(this->assetArchiveFile);
this->assetArchiveFile = nullptr;
return res;
}
size_t AssetDataLoader::read(uint8_t *buffer, size_t size) {
assertNotNull(buffer, "Buffer is NULL!");
assertTrue(size > 0, "Size must be greater than 0!");
assertNotNull(this->assetArchive, "assetRead: Archive is NULL!");
assertNotNull(this->assetArchiveEntry, "assetRead: Entry is NULL!");
ssize_t read = archive_read_data(this->assetArchive, buffer, size);
this->position += read;
if(read == ARCHIVE_FATAL) {
assertUnreachable(archive_error_string(this->assetArchive));
}
assertTrue(read != ARCHIVE_RETRY, "assetRead: Failed to read data (RETRY)!");
assertTrue(read != ARCHIVE_WARN, "assetRead: Failed to read data (WARN)!");
return read;
}
size_t AssetDataLoader::readUntil(
uint8_t *buffer,
const size_t maxSize,
const char_t delimiter
) {
size_t totalRead = this->read(buffer, maxSize);
size_t i = 0;
while(i < totalRead) {
if(buffer[i] == delimiter) break;
i++;
}
buffer[i++] = '\0';
return i;
}
size_t AssetDataLoader::getSize() {
assertTrue(this->assetArchiveEntry != nullptr, "AssetDataLoader::getSize: Entry is NULL!");
assertTrue(archive_entry_size_is_set(assetArchiveEntry), "assetGetSize: Entry size is not set!");
return archive_entry_size(assetArchiveEntry);
}
size_t AssetDataLoader::skip(size_t n) {
assertTrue(n >= 0, "AssetDataLoader::skip: Byte count must be greater than 0.");
uint8_t dumpBuffer[ASSET_LOADER_BUFFER_SIZE];
size_t skipped = 0;
size_t n2, n3;
while(n != 0) {
n2 = Math::min<size_t>(n, ASSET_LOADER_BUFFER_SIZE);
n3 = this->read(dumpBuffer, n2);
assertTrue(n3 == n2, "AssetDataLoader::skip: Failed to skip bytes!");
n -= n3;
}
return skipped;
}
size_t AssetDataLoader::setPosition(const size_t position) {
assertTrue(position >= 0, "Position must be greater than or equal to 0");
this->rewind();
return this->skip(position);
}
void AssetDataLoader::rewind() {
// TODO: See if I can optimize this
this->close();
this->open();
}
size_t AssetDataLoader::getPosition() {
assertNotNull(this->assetArchiveFile, "AssetDataLoader::getPosition: File is not open!");
return this->position;
}
AssetDataLoader::~AssetDataLoader() {
if(this->assetArchiveFile != nullptr) this->close();
}

View File

@ -1,166 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
extern "C" {
#include <archive.h>
#include <archive_entry.h>
}
#define ASSET_LOADER_BUFFER_SIZE 32768
/**
* Method invoked by the libarchive internals to read bytes from the archive
* file pointer.
*
* @param archive Archive requesting the read.
* @param data Data pointer passed to the archive.
* @param buffer Pointer to where the buffer pointer should be stored.
* @return Count of bytes read.
*/
ssize_t assetDataLoaderArchiveRead(
struct archive *archive,
void *data,
const void **buffer
);
/**
* Method invoked by the libarchive internals to seek the archive file pointer.
*
* @param archive Archive requesting the seek.
* @param data Data pointer passed to the archive.
* @param offset Offset to seek to.
* @param whence Whence to seek from.
* @return The new offset.
*/
int64_t assetDataLoaderArchiveSeek(
struct archive *archive,
void *data,
int64_t offset,
int32_t whence
);
/**
* Method invoked by the libarchive internals to open the archive file pointer.
*
* @param archive Archive requesting the open.
* @param data Data pointer passed to the archive.
* @return 0 if success, otherwise for failure.
*/
int32_t assetDataLoaderArchiveOpen(struct archive *a, void *data);
/**
* Method invoked by the libarchive internals to close the archive file pointer.
*
* @param archive Archive requesting the close.
* @param data Data pointer passed to the archive.
* @return 0 if success, otherwise for failure.
*/
int32_t assetDataLoaderArchiveClose(struct archive *a, void *data);
namespace Dawn {
class AssetDataLoader {
protected:
struct archive *assetArchive = nullptr;
struct archive_entry *assetArchiveEntry = nullptr;
size_t position;
std::string fileName;
public:
uint8_t buffer[ASSET_LOADER_BUFFER_SIZE];
FILE *assetArchiveFile = nullptr;
/**
* Unimplemented method intended to be implemented by the platform that
* will be used to request a File pointer to the asset.
*
* @return Pointer to the opened asset archive.
*/
FILE * openAssetArchiveFile();
/**
* Create a new asset loader. Asset Loaders can be used to load data from
* a file in a myriad of ways.
*
* @param fileName File name of the asset that is to be loaded.
*/
AssetDataLoader(std::string filename);
/**
* Platform-centric method to open a file buffer to an asset.
*/
void open();
/**
* Closes the previously ppened asset.
* @return 0 if successful, otherwise false.
*/
int32_t close();
/**
* Read bytes from buffer.
* @param buffer Pointer to a ubyte array to buffer data into.
* @param size Length of the data buffer (How many bytes to read).
* @return The count of bytes read.
*/
size_t read(uint8_t *buffer, size_t size);
/**
* Reads bytes from the buffer until a given delimiter is found. Returned
* position will be the index of the delimiter within the buffer.
*
* @param buffer Buffer to read into.
* @param maxSize Maximum size of the buffer.
* @param delimiter Delimiter to read until.
* @return The count of bytes read (including null terminator)
*/
size_t readUntil(
uint8_t *buffer,
const size_t maxSize,
const char_t delimiter
);
/**
* Get the size of the asset.
* @return The size of the asset in bytes.
*/
size_t getSize();
/**
* Skips the read head forward to a given position.
*
* @param n Count of bytes to progress the read head by.
* @return Count of bytes progressed.
*/
size_t skip(size_t n);
/**
* Rewind the read head to the beginning of the file.
*/
void rewind();
/**
* Sets the absolute position of the read head within the buffer of the
* file.
*
* @param absolutePosition Absolute position to set the read head to.
*/
size_t setPosition(const size_t absolutePosition);
/**
* Returns the current position of the read head.
*
* @return The current read head position.
*/
size_t getPosition();
/**
* Cleanup the asset loader.
*/
virtual ~AssetDataLoader();
};
}

View File

@ -1,17 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AssetLoader.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
AssetLoader::AssetLoader(const std::string name) : name(name) {
assertTrue(name.size() > 0, "Asset::Asset: Name cannot be empty");
}
AssetLoader::~AssetLoader() {
this->loaded = false;
}

View File

@ -1,41 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
namespace Dawn {
class AssetLoader {
public:
const std::string name;
bool_t loaded = false;
/**
* Create an abstract Asset object.
*
* @param name Name of the asset.
*/
AssetLoader(const std::string name);
/**
* Virtual function that will be called by the asset manager on a
* synchronous basis. This will only trigger if the blocks are false and
* the loaded is also false.
*/
virtual void updateSync() = 0;
/**
* Virtual function called by the asset manager asynchronously every tick.
* This will only trigger if blocks are false and the loaded state is also
* false.
*/
virtual void updateAsync() = 0;
/**
* Dispose the asset item.
*/
virtual ~AssetLoader();
};
}

View File

@ -1,101 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AssetManager.hpp"
#include "loaders/TextureLoader.hpp"
#include "loaders/TrueTypeLoader.hpp"
#include "loaders/JSONLoader.hpp"
using namespace Dawn;
void AssetManager::init() {
}
void AssetManager::update() {
auto itPending = pendingAssetLoaders.begin();
while(itPending != pendingAssetLoaders.end()) {
auto loader = *itPending;
loader->updateSync();
loader->updateAsync();
if(loader->loaded) {
finishedAssetLoaders.push_back(loader);
itPending = pendingAssetLoaders.erase(itPending);
} else {
itPending++;
}
}
}
void AssetManager::removeExisting(const std::string filename) {
auto existing = std::find_if(
pendingAssetLoaders.begin(), pendingAssetLoaders.end(),
[&](auto &loader) {
return loader->name == filename;
}
);
if(existing != pendingAssetLoaders.end()) {
pendingAssetLoaders.erase(existing);
}
existing = std::find_if(
finishedAssetLoaders.begin(), finishedAssetLoaders.end(),
[&](auto &loader) {
return loader->name == filename;
}
);
if(existing != finishedAssetLoaders.end()) {
finishedAssetLoaders.erase(existing);
}
}
bool_t AssetManager::isEverythingLoaded() {
return pendingAssetLoaders.size() == 0;
}
bool_t AssetManager::isLoaded(const std::string filename) {
auto existing = this->getExisting<AssetLoader>(filename);
if(existing) return existing->loaded;
return false;
}
template<>
std::shared_ptr<TrueTypeTexture> AssetManager::get<TrueTypeTexture>(
const std::string filename,
const uint32_t fontSize
) {
auto existing = this->getExisting<TrueTypeLoader>(filename);
if(existing) {
// Check pointer hasn't gone stale, if it has remove it and create new.
auto texture = existing->getTexture(fontSize);
if(texture) return texture;
this->removeExisting(filename);
}
std::shared_ptr<TrueTypeLoader> loader = std::make_shared<TrueTypeLoader>(
filename
);
pendingAssetLoaders.push_back(std::static_pointer_cast<AssetLoader>(loader));
return loader->getTexture(fontSize);
}
template<>
std::shared_ptr<json> AssetManager::get<json>(
const std::string filename
) {
auto existing = this->getExisting<JSONLoader>(filename);
if(existing) return existing->data;
std::shared_ptr<JSONLoader> loader = std::make_shared<JSONLoader>(
filename
);
pendingAssetLoaders.push_back(std::static_pointer_cast<AssetLoader>(loader));
return loader->data;
}
AssetManager::~AssetManager() {
}

View File

@ -1,107 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
#include "asset/AssetLoader.hpp"
namespace Dawn {
class AssetManager final {
private:
std::vector<std::shared_ptr<AssetLoader>> pendingAssetLoaders;
std::vector<std::shared_ptr<AssetLoader>> finishedAssetLoaders;
/**
* Returns an existing asset loader if it exists.
*
* @param filename The filename of the asset to get.
* @return The asset loader if it exists, otherwise nullptr.
*/
template<class T>
std::shared_ptr<T> getExisting(const std::string filename) {
auto existing = std::find_if(
pendingAssetLoaders.begin(), pendingAssetLoaders.end(),
[&](auto &loader) {
return loader->name == filename;
}
);
if(existing == pendingAssetLoaders.end()) {
existing = std::find_if(
finishedAssetLoaders.begin(), finishedAssetLoaders.end(),
[&](auto &loader) {
return loader->name == filename;
}
);
if(existing == finishedAssetLoaders.end()) return nullptr;
}
return std::static_pointer_cast<T>(*existing);
}
/**
* Removes an existing asset loader if it exists.
*
* @param filename The filename of the asset to remove.
*/
void removeExisting(const std::string filename);
public:
/**
* Initializes this asset manager so it can begin accepting assets.
*/
void init();
/**
* Updates the asset manager.
*/
void update();
/**
* Returns whether the asset manager has loaded all of the currently
* managed assets.
*
* @return True if all assets have been loaded.
*/
bool_t isEverythingLoaded();
/**
* Returns whether the asset manager has loaded the given asset.
*
* @param filename The filename of the asset to check.
* @return True if the asset has been loaded.
*/
bool_t isLoaded(const std::string filename);
/**
* Returns the asset loader for the given asset.
*
* @param filename The filename of the asset to get.
* @param fontSize The font size to get the truetype asset of.
* @return The asset loader for the given asset.
*/
template<class T>
std::shared_ptr<T> get(const std::string filename);
/**
* Returns the asset loader for the given asset.
*
* @param filename The filename of the asset to get.
* @param fontSize The font size to get the truetype asset of.
* @return The asset loader for the given asset.
*/
template<class T>
std::shared_ptr<T> get(
const std::string filename,
const uint32_t fontSize
);
/**
* Dispose the asset manager, and all attached assets.
*/
~AssetManager();
};
}

View File

@ -1,15 +0,0 @@
# Copyright (c) 2022 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
AssetLoader.cpp
AssetDataLoader.cpp
AssetManager.cpp
)
# Subdirs
add_subdirectory(loaders)

View File

@ -1,12 +0,0 @@
# Copyright (c) 2022 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
TextureLoader.cpp
TrueTypeLoader.cpp
JSONLoader.cpp
)

View File

@ -1,46 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "JSONLoader.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
JSONLoader::JSONLoader(const std::string name) :
AssetLoader(name),
loader(name + ".json"),
state(JSONLoaderLoadState::INITIAL)
{
data = std::make_shared<json>();
}
void JSONLoader::updateAsync() {
if(this->state != JSONLoaderLoadState::INITIAL) return;
this->state = JSONLoaderLoadState::LOADING_FILE;
this->loader.open();
auto size = this->loader.getSize();
auto buffer = new uint8_t[size + 1];
assertNotNull(buffer, "Failed to allocate buffer!");
this->state = JSONLoaderLoadState::PARSING_DATA;
auto read = this->loader.read(buffer, size);
assertTrue(read == size, "Failed to read entire file!");
buffer[size] = '\0';
*data = json::parse(buffer);
delete[] buffer;
this->state = JSONLoaderLoadState::DONE;
this->loaded = true;
}
void JSONLoader::updateSync() {
}
JSONLoader::~JSONLoader() {
this->data = nullptr;
}

View File

@ -1,42 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/AssetLoader.hpp"
#include "asset/AssetDataLoader.hpp"
namespace Dawn {
enum class JSONLoaderLoadState {
INITIAL,
LOADING_FILE,
PARSING_DATA,
DONE
};
class JSONLoader : public AssetLoader {
protected:
AssetDataLoader loader;
enum JSONLoaderLoadState state;
public:
std::shared_ptr<json> data;
/**
* Constructs a JSON asset loader. You should instead use the parent
* asset managers' abstracted load method
*
* @param name File name asset to load, omitting the extension.
*/
JSONLoader(const std::string name);
void updateSync() override;
void updateAsync() override;
/**
* Dispose / Cleanup the JSON asset.
*/
~JSONLoader();
};
}

View File

@ -1,147 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TextureLoader.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
TextureLoader::TextureLoader(const std::string name) :
AssetLoader(name),
loader(name + ".texture"),
state(TextureLoaderLoadState::INITIAL)
{
sharedTexture = std::make_shared<Texture>();
weakTexture = sharedTexture;
}
void TextureLoader::updateAsync() {
if(this->state != TextureLoaderLoadState::INITIAL) return;
this->state = TextureLoaderLoadState::ASYNC_LOADING;
this->loader.open();
// Read in the header.
uint8_t buffer[TEXTURE_LOADER_HEADER_SIZE];
size_t pos = 0;
// Read Version
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
std::string version = std::string((char*)buffer);
assertTrue(version == "DT_2.00", "Invalid Texture Version!");
// Read Texture Width
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
width = std::stoi(std::string((char*)buffer));
assertTrue(width > 0, "Invalid Texture Width!");
// Read Texture Height
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
height = std::stoi(std::string((char*)buffer));
assertTrue(height > 0, "Invalid Texture Height!");
// Texture Format (RGBA, RGB, etc)
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
int32_t iFormat = std::stoi(std::string((char*)buffer));
switch(iFormat) {
case 1: format = TextureFormat::R; break;
case 2: format = TextureFormat::RG; break;
case 3: format = TextureFormat::RGB; break;
case 4: format = TextureFormat::RGBA; break;
default: assertUnreachable("Invalid Texture Format %i!", iFormat);
}
// Wrap X
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
int32_t iWrapX = std::stoi(std::string((char*)buffer));
switch(iWrapX) {
case 0: wrapX = TextureWrapMode::REPEAT; break;
case 1: wrapX = TextureWrapMode::MIRRORED_REPEAT; break;
case 2: wrapX = TextureWrapMode::CLAMP_TO_EDGE; break;
case 3: wrapX = TextureWrapMode::CLAMP_TO_BORDER; break;
default: assertUnreachable("Invalid Texture Wrap X %i!", iWrapX);
}
// Wrap Y
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
int32_t iWrapY = std::stoi(std::string((char*)buffer));
switch(iWrapY) {
case 0: wrapY = TextureWrapMode::REPEAT; break;
case 1: wrapY = TextureWrapMode::MIRRORED_REPEAT; break;
case 2: wrapY = TextureWrapMode::CLAMP_TO_EDGE; break;
case 3: wrapY = TextureWrapMode::CLAMP_TO_BORDER; break;
default: assertUnreachable("Invalid Texture Wrap Y %i!", iWrapY);
}
// Filter Min
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
int32_t iFilterMin = std::stoi(std::string((char*)buffer));
switch(iFilterMin) {
case 0: filterMin = TextureFilterMode::NEAREST; break;
case 1: filterMin = TextureFilterMode::LINEAR; break;
default: assertUnreachable("Invalid Texture Filter Min %i!", iFilterMin);
}
// Filter Mag
this->loader.setPosition(pos);
pos += this->loader.readUntil(buffer, TEXTURE_LOADER_HEADER_SIZE, '|');
int32_t iFilterMag = std::stoi(std::string((char*)buffer));
switch(iFilterMag) {
case 0: filterMag = TextureFilterMode::NEAREST; break;
case 1: filterMag = TextureFilterMode::LINEAR; break;
default: assertUnreachable("Invalid Texture Filter Mag %i!", iFilterMag);
}
// Data begins here. This part is done synchronously directly to the GPU.
this->loader.setPosition(pos);
size_t bufferSize = width * height * iFormat;
data = new uint8_t[bufferSize];
assertNotNull(data, "Failed to allocate texture data!");
this->loader.read(data, bufferSize);
// Handoff to sync to buffer to GPU.
this->state = TextureLoaderLoadState::ASYNC_DONE;
}
void TextureLoader::updateSync() {
if(this->state != TextureLoaderLoadState::ASYNC_DONE) return;
this->state = TextureLoaderLoadState::SYNC_LOADING;
assertNotNull(this->sharedTexture, "Texture is null!");
assertNotNull(this->data, "Texture data is null!");
// Setup Texture
this->sharedTexture->setSize(
this->width,
this->height,
this->format,
TextureDataFormat::UNSIGNED_BYTE
);
this->sharedTexture->buffer(this->data);
// Free data buffer
delete[] this->data;
this->data = nullptr;
// Leat go of the held pointer
this->sharedTexture = nullptr;
// Hand off and call done
this->state = TextureLoaderLoadState::SYNC_DONE;
this->loaded = true;
}
TextureLoader::~TextureLoader() {
if(this->data != nullptr) {
delete[] this->data;
this->data = nullptr;
}
this->sharedTexture = nullptr;
}

View File

@ -1,55 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/AssetLoader.hpp"
#include "asset/AssetDataLoader.hpp"
#include "display/Texture.hpp"
#define TEXTURE_LOADER_HEADER_SIZE 256
namespace Dawn {
enum class TextureLoaderLoadState {
INITIAL,
ASYNC_LOADING,
ASYNC_DONE,
SYNC_LOADING,
SYNC_DONE
};
class TextureLoader : public AssetLoader {
protected:
AssetDataLoader loader;
enum TextureLoaderLoadState state;
uint8_t *data = nullptr;
int32_t width = -1, height = -1;
enum TextureFormat format;
enum TextureWrapMode wrapX;
enum TextureWrapMode wrapY;
enum TextureFilterMode filterMin;
enum TextureFilterMode filterMag;
public:
std::shared_ptr<Texture> sharedTexture;
std::weak_ptr<Texture> weakTexture;
/**
* Constructs a texture asset loader. You should instead use the parent
* asset managers' abstracted load method
*
* @param name File name asset to load, omitting the extension.
*/
TextureLoader(const std::string name);
void updateSync() override;
void updateAsync() override;
/**
* Dispose / Cleanup the texture asset. Will also dispose the underlying
* texture itself.
*/
~TextureLoader();
};
}

View File

@ -1,97 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TrueTypeLoader.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
TrueTypeLoader::TrueTypeLoader(const std::string name) :
AssetLoader(name),
loader(name + ".ttf")
{
// Init the font.
auto ret = FT_Init_FreeType(&fontLibrary);
assertTrue(ret == 0, "Failed to initialize FreeType library.");
}
void TrueTypeLoader::updateSync() {
if(state != TrueTypeLoaderState::ASYNC_DONE) return;
state = TrueTypeLoaderState::SYNC_LOADING;
// Init all the textures.
auto it = textures.begin();
while(it != textures.end()) {
auto texture = it->second.lock();
if(texture) {
texture->setFace(face);
it++;
continue;
}
it = textures.erase(it);
}
// Done
state = TrueTypeLoaderState::SYNC_DONE;
this->loaded = true;
}
void TrueTypeLoader::updateAsync() {
if(state != TrueTypeLoaderState::INITIAL) return;
state = TrueTypeLoaderState::ASYNC_LOADING;
// Load the data.
this->loader.open();
size_t size = loader.getSize();
buffer = new uint8_t[size];
// Read the data.
size_t readSize = loader.read(buffer, size);
assertTrue(readSize == size, "Failed to read all data from TrueTypeLoader.");
// Init the font.
auto ret = FT_New_Memory_Face(fontLibrary, buffer, size, 0, &face);
assertTrue(ret == 0, "Failed to load font face.");
// Now close the asset loader
loader.close();
state = TrueTypeLoaderState::ASYNC_DONE;
}
std::shared_ptr<TrueTypeTexture> TrueTypeLoader::getTexture(
const uint32_t fontSize
) {
// Check if we have the texture already and it hasn't gone stale.
auto it = textures.find(fontSize);
if(it != textures.end()) {
if(!it->second.expired()) return it->second.lock();
textures.erase(it);
}
// Create the texture.
auto texture = std::make_shared<TrueTypeTexture>(fontSize);
textures[fontSize] = texture;
if(this->loaded) texture->setFace(face);
return texture;
}
TrueTypeLoader::~TrueTypeLoader() {
if(
this->state == TrueTypeLoaderState::SYNC_DONE ||
this->state == TrueTypeLoaderState::SYNC_LOADING ||
this->state == TrueTypeLoaderState::ASYNC_DONE
) {
FT_Done_Face(face);
}
FT_Done_FreeType(fontLibrary);
if(buffer != nullptr) {
delete[] buffer;
buffer = nullptr;
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/AssetLoader.hpp"
#include "asset/AssetDataLoader.hpp"
#include "display/font/TrueTypeTexture.hpp"
namespace Dawn {
enum class TrueTypeLoaderState {
INITIAL,
ASYNC_LOADING,
ASYNC_DONE,
SYNC_LOADING,
SYNC_DONE
};
class TrueTypeLoader : public AssetLoader {
protected:
FT_Library fontLibrary;
FT_Face face;
AssetDataLoader loader;
std::unordered_map<uint32_t, std::weak_ptr<TrueTypeTexture>> textures;
enum TrueTypeLoaderState state = TrueTypeLoaderState::INITIAL;
uint8_t *buffer = nullptr;
public:
/**
* Constructs a TrueTypeLoader. You should instead use the parent
* asset managers' abstracted load method
*
* @param name File name asset to load, omitting the extension.
*/
TrueTypeLoader(const std::string name);
void updateSync() override;
void updateAsync() override;
/**
* Returns the texture for the given font size.
*
* @param fontSize Font size to get the texture for.
* @return Texture for the given character.
*/
std::shared_ptr<TrueTypeTexture> getTexture(
const uint32_t fontSize
);
/**
* Dispose / Cleanup the truetype asset. Will also dispose the underlying
* truetype itself.
*/
~TrueTypeLoader();
};
}