Base refactor

This commit is contained in:
2023-11-14 09:16:48 -06:00
parent 214082d00f
commit 1817dcaf3a
410 changed files with 749 additions and 20823 deletions

View File

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

View File

@ -1,44 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "state/StateEvent.hpp"
namespace Dawn {
class AssetManager;
class Asset {
public:
const std::string name;
bool_t loaded = false;
StateEvent<> eventLoaded;
/**
* Create an abstract Asset object.
*
* @param name Name of the asset.
*/
Asset(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 ~Asset();
};
}

View File

@ -1,92 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AssetManager.hpp"
using namespace Dawn;
void AssetManager::init() {
}
void AssetManager::update() {
this->syncTick();
}
void AssetManager::queueLoad(const std::vector<std::shared_ptr<Asset>> assets) {
assetsToLoad.insert(this->assetsToLoad.end(), assets.begin(), assets.end());
}
void AssetManager::queueLoad(const std::shared_ptr<Asset> &asset) {
this->assetsToLoad.push_back(asset);
}
void AssetManager::queueUnload(
const std::vector<std::shared_ptr<Asset>> &assets
) {
std::cout <<
"Asset list was queued to unload, but is not yet implemented" <<
std::endl;
assetsToUnload.insert(assetsToUnload.end(), assets.begin(), assets.end());
}
void AssetManager::queueUnload(const std::shared_ptr<Asset> &asset) {
std::cout <<
"Asset was queued to unload, but is not yet implemented" <<
std::endl;
this->assetsToUnload.push_back(asset);
}
void AssetManager::queueSwap(
const std::vector<std::shared_ptr<Asset>> &newAssets,
const std::vector<std::shared_ptr<Asset>> &oldAssets
) {
std::vector<std::shared_ptr<Asset>> unload;
std::vector<std::shared_ptr<Asset>> load;
// Determine assets to unload.
std::for_each(oldAssets.begin(), oldAssets.end(), [&](const auto &asset){
auto it = std::find(newAssets.begin(), newAssets.end(), asset);
if(it == newAssets.end()) unload.push_back(asset);
});
// Determine assets to load
std::for_each(newAssets.begin(), newAssets.end(), [&](const auto &asset){
auto it = std::find(oldAssets.begin(), oldAssets.end(), asset);
if(it == oldAssets.end()) load.push_back(asset);
});
this->queueUnload(unload);
this->queueLoad(load);
}
void AssetManager::syncTick() {
std::erase_if(assetsToLoad, [&](auto &asset){
if(asset->loaded) {
asset->eventLoaded.invoke();
return true;
}
asset->updateSync();
asset->updateAsync();//TODO: Make Async
if(asset->loaded) {
asset->eventLoaded.invoke();
return true;
}
return asset->loaded;
});
}
void AssetManager::syncLoad() {
while(this->assetsToLoad.size() > 0) {
this->syncTick();
}
}
AssetManager::~AssetManager() {
this->assets.clear();
}

View File

@ -1,127 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "Asset.hpp"
namespace Dawn {
class AssetManager {
private:
/** List of pointers to assets, mapped by their asset key. */
std::map<std::string, std::shared_ptr<Asset>> assets;
std::vector<std::shared_ptr<Asset>> assetsToLoad;
std::vector<std::shared_ptr<Asset>> assetsToUnload;
public:
/**
* Initializes this asset manager so it can begin accepting assets.
*/
void init();
/**
* Updates the asset manager.
*/
void update();
/**
* Queue a loading of a list of assets. Does not actually begin loading.
*
* @param assets Assets to load.
*/
void queueLoad(const std::vector<std::shared_ptr<Asset>> assets);
/**
* Queue a loading of a single asset. Does not actually begin loading.
*
* @param asset Asset to load.
*/
void queueLoad(const std::shared_ptr<Asset> &asset);
/**
* Takes a list of lists to queue to unload. Does not immediately unload.
*
* @param assets Assets to unload.
*/
void queueUnload(const std::vector<std::shared_ptr<Asset>> &assets);
/**
* Takes a single asset to queue to unload. Does not immediately unload.
*
* @param assets Assets to unload.
*/
void queueUnload(const std::shared_ptr<Asset> &assets);
/**
* Queues load and unload based on the difference between two sets of
* assets. This is mostly used to perform a scene change.
*
* @param newAssets New list of assets to maintain.
* @param oldAssets Old list of assets to no longer maintain.
*/
void queueSwap(
const std::vector<std::shared_ptr<Asset>> &newAssets,
const std::vector<std::shared_ptr<Asset>> &oldAssets
);
/**
* Ticks the asset manager, synchronously.
*/
void syncTick();
/**
* Loads everything that isn't loaded, blocks the current thread until
* that has finished.
*/
void syncLoad();
/**
* Creates and queue an asset to load.
*
* @param name Name of the asset to load.
* @return The asset element to be loaded.
*/
template<class T>
std::shared_ptr<T> get(std::string name) {
assertTrue(
name.size() > 0, "AssetManager::get: name must be greater than 0"
);
auto existing = this->assets.find(name);
if(existing != this->assets.end()) {
return dynamic_pointer_cast<T>(existing->second);
}
auto asset = std::make_shared<T>(name);
this->assets[name] = asset;
return asset;
}
/**
* Both gets an asset, and puts it into the load queue.
*
* @param name Name of the asset to load.
* @return The asset element to be loaded.
*/
template<class T>
std::shared_ptr<T> getAndLoad(std::string name) {
auto asset = this->get<T>(name);
this->queueLoad(asset);
return asset;
}
template<class T>
void unload(std::shared_ptr<T> asset) {
assertUnreachable("AssetManager::unload: NOT IMPLEMENTED");
}
void unload(std::string name) {
assertUnreachable("AssetManager::unload: NOT IMPLEMENTED");
}
/**
* 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
Asset.cpp
IAssetLoader.cpp
AssetManager.cpp
)
# Subdirs
add_subdirectory(assets)

View File

@ -1,27 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "IAssetLoader.hpp"
using namespace Dawn;
IAssetLoader::IAssetLoader(const std::string fileName) : fileName(fileName) {
assertTrue(
fileName.size() > 0,
"IAssetLoader::IAssetLoader: fileName must be greater than 0"
);
}
size_t IAssetLoader::setPosition(const size_t position) {
assertTrue(
position >= 0,
"IAssetLoader::setPosition: position must be greater than or equal to 0"
);
this->rewind();
return this->skip(position);
}
IAssetLoader::~IAssetLoader() {
}

View File

@ -1,132 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "assert/assert.hpp"
#define ASSET_LOADER_BUFFER_SIZE 32768
#if !defined(DAWN_ASSET_LOCATION)
#error Asset Archive Location has not been defined.
#endif
namespace Dawn {
class IAssetLoader {
protected:
std::string fileName;
public:
/**
* 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.
*/
IAssetLoader(const std::string fileName);
/**
* Platform-centric method to open a file buffer to an asset.
*/
virtual void open() = 0;
/**
* Closes the previously ppened asset.
* @return 0 if successful, otherwise false.
*/
virtual int32_t close() = 0;
/**
* 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.
*/
virtual size_t read(uint8_t *buffer, const size_t size) = 0;
/**
* Get the size of the asset.
* @return The size of the asset in bytes.
*/
virtual size_t getSize() = 0;
/**
* 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.
*/
virtual size_t skip(const size_t n) = 0;
/**
* Rewind the read head to the beginning of the file.
*/
virtual void rewind() = 0;
/**
* 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.
*/
virtual size_t getPosition() = 0;
/**
* Run a callback for each byte within the asset. The callback will
* receive each byte individually.
*
* @tparam T Type of instance to run callback against.
* @param instance Instance of the object to run the callback against.
* @param callback Callback method on the class to run the callback for.
* @return The count of bytes read.
*/
template<class T>
size_t loadBufferedCallback(
std::function<bool_t(uint8_t n)> callback
) {
uint8_t buffer[1024];
size_t read, length;
int32_t i;
bool_t result;
assertNotNull(callback, "Callback cannot be null.");
// Open the buffer.
this->open();
// Reset length size
length = 0;
// Buffer from input
while((read = this->read(buffer, 1024)) != 0) {
for(i = 0; i < read; i++) {
result = callback(buffer[i]);
if(!result) {
length += i;
break;
}
}
if(!result) break;
length += read;
}
// Close the buffer
this->close();
return length;
}
/**
* Cleanup the asset loader.
*/
virtual ~IAssetLoader();
};
}

View File

@ -1,79 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AudioAsset.hpp"
using namespace Dawn;
AudioAsset::AudioAsset(const std::string name) :
Asset(name),
loader(name + ".audio")
{
}
void AudioAsset::updateSync() {
if(this->state != AUDIO_ASSET_LOAD_STATE_DATA_READ) return;
// THIS WILL DEFINITELY CHANGE
this->state = AUDIO_ASSET_LOAD_STATE_COMPLETE;
this->loaded = true;
}
void AudioAsset::updateAsync() {
if(this->state != AUDIO_ASSET_LOAD_STATE_INITIAL) return;
char *start, *end;
char buffer[1024];
// Open asset for reading
this->state = AUDIO_ASSET_LOAD_STATE_OPENING;
this->loader.open();
// Parse header data.
this->state = AUDIO_ASSET_LOAD_STATE_READING_HEADER;
this->loader.read((uint8_t *)buffer, 1024);
// Channel count
this->state = AUDIO_ASSET_LOAD_STATE_READING_CHANNEL_COUNT;
start = buffer;
end = strchr(start, '|');
*end = '\0';
this->channelCount = atoi(start);
assertTrue(this->channelCount > 0, "Channel count must be greater than 0");
// Sample Rate
this->state = AUDIO_ASSET_LOAD_STATE_READING_SAMPLE_RATE;
start = end + 1;
end = strchr(start, '|');
*end = '\0';
this->sampleRate = (uint32_t)strtoul(start, NULL, 10);
assertTrue(this->sampleRate > 0, "Sample rate must be greater than 0");
// Number of samples per channel
this->state = AUDIO_ASSET_LOAD_STATE_READING_SAMPLES_PER_CHANNEL;
start = end + 1;
end = strchr(start, '|');
*end = '\0';
this->samplesPerChannel = atoi(start);
assertTrue(
this->samplesPerChannel > 0,
"Samples per channel must be greater than 0"
);
// Total Data Length
this->state = AUDIO_ASSET_LOAD_STATE_READING_DATA_LENGTH;
start = end + 1;
end = strchr(start, '|');
*end = '\0';
this->bufferSize = (size_t)atoll(start);
assertTrue(this->bufferSize > 0, "Buffer size must be greater than 0");
// Determine frame size
this->frameSize = sizeof(int16_t) * this->channelCount;
// Indicated start of data
this->state = AUDIO_ASSET_LOAD_STATE_DATA_READ;
this->bufferStart = end - buffer;
}

View File

@ -1,45 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../Asset.hpp"
#include "asset/AssetLoader.hpp"
namespace Dawn {
class AudioSource;
enum AudioAssetLoadState {
AUDIO_ASSET_LOAD_STATE_INITIAL,
AUDIO_ASSET_LOAD_STATE_OPENING,
AUDIO_ASSET_LOAD_STATE_READING_HEADER,
AUDIO_ASSET_LOAD_STATE_READING_CHANNEL_COUNT,
AUDIO_ASSET_LOAD_STATE_READING_SAMPLE_RATE,
AUDIO_ASSET_LOAD_STATE_READING_SAMPLES_PER_CHANNEL,
AUDIO_ASSET_LOAD_STATE_READING_DATA_LENGTH,
AUDIO_ASSET_LOAD_STATE_DATA_READ,
AUDIO_ASSET_LOAD_STATE_COMPLETE
};
class AudioAsset : public Asset {
protected:
AssetLoader loader;
enum AudioAssetLoadState state = AUDIO_ASSET_LOAD_STATE_INITIAL;
int32_t channelCount;
uint32_t sampleRate;
int32_t samplesPerChannel;
size_t bufferSize;
size_t bufferStart;
size_t frameSize;
public:
AudioAsset(const std::string name);
void updateSync() override;
void updateAsync() override;
friend class AudioSource;
};
}

View File

@ -1,13 +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
AudioAsset.cpp
LanguageAsset.cpp
TextureAsset.cpp
TrueTypeAsset.cpp
)

