Texture loading done.

This commit is contained in:
2023-11-25 19:31:16 -06:00
parent 89fe77c07e
commit 94941b1c14
12 changed files with 233 additions and 32 deletions

View File

@ -23,6 +23,7 @@ add_subdirectory(asset)
# add_subdirectory(audio)
add_subdirectory(component)
add_subdirectory(display)
add_subdirectory(environment)
add_subdirectory(game)
# add_subdirectory(games)
# add_subdirectory(input)

View File

@ -152,7 +152,7 @@ size_t AssetDataLoader::readUntil(
if(buffer[i] == delimiter) break;
i++;
}
buffer[i] = '\0';
buffer[i++] = '\0';
return i;
}

View File

@ -116,7 +116,7 @@ namespace Dawn {
* @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.
* @return The count of bytes read (including null terminator)
*/
size_t readUntil(
uint8_t *buffer,

View File

@ -14,6 +14,7 @@ TextureLoader::TextureLoader(const std::string name) :
state(TextureLoaderLoadState::INITIAL)
{
sharedTexture = std::make_shared<Texture>();
weakTexture = sharedTexture;
}
void TextureLoader::updateAsync() {
@ -23,23 +24,124 @@ void TextureLoader::updateAsync() {
// Read in the header.
uint8_t buffer[TEXTURE_LOADER_HEADER_SIZE];
this->loader.read(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, pos);
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

@ -11,34 +11,25 @@
#define TEXTURE_LOADER_HEADER_SIZE 256
namespace Dawn {
enum class TextureLoaderHeaderParseState {
VERSION,
WIDTH,
HEIGHT,
FORMAT,
WRAP_MODE_X,
WRAP_MODE_Y,
FILTER_MODE_MIN,
FILTER_MODE_MAG,
DONE
};
enum class TextureLoaderLoadState {
INITIAL,
ASYNC_LOADING,
ASYNC_DONE,
SYNC_LOADING,
SYNC_DONE
};
class TextureLoader : public AssetLoader {
protected:
AssetDataLoader loader;
// int32_t width = -1, height = -1;
// uint8_t *colors;
enum TextureLoaderLoadState state;
// enum TextureFormat format;
// enum TextureWrapMode wrapModeX;
// enum TextureWrapMode wrapModeY;
// enum TextureFilterMode filterModeMin;
// enum TextureFilterMode filterModeMag;
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;

View File

@ -17,6 +17,7 @@ extern "C" {
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#include <errno.h>
typedef bool bool_t;
typedef char char_t;

View File

@ -27,8 +27,8 @@ namespace Dawn {
};
enum class TextureDataFormat {
UNSIGNED_BYTE = 0,
FLOAT = 1
UNSIGNED_BYTE = sizeof(uint8_t),
FLOAT = sizeof(float_t)
};
class ITexture {

View File

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

View File

@ -0,0 +1,31 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Environment.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
Environment environment;
bool_t Environment::hasVariable(const std::string &key) {
assertTrue(key.length() > 0, "Key must be at least 1 character long.");
return this->variables.find(key) != this->variables.end();
}
void Environment::setVariable(
const std::string &key,
const std::string &value
) {
assertTrue(key.length() > 0, "Key must be at least 1 character long.");
this->variables[key] = value;
}
std::string Environment::getVariable(const std::string &key) {
assertTrue(key.length() > 0, "Key must be at least 1 character long.");
assertTrue(this->hasVariable(key), "Variable does not exist.");
return this->variables[key];
}

View File

@ -8,8 +8,34 @@
namespace Dawn {
class Environment {
public:
private:
std::map<std::string, std::string> variables;
public:
/**
* Checks if the environment has a variable.
*
* @param key Variable key to check.
* @return True if the variable exists, false otherwise.
*/
bool_t hasVariable(const std::string &key);
/**
* Sets a variable in the environment.
*
* @param key Variable key to set.
* @param value Variable value to set.
*/
void setVariable(const std::string &key, const std::string &value);
/**
* Gets a variable from the environment.
*
* @param key Variable key to get.
* @return Variable value, or empty string if not found.
*/
std::string getVariable(const std::string &key);
};
extern Dawn::Environment environment;
}
extern Dawn::Environment environment;

View File

@ -23,7 +23,7 @@ void Dawn::helloWorldScene(Scene &s) {
cubeMesh->createBuffers(CUBE_VERTICE_COUNT, CUBE_INDICE_COUNT);
CubeMesh::buffer(cubeMesh, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1), 0, 0);
auto texture = s.getGame()->assetManager.get<Texture>("test_texture");
auto texture = s.getGame()->assetManager.get<Texture>("texture_border");
auto cubeItem = s.createSceneItem();
auto cubeMeshRenderer = cubeItem->addComponent<MeshRenderer>();

View File

@ -4,21 +4,60 @@
// https://opensource.org/licenses/MIT
#include "main.hpp"
#include "assert/assert.hpp"
#include "display/RenderHost.hpp"
#include "game/Game.hpp"
#include "asset/AssetDataLoader.hpp"
#include "environment/Environment.hpp"
#include <filesystem>
using namespace Dawn;
std::string executablePath;
namespace fs = std::filesystem;
FILE * AssetDataLoader::openAssetArchiveFile() {
std::string path =
return fopen((path + "../../assets.tar").c_str(), "rb");
auto path = environment.getVariable("assetsPath");
auto file = fopen(path.c_str(), "rb");
if(!file) {
assertUnreachable("Failed to open assets file.\n%s!", strerror(errno));
return nullptr;
}
return file;
}
int32_t main(int32_t argc, const char **argv) {
//Set the path
path = argv[0];
assertTrue(argc > 0, "No executable path provided.");
environment.setVariable("executablePath", argv[0]);
auto execPath = fs::path(environment.getVariable("executablePath"));
auto execDir = execPath;
while(fs::is_directory(execDir)) execDir = execDir.parent_path();
environment.setVariable("executableDir", execDir.string());
// Find the assets
std::vector<fs::path> pathsToTryAndFindAssets = {
execDir / "assets.tar",
execDir / "assets.zip",
execDir / "data" / "assets.tar",
execDir / "data" / "assets.zip",
execDir.parent_path() / "assets.tar",
execDir.parent_path() / "assets.zip",
execDir.parent_path() / "data" / "assets.tar",
execDir.parent_path() / "data" / "assets.zip",
execDir.parent_path().parent_path() / "assets.tar",
execDir.parent_path().parent_path() / "assets.zip",
execDir.parent_path().parent_path() / "data" / "assets.tar",
execDir.parent_path().parent_path() / "data" / "assets.zip"
};
auto matchingPathIfAny = std::find_if(pathsToTryAndFindAssets.begin(), pathsToTryAndFindAssets.end(), [](const fs::path &p) {
return fs::exists(p);
});
if(matchingPathIfAny == pathsToTryAndFindAssets.end()) {
std::cout << "Could not find game assets" << std::endl;
return 1;
}
environment.setVariable("assetsPath", matchingPathIfAny->string());
//Create the game
auto game = std::make_shared<Game>();