View File

@ -1,86 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "LanguageAsset.hpp"
using namespace Dawn;
LanguageAsset::LanguageAsset(const std::string name) :
Asset(name),
loader(name + ".language")
{
}
void LanguageAsset::updateSync() {
}
void LanguageAsset::updateAsync() {
assertTrue(
this->state == LANGUAGE_ASSET_LOAD_STATE_INITIAL,
"State must be initial"
);
// Open Asset
this->state = LANGUAGE_ASSET_LOAD_STATE_OPENING;
this->loader.open();
// Get Length
size_t len = this->loader.getSize();
// Create buffer
this->state = LANGUAGE_ASSET_LOAD_STATE_CREATING_BUFFER;
size_t position = 0;
// Loop over CSV
while(position < len) {
this->loader.read(buffer, 1024);
// Get strings
uint8_t *keyStart = buffer;
uint8_t *keyEnd = (uint8_t*)strchr((char*)keyStart, '|');
*keyEnd = '\0';
uint8_t *valueStart = keyEnd + 1;
uint8_t *valueEnd = (uint8_t*)strchr((char*)valueStart, '|');
// Load value positions
struct AssetLanguageValue value;
value.begin = position + (size_t)(valueStart - buffer);
value.length = (size_t)(valueEnd - valueStart);
// Prepare for next string.
position = position + (size_t)(valueEnd - buffer + 1);
this->loader.setPosition(position);
// Store strings.
std::string key((char *)keyStart);
this->values[key] = value;
}
this->state = LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ;
this->loaded = true;
}
std::string LanguageAsset::getValue(const std::string key) {
assertTrue(
this->state == LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ,
"State must be LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ"
);
assertMapHasKey(this->values, key, "Key does not exist");
assertTrue(
this->values[key].begin >= 0 && this->values[key].length > 0,
"Value is invalid"
);
// Get the positions
struct AssetLanguageValue value = this->values[key];
this->loader.setPosition(value.begin);
this->loader.read(buffer, value.length);
buffer[value.length] = '\0';
return std::string((char *)buffer, value.length + 1);
}

View File

@ -1,36 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../Asset.hpp"
#include "asset/AssetLoader.hpp"
namespace Dawn {
struct AssetLanguageValue {
size_t begin;
size_t length;
};
enum LangageAssetLoadState {
LANGUAGE_ASSET_LOAD_STATE_INITIAL,
LANGUAGE_ASSET_LOAD_STATE_OPENING,
LANGUAGE_ASSET_LOAD_STATE_CREATING_BUFFER,
LANGUAGE_ASSET_LOAD_STATE_READY_TO_READ
};
class LanguageAsset : public Asset {
protected:
AssetLoader loader;
enum LangageAssetLoadState state = LANGUAGE_ASSET_LOAD_STATE_INITIAL;
std::map<std::string, struct AssetLanguageValue> values;
uint8_t buffer[1024];
public:
LanguageAsset(const std::string name);
void updateSync() override;
void updateAsync() override;
std::string getValue(const std::string key);
};
}

View File

@ -1,136 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TextureAsset.hpp"
#include "util/memory.hpp"
using namespace Dawn;
TextureAsset::TextureAsset(const std::string name) :
Asset(name),
loader(name + ".texture"),
texture()
{
}
void TextureAsset::updateSync() {
if(this->state != TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF) return;
this->state = TEXTURE_ASSET_LOAD_STATE_BUFFERING_TEXTURE;
this->texture.setSize(
this->width, this->height, this->format, TEXTURE_DATA_FORMAT_UNSIGNED_BYTE
);
this->texture.buffer(this->colors);
this->texture.wrapModeX = this->wrapModeX;
this->texture.wrapModeY = this->wrapModeY;
this->texture.filterModeMin = this->filterModeMin;
this->texture.filterModeMag = this->filterModeMag;
this->state = TEXTURE_ASSET_LOAD_STATE_COMPLETE;
this->loaded = true;
}
void TextureAsset::updateAsync() {
if(this->state != TEXTURE_ASSET_LOAD_STATE_INITIAL) return;
this->state = TEXTURE_ASSET_LOAD_STATE_OPENING;
this->loader.open();
this->buffer = memoryAllocate<uint8_t>(this->loader.getSize());
this->loader.read(this->buffer, this->loader.getSize());
this->loader.close();
this->state = TEXTURE_ASSET_LOAD_STATE_PARSING_HEADER;
// Parse header data.
char integer[256];
size_t j = 0, i = 0;
enum TextureAssetHeaderParseState parseState =
TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION
;
while(true) {
if(parseState == TEXTURE_ASSET_HEADER_PARSE_STATE_END) break;
auto c = this->buffer[i++];
if(c != '|') {
integer[j++] = c;
continue;
}
integer[j] = '\0';
switch(parseState) {
case TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION: {
auto compared = strcmp(integer, "DT_2.00");
assertTrue(compared == 0, "Invalid version");
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH: {
this->width = atoi(integer);
assertTrue(this->width > 0, "Invalid width");
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT: {
this->height = atoi(integer);
assertTrue(this->height > 0, "Invalid height");
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT: {
this->format = (enum TextureFormat)atoi(integer);
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X: {
this->wrapModeX = (enum TextureWrapMode)atoi(integer);
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y: {
this->wrapModeY = (enum TextureWrapMode)atoi(integer);
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN: {
this->filterModeMin = (enum TextureFilterMode)atoi(integer);
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG;
break;
}
case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG: {
this->filterModeMag = (enum TextureFilterMode)atoi(integer);
j = 0;
parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_END;
break;
}
default:
assertUnreachable("Invalid parse state");
}
}
this->colors = (uint8_t*)((void *)(this->buffer + i));
this->state = TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF;
}
TextureAsset::~TextureAsset() {
if(this->buffer != nullptr) {
memoryFree(this->buffer);
this->buffer = nullptr;
}
}

View File

@ -1,66 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../Asset.hpp"
#include "asset/AssetLoader.hpp"
#include "display/Texture.hpp"
namespace Dawn {
enum TextureAssetHeaderParseState {
TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION,
TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH,
TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT,
TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT,
TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X,
TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y,
TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN,
TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG,
TEXTURE_ASSET_HEADER_PARSE_STATE_END
};
enum TextureAssetLoadState {
TEXTURE_ASSET_LOAD_STATE_INITIAL,
TEXTURE_ASSET_LOAD_STATE_OPENING,
TEXTURE_ASSET_LOAD_STATE_PARSING_HEADER,
TEXTURE_ASSET_LOAD_STATE_SYNC_HANDOFF,
TEXTURE_ASSET_LOAD_STATE_BUFFERING_TEXTURE,
TEXTURE_ASSET_LOAD_STATE_COMPLETE,
};
class TextureAsset : public Asset {
protected:
AssetLoader loader;
uint8_t *buffer = nullptr;
int32_t width = -1, height = -1;
uint8_t *colors;
enum TextureAssetLoadState state = TEXTURE_ASSET_LOAD_STATE_INITIAL;
enum TextureFormat format;
enum TextureWrapMode wrapModeX;
enum TextureWrapMode wrapModeY;
enum TextureFilterMode filterModeMin;
enum TextureFilterMode filterModeMag;
public:
Texture texture;
/**
* 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.
*/
TextureAsset(const std::string name);
void updateSync() override;
void updateAsync() override;
/**
* Dispose / Cleanup the texture asset. Will also dispose the underlying
* texture itself.
*/
~TextureAsset();
};
}

View File

@ -1,239 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TrueTypeAsset.hpp"
#include "asset/AssetManager.hpp"
#include "util/memory.hpp"
using namespace Dawn;
TrueTypeAsset::TrueTypeAsset(const std::string name) :
Asset(name),
loader(name + ".truetype")
{
this->locks.onLockRemoved = [&](usagelockid_t id){
auto texture = this->textureByLock[id];
assertNotNull(texture, "Texture cannot be null");
std::vector<usagelockid_t> &lbt = this->locksByTexture[texture];
auto it0 = std::find(lbt.begin(), lbt.end(), id);
assertTrue(it0 != lbt.end(), "Could not remove locksByTexture[texture]");
lbt.erase(it0);
auto it1 = this->textureByLock.find(id);
assertTrue(
it1 != this->textureByLock.end(), "Could not remove textureByLock"
);
this->textureByLock.erase(it1);
if(lbt.empty()) {
auto it2 = locksByTexture.find(texture);
assertTrue(
it2 != locksByTexture.end(), "Could not remove locksByTexture"
);
locksByTexture.erase(it2);
std::erase_if(textureByStyle, [&](const auto &item){
auto const& [key, value] = item;
return value == texture;
});
std::erase(textures, texture);
delete texture;
}
};
}
void TrueTypeAsset::updateSync() {
}
void TrueTypeAsset::updateAsync() {
if(this->state != TRUE_TYPE_ASSET_STATE_INITIAL) return;
this->state = TRUE_TYPE_ASSET_STATE_OPEN;
this->loader.open();
this->state = TRUE_TYPE_ASSET_STATE_VALIDATE_HEADER;
uint8_t buffer[64];
this->loader.rewind();
size_t read = this->loader.read(buffer, sizeof(char) * 6);
assertTrue(read == (6 * sizeof(char)), "Could not read header");
buffer[6] = '\0';
// Confirm "DE_TTF"
assertTrue(
std::string((char *)buffer) == "DE_TTF",
"Header is invalid (Missing DE_TTF)"
);
// Vertical bar
this->loader.read(buffer, 1);
assertTrue(
buffer[0] == '|',
"Header is invalid (Missing first vertical bar)"
);
// Read version
this->state = TRUE_TYPE_ASSET_STATE_VALIDATE_VERSION;
read = this->loader.read(buffer, sizeof(char) * 5);
assertTrue(buffer[0] == '3', "Version is invalid 3");
assertTrue(buffer[1] == '.', "Version is invalid .");
assertTrue(buffer[2] == '0', "Version is invalid 0(1)");
assertTrue(buffer[3] == '0', "Version is invalid 0(2)");
assertTrue(
buffer[4] == '|',
"Version is invalid (Missing second vertical bar)"
);
// Read the count of font styles / variants.
size_t styleListBegin = this->loader.getPosition();
this->state = TRUE_TYPE_ASSET_STATE_READ_VARIANT_COUNT;
read = this->loader.read(buffer, 64);
assertTrue(read > 0, "Could not read variant count");
// Get position of vertical bar.
size_t i = 0;
while(buffer[i] != '|' && i < 64) i++;
assertTrue(buffer[i] == '|', "Could not find vertical bar");
styleListBegin += i + 1;
buffer[i] = '\0';
int32_t count = atoi((char *)buffer);
assertTrue(count > 0, "Invalid variant count");
// Now begin parsing each font style.
this->state = TRUE_TYPE_ASSET_STATE_READ_VARIANT;
assetStyles.clear();
while(assetStyles.size() != count) {
struct TrueTypeAssetStyle style;
// Buffer
this->loader.setPosition(styleListBegin);
read = this->loader.read(buffer, 32);
assertTrue(read == 32, "Could not read variant");
// Read style
i = 0;
while(buffer[i] != ':' && i < 64) i++;
buffer[i] = '\0';
style.style = atoi((char *)buffer);
styleListBegin += i + 1;
// Buffer
this->loader.setPosition(styleListBegin);
read = this->loader.read(buffer, 32);
assertTrue(read == 32, "Could not read variant style");
// Read length
i = 0;
while(buffer[i] != '|' && i < 64) i++;
buffer[i] = '\0';
styleListBegin += i + 1;
style.dataSize = atol((char *)buffer);
// Push
assetStyles.push_back(style);
}
// Now we are at the first byte of the first style.
this->state = TRUE_TYPE_ASSET_STATE_ADJUSTING_OFFSETS;
std::for_each(
assetStyles.begin(),
assetStyles.end(),
[&](struct TrueTypeAssetStyle &style){
style.dataOffset = styleListBegin;
styleListBegin += style.dataSize;
styleListBegin += 1;
}
);
// Init FreeType
this->state = TRUE_TYPE_ASSET_STATE_INIT_FREETYPE;
int32_t ret = FT_Init_FreeType(&fontLibrary);
assertTrue(ret == 0, "Could not init FreeType");
// Done parsing!
this->state = TRUE_TYPE_ASSET_STATE_READY;
this->loaded = true;
}
usagelockid_t TrueTypeAsset::lock(const struct TrueTypeFaceTextureStyle style) {
assertTrue(this->state == TRUE_TYPE_ASSET_STATE_READY, "Asset is not ready");
// Try and find an existing texture that matches this style
auto it = this->textureByStyle.find(style);
TrueTypeFaceTexture *texture = nullptr;
if(it == this->textureByStyle.end()) {
// Does not exist, Find asset style
auto itAssetStyle = std::find_if(
assetStyles.begin(),
assetStyles.end(),
[&](const struct TrueTypeAssetStyle &assetStyle) {
return assetStyle.style == style.style;
}
);
assertTrue(
itAssetStyle != this->assetStyles.end(),
"Could not find asset style"
);
// Create and read buffer.
uint8_t *dataBuffer = memoryAllocate<uint8_t>(itAssetStyle->dataSize);
this->loader.rewind();
this->loader.setPosition(itAssetStyle->dataOffset);
auto read = this->loader.read(dataBuffer, itAssetStyle->dataSize);
assertTrue(read == itAssetStyle->dataSize, "Could not read data");
// Create the face
FT_Face face;
auto ret = FT_New_Memory_Face(
this->fontLibrary,
(FT_Byte*)dataBuffer,
itAssetStyle->dataSize,
0,
&face
);
assertTrue(ret == 0, "Could not create face");
texture = new TrueTypeFaceTexture(face, style);
memoryFree(dataBuffer);
this->textures.push_back(texture);
this->textureByStyle[style] = texture;
} else {
// Exists
texture = it->second;
}
auto lock = this->locks.createLock();
this->textureByLock[lock] = texture;
this->locksByTexture[texture].push_back(lock);
return lock;
}
TrueTypeFaceTexture * TrueTypeAsset::getTexture(const usagelockid_t id) {
auto it = this->textureByLock.find(id);
assertTrue(it != this->textureByLock.end(), "Could not find texture");
return it->second;
}
void TrueTypeAsset::unlock(const usagelockid_t id) {
this->locks.removeLock(id);
}
TrueTypeAsset::~TrueTypeAsset() {
std::for_each(
this->textures.begin(),
this->textures.end(),
[](TrueTypeFaceTexture *texture){
delete texture;
}
);
FT_Done_FreeType(this->fontLibrary);
}

View File

@ -1,77 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "../Asset.hpp"
#include "asset/AssetLoader.hpp"
#include "util/flag.hpp"
#include "display/font/truetype/TrueTypeFaceTexture.hpp"
#include "util/UsageLock.hpp"
namespace Dawn {
enum TrueTypeAssetState {
TRUE_TYPE_ASSET_STATE_INITIAL,
TRUE_TYPE_ASSET_STATE_OPEN,
TRUE_TYPE_ASSET_STATE_VALIDATE_HEADER,
TRUE_TYPE_ASSET_STATE_VALIDATE_VERSION,
TRUE_TYPE_ASSET_STATE_READ_VARIANT_COUNT,
TRUE_TYPE_ASSET_STATE_READ_VARIANT,
TRUE_TYPE_ASSET_STATE_ADJUSTING_OFFSETS,
TRUE_TYPE_ASSET_STATE_INIT_FREETYPE,
TRUE_TYPE_ASSET_STATE_READY
};
struct TrueTypeAssetStyle {
flag_t style;
size_t dataSize;
size_t dataOffset;
};
class TrueTypeAsset : public Asset {
protected:
UsageLock locks;
AssetLoader loader;
FT_Library fontLibrary;
enum TrueTypeAssetState state = TRUE_TYPE_ASSET_STATE_INITIAL;
std::vector<struct TrueTypeAssetStyle> assetStyles;
std::vector<TrueTypeFaceTexture*> textures;
std::map<usagelockid_t, TrueTypeFaceTexture*> textureByLock;
std::map<struct TrueTypeFaceTextureStyle, TrueTypeFaceTexture*>
textureByStyle
;
std::map<TrueTypeFaceTexture*, std::vector<usagelockid_t>> locksByTexture;
public:
TrueTypeAsset(const std::string name);
void updateSync() override;
void updateAsync() override;
/**
* Create a lock for a specific style. Locks will ensure that the font is
* held loaded until it is no longer required.
*
* @param style Style to lock.
* @return A unique lock ID for this style.
*/
usagelockid_t lock(const struct TrueTypeFaceTextureStyle style);
/**
* Get a texture by a previous lock ID.
*
* @param lock Lock to get the texture of.
* @return Matching texture by this ID.
*/
TrueTypeFaceTexture * getTexture(const usagelockid_t lock);
/**
* Releases a previously held font lock.
*
* @param lock Lock to release/unlock.
*/
void unlock(const usagelockid_t lock);
~TrueTypeAsset();
};
}