72 Commits
main ... reset

Author SHA1 Message Date
57995a0e00 Remove train station. 2024-11-24 11:18:08 -06:00
53dc496f2f Dawn progress 2024-11-07 18:28:54 -06:00
6a0ffd4a45 about to start work on downtown 2024-10-25 23:02:55 -05:00
ef84c85527 Cleaned a bit of the tile code. Built train station 2024-10-25 10:30:49 -05:00
39d74cc375 Map loading fixes and improvements 2024-10-22 08:00:48 -05:00
ddbef64f43 Started work on using tiled 2024-10-21 20:50:16 -05:00
b2a3ca4411 Example sign with conversation. 2024-10-20 15:31:04 -07:00
a74f285cb2 Memory functions 2024-10-17 09:30:36 -07:00
5fb36aad35 Moved tile interactions over. 2024-10-17 08:44:17 -07:00
258976b76c Made NPCs interactable with the conversation system. 2024-10-17 07:36:33 -07:00
7867076bbe Added language support to main menu and sign 2024-10-17 07:17:36 -07:00
3baafec9cb Adding language 2024-10-16 14:37:34 -07:00
6c062df9bb Added main menu. 2024-10-09 09:47:05 -05:00
825cc88e17 Moving some logic into separate files 2024-10-08 09:36:15 -05:00
9f4cb283c1 UI Menu more or less done perfectly. 2024-10-08 09:17:00 -05:00
86feb7e56a Mid menu coding 2024-10-07 09:49:22 -05:00
a7dc7fdcf8 Remove testmap2 2024-10-07 00:29:59 -05:00
cb3a58e456 Door and map changing 2024-10-07 00:27:20 -05:00
5334f0944e Add direction to the door 2024-10-06 23:21:28 -05:00
a1d4b0a1d7 Door 2024-10-06 23:11:45 -05:00
ecb3b9c5d1 Fixed JSON parsing throwing errors 2024-10-06 22:46:16 -05:00
bf3912bb7f Added sign 2024-10-06 22:23:26 -05:00
b5d7b7e229 Bit more cleanup 2024-10-06 21:01:05 -05:00
b7987401af Map loading basically done for now 2024-10-06 19:03:22 -05:00
ffc46c677c Added triggers to parsing. 2024-10-06 18:57:28 -05:00
7a8ca2fca1 Test loading asset data. 2024-10-06 18:52:52 -05:00
5751f7c83c Add asset loading support. 2024-10-06 18:27:54 -05:00
c69d0ec1cc Adding triggers, prepping for map loading. 2024-10-06 18:03:46 -05:00
e14445680f Add newlines to draw text 2024-10-06 17:30:04 -05:00
5256b32055 Textbox rendering back. 2024-10-06 17:16:24 -05:00
5444b0b8c7 Ensure linux terminal is still working 2024-10-06 16:43:54 -05:00
45b3cf9478 Cleaned old frame code. 2024-10-06 16:34:47 -05:00
0224ddd36b Getting around to cleaning drawing code finally. 2024-10-06 16:28:34 -05:00
40b0395552 idk what I coded 2024-10-06 01:30:45 -05:00
b7829fda5c Add tile interactions. 2024-10-05 10:29:15 -05:00
bdef59bbe1 Make map rendering centered 2024-10-05 10:17:12 -05:00
27ce6526e6 Vastly improve UI 2024-10-05 09:16:41 -05:00
704002e671 Moved TERM files around 2024-10-05 08:35:36 -05:00
cfe4cf6cad Testing mostly 2024-10-04 22:43:33 -05:00
69672cf8a6 Rendering working 2024-10-04 21:51:38 -05:00
c1345218a3 glfw 2024-10-04 16:41:01 -05:00
be27408cf4 Adding back GLFW 2024-10-04 09:37:32 -05:00
4205b919d4 Adding back GLFW 2024-10-04 09:37:24 -05:00
e14083b4b4 t 2024-10-03 22:35:22 -05:00
ad317da97e Reset 2024-10-03 20:09:10 -05:00
2ff1a159bc idk 2024-10-03 20:07:35 -05:00
c770953b2e VN Dummy 2024-09-29 00:47:12 -05:00
2cb1d745b2 Add JSON parser 2024-09-27 21:55:53 -05:00
8ce0e8f9f6 Changed more deps to use FetchContent 2024-09-25 15:11:04 -04:00
5101a856be Remove glm 2024-09-25 15:01:26 -04:00
303d0c0a6f Add camera pixel perfect. 2024-09-16 21:35:04 -05:00
e3a4368d1e Basic tile code ready. 2024-09-16 07:07:01 -05:00
7c34127900 Some more chunk work. 2024-09-16 06:50:47 -05:00
49d90b3362 Working on chunks 2024-09-15 08:41:44 -05:00
935398d45e Minigolf is pog 2024-09-15 08:06:45 -05:00
4065556d4a Switched map loops to weakptrs 2024-09-15 07:50:11 -05:00
fb8f6e3f95 Commit prog 2024-09-14 10:23:31 -05:00
b4c2ce16a0 idk if I like this structure. 2024-09-13 09:26:21 -05:00
b309478922 Trying to tune turning. 2024-09-11 10:07:23 -05:00
ad3974bde5 Testing walking. 2024-09-11 10:04:54 -05:00
e5349cc093 Created basic movement. 2024-09-11 09:21:56 -05:00
01c56477aa Basic movement example 2024-09-11 08:21:26 -05:00
916396e175 Fixed input 2024-09-10 20:17:32 -05:00
0e5b85633c Worked a bit on prefabs of all things 2024-09-10 18:26:14 -05:00
e5f3f69120 Restored UI Label support 2024-09-10 17:36:04 -05:00
ca240bc180 Moved poker code to main dawn code. 2024-09-10 08:46:57 -05:00
a3a891ddb2 Cleanup of poker code done, about to start testing. 2024-09-10 06:51:04 -05:00
5fae94c722 More refactoring 2024-09-10 00:07:15 -05:00
d5b3b6d619 Cleaning poker code pt 1. 2024-09-08 23:12:03 -05:00
b4e261d954 Move over old poker code 2024-09-08 21:54:19 -05:00
856bc306fe More cleanup complete 2024-09-08 15:30:41 -05:00
cffe7f73a2 Cleanup complete 2024-09-08 15:30:32 -05:00
418 changed files with 12082 additions and 16725 deletions

View File

@ -1,47 +0,0 @@
name: build-linux-glfw-x64
on:
# ON tag
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Dependencies
run: |
mkdir release
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
xorg-dev \
libglu1-mesa-dev \
libglfw3-dev \
libx11-dev \
libxkbcommon-dev \
python3-pil
- name: Build Linux GLFW x64
run: |
if [ -d "build" ]; then
rm -rf build
fi
mkdir build
mkdir release/linux-glfw-x64
cd build
cmake ..
make
cd ..
cp build/src/Dawn release/linux-glfw-x64/Dawn
cp build/dawn.tar release/linux-glfw-x64/dawn.tar
# - name: Release
# uses: akkuman/gitea-release-action@v1
# with:
# files: |-
# release/

View File

@ -0,0 +1,56 @@
name: build-helloworld-vita
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
env:
VITASDK: /usr/local/vitasdk
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache VITASDK
id: cache-vitasdk-restore
uses: actions/cache/restore@v3
with:
path: /usr/local/vitasdk
key: ${{ runner.os }}-vitasdk
- name: Install Vita Toolchain
if: steps.cache-vitasdk.outputs.cache-hit != 'true'
run: ./ci/install-vita-toolchain.sh
- name: Save VITASDK
id: cache-vitasdk-save
uses: actions/cache/save@v3
with:
path: /usr/local/vitasdk
key: ${{ steps.cache-vitasdk-restore.outputs.cache-primary-key }}
- name: Install Libraries
run: ./ci/install-libraries.sh
- name: Build Tools
run: ./ci/build-tools.sh
- name: Build Game
run: |
export PATH=$VITASDK/bin:$PATH
mkdir build
cd build
cmake .. -DDAWN_BUILD_TARGET=target-helloworld-vita -DCMAKE_BUILD_TYPE=Debug
make
- name: Deploying
env:
DAWN_SSH_KEY: ${{ secrets.DAWN_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo -e "${DAWN_SSH_KEY}" > ~/.ssh/id_rsa
chmod og-rwx ~/.ssh/id_rsa
ssh-keyscan -H wish.moe >> ~/.ssh/known_hosts
ssh -t yourwishes@wish.moe "mkdir -p /home/yourwishes/Dawn/vita/debug"
scp ./build/src/dawnvita/HelloWorld.vpk yourwishes@wish.moe:/home/yourwishes/Dawn/vita/debug/

View File

@ -0,0 +1,26 @@
name: build-liminal-glfw-linux64
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Toolchain
run: ./ci/install-linux-toolchain.sh
- name: Install Libraries
run: ./ci/install-libraries.sh
- name: Build Tools
run: ./ci/build-tools.sh
- name: Build Game
run: |
mkdir build
cd build
cmake .. -DDAWN_BUILD_TARGET=target-liminial-linux64-glfw
make

2
.gitignore vendored
View File

@ -65,7 +65,7 @@ CTestTestfile.cmake
_deps
# Custom
build
/build/*
.vscode
assets/testworld/tileset.png

3
.gitmodules vendored
View File

@ -0,0 +1,3 @@
[submodule "lib/font8x8"]
path = lib/font8x8
url = https://github.com/dhepper/font8x8

View File

@ -1,43 +1,42 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Variable Caches
set(DAWN_CACHE_TARGET "dawn-target")
set(DAWN_TARGET_NAME "Dawn")
# Set Common Build Variables
set(DAWN_ROOT_DIR "${CMAKE_SOURCE_DIR}")
set(DAWN_BUILD_DIR "${CMAKE_BINARY_DIR}")
set(DAWN_SOURCES_DIR "${DAWN_ROOT_DIR}/src")
set(DAWN_TOOLS_DIR "${DAWN_ROOT_DIR}/tools")
set(DAWN_ASSETS_SOURCE_DIR "${DAWN_ROOT_DIR}/assets")
set(DAWN_ASSETS_BUILD_DIR "${DAWN_BUILD_DIR}/assets")
set(DAWN_GENERATED_DIR "${DAWN_BUILD_DIR}/generated")
set(DAWN_TEMP_DIR "${DAWN_BUILD_DIR}/temp")
# Options
option(DAWN_ENABLE_PHYSICS "Enable Physics" OFF)
option(DAWN_DEBUG_SHADERS "Enable Debug Shaders" ON)
# Initialize Project First.
project(Dawn
VERSION 1.0.0
LANGUAGES C CXX
)
# Add tools
add_subdirectory(tools)
# Add Libraries
add_subdirectory(lib)
# Add Project Files
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Variable Caches
set(DAWN_CACHE_TARGET "dawn-target")
set(DAWN_TARGET_NAME "Dawn")
if(NOT DEFINED DAWN_TARGET)
set(DAWN_TARGET linux-x64-glfw CACHE INTERNAL ${DAWN_CACHE_TARGET})
# set(DAWN_TARGET linux-x64-terminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
endif()
# Set Common Build Variables
set(DAWN_ROOT_DIR "${CMAKE_SOURCE_DIR}")
set(DAWN_BUILD_DIR "${CMAKE_BINARY_DIR}")
set(DAWN_SOURCES_DIR "${DAWN_ROOT_DIR}/src")
set(DAWN_TOOLS_DIR "${DAWN_ROOT_DIR}/tools")
set(DAWN_ASSETS_SOURCE_DIR "${DAWN_ROOT_DIR}/assets")
set(DAWN_ASSETS_BUILD_DIR "${DAWN_BUILD_DIR}/assets")
set(DAWN_GENERATED_DIR "${DAWN_BUILD_DIR}/generated")
set(DAWN_TEMP_DIR "${DAWN_BUILD_DIR}/temp")
# Initialize Project.
project(Dawn
VERSION 1.0.0
LANGUAGES C
)
# Add tools
add_subdirectory(tools)
# Add Libraries
add_subdirectory(lib)
# Add Project Files
add_subdirectory(src)

View File

@ -1,3 +0,0 @@
# Dawn Project
Simple in code, complex in structure game engine for creating small, fast and
reusable games.

View File

@ -1,8 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Shader.hpp"
using namespace Dawn;

View File

@ -1,259 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/ShaderStage.hpp"
#include "display/shader/IShader.hpp"
#include "assert/assert.hpp"
#include "assert/assertgl.hpp"
#include "display/Color.hpp"
#include "display/Texture.hpp"
#include "ShaderParameter.hpp"
#include "ShaderStructure.hpp"
namespace Dawn {
typedef GLuint shadertexturebinding_t;
enum class ShaderOpenGLVariant {
GLSL_330_CORE
};
template<typename T>
class Shader : public IShader<T> {
private:
std::vector<std::shared_ptr<ShaderStage>> stages;
std::vector<struct ShaderParameter> parameters;
std::vector<struct IShaderStructure> structures;
enum ShaderOpenGLVariant variant;
GLuint shaderProgram = -1;
protected:
/**
* Overridable function to get the stages for the shader.
*
* @param variant The variant of the shader to use.
* @param rel The relative data to use.
* @param stages The stages to add to.
* @param parameters The parameters to add to.
* @param structures The structures to add to.
*/
virtual void getStages(
const enum ShaderOpenGLVariant variant,
const T *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderParameter> &parameters,
std::vector<struct IShaderStructure> &structures
) = 0;
public:
/**
* Initializes the shader, this needs to be called before the shader can
* be used.
*/
void init() override {
// Determine which kind of OpenGL shader to use.
variant = ShaderOpenGLVariant::GLSL_330_CORE;
// Now get the stages
T dummy;
this->getStages(
variant,
&dummy,
stages,
parameters,
structures
);
// Create the shader program
shaderProgram = glCreateProgram();
assertNoGLError();
// Attach all the stages
for(auto stage : stages) {
glAttachShader(shaderProgram, stage->id);
assertNoGLError();
}
// Link and verify the program
glLinkProgram(shaderProgram);
assertNoGLError();
GLint status;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
assertNoGLError();
assertTrue(status == GL_TRUE, "Failed to link shader program.");
std::vector<std::string> uniformNames;
GLint numUniforms = 0;
// Get the number of active uniforms
glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &numUniforms);
assertNoGLError();
// Iterate through each uniform
// for (GLint i = 0; i < numUniforms; ++i) {
// char name[256];
// GLsizei length;
// GLint size;
// GLenum type;
// // Get the uniform name
// glGetActiveUniform(shaderProgram, i, sizeof(name), &length, &size, &type, name);
// assertNoGLError();
// std::cout << "Uniform: " << i << ":" << name << std::endl;
// // uniformNames.push_back(std::string(name));
// }
// Map parameters correctly.
std::for_each(
parameters.begin(),
parameters.end(),
[&](struct ShaderParameter &param) {
// Correct offset
param.offset = param.offset - (size_t)(&dummy);
param.location = glGetUniformLocation(
shaderProgram,
param.name.c_str()
);
assertNoGLError();
assertTrue(
param.location != -1,
"Failed to get location for parameter %s.",
param.name.c_str()
);
}
);
// Map structures
std::for_each(
structures.begin(),
structures.end(),
[&](struct IShaderStructure &structure) {
structure.offset = structure.offset - (size_t)(&dummy);
structure.location = glGetUniformBlockIndex(
shaderProgram,
structure.structureName.c_str()
);
assertNoGLError();
assertTrue(
structure.location != -1,
"Failed to get location for structure %s.",
structure.structureName.c_str()
);
// Create the buffer
glGenBuffers(1, &structure.buffer);
}
);
this->bind();
}
/**
* Binds the shader as the current one, does not upload any data, somewhat
* relies on something else uploading the data.
*/
void bind() override {
glUseProgram(shaderProgram);
assertNoGLError();
}
/**
* Uploads the data to the GPU.
*/
void upload() override {
switch(this->variant) {
case ShaderOpenGLVariant::GLSL_330_CORE:
for(auto param : parameters) {
void *value = (void*)(
((size_t)&this->data) + param.offset
);
switch(param.type) {
case ShaderParameterType::MAT4: {
glm::mat4 *matrix = (glm::mat4 *)value;
if(param.count != 1) {
assertUnreachable("I haven't implemented multiple mat4s");
}
glUniformMatrix4fv(
param.location, 1, GL_FALSE, glm::value_ptr(*matrix)
);
break;
}
case ShaderParameterType::COLOR: {
auto color = (Color *)value;
glUniform4fv(
param.location,
param.count,
(GLfloat*)value
);
break;
}
case ShaderParameterType::BOOLEAN: {
glUniform1iv(param.location, param.count, (GLint*)value);
break;
}
case ShaderParameterType::TEXTURE: {
glUniform1iv(param.location, param.count, (GLint*)value);
break;
}
default: {
assertUnreachable("Unsupported ShaderParameterType");
}
}
assertNoGLError();
}
break;
default:
assertUnreachable("Unsupported ShaderOpenGLVariant");
}
// Upload structures
for(auto structure : structures) {
switch(structure.structureType) {
case ShaderOpenGLStructureType::STD140: {
// Upload the data
glBindBuffer(GL_UNIFORM_BUFFER, structure.buffer);
assertNoGLError();
glBindBufferBase(GL_UNIFORM_BUFFER, structure.location, structure.buffer);
assertNoGLError();
glBufferData(
GL_UNIFORM_BUFFER,
structure.size * structure.count,
(void*)((size_t)&this->data + (size_t)structure.offset),
GL_STATIC_DRAW
);
assertNoGLError();
break;
}
default:
assertUnreachable("Unsupported ShaderOpenGLStructureType");
}
}
}
~Shader() {
// Delete the structures
for(auto structure : structures) {
assertTrue(structure.buffer != -1, "Invalid buffer.");
glDeleteBuffers(1, &structure.buffer);
assertNoGLError();
}
// Delete the shader program
glDeleteProgram(shaderProgram);
assertNoGLError();
}
};
}

View File

@ -1,20 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "ShaderParameter.hpp"
using namespace Dawn;
ShaderParameter::ShaderParameter(
const std::string &name,
const void *offset,
const enum ShaderParameterType type,
const size_t count
) {
this->name = name;
this->offset = (size_t)offset;
this->type = type;
this->count = count;
}

View File

@ -1,33 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/IShader.hpp"
#include "dawnopengl.hpp"
namespace Dawn {
struct ShaderParameter {
std::string name;
size_t offset;
enum ShaderParameterType type;
size_t count;
GLint location = -1;
/**
* Construct a new shader parameter.
*
* @param name Name of the parameter within the shader.
* @param offset Offset, relative to the structure of the data.
* @param type Type of the parameter.
* @param count How many elements in the array (if multiple).
*/
ShaderParameter(
const std::string &name,
const void *offset,
const enum ShaderParameterType type,
const size_t count = 1
);
};
}

View File

@ -1,74 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assertgl.hpp"
#include "assert/assert.hpp"
#include "ShaderStage.hpp"
using namespace Dawn;
ShaderStage::ShaderStage(
const enum ShaderStageType type,
const std::string source
) : IShaderStage(type) {
// Get OpenGL Shader Type
GLenum shaderType;
switch(this->type) {
case ShaderStageType::VERTEX:
shaderType = GL_VERTEX_SHADER;
break;
case ShaderStageType::FRAGMENT:
shaderType = GL_FRAGMENT_SHADER;
break;
// case ShaderStageType::COMPUTE:
// shaderType = GL_COMPUTE;
// break;
default:
assertUnreachable("Unknown ShaderStageType");
}
// Initialize the shader
this->id = glCreateShader(shaderType);
assertNoGLError();
// Compile the shader
auto cSource = source.c_str();
glShaderSource(this->id, 1, &cSource, NULL);
assertNoGLError();
glCompileShader(this->id);
assertNoGLError();
// glShaderBinary(1, &this->id, GL_SHADER_BINARY_FORMAT_SPIR_V, source.data(), source.size());
// assertNoGLError();
// glSpecializeShader(this->id, "main", 0, NULL, NULL);
// assertNoGLError();
// Validate
GLint status;
glGetShaderiv(this->id, GL_COMPILE_STATUS, &status);
assertNoGLError();
if(!status) {
// Failed to compile
GLint logLength;
glGetShaderiv(this->id, GL_INFO_LOG_LENGTH, &logLength);
assertNoGLError();
GLchar *log = new GLchar[logLength];
glGetShaderInfoLog(this->id, logLength, NULL, log);
assertNoGLError();
assertUnreachable("Failed to compile shader stage %i:\n%s", type, log);
}
}
ShaderStage::~ShaderStage() {
if(this->id != -1) {
glDeleteShader(this->id);
assertNoGLError();
}
}

View File

@ -1,28 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnopengl.hpp"
#include "display/shader/IShaderStage.hpp"
namespace Dawn {
class ShaderStage : public IShaderStage {
public:
GLuint id = -1;
/**
* Constructs a new ShaderStage.
*
* @param type The type of shader this is.
* @param source The source code to compile.
*/
ShaderStage(const enum ShaderStageType type, const std::string source);
/**
* Disposes of the shader stage.
*/
~ShaderStage();
};
}

View File

@ -1,96 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma ocne
#include "display/shader/ShaderParameter.hpp"
namespace Dawn {
enum class ShaderOpenGLStructureType {
STD140
};
struct IShaderStructure {
std::string structureName;
size_t offset;
enum ShaderOpenGLStructureType structureType;
size_t size;
size_t count;
std::vector<struct ShaderParameter> parameters;
GLint location = -1;
GLuint buffer = -1;
};
template<typename T>
struct ShaderStructure final : public IShaderStructure {
public:
/**
* Constructs a new shader structure. Shader structures allow for larger
* amounts/volumes of data to be passed to the shader in a single call.
* Ideally I wouldn't really need this as I wanted the entire shader to
* basically be a single large structure, but OpenGL doesn't support that
* so I have to do this instead.
*
* @param structureName Structure name within the shader.
* @param offset Offset, within the data structure, that this structure
* starts at.
* @param structureType The type of structure data format to use.
* @param getParameters A callback that, when invoked, will populate the
* parameters vector with the parameters for this
* structure.
* @param count The number of structures to create.
*/
ShaderStructure(
const std::string &structureName,
const void *offset,
const enum ShaderOpenGLStructureType structureType,
std::function<
void(const T&, std::vector<struct ShaderParameter>&)
> getParameters,
size_t count = 1
) {
this->structureName = structureName;
this->offset = (size_t)offset;
this->structureType = structureType;
this->size = sizeof(T);
this->count = count;
this->parameters = std::vector<struct ShaderParameter>();
T dummy;
getParameters(dummy, this->parameters);
// Update offsets.
auto itParams = this->parameters.begin();
while(itParams != this->parameters.end()) {
struct ShaderParameter &param = *itParams;
param.offset -= (size_t)(&dummy);
// Check for non-aligned OpenGL structures.
if(param.offset % sizeof(glm::vec4) != 0) {
assertUnreachable(
"%s%s%s",
"Non-aligned OpenGL structure detected on param ",
param.name.c_str(),
"!\nEnsure you have padded correctly."
);
}
if(
itParams == (this->parameters.end() - 1) &&
count > 1 &&
(sizeof(T) % sizeof(glm::vec4)) != 0
) {
assertUnreachable(
"%s%s%s",
"Non-aligned OpenGL structure detected on last element in array structure on param ",
param.name.c_str(),
"!\nEnsure you have padded correctly."
);
}
++itParams;
}
}
};
}

View File

@ -1,230 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "display/shader/SimpleTexturedShader.hpp"
#include <fstream>
#include "slang.h"
#include "slang-gfx.h"
using namespace slang;
using namespace Dawn;
void SimpleTexturedShader::getStages(
const enum ShaderOpenGLVariant variant,
const struct SimpleTexturedShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderParameter> &parameters,
std::vector<struct IShaderStructure> &structures
) {
// Stages
std::shared_ptr<ShaderStage> vertex;
std::shared_ptr<ShaderStage> fragment;
std::string shader = R"(
cbuffer Uniforms {
float4x4 u_Projection;
float4x4 u_View;
float4x4 u_Model;
float4 u_Color;
bool u_HasTexture;
uniform Sampler2D u_Texture;
};
struct AssembledVertex {
float3 position : POSITION;
float2 texcoord : TEXCOORD;
};
struct Fragment {
float4 color;
};
struct VertexStageOutput {
float2 uv : UV;
float4 sv_position : SV_Position;
};
[shader("vertex")]
VertexStageOutput vertexMain(
AssembledVertex assembledVertex
) {
VertexStageOutput output;
float3 position = assembledVertex.position;
output.uv = assembledVertex.texcoord;
output.sv_position = mul(
float4(position, 1.0),
mul(u_Model, mul(u_View, u_Projection))
);
return output;
}
[shader("fragment")]
Fragment fragmentMain(
float2 uv: UV
) : SV_Target {
Fragment output;
if(u_HasTexture) {
output.color = u_Texture.Sample(uv) * u_Color;
} else {
output.color = u_Color;
}
return output;
}
)";
Slang::ComPtr<IGlobalSession> globalSession;
createGlobalSession(globalSession.writeRef());
SessionDesc sessionDesc;
TargetDesc targetDesc;
targetDesc.format = SLANG_GLSL;
targetDesc.profile = globalSession->findProfile("glsl_330");
sessionDesc.targets = &targetDesc;
sessionDesc.targetCount = 1;
Slang::ComPtr<IBlob> diagnostics;
const char* searchPaths[] = { "/home/yourwishes/htdocs/Dawn/assets/shaders/" };
sessionDesc.searchPaths = searchPaths;
sessionDesc.searchPathCount = 1;
Slang::ComPtr<ISession> session;
globalSession->createSession(sessionDesc, session.writeRef());
auto module = session->loadModuleFromSourceString(
"hello-world.slang",
"hello-world.slang",
shader.c_str(),
diagnostics.writeRef()
);
if(diagnostics) {
assertUnreachable("Failed to load module %s", (const char*) diagnostics->getBufferPointer());
return;
}
Slang::ComPtr<IEntryPoint> vertexEntryPoint;
Slang::ComPtr<IEntryPoint> fragEntryPoint;
module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef());
module->findEntryPointByName("fragmentMain", fragEntryPoint.writeRef());
IComponentType* components[] = { module, vertexEntryPoint, fragEntryPoint };
Slang::ComPtr<IComponentType> program;
session->createCompositeComponentType(
components,
sizeof(components) / sizeof(components[0]),
program.writeRef()
);
Slang::ComPtr<IComponentType> linkedProgram;
auto result = program->link(linkedProgram.writeRef(), diagnostics.writeRef());
std::cout << "Result: " << result << std::endl;
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
return;
}
int entryPointIndex = 0;
int targetIndex = 0; // only one target
Slang::ComPtr<IBlob> vertexBlob;
result = linkedProgram->getEntryPointCode(
entryPointIndex,
targetIndex,
vertexBlob.writeRef(),
diagnostics.writeRef()
);
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
return;
}
slang::ProgramLayout* layout = program->getLayout();
unsigned parameterCount = layout->getParameterCount();
for(unsigned pp = 0; pp < parameterCount; pp++) {
slang::VariableLayoutReflection* parameter = layout->getParameterByIndex(pp);
std::cout << "Parameter: " << parameter->getName() << std::endl;
auto layout = parameter->getTypeLayout();
auto fields = layout->getFieldCount();
for(unsigned ff = 0; ff < fields; ff++) {
slang::VariableLayoutReflection* field = layout->getFieldByIndex(ff);
std::string fieldName = field->getName();
std::cout << "Field: " << fieldName << std::endl;
}
}
std::string vertexString = (const char*)vertexBlob->getBufferPointer();
entryPointIndex = 1;
Slang::ComPtr<IBlob> fragmentBlob;
result = linkedProgram->getEntryPointCode(
entryPointIndex,
targetIndex,
fragmentBlob.writeRef(),
diagnostics.writeRef()
);
if(diagnostics) {
assertUnreachable("%s\n", (const char*) diagnostics->getBufferPointer());
return;
}
std::string fragmentString = (const char*)fragmentBlob->getBufferPointer();
vertex = std::make_shared<ShaderStage>(
ShaderStageType::VERTEX, vertexString
);
stages.push_back(vertex);
fragment = std::make_shared<ShaderStage>(
ShaderStageType::FRAGMENT, fragmentString
);
stages.push_back(fragment);
structures.push_back(ShaderStructure<struct SimpleTexturedShaderDataSub>(
"block_SLANG_ParameterGroup_Uniforms_std140_0",
&rel->data,
ShaderOpenGLStructureType::STD140,
[](const SimpleTexturedShaderDataSub &data, std::vector<struct ShaderParameter> &parameters) {
parameters.push_back(ShaderParameter(
"u_Projection_0",
&data.projection,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_View_0",
&data.view,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_Model_0",
&data.model,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_Color_0",
&data.color,
ShaderParameterType::COLOR
));
parameters.push_back(ShaderParameter(
"u_HasTexture_0",
&data.hasTexture,
ShaderParameterType::BOOLEAN
));
}
));
// Parameters
parameters.push_back(ShaderParameter(
"Uniforms_u_Texture_0",
&rel->texture,
ShaderParameterType::TEXTURE
));
}

View File

@ -1,34 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/Shader.hpp"
namespace Dawn {
struct SimpleTexturedShaderDataSub {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
struct Color color = COLOR_WHITE;
bool hasTexture = false;
};
struct SimpleTexturedShaderData {
struct SimpleTexturedShaderDataSub data;
shadertexturebinding_t texture = 0;
};
class SimpleTexturedShader : public Shader<SimpleTexturedShaderData> {
protected:
void getStages(
const enum ShaderOpenGLVariant variant,
const struct SimpleTexturedShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderParameter> &parameters,
std::vector<struct IShaderStructure> &structures
) override;
};
}

View File

@ -1,194 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "display/shader/UIShader.hpp"
#include "util/Macro.hpp"
using namespace Dawn;
void UIShader::getStages(
const enum ShaderOpenGLVariant variant,
const struct UIShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderParameter> &parameters,
std::vector<struct IShaderStructure> &structures
) {
// Stages
std::shared_ptr<ShaderStage> vertex;
std::shared_ptr<ShaderStage> fragment;
switch(variant) {
case ShaderOpenGLVariant::GLSL_330_CORE:
vertex = std::make_shared<ShaderStage>(
ShaderStageType::VERTEX,
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"uniform mat4 u_Projection;\n"
"uniform mat4 u_View;\n"
"uniform mat4 u_Model;\n"
"struct UIShaderQuad {\n"
"vec4 quad;\n"
"vec4 uv;\n"
"vec4 color;\n"
"vec4 style;\n"
"};\n"
"layout (std140) uniform ub_Quad {\n"
"UIShaderQuad quads[" MACRO_STRINGIFY(UI_SHADER_QUAD_COUNT) "];\n"
"};\n"
"out vec2 v_TextCoord;\n"
"out vec4 v_Color;\n"
"out vec4 v_Style;\n"
"void main() {\n"
"vec4 pos;\n"
"vec2 coord;\n"
"int index = int(aPos.z);\n"
"int quadIndex = index / 4;\n"
"int vertexIndex = index % 4;\n"
"UIShaderQuad quad = quads[quadIndex];\n"
"if(vertexIndex == 0) {\n"
"pos.x = quad.quad.x;\n"
"pos.y = quad.quad.y;\n"
"coord.x = quad.uv.x;\n"
"coord.y = quad.uv.y;\n"
"} else if(vertexIndex == 1) {\n"
"pos.x = quad.quad.z;\n"
"pos.y = quad.quad.y;\n"
"coord.x = quad.uv.z;\n"
"coord.y = quad.uv.y;\n"
"} else if(vertexIndex == 2) {\n"
"pos.y = quad.quad.w;\n"
"pos.x = quad.quad.x;\n"
"coord.x = quad.uv.x;\n"
"coord.y = quad.uv.w;\n"
"} else if(vertexIndex == 3) {\n"
"pos.x = quad.quad.z;\n"
"pos.y = quad.quad.w;\n"
"coord.x = quad.uv.z;\n"
"coord.y = quad.uv.w;\n"
"}\n"
"pos.z = 0;\n"
"pos.w = 1;\n"
"gl_Position = u_Projection * u_View * u_Model * pos;\n"
"v_TextCoord = coord;\n"
"v_Color = quad.color;\n"
"v_Style = quad.style;\n"
"}"
);
fragment = std::make_shared<ShaderStage>(
ShaderStageType::FRAGMENT,
"#version 330 core\n"
"in vec2 v_TextCoord;\n"
"in vec4 v_Color;\n"
"in vec4 v_Style;\n"
"uniform sampler2D u_Texture[" MACRO_STRINGIFY(UI_SHADER_TEXTURE_COUNT) "];\n"
"out vec4 o_Color;\n"
"void main() {\n"
"vec4 texColor = vec4(1, 1, 1, 1);\n"
"int vStyle = int(round(v_Style[0]));\n"
"int vTextInd = int(round(v_Style[1]));\n"
"switch(vTextInd) {\n"
"case -1:\n"
"texColor = vec4(1, 1, 1, 1);\n"
"break;\n"
"case 0:\n"
"texColor = texture(u_Texture[0], v_TextCoord);\n"
"break;\n"
"case 1:\n"
"texColor = texture(u_Texture[1], v_TextCoord);\n"
"break;\n"
"case 2:\n"
"texColor = texture(u_Texture[2], v_TextCoord);\n"
"break;\n"
"case 3:\n"
"texColor = texture(u_Texture[3], v_TextCoord);\n"
"break;\n"
"case 4:\n"
"texColor = texture(u_Texture[4], v_TextCoord);\n"
"break;\n"
"case 5:\n"
"texColor = texture(u_Texture[5], v_TextCoord);\n"
"break;\n"
"}\n"
"switch(vStyle) {\n"
"case 0:\n"
"o_Color = texColor * v_Color;\n"
"break;\n"
"case 1:\n"
"o_Color.rgb = v_Color.rgb;\n"
"o_Color.a = texColor.r * v_Color.a;\n"
"break;\n"
"}\n"
"}\n"
);
break;
default:
assertUnreachable("Unsupported ShaderOpenGLVariant");
}
// Add stages
stages.push_back(vertex);
stages.push_back(fragment);
// Parameters
parameters.push_back(ShaderParameter(
"u_Projection",
&rel->projection,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_View",
&rel->view,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_Model",
&rel->model,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderParameter(
"u_Texture",
&rel->textures,
ShaderParameterType::TEXTURE,
UI_SHADER_TEXTURE_COUNT
));
structures.push_back(ShaderStructure<struct UIShaderQuad>(
"ub_Quad",
&rel->quads,
ShaderOpenGLStructureType::STD140,
[&](const struct UIShaderQuad &rel, std::vector<struct ShaderParameter> &parameters) {
parameters.push_back(ShaderParameter(
"quad",
&rel.quad,
ShaderParameterType::VEC4
));
parameters.push_back(ShaderParameter(
"uv",
&rel.uv,
ShaderParameterType::VEC4
));
parameters.push_back(ShaderParameter(
"color",
&rel.color,
ShaderParameterType::COLOR
));
parameters.push_back(ShaderParameter(
"style",
&rel.style,
ShaderParameterType::VEC4
));
},
UI_SHADER_QUAD_COUNT
));
}

View File

@ -1,43 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/Shader.hpp"
namespace Dawn {
#define UI_SHADER_QUAD_COUNT 1024
#define UI_SHADER_TEXTURE_COUNT 16
enum class UIShaderQuadStyle {
TEXTURED = 0,
FONT = 1
};
struct UIShaderQuad {
glm::vec4 quad;
glm::vec4 uv;
struct Color color;
glm::vec4 style;
};
struct UIShaderData {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
shadertexturebinding_t textures[UI_SHADER_TEXTURE_COUNT];
struct UIShaderQuad quads[UI_SHADER_QUAD_COUNT];
};
class UIShader : public Shader<UIShaderData> {
protected:
void getStages(
const enum ShaderOpenGLVariant variant,
const struct UIShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderParameter> &parameters,
std::vector<struct IShaderStructure> &structures
) override;
};
}

View File

@ -1,144 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UICanvas.hpp"
#include "display/pass/RenderPass.hpp"
#include "display/mesh/QuadMesh.hpp"
#include "ui/UIElement.hpp"
using namespace Dawn;
void UICanvas::onInit() {
mesh = std::make_shared<Mesh>();
mesh->createBuffers(
QUAD_VERTICE_COUNT * UI_SHADER_QUAD_COUNT,
QUAD_INDICE_COUNT * UI_SHADER_QUAD_COUNT
);
for(int32_t i = 0; i < UI_SHADER_QUAD_COUNT; i++) {
QuadMesh::bufferWithIndex(
mesh,
glm::vec4(0, 0, 1, 1),
glm::vec4(0, 0, 1, 1),
i * QUAD_VERTICE_COUNT,
i * QUAD_INDICE_COUNT,
i * QUAD_VERTICE_COUNT
);
}
}
void UICanvas::onDispose() {
mesh = nullptr;
}
std::vector<std::shared_ptr<IRenderPass>> UICanvas::getPasses(
struct RenderPassContext &ctx
) {
if(this->elements.empty()) return {};
glm::mat4 projection;
glm::mat4 view;
// Setup the projection and views
data.projection = glm::ortho(
0.0f, ctx.renderTarget->getWidth(),
ctx.renderTarget->getHeight(), 0.0f,
0.0f, 1.0f
);
data.view = glm::mat4(1.0f);
data.model = glm::mat4(1.0f);
// Reset the passes
this->passes.clear();
this->textureBindings.clear();
this->textures.clear();
quadCount = 0;
nextBinding = 0;
// Alignment root
const glm::vec2 rootPosition = { 0, 0 };
const glm::vec2 rootSize = {
ctx.renderTarget->getWidth(),
ctx.renderTarget->getHeight()
};
const float_t rootScale = 1.0f;
// Get the quads for each component
auto itComponents = elements.begin();
auto self = std::ref(*this);
while(itComponents != elements.end()) {
auto component = *itComponents;
component->updateAlignment(rootPosition, rootSize, rootScale);
component->getQuads(self);
++itComponents;
}
// Flush the remaining quads
flushPass();
return passes;
}
void UICanvas::addQuad(
const glm::vec4 quad,
const glm::vec4 uvs,
const struct Color color,
const enum UIShaderQuadStyle style,
const std::shared_ptr<Texture> text
) {
glm::vec4 styleData;
styleData[0] = (float_t)style;
if(text == nullptr) {
styleData[1] = -1;
} else {
shadertexturebinding_t texture;
auto bindingIt = textureBindings.find(text);
if(bindingIt == textureBindings.end()) {
if(nextBinding >= UI_SHADER_TEXTURE_COUNT) {
flushPass();
}
textureBindings[text] = nextBinding;
textures[nextBinding] = text;
data.textures[nextBinding] = nextBinding;
texture = nextBinding++;
} else {
texture = bindingIt->second;
}
styleData[1] = (float_t)texture;
}
data.quads[quadCount] = {
quad,
uvs,
color,
styleData
};
quadCount++;
if(quadCount == UI_SHADER_QUAD_COUNT) flushPass();
}
void UICanvas::flushPass() {
if(quadCount == 0) return;
auto pass = createRenderPass<UIShader, UIShaderData>(
std::ref(*this),
data,
textures,
mesh,
MeshDrawMode::TRIANGLES,
0,
quadCount * QUAD_INDICE_COUNT
);
passes.push_back(pass);
quadCount = 0;
nextBinding = 0;
textures.clear();
textureBindings.clear();
}
void UICanvas::addElement(const std::shared_ptr<UIElement> element) {
elements.push_back(element);
}

View File

@ -1,73 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneItem.hpp"
#include "component/display/IRenderableComponent.hpp"
#include "display/shader/UIShader.hpp"
namespace Dawn {
class UIElement;
class UICanvas :
public SceneComponent,
public IRenderableComponent
{
private:
std::shared_ptr<Mesh> mesh;
UIShaderData data;
std::vector<std::shared_ptr<UIElement>> elements;
size_t quadCount = 0;
shadertexturebinding_t nextBinding = 0;
std::unordered_map<
shadertexturebinding_t, std::shared_ptr<Texture>
> textures;
std::map<
std::shared_ptr<Texture>, shadertexturebinding_t
> textureBindings;
std::vector<std::shared_ptr<IRenderPass>> passes;
protected:
virtual void onInit() override;
virtual void onDispose() override;
/**
* Flushes all pending quads to the render pass. This doesn't actually
* render anything, it just flushes the data buffer to a new pass.
*/
void flushPass();
public:
std::vector<std::shared_ptr<IRenderPass>> getPasses(
struct RenderPassContext &ctx
) override;
/**
* Adds a quad to the canvas and performs a flush if necessary.
*
* @param quad The quad to add.
* @param uvs The UVs to use for the quad.
* @param color The color to use for the quad.
* @param style Style that the quad should be rendered in.
* @param texture The texture to use for the quad, can be null.
*/
void addQuad(
const glm::vec4 quad,
const glm::vec4 uvs,
const struct Color color,
const enum UIShaderQuadStyle style,
const std::shared_ptr<Texture> texture = nullptr
);
/**
* Adds a component to the canvas.
*
* @param component The component to add.
*/
void addElement(const std::shared_ptr<UIElement> component);
};
}

View File

@ -1,16 +0,0 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
UIAlignableElement.cpp
UISubAlignableElement.cpp
UIElement.cpp
UIMenu.cpp
)
# Subdirs
add_subdirectory(container)
add_subdirectory(elements)

View File

@ -1,247 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIAlignableElement.hpp"
using namespace Dawn;
UIAlignableElement::UIAlignableElement() {
alignUnit[0] = UIAlignmentUnit::SCALE;
alignUnit[1] = UIAlignmentUnit::SCALE;
alignUnit[2] = UIAlignmentUnit::SCALE;
alignUnit[3] = UIAlignmentUnit::SCALE;
eventAlignmentUpdated = [&](const glm::vec2 p, const glm::vec2 s) {
};
}
void UIAlignableElement::updateSelfAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
auto valueAxis = [&](
const enum UIAlignmentUnit unit,
const float_t alignment,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize
) {
if(alignment == UI_ALIGN_SIZE_AUTO) return contentSize;
switch(unit) {
case UIAlignmentUnit::PIXEL:
return alignment;
case UIAlignmentUnit::SCALE:
return canvasScale * alignment;
case UIAlignmentUnit::PERCENT:
return parentSize * (alignment / 100.0f);
case UIAlignmentUnit::RATIO:
return (alignment / 100.0f) * ratioSize;
default:
assertUnreachable("Invalid UIAlignmentType");
return 0.0f;
}
};
auto alignAxis = [&](
const enum UIAlignmentType type,
const enum UIAlignmentUnit unit0,
const enum UIAlignmentUnit unit1,
const float_t alignment0,
const float_t alignment1,
const float_t parentSize,
const float_t ratioSize,
const float_t contentSize,
float_t &outPosition,
float_t &outSize
) {
switch(type) {
case UIAlignmentType::START:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::MIDDLE:
outSize = valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
outPosition = (parentSize / 2.0f) - (contentSize / 2.0f) + valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::END:
outSize = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outPosition = parentSize - outSize - valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
);
break;
case UIAlignmentType::STRETCH:
outPosition = valueAxis(
unit0,
alignment0,
parentSize,
ratioSize,
contentSize
);
outSize = parentSize - (outPosition + valueAxis(
unit1,
alignment1,
parentSize,
ratioSize,
contentSize
));
break;
default:
assertUnreachable("Invalid UIAlignmentType");
}
};
bool_t heightFirst = (
alignUnit[0] == UIAlignmentUnit::RATIO ||
alignUnit[2] == UIAlignmentUnit::RATIO
);
if(heightFirst) {
// Align height first, this will define size.y which we can use as the ratio
// for the width/X axis alignment.
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
0,
this->getContentHeight(),
position.y,
size.y
);
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
size.y,
this->getContentWidth(),
position.x,
size.x
);
} else {
alignAxis(
alignX,
alignUnit[0],
alignUnit[2],
align[0],
align[2],
pSize.x,
0,
this->getContentWidth(),
position.x,
size.x
);
alignAxis(
alignY,
alignUnit[1],
alignUnit[3],
align[1],
align[3],
pSize.y,
size.x,
this->getContentHeight(),
position.y,
size.y
);
}
this->position += pPos;
this->eventAlignmentUpdated(position, size);
}
bool_t UIAlignableElement::hasExplicitWidth() {
if(size.x == 0.0f) return false;
if(
(alignX == UIAlignmentType::STRETCH) ||
(alignX == UIAlignmentType::END)
) {
return align[0] != UI_ALIGN_SIZE_AUTO;
}
return align[2] != UI_ALIGN_SIZE_AUTO;
}
bool_t UIAlignableElement::hasExplicitHeight() {
if(size.y == 0.0f) return false;
if(
(alignY == UIAlignmentType::STRETCH) ||
(alignY == UIAlignmentType::END)
) {
return align[1] != UI_ALIGN_SIZE_AUTO;
}
return align[3] != UI_ALIGN_SIZE_AUTO;
}
float_t UIAlignableElement::getWidth() {
if(hasExplicitWidth()) return size.x;
return getContentWidth();
}
float_t UIAlignableElement::getHeight() {
if(hasExplicitHeight()) return size.y;
return getContentHeight();
}
void UIAlignableElement::updateAlignment(
const glm::vec2 pPos,
const glm::vec2 pSize,
const float_t canvasScale
) {
this->updateSelfAlignment(pPos, pSize, canvasScale);
// Now update children alignment
auto children = getChildren();
for(auto &c : children) {
c->updateAlignment(this->position, this->size, canvasScale);
}
}

View File

@ -1,83 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIElement.hpp"
namespace Dawn {
#define UI_ALIGN_SIZE_AUTO -1.0f
enum class UIAlignmentType {
START,
MIDDLE,
END,
STRETCH
};
enum class UIAlignmentUnit {
PIXEL,
SCALE,
PERCENT,
RATIO
};
class UIAlignableElement : public UIElement {
protected:
glm::vec2 position;
glm::vec2 size;
/**
* Updates the alignment of this element ONLY.
*
* @param parentPosition The position of the parent.
* @param parentSize The size of the parent.
* @param canvasScale The scale of the canvas.
*/
virtual void updateSelfAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
);
/**
* Returns true only if the width of this component is explicitly set.
*
* @return True if the width of this component is explicitly set.
*/
bool_t hasExplicitWidth();
/**
* Returns true only if the height of this component is explicitly set.
*
* @return True if the height of this component is explicitly set.
*/
bool_t hasExplicitHeight();
public:
// Primary alignment controls
glm::vec4 align = glm::vec4(0, 0, 0, 0);
enum UIAlignmentType alignX = UIAlignmentType::STRETCH;
enum UIAlignmentType alignY = UIAlignmentType::STRETCH;
enum UIAlignmentUnit alignUnit[4];
std::function<
void(const glm::vec2, const glm::vec2)
> eventAlignmentUpdated;
/**
* Constructor for the UIAlignableElement.
*/
UIAlignableElement();
float_t getWidth() override;
float_t getHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -1,53 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIElement.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
std::vector<std::shared_ptr<UIElement>> UIElement::getChildren() {
return {};
}
void UIElement::getSelfQuads(UICanvas &ctx) {
//Do nothing
}
float_t UIElement::getContentWidth() {
return 0.0f;
}
float_t UIElement::getContentHeight() {
return 0.0f;
}
float_t UIElement::getWidth() {
return this->getContentWidth();
}
float_t UIElement::getHeight() {
return this->getContentHeight();
}
void UIElement::getQuads(UICanvas &ctx) {
this->getSelfQuads(ctx);
auto children = getChildren();
for(auto &c : children) {
c->getQuads(ctx);
}
}
void UIElement::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
auto children = getChildren();
for(auto &c : children) {
c->updateAlignment(parentPosition, parentSize, canvasScale);
}
}

View File

@ -1,80 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/UIShader.hpp"
#include "component/ui/UICanvas.hpp"
namespace Dawn {
class UIElement {
protected:
/**
* Virtual method overridden by the UIElement to get the quads for the
* component.
*
* @param alignment The alignment of this component.
* @param ctx The canvas to add the quads to.
*/
virtual void getSelfQuads(UICanvas &ctx);
public:
/**
* Overrided method by the UI Element that requests the minimum
* width of the content.
*
* @return The minimum width of the content.
*/
virtual float_t getContentWidth();
/**
* Overrided method by the UI Element that requests the minimum
* height of the content.
*
* @return The minimum height of the content.
*/
virtual float_t getContentHeight();
/**
* Returns the width of this component.
*
* @return The width of this component.
*/
virtual float_t getWidth();
/**
* Returns the height of this component.
*
* @return The height of this component.
*/
virtual float_t getHeight();
/**
* Virtual method overridden by the UIElement to get the children of
* this component.
*/
virtual std::vector<std::shared_ptr<UIElement>> getChildren();
/**
* Method called by the UICanvas to get the quads for this component.
*
* @param ctx The canvas to add the quads to.
*/
void getQuads(UICanvas &ctx);
/**
* Updates the alignment of this component based on the parent. Typically
* left to the UIAlignableElement to implement, default implementation
* does nothing but invoke children.
*
* @param parentPosition The position of the parent.
* @param parentSize The size of the parent.
*/
virtual void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
);
};
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIMenu.hpp"
using namespace Dawn;
void UIMenu::setPosition(int32_t x, int32_t y) {
assertTrue(x >= 0, "X position must be greater than or equal to 0.");
assertTrue(y >= 0, "Y position must be greater than or equal to 0.");
assertTrue(x < columns, "X must be less than the number of columns.");
assertTrue(y < rows, "Y must be less than the number of rows.");
if(this->x == x && this->y == y) return;
this->x = x;
this->y = y;
eventPositionChanged.emit(x, y);
}
void UIMenu::setSize(int32_t columns, int32_t rows) {
assertTrue(columns > 0, "Columns must be greater than 0.");
assertTrue(rows > 0, "Rows must be greater than 0.");
assertTrue(columns > x, "Columns must be greater than current x position.");
assertTrue(rows > y, "Rows must be greater than current y position.");
if(this->columns == columns && this->rows == rows) return;
this->columns = columns;
this->rows = rows;
}
int32_t UIMenu::getX() {
return x;
}
int32_t UIMenu::getY() {
return y;
}
int32_t UIMenu::getColumns() {
return columns;
}
int32_t UIMenu::getRows() {
return rows;
}

View File

@ -1,64 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIElement.hpp"
namespace Dawn {
class UIMenu final : public UIElement {
private:
int32_t x = 0;
int32_t y = 0;
int32_t columns = 1;
int32_t rows = 1;
public:
Event<int32_t, int32_t> eventPositionChanged;
/**
* Sets the position of this menu.
*
* @param x The x position of this menu.
* @param y The y position of this menu.
*/
void setPosition(int32_t x, int32_t y);
/**
* Sets the size of this menu.
*
* @param columns The number of columns in this menu.
* @param rows The number of rows in this menu.
*/
void setSize(int32_t columns, int32_t rows);
/**
* Gets the x position of this menu.
*
* @return The x position of this menu.
*/
int32_t getX();
/**
* Gets the y position of this menu.
*
* @return The y position of this menu.
*/
int32_t getY();
/**
* Gets the number of columns in this menu.
*
* @return The number of columns in this menu.
*/
int32_t getColumns();
/**
* Gets the number of rows in this menu.
*
* @return The number of rows in this menu.
*/
int32_t getRows();
};
}

View File

@ -1,68 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UISubAlignableElement.hpp"
using namespace Dawn;
void UISubAlignableElement::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
UIAlignableElement::updateAlignment(parentPosition, parentSize, canvasScale);
switch(this->subAlignX) {
case UISubAlignment::START:
this->subAlignedPosition.x = this->position.x;
break;
case UISubAlignment::MIDDLE:
this->subAlignedPosition.x = (
this->position.x +
(this->size.x / 2.0f) -
(this->getContentWidth() / 2.0f)
);
break;
case UISubAlignment::END:
this->subAlignedPosition.x = (
this->position.x +
this->size.x -
this->getContentWidth()
);
break;
default:
assertUnreachable("Unknown UISubAlignment!");
}
switch(this->subAlignY) {
case UISubAlignment::START:
this->subAlignedPosition.y = this->position.y;
break;
case UISubAlignment::MIDDLE:
this->subAlignedPosition.y = (
this->position.y +
(this->size.y / 2.0f) -
(this->getContentHeight() / 2.0f)
);
break;
case UISubAlignment::END:
this->subAlignedPosition.y = (
this->position.y +
this->size.y -
this->getContentHeight()
);
break;
default:
assertUnreachable("Unknown UISubAlignment!");
}
this->eventSubAlignmentUpdated.emit(this->subAlignedPosition);
}

View File

@ -1,32 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
enum class UISubAlignment {
START,
MIDDLE,
END
};
class UISubAlignableElement : public UIAlignableElement {
protected:
glm::vec2 subAlignedPosition;
public:
Event<glm::vec2> eventSubAlignmentUpdated;
enum UISubAlignment subAlignX = UISubAlignment::START;
enum UISubAlignment subAlignY = UISubAlignment::START;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -1,12 +0,0 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
UIColumnContainer.cpp
UIContainer.cpp
UIPaddingContainer.cpp
UIRowContainer.cpp
)

View File

@ -1,36 +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 "UIColumnContainer.hpp"
using namespace Dawn;
void UIColumnContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
this->updateSelfAlignment(parentPosition, parentSize, canvasScale);
// Now we have our dimensions, divide evenly
auto children = this->getChildren();
float_t x = 0.0f;
float_t xPiece = this->size.x / (float_t)children.size();
// Update all children
for(auto &child : children) {
child->updateAlignment(
this->position + glm::vec2(x, 0),
glm::vec2(
xPiece,
this->size.y
),
canvasScale
);
x += xPiece;
}
}

View File

@ -1,18 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIColumnContainer final : public UIContainer {
public:
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -1,47 +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 "UIContainer.hpp"
using namespace Dawn;
std::vector<std::shared_ptr<UIElement>> UIContainer::getChildren() {
return this->children;
}
float_t UIContainer::getContentWidth() {
float_t width = 0;
auto children = this->getChildren();
for(auto child : children) {
width = Math::max(width, child->getWidth());
}
return width;
}
float_t UIContainer::getContentHeight() {
float_t height = 0;
auto children = this->getChildren();
for(auto child : children) {
height = Math::max(height, child->getHeight());
}
return height;
}
void UIContainer::appendChild(std::shared_ptr<UIElement> child) {
assertNotNull(child, "Cannot append a null child!");
this->children.push_back(child);
}
void UIContainer::removeChild(std::shared_ptr<UIElement> child) {
assertNotNull(child, "Cannot remove a null child!");
auto it = std::find(this->children.begin(), this->children.end(), child);
if(it == this->children.end()) return;
this->children.erase(it);
}
void UIContainer::clearChildren() {
this->children.clear();
}

View File

@ -1,39 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
class UIContainer : public UIAlignableElement {
private:
std::vector<std::shared_ptr<UIElement>> children;
public:
std::vector<std::shared_ptr<UIElement>> getChildren() override;
float_t getContentWidth() override;
float_t getContentHeight() override;
/**
* Appends a child to this container.
*
* @param child Child to append.
*/
void appendChild(std::shared_ptr<UIElement> child);
/**
* Removes a child from this container.
*
* @param child Child to remove.
*/
void removeChild(std::shared_ptr<UIElement> child);
/**
* Removes all children from this container.
*/
void clearChildren();
};
}

View File

@ -1,38 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIPaddingContainer.hpp"
using namespace Dawn;
float_t UIPaddingContainer::getContentWidth() {
float_t width = 0.0f;
for(auto &child : getChildren()) {
width = Math::max(width, child->getWidth());
}
return width + padding.x + padding.z;
}
float_t UIPaddingContainer::getContentHeight() {
float_t height = 0.0f;
for(auto &child : getChildren()) {
height = Math::max(height, child->getHeight());
}
return height + padding.y + padding.w;
}
void UIPaddingContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
glm::vec2 childPosition = parentPosition + glm::vec2(padding.x, padding.y);
glm::vec2 childSize = parentSize - glm::vec2(padding.x + padding.z, padding.y + padding.w);
auto children = getChildren();
for(auto &child : children) {
child->updateAlignment(childPosition, childSize, canvasScale);
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIPaddingContainer final : public UIContainer {
public:
glm::vec4 padding = { 0, 0, 0, 0 };
float_t getContentWidth() override;
float_t getContentHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIRowContainer.hpp"
using namespace Dawn;
float_t UIRowContainer::getContentWidth() {
float_t width = 0.0f;
for(auto &child : this->getChildren()) {
width = Math::max(width, child->getWidth());
}
return width;
}
float_t UIRowContainer::getContentHeight() {
float_t height = 0.0f;
for(auto &child : this->getChildren()) {
height += child->getHeight();
}
return height;
}
void UIRowContainer::updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) {
this->updateSelfAlignment(parentPosition, parentSize, canvasScale);
// Now we have our dimensions, divide evenly
auto children = this->getChildren();
float_t y = 0.0f;
float_t yPiece = this->size.y / (float_t)children.size();
// Update all children
for(auto &child : children) {
child->updateAlignment(
this->position + glm::vec2(0, y),
glm::vec2(
this->size.x,
yPiece
),
canvasScale
);
y += yPiece;
}
}

View File

@ -1,20 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/container/UIContainer.hpp"
namespace Dawn {
class UIRowContainer final : public UIContainer {
public:
float_t getContentWidth() override;
float_t getContentHeight() override;
void updateAlignment(
const glm::vec2 parentPosition,
const glm::vec2 parentSize,
const float_t canvasScale
) override;
};
}

View File

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

View File

@ -1,175 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UILabel.hpp"
using namespace Dawn;
void UILabel::getSelfQuads(UICanvas &ctx) {
std::vector<struct UIShaderQuad> quads;
if(this->texture == nullptr || this->text.empty()) return;
glm::vec4 quad;
glm::vec2 pos = glm::vec2(0, this->texture->fontSize);
bool_t lastCharWasSpace = false;
for(size_t i = 0; i < text.size(); i++) {
wchar_t c = text[i];
auto info = texture->getCharacterData(c);
// Newline(s)
if(c == L'\n') {
pos.x = 0;
pos.y += this->texture->fontSize;
continue;
}
// Spaces
if(c == L' ') {
pos.x += info.advance.x;
lastCharWasSpace = true;
continue;
}
// Word Wrap
if(wordWrap) {
if(lastCharWasSpace) {
// Scan ahead to next space
float_t wordWidth = pos.x;// Start at current position and scan ahead.
for(size_t j = i; j < text.size(); j++) {
wchar_t c2 = text[j];
if(c2 == L' ' || c2 == L'\n') {
break;// If we hit another space, we are OK.
}
// Will this character fit on the row? If not the whole word will wrap.
auto info2 = texture->getCharacterData(c);
wordWidth += info.advance.x;
if(wordWidth > size.x) {
pos.x = 0;
pos.y += this->texture->fontSize;
break;
}
}
lastCharWasSpace = false;
}
// } else if(pos.x + info.size.x > subAlignedPosition.x + size.x) {
// // Not word wrap, but instead just overflow characters.
// pos.x = 0;
// pos.y += this->texture->fontSize;
}
ctx.addQuad(
{
subAlignedPosition.x + pos.x + info.offset.x,
subAlignedPosition.y + pos.y + info.offset.y,
subAlignedPosition.x + pos.x + info.size.x + info.offset.x,
subAlignedPosition.y + pos.y + info.size.y + info.offset.y
},
{
info.quad.x,
info.quad.y,
info.quad.z,
info.quad.w
},
this->color,
UIShaderQuadStyle::FONT,
texture->texture
);
pos += info.advance;
}
}
float_t UILabel::getContentWidth() {
if(this->texture == nullptr || this->text.empty()) return 0.0f;
float_t lineWidth = 0.0f;
float_t width = 0.0f;
for(wchar_t c : text) {
if(c == L'\n') {
width = Math::max<float_t>(width, lineWidth);
lineWidth = 0.0f;
continue;
}
auto info = texture->getCharacterData(c);
lineWidth += info.advance.x;
if(
this->hasExplicitWidth() &&
lineWidth >= size.x
) return size.x;
}
width = Math::max<float_t>(width, lineWidth);
return width;
}
float_t UILabel::getContentHeight() {
if(this->texture == nullptr || this->text.empty()) return 0.0f;
float_t height = this->texture->fontSize;
float_t lineWidth = 0.0f;
bool_t lastCharWasSpace = false;
for(wchar_t c : text) {
if(c == L'\n') {
height += this->texture->fontSize;
continue;
}
auto info = texture->getCharacterData(c);
if(c == L' ') {
lineWidth += info.advance.x;
lastCharWasSpace = true;
continue;
}
if(wordWrap) {
if(lastCharWasSpace) {
// Scan ahead to next space
float_t wordWidth = lineWidth;// Start at current position and scan ahead.
for(size_t j = 0; j < text.size(); j++) {
wchar_t c2 = text[j];
if(c2 == L' ' || c2 == L'\n') {
break;// If we hit another space, we are OK.
}
// Will this character fit on the row? If not the whole word will wrap.
auto info2 = texture->getCharacterData(c);
wordWidth += info.advance.x;
if(wordWidth > size.x) {
height += this->texture->fontSize;
lineWidth = 0.0f;
break;
}
}
lastCharWasSpace = false;
}
// } else if(lineWidth + info.size.x > size.x) {
// height += this->texture->fontSize;
// lineWidth = 0.0f;
}
}
return height;
}
std::shared_ptr<TrueTypeTexture> UILabel::getFont() {
return this->texture;
}
std::wstring UILabel::getText() {
return this->text;
}
void UILabel::setFont(std::shared_ptr<TrueTypeTexture> texture) {
this->texture = texture;
}
void UILabel::setText(const std::wstring &text) {
this->text = text;
}

View File

@ -1,54 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UISubAlignableElement.hpp"
#include "display/font/TrueTypeTexture.hpp"
namespace Dawn {
class UILabel final : public UISubAlignableElement {
private:
std::shared_ptr<TrueTypeTexture> texture = nullptr;
std::wstring text = L"Hello World";
protected:
void getSelfQuads(UICanvas &ctx) override;
public:
bool_t wordWrap = true;
struct Color color = COLOR_WHITE;
float_t getContentWidth() override;
float_t getContentHeight() override;
/**
* Returns the font used for this label.
*
* @return The font used for this label.
*/
std::shared_ptr<TrueTypeTexture> getFont();
/**
* Returns the text used for this label.
*
* @return The text used for this label.
*/
std::wstring getText();
/**
* Sets the font to use for this label.
*
* @param texture TrueType texture to use for this label.
*/
void setFont(std::shared_ptr<TrueTypeTexture> texture);
/**
* Sets the text to use for this label.
*
* @param text The text to use for this label.
*/
void setText(const std::wstring &text);
};
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIRectangle.hpp"
using namespace Dawn;
void UIRectangle::getSelfQuads(UICanvas &ctx) {
std::vector<struct UIShaderQuad> quads;
ctx.addQuad(
glm::vec4(position, position + size),
uv,
color,
UIShaderQuadStyle::TEXTURED,
texture
);
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "ui/UIAlignableElement.hpp"
namespace Dawn {
class UIRectangle final : public UIAlignableElement {
protected:
void getSelfQuads(UICanvas &ctx) override;
public:
struct Color color = COLOR_WHITE;
std::shared_ptr<Texture> texture = nullptr;
glm::vec4 uv = glm::vec4(0,0,1,1);
};
}

View File

@ -1,8 +0,0 @@
{
"name": "Test Map",
"layers": [
{
}
]
}

46
assets/maps/testmap.tmx Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="7">
<tileset firstgid="1" source="../tilemaps/tilemap.tsx"/>
<tileset firstgid="65" source="../tilemaps/entities.tsx"/>
<layer id="1" name="Map" width="30" height="20" locked="1">
<data encoding="csv">
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,6,6,6,6,6,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,6,6,6,6,6,2,2,2,2,2,3,3,3,3,2,2,2,2,
1,1,1,1,1,2,2,2,2,2,2,2,5,5,5,5,5,2,2,2,2,2,3,3,3,2,2,2,2,2,
1,1,1,1,1,2,2,2,2,2,2,2,5,5,5,5,5,2,2,2,2,2,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,5,5,1,5,5,2,2,2,2,3,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2
</data>
</layer>
<objectgroup id="2" name="Entities">
<object id="4" name="Player" type="player" gid="66" x="87.7275" y="119.497" width="8" height="8"/>
<object id="5" name="Sign" type="sign" gid="68" x="86.8498" y="55.0415" width="8" height="8">
<properties>
<property name="texts_0" value="maps.testmap.sign2.1"/>
<property name="texts_1" value="maps.testmap.sign2.2"/>
</properties>
</object>
<object id="6" name="Door" type="door" gid="69" x="111.791" y="55.7608" width="8" height="8">
<properties>
<property name="direction" type="int" value="2"/>
<property name="map" value="testmap2.map"/>
<property name="x" type="int" value="11"/>
<property name="y" type="int" value="2"/>
</properties>
</object>
</objectgroup>
</map>

17
assets/maps/testmap2.tmx Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="8" tileheight="8" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="../tilemaps/tilemap.tsx"/>
<tileset firstgid="67" source="../tilemaps/entities.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
2,2,2,2,2,
2,2,2,3,2,
2,2,3,3,2,
2,2,3,2,2,
2,3,3,2,2
</data>
</layer>
<objectgroup id="2" name="Entities">
<object id="4" name="Player" type="player" gid="68" x="6.54983" y="15.3437" width="8" height="8"/>
</objectgroup>
</map>

View File

@ -1,8 +0,0 @@
{
"assets": {
"simpleTexturedShader": {
"type": "shader",
"path": "shaders/simple-textured.shader"
}
}
}

View File

@ -1,26 +0,0 @@
{
"name": "Rosa",
"assets": {
"rosa": {
"type": "texture",
"path": "rosa.texture"
}
},
"components": {
"mesh": {
"type": "QuadMesh"
},
"material": {
"type": "SimpleTexturedMaterial",
"texture": "rosa"
},
"meshRenderer": {
"type": "MeshRenderer"
},
"entity": {
"type": "RPGEntity"
}
}
}

View File

@ -1,29 +0,0 @@
{
"name": "Rosa",
"assets": {
"rosa": {
"type": "texture",
"path": "rosa.texture"
}
},
"components": {
"mesh": {
"type": "QuadMesh"
},
"material": {
"type": "SimpleTexturedMaterial",
"texture": "rosa"
},
"meshRenderer": {
"type": "MeshRenderer"
},
"entity": {
"type": "RPGEntity"
},
"player": {
"type": "RPGPlayer"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,47 +0,0 @@
{
"name": "Test RPG Scene",
"assets": {
"rosa": {
"type": "prefab",
"path": "prefabs/rosa.json"
},
"npc": {
"type": "prefab",
"path": "prefabs/npc.json"
},
"rosatext": {
"type": "texture",
"path": "rosa.texture"
},
"simpleTexturedShader": {
"type": "shader",
"path": "shaders/simple-textured.slang"
}
},
"items": {
"camera": {
"components": {
"camera": {
"type": "camera"
}
}
},
"rosa": {
"prefab": "rosa",
"position": [ 0, 0, 0 ],
"components": {
"player": {
"camera": "camera"
}
}
},
"npc": {
"prefab": "npc",
"position": [ 32, 0, 0 ]
}
}
}

View File

@ -1,53 +0,0 @@
uniform float4x4 projection;
uniform float4x4 view;
uniform float4x4 model;
uniform float4 color;
uniform bool hasTexture;
uniform Sampler2D texture;
struct AssembledVertex {
float3 position : POSITION;
float2 texcoord : TEXCOORD;
};
struct Fragment {
float4 color;
};
struct VertexStageOutput {
float2 uv : UV;
float4 sv_position : SV_Position;
};
[shader("vertex")]
VertexStageOutput vertexMain(
AssembledVertex assembledVertex
) {
VertexStageOutput output;
float3 position = assembledVertex.position;
output.uv = assembledVertex.texcoord;
output.sv_position = mul(
float4(position, 1.0),
mul(model, mul(view, projection))
);
return output;
}
[shader("fragment")]
Fragment fragmentMain(
float2 uv: UV
) : SV_Target {
Fragment output;
if (hasTexture) {
output.color = texture.Sample(uv) * color;
} else {
output.color = color;
}
return output;
}

View File

@ -0,0 +1,14 @@
{
"automappingRulesFile": "",
"commands": [
],
"compatibilityVersion": 1100,
"extensionsPath": "extensions",
"folders": [
"."
],
"properties": [
],
"propertyTypes": [
]
}

View File

@ -0,0 +1,114 @@
{
"Map/SizeTest": {
"height": 4300,
"width": 2
},
"activeFile": "maps/testmap.tmx",
"expandedProjectPaths": [
".",
"maps"
],
"file.lastUsedOpenFilter": "All Files (*)",
"fileStates": {
"": {
"scaleInDock": 1
},
"entities.tsx": {
"scaleInDock": 1,
"scaleInEditor": 1
},
"maps/downtown.tmx": {
"scale": 4.9072,
"selectedLayer": 0,
"viewCenter": {
"x": 39.94131072709489,
"y": 40.0432018258885
}
},
"maps/testmap.tmx": {
"expandedObjectLayers": [
2
],
"scale": 3.404166666666667,
"selectedLayer": 1,
"viewCenter": {
"x": 95.17747858017135,
"y": 86.80538555691552
}
},
"maps/testmap2.tmx": {
"expandedObjectLayers": [
2
],
"scale": 5.0383,
"selectedLayer": 1,
"viewCenter": {
"x": 19.84796459123116,
"y": 19.947204414187325
}
},
"maps/train_station.tmx": {
"expandedObjectLayers": [
2
],
"scale": 2.7603,
"selectedLayer": 1,
"viewCenter": {
"x": 160.48980183313407,
"y": 120.4579212404449
}
},
"testmap.tmx": {
"scale": 3.23,
"selectedLayer": 1,
"viewCenter": {
"x": 122.60061919504646,
"y": 56.965944272445824
}
},
"testmap2.tmx": {
"scale": 3.281458333333333,
"selectedLayer": 0,
"viewCenter": {
"x": 119.91619579709226,
"y": 80.14729223541363
}
},
"tilemap.tsx": {
"scaleInDock": 1,
"scaleInEditor": 4
},
"tilemaps/entities.tsx": {
"scaleInDock": 2,
"scaleInEditor": 9.7785
},
"tilemaps/tilemap.tsx": {
"scaleInDock": 2
}
},
"last.externalTilesetPath": "/home/yourwishes/htdocs/Dawn/assets",
"last.imagePath": "/home/yourwishes/htdocs/Dawn/assets",
"map.height": 10,
"map.lastUsedFormat": "tmx",
"map.tileHeight": 8,
"map.tileWidth": 8,
"map.width": 10,
"openFiles": [
"maps/testmap.tmx"
],
"project": "tiled_project.tiled-project",
"property.type": "string",
"recentFiles": [
"maps/testmap.tmx",
"maps/downtown.tmx",
"maps/testmap2.tmx",
"maps/train_station.tmx",
"tilemaps/entities.tsx"
],
"tileset.lastUsedFilter": "All Files (*)",
"tileset.lastUsedFormat": "tsx",
"tileset.tileSize": {
"height": 8,
"width": 8
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="entities" tilewidth="8" tileheight="8" tilecount="64" columns="8">
<image source="entities.png" width="64" height="64"/>
<tile id="1" type="player"/>
<tile id="2" type="npc"/>
<tile id="3" type="sign"/>
<tile id="4" type="door"/>
</tileset>

BIN
assets/tilemaps/tilemap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tilemap" tilewidth="8" tileheight="8" tilecount="64" columns="8">
<image source="tilemap.png" width="64" height="64"/>
</tileset>

234
gentileset.py Normal file
View File

@ -0,0 +1,234 @@
# font is a 2D array of 8x8 pixel characters where each bit is a pixel on the
# row.
font8x8_basic = [
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0000 (nul)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0001
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0002
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0003
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0004
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0005
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0006
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0007
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0008
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0009
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0010
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0011
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0012
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0013
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0014
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0015
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0016
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0017
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0018
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0019
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0020 (space)
[0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00], # U+0021 (!)
[0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0022 (")
[0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00], # U+0023 (#)
[0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00], # U+0024 ($)
[0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00], # U+0025 (%)
[0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00], # U+0026 (&)
[0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0027 (')
[0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00], # U+0028 (()
[0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00], # U+0029 ())
[0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00], # U+002A (*)
[0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00], # U+002B (+)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06], # U+002C (,)
[0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00], # U+002D (-)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00], # U+002E (.)
[0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00], # U+002F (/)
[0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00], # U+0030 (0)
[0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00], # U+0031 (1)
[0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00], # U+0032 (2)
[0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00], # U+0033 (3)
[0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00], # U+0034 (4)
[0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00], # U+0035 (5)
[0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00], # U+0036 (6)
[0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00], # U+0037 (7)
[0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00], # U+0038 (8)
[0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00], # U+0039 (9)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00], # U+003A (:)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06], # U+003B (;)
[0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00], # U+003C (<)
[0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00], # U+003D (=)
[0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00], # U+003E (>)
[0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00], # U+003F (?)
[0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00], # U+0040 (@)
[0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00], # U+0041 (A)
[0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00], # U+0042 (B)
[0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00], # U+0043 (C)
[0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00], # U+0044 (D)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00], # U+0045 (E)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00], # U+0046 (F)
[0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00], # U+0047 (G)
[0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00], # U+0048 (H)
[0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+0049 (I)
[0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00], # U+004A (J)
[0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00], # U+004B (K)
[0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00], # U+004C (L)
[0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00], # U+004D (M)
[0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00], # U+004E (N)
[0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00], # U+004F (O)
[0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00], # U+0050 (P)
[0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00], # U+0051 (Q)
[0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00], # U+0052 (R)
[0x1E, 0x33, 0x07, 0x1E, 0x38, 0x33, 0x1E, 0x00], # U+0053 (S)
[0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00], # U+0054 (T)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00], # U+0055 (U)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], # U+0056 (V)
[0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00], # U+0057 (W)
[0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00], # U+0058 (X)
[0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x0C, 0x00], # U+0059 (Y)
[0x3F, 0x33, 0x19, 0x0C, 0x26, 0x33, 0x3F, 0x00], # U+005A (Z)
[0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+005B ([)
[0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00], # U+005C (\)
[0x1E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x1E, 0x00], # U+005D (])
[0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00], # U+005E (^)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF], # U+005F (_)
[0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0060 (`)
[0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00], # U+0061 (a)
[0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00], # U+0062 (b)
[0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00], # U+0063 (c)
[0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00], # U+0064 (d)
[0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00], # U+0065 (e)
[0x1C, 0x36, 0x06, 0x0F, 0x06, 0x06, 0x0F, 0x00], # U+0066 (f)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1E], # U+0067 (g)
[0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00], # U+0068 (h)
[0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+0069 (i)
[0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E], # U+006A (j)
[0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00], # U+006B (k)
[0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+006C (l)
[0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00], # U+006D (m)
[0x00, 0x00, 0x1B, 0x37, 0x33, 0x33, 0x33, 0x00], # U+006E (n)
[0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00], # U+006F (o)
[0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F], # U+0070 (p)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78], # U+0071 (q)
[0x00, 0x00, 0x1B, 0x36, 0x36, 0x06, 0x0F, 0x00], # U+0072 (r)
[0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00], # U+0073 (s)
[0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00], # U+0074 (t)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00], # U+0075 (u)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], # U+0076 (v)
[0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00], # U+0077 (w)
[0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00], # U+0078 (x)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1E], # U+0079 (y)
[0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00], # U+007A (z)
[0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00], # U+007B ({)
[0x0C, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x00], # U+007C (|)
[0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00], # U+007D (})
[0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+007E (~)
]
# COLOR4F(0.0f, 0.0f, 0.0f, 1.0f), # Black
# COLOR4F(1.0f, 1.0f, 1.0f, 1.0f), # White
# COLOR4F(0.8f, 0.0f, 0.0f, 1.0f), # Red
# COLOR4F(0.0f, 0.5f, 0.0f, 1.0f), # Green
# COLOR4F(0.0f, 0.0f, 0.8f, 1.0f), # Blue
# COLOR4F(0.8f, 0.8f, 0.0f, 1.0f), # Yellow
# COLOR4F(0.8f, 0.0f, 0.8f, 1.0f), # Magenta
# COLOR4F(0.0f, 0.8f, 0.8f, 1.0f), # Cyan
# COLOR4F(0.5f, 0.5f, 0.5f, 1.0f), # Gray
# COLOR4F(0.5f, 0.25f, 0.0f, 1.0f) # Brown
# Tilemap
COLORS = {
"BLACK": [ 0, 0, 0 ],
"WHITE": [ 255, 255, 255 ],
"RED": [ 204, 0, 0 ],
"GREEN": [ 0, 128, 0 ],
"BLUE": [ 0, 0, 204 ],
"YELLOW": [ 204, 204, 0 ],
"MAGENTA": [ 204, 0, 204 ],
"CYAN": [ 0, 204, 204 ],
"GRAY": [ 128, 128, 128 ],
"BROWN": [ 128, 64, 0 ]
}
TILES = {
# NAME: [ id, symbol, color ]
"NULL": [ 0, 'N', COLORS["RED"] ],
"GRASS": [ 1, '#', COLORS["GREEN"] ],
"WATER": [ 2, '\\', COLORS["BLUE"] ],
# "DOOR": [ 3, 'D', COLORS["BROWN"] ],
"BUILDING_WALL": [ 4, '-', COLORS["GRAY"] ],
"ROOF": [ 5, '/', COLORS["BROWN"] ],
"WALKABLE_NULL": [ 6, ' ', COLORS["BLACK"] ],
"COBBLESTONE": [ 7, '#', COLORS["GRAY"] ],
"STAIRS": [ 8, '=', COLORS["GRAY"] ],
"RAILING": [ 9, 'n', COLORS["BROWN"] ],
"COLUMN": [ 10, 'I', COLORS["WHITE"] ],
"RAIL_TRACK": [ 11, '|', COLORS["GRAY"] ],
"RAIL_SLEEPER": [ 12, '-', COLORS["BROWN"] ],
"CARPET": [ 13, '#', COLORS["RED"] ],
"LAMP": [ 14, 'i', COLORS["YELLOW"] ],
}
ENTITIES = {
"NULL": [ 0, 'N', COLORS["RED"] ],
"PLAYER": [ 1, 'v', COLORS["RED"] ],
"NPC": [ 2, 'V', COLORS["RED"] ],
"SIGN": [ 3, '+', COLORS["YELLOW"] ],
"DOOR": [ 4, 'D', COLORS["BROWN"] ],
}
# Create 64 x 64 RGB pixel buffer.
import png
WIDTH = 64
HEIGHT = 64
def genTileset(filename, tileset, background):
# Create 64x64 pixel buffer with black
PIXEL_BUFFER = []
for y in range(HEIGHT):
row = []
for x in range(WIDTH):
row.append(background)
PIXEL_BUFFER.append(row)
# For each TILES
for tile in tileset:
# Get the tile data
tile_data = tileset[tile]
tile_id = tile_data[0]
tile_char = tile_data[1]
tile_color = tile_data[2]
# Get char pixels
char_pixels = font8x8_basic[ord(tile_char)]
tile_color_rgba = [ tile_color[0], tile_color[1], tile_color[2], 255 ]
# Write char pixels to output buffer, using tile_id to determine pixels with
# each row holding 8 characters of 8 pixels
for y in range(8):
row = char_pixels[y]
for x in range(8):
if row & (1 << x):
PIXEL_BUFFER[(tile_id // 8) * 8 + y][(tile_id % 8) * 8 + x] = tile_color_rgba
# Convert from [ [ [ r, g, b ], [ r, g, b] ], [ [ r, g, b ], [ r, g, b ] ] ] to
# [ [R, G, B, A, R, G, B, A] ] (Flatten level 2 and add alpha channel)
FLATTENED_PIXEL_BUFFER = [ [ 0 for i in range(WIDTH * 4) ] for j in range(HEIGHT) ]
for y in range(HEIGHT):
for x in range(WIDTH):
FLATTENED_PIXEL_BUFFER[y][x * 4 + 0] = PIXEL_BUFFER[y][x][0]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 1] = PIXEL_BUFFER[y][x][1]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 2] = PIXEL_BUFFER[y][x][2]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 3] = PIXEL_BUFFER[y][x][3]
# Now write PIXEL_BUFFER to png
png.from_array(FLATTENED_PIXEL_BUFFER, 'RGBA').save(filename)
genTileset("./assets/tilemaps/tilemap.png", TILES, [ 0, 0, 0, 255 ])
genTileset("./assets/tilemaps/entities.png", ENTITIES, [ 0, 0, 0, 100 ])

View File

@ -1,74 +1,31 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
include(FetchContent)
# GLFW
FetchContent_Declare(glfw URL https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip)
FetchContent_MakeAvailable(glfw)
add_subdirectory(glad)
# GLM
FetchContent_Declare(
glm
GIT_REPOSITORY https://github.com/g-truc/glm
GIT_TAG 0af55ccecd98d4e5a8d1fad7de25ba429d60e863
)
FetchContent_MakeAvailable(glm)
# FreeType
FetchContent_Declare(
freetype
GIT_REPOSITORY https://gitlab.freedesktop.org/freetype/freetype
GIT_TAG VER-2-13-3
)
FetchContent_MakeAvailable(freetype)
#LibArchive
FetchContent_Declare(
libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive
GIT_TAG v3.7.6
)
FetchContent_MakeAvailable(libarchive)
# JSON
FetchContent_Declare(
json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz
)
FetchContent_MakeAvailable(json)
# JOLT Physics
if(DAWN_ENABLE_PHYSICS)
FetchContent_Declare(
JoltPhysics
GIT_REPOSITORY "https://github.com/jrouwe/JoltPhysics"
GIT_TAG "v5.2.0"
SOURCE_SUBDIR "Build"
)
FetchContent_MakeAvailable(JoltPhysics)
endif()
# SLANG
set(SLANG_ENABLE_GFX ON CACHE BOOL "Enable GFX" FORCE)
FetchContent_Declare(
slang
GIT_REPOSITORY https://github.com/shader-slang/slang
GIT_TAG v2024.17
)
FetchContent_MakeAvailable(slang)
# OpenAL
# if(DAWN_TARGET_OPENAL)
# set(LIBTYPE "STATIC")
# add_subdirectory(openal-soft)
# set(BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
# set(BUILD_EXAMPLES OFF CACHE BOOL "Build examples" FORCE)
# add_subdirectory(AudioFile)
# endif()
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
include(FetchContent)
add_library(font8x8 INTERFACE)
target_include_directories(font8x8 INTERFACE font8x8)
add_subdirectory(glad)
# GLFW
FetchContent_Declare(glfw URL https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip)
FetchContent_MakeAvailable(glfw)
# GLM
FetchContent_Declare(
cglm
GIT_REPOSITORY https://github.com/recp/cglm
GIT_TAG 1796cc5ce298235b615dc7a4750b8c3ba56a05dd
)
FetchContent_MakeAvailable(cglm)
#LibArchive
FetchContent_Declare(
libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive
GIT_TAG v3.7.6
)
FetchContent_MakeAvailable(libarchive)

1
lib/font8x8 Submodule

Submodule lib/font8x8 added at 8e279d2d86

View File

@ -153,20 +153,6 @@ typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
@ -249,21 +235,14 @@ typedef unsigned short int khronos_uint16_t;
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
#ifdef _WIN64
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +1,22 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Build Project
add_executable(${DAWN_TARGET_NAME})
# Validate game project includes the target name
if(NOT DEFINED DAWN_TARGET_NAME)
message(FATAL_ERROR "You need to define a target name")
endif()
# Add in base library
add_subdirectory(dawn)
add_subdirectory(dawnrpg)
if(DAWN_ENABLE_PHYSICS)
add_subdirectory(dawnphysics)
endif()
# Host Libraries
target_link_libraries(${DAWN_TARGET_NAME}
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)
# Compile support targets
add_subdirectory(dawnglfw)
add_subdirectory(dawnopengl)
add_subdirectory(dawnlinux)
# Compress the game assets.
add_dependencies(${DAWN_TARGET_NAME} dawnassets)
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Build Project
add_executable(${DAWN_TARGET_NAME})
# Add base
add_subdirectory(dawn)
# Compile entries
if(DAWN_TARGET STREQUAL "linux-x64-terminal")
add_subdirectory(dawnlinux)
add_subdirectory(dawntermlinux)
elseif(DAWN_TARGET STREQUAL "linux-x64-glfw")
add_subdirectory(dawnlinux)
add_subdirectory(dawnglfw)
add_subdirectory(dawnopengl)
else()
message(FATAL_ERROR "Unknown target: ${DAWN_TARGET}")
endif()

View File

@ -1,48 +1,39 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Libraries
target_link_libraries(${DAWN_TARGET_NAME}
PUBLIC
archive_static
glm::glm
nlohmann_json::nlohmann_json
freetype
slang
)
# Includes
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
# Definitions
target_compile_definitions(${DAWN_TARGET_NAME}
PUBLIC
DAWN_DEBUG_SHADERS=$<BOOL:${DAWN_DEBUG_SHADERS}>
)
# Subdirs
add_subdirectory(assert)
add_subdirectory(asset)
add_subdirectory(audio)
add_subdirectory(component)
add_subdirectory(display)
add_subdirectory(environment)
add_subdirectory(game)
add_subdirectory(locale)
add_subdirectory(save)
add_subdirectory(scene)
add_subdirectory(settings)
add_subdirectory(time)
add_subdirectory(util)
# Assets
tool_copy(en en.json)
tool_copy(simpleTexturedShader shaders/simple-textured.slang)
add_dependencies(${DAWN_TARGET_NAME} dawnassets)
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Libraries
target_link_libraries(${DAWN_TARGET_NAME}
PUBLIC
archive_static
)
# Includes
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
# Subdirs
add_subdirectory(assert)
add_subdirectory(asset)
add_subdirectory(display)
add_subdirectory(game)
add_subdirectory(rpg)
add_subdirectory(ui)
add_subdirectory(locale)
add_subdirectory(util)
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
input.c
)
# Assets
tool_map(testmap maps/testmap.tmx)
tool_map(testmap2 maps/testmap2.tmx)
tool_copy(en en.json)
add_dependencies(${DAWN_TARGET_NAME} dawnassets)

View File

@ -1,9 +1,12 @@
# Copyright (c) 2022 Dominic Masters
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
assert.cpp
assert.c
)

View File

@ -5,7 +5,8 @@
* https://opensource.org/licenses/MIT
*/
#include "assert.hpp"
#include "assert.h"
#include <stdarg.h>
void assertTrueImplement(
const char *file,
@ -26,10 +27,11 @@ void assertTrueImplement(
func
);
va_list argptr;
va_start(argptr, message);
vfprintf(stderr, message, argptr);
va_end(argptr);
// Print message.
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fprintf(stderr, "\n");
throw std::runtime_error("Assert failed.");
abort();
}

View File

@ -6,7 +6,7 @@
*/
#pragma once
#include "util/Flag.hpp"
#include "dawn.h"
/**
* Asserts that a given statement must evaluate to true or the assertion fails
@ -63,7 +63,7 @@ void assertTrueImplement(
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertNotNull(x, ...) assertTrue(x != nullptr, __VA_ARGS__)
#define assertNotNull(x, ...) assertTrue(x != NULL, __VA_ARGS__)
/**
* Asserts that a given pointer is null.
@ -71,29 +71,7 @@ void assertTrueImplement(
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertNull(x, ...) assertTrue(x == nullptr, __VA_ARGS__)
/**
* Asserts that a given map has a specific key.
* @param map Map to check.
* @param key Key to check for.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertMapHasKey(map, key, ...) assertTrue( \
map.find(key) != map.end(), __VA_ARGS__ \
)
/**
* Asserts that a given map does not have a specific key.
* @param map Map to check.
* @param key Key to check for.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertMapNotHasKey(map, key, ...) assertTrue( \
map.find(key) == map.end(), __VA_ARGS__ \
)
#define assertNull(x, ...) assertTrue(x == NULL, __VA_ARGS__)
/**
* Asserts that a given value has a specific flag turned off.
@ -104,7 +82,7 @@ void assertTrueImplement(
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertFlagOff(value, flag, ...) assertTrue( \
Flag::isOff(value, flag), __VA_ARGS__ \
(value & flag) == 0, __VA_ARGS__ \
)
/**
@ -116,7 +94,20 @@ void assertTrueImplement(
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertFlagOn(value, flag, ...) assertTrue( \
Flag::isOn(value, flag), __VA_ARGS__ \
(value & flag) == flag, __VA_ARGS__ \
)
/**
* Asserts that the given string is not null, and has a length that is less
* the maximum buffer size, including the NULL terminator.
*
* @param str String to check.
* @param bufferSize Maximum buffer size.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertStringValid(str, bufferSize, ...) assertTrue( \
((str != NULL) && ((strlen(str)+1) < bufferSize)), __VA_ARGS__ \
)
/**

View File

@ -1,230 +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(const std::string &fileName) :
fileName(fileName)
{
assertTrue(
fileName.size() > 0,
"IAssetDataLoader::IAssetDataLoader: fileName must be greater than 0"
);
}
size_t AssetDataLoader::getSize() {
assertTrue(this->assetArchiveEntry != nullptr, "Entry is NULL!");
assertTrue(
archive_entry_size_is_set(assetArchiveEntry),
"Entry size is not set!"
);
return archive_entry_size(assetArchiveEntry);
}
size_t AssetDataLoader::getPosition() {
assertNotNull(this->assetArchiveFile, "File is not open!");
return this->position;
}
std::string AssetDataLoader::getEntireContentsAsString() {
if(!this->isOpen()) {
this->open();
} else {
this->rewind();
}
std::string buffer;
buffer.resize(this->getSize());
this->read((uint8_t*)buffer.data(), buffer.size());
this->close();
return buffer;
}
bool_t AssetDataLoader::isOpen() {
return this->assetArchive != nullptr;
}
void AssetDataLoader::open() {
assertNull(this->assetArchiveFile, "File is already open");
assertNull(this->assetArchive, "Archive is already open");
assertNull(this->assetArchiveEntry, "Entry is already open");
this->assetArchiveFile = this->openAssetArchiveFile();
assertNotNull(this->assetArchiveFile, "Failed to open archive file!");
// Open archive reader
assetArchive = archive_read_new();
assertNotNull(assetArchive, "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, "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, "Failed to skip data!");
}
assertUnreachable("Failed to find file!");
}
int32_t AssetDataLoader::close() {
assertNotNull(this->assetArchiveFile, "File is NULL");
assertNotNull(this->assetArchive, "Archive is NULL!");
assertNotNull(this->assetArchiveEntry, "Entry is NULL!");
// Close the archive
int32_t ret = archive_read_free(this->assetArchive);
assertTrue(ret == ARCHIVE_OK, "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, const size_t &size) {
assertNotNull(buffer, "Buffer is NULL!");
assertTrue(size > 0, "Size must be greater than 0!");
assertNotNull(this->assetArchive, "Archive is NULL!");
assertNotNull(this->assetArchiveEntry, "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, "Failed to read data (RETRY)!");
assertTrue(read != ARCHIVE_WARN, "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::skip(const size_t &n) {
assertTrue(n >= 0, "Byte count must be greater than 0.");
assertTrue(n < (this->getSize() - this->position), "Cannot skip past EOF!");
uint8_t dumpBuffer[ASSET_LOADER_BUFFER_SIZE];
size_t skipped = 0;
size_t n2, n3, n4;
n4 = n;
while(n4 != 0) {
n2 = Math::min<size_t>(n4, ASSET_LOADER_BUFFER_SIZE);
n3 = this->read(dumpBuffer, n2);
assertTrue(n3 == n2, "Failed to skip bytes!");
n4 -= 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() {
assertTrue(this->isOpen(), "Asset is not open!");
if(this->position == 0) return;
// TODO: See if I can optimize this
this->close();
this->open();
}
AssetDataLoader::~AssetDataLoader() {
if(this->assetArchiveFile != nullptr) this->close();
}

View File

@ -1,180 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.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(const std::string &filename);
/**
* Get the size of the asset.
* @return The size of the asset in bytes.
*/
size_t getSize();
/**
* Returns the current position of the read head.
*
* @return The current read head position.
*/
size_t getPosition();
/**
* Get the entire contents of the asset as a string.
*
* @return The entire contents of the asset as a string.
*/
std::string getEntireContentsAsString();
/**
* Check if the asset is open.
*
* @return True if the asset is open, otherwise false.
*/
bool_t isOpen();
/**
* 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, const 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
);
/**
* 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(const 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);
/**
* Cleanup the asset loader.
*/
virtual ~AssetDataLoader();
};
}

View File

@ -1,42 +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"
#include "asset/AssetManager.hpp"
using namespace Dawn;
const std::string AssetLoader::ASSET_TYPE = "unknown";
AssetLoader::AssetLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
assetManager(assetManager),
name(name)
{
assertNotNull(assetManager, "AssetManager cannot be null");
assertTrue(name.size() > 0, "Name cannot be empty");
std::cout << "Loading: " << name << std::endl;
}
std::shared_ptr<AssetManager> AssetLoader::getAssetManager() {
auto am = this->assetManager.lock();
assertNotNull(am, "AssetManager is null");
return am;
}
void AssetLoader::loadImmediately() {
while(!this->loaded) {
this->getAssetManager()->update();
}
}
AssetLoader::~AssetLoader() {
this->loaded = false;
std::cout << "Unloading: " << name << std::endl;
}

View File

@ -1,71 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class AssetManager;
class AssetLoader {
private:
std::weak_ptr<AssetManager> assetManager;
public:
std::string typetest;
const static std::string ASSET_TYPE;
const std::string name;
bool_t loaded = false;
/**
* Create an abstract Asset object.
*
* @param name Name of the asset.
*/
AssetLoader(
const std::shared_ptr<AssetManager> assetManager,
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;
/**
* Returns the asset type.
*
* @return The asset type.
*/
virtual std::string getAssetType() const = 0;
/**
* Returns the asset manager.
*
* @return The asset manager.
*/
std::shared_ptr<AssetManager> getAssetManager();
/**
* Load the asset immediately, this is blocking on the main thread.
*/
void loadImmediately();
/**
* Dispose the asset item.
*/
virtual ~AssetLoader();
};
}

View File

@ -1,77 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "AssetManager.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
void AssetManager::init(const std::shared_ptr<Game> &game) {
assertNotNull(game, "Game is NULL?");
this->game = game;
}
void AssetManager::update() {
auto copyPendingAssets = pendingAssetLoaders;
auto itPending = copyPendingAssets.begin();
while(itPending != copyPendingAssets.end()) {
auto loader = *itPending;
loader->updateSync();
loader->updateAsync();
loader->updateSync();
if(!loader->loaded) {
++itPending;
continue;
}
finishedAssetLoaders.push_back(loader);
auto it = std::find(
pendingAssetLoaders.begin(),
pendingAssetLoaders.end(),
loader
);
assertTrue(it != pendingAssetLoaders.end(), "Loader not found?");
pendingAssetLoaders.erase(it);
++itPending;
}
}
void AssetManager::remove(const std::shared_ptr<AssetLoader> loader) {
for(
auto it = pendingAssetLoaders.begin();
it != pendingAssetLoaders.end();
it++
) {
if(*it != loader) continue;
pendingAssetLoaders.erase(it);
return;
}
for(
auto it = finishedAssetLoaders.begin();
it != finishedAssetLoaders.end();
it++
) {
if(it->lock() != loader) continue;
finishedAssetLoaders.erase(it);
return;
}
}
bool_t AssetManager::isEverythingLoaded() {
return pendingAssetLoaders.size() == 0;
}
std::shared_ptr<Game> AssetManager::getGame() {
auto g = game.lock();
assertNotNull(g, "Game is NULL?");
return g;
}
AssetManager::~AssetManager() {
}

View File

@ -1,114 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
#include "asset/AssetLoader.hpp"
namespace Dawn {
class Game;
class AssetManager final : public std::enable_shared_from_this<AssetManager> {
private:
std::weak_ptr<Game> game;
std::vector<std::shared_ptr<AssetLoader>> pendingAssetLoaders;
std::vector<std::weak_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) {
for(auto &loader : pendingAssetLoaders) {
if(loader->name != filename) continue;
if(loader->getAssetType() != T::ASSET_TYPE) continue;
return std::static_pointer_cast<T>(loader);
}
for(auto &wLoader : finishedAssetLoaders) {
auto loader = wLoader.lock();
if(!loader) continue;
if(loader->name != filename) continue;
if(loader->getAssetType() != T::ASSET_TYPE) continue;
return std::static_pointer_cast<T>(loader);
}
return nullptr;
}
/**
* 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.
*
* @param game Game context that this asset manager is attached to.
*/
void init(const std::shared_ptr<Game> &game);
/**
* 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 the asset loader for the given asset.
*
* @param filename The filename of the asset to get.
* @return The asset loader for the given asset.
*/
template<class T>
std::shared_ptr<T> get(const std::string &filename) {
auto existing = this->getExisting<T>(filename);
if(existing) return existing;
std::shared_ptr<T> loader = std::make_shared<T>(
shared_from_this(),
filename
);
pendingAssetLoaders.push_back(
std::static_pointer_cast<AssetLoader>(loader)
);
return loader;
}
/**
* Returns the game context that this asset manager is attached to.
*
* @return The game context.
*/
std::shared_ptr<Game> getGame();
/**
* Removes the given asset loader from the asset manager, assumes that
* nothing else needs to access it and any dangling shared_ptrs will have
* to remain in memory.
*
* @param loader The asset loader to remove.
*/
void remove(const std::shared_ptr<AssetLoader> loader);
/**
* Dispose the asset manager, and all attached assets.
*/
~AssetManager();
};
}

View File

@ -1,15 +1,14 @@
# Copyright (c) 2022 Dominic Msters
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# https:#opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
AssetLoader.cpp
AssetDataLoader.cpp
AssetManager.cpp
)
# Subdirs
add_subdirectory(loader)
asset.c
assetarchive.c
assetjson.c
assetmap.c
assetlanguage.c
)

159
src/dawn/asset/asset.c Normal file
View File

@ -0,0 +1,159 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
#include "assetarchive.h"
#include "assert/assert.h"
#include "util/math.h"
void assetInit() {
// TODO: Works on Windows? path sep probs wrong.
// const char_t *assetFilename = "dawn.tar";
// char_t *assetPath = malloc(sizeof(char_t) * (
// strlen(SYSTEM.executableDirectory) + strlen(assetFilename) + 1
// ));
// sprintf(assetPath, "%s/%s", SYSTEM.executableDirectory, assetFilename);
char_t *assetPath = "/home/yourwishes/htdocs/Dawn/build/dawn.tar";
ASSET_FILE = fopen(assetPath, "rb");
// free(assetPath);
assertNotNull(ASSET_FILE, "assetInit: Failed to open asset file!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
size_t assetReadUntil(uint8_t *buffer, const char_t c, const size_t maxLength) {
if(buffer == NULL) {
assertTrue(
maxLength == -1, "If no buffer is provided, maxLength must be -1."
);
uint8_t tBuffer[1];
size_t read = 0;
while(assetRead(tBuffer, 1) == 1 && (char_t)tBuffer[0] != c) read++;
return read;
} else {
size_t read = 0;
while(read < maxLength) {
// TODO: Read more than 1 char at a time.
read += assetRead(buffer + read, 1);
if((char_t)buffer[read-1] == c) return read - 1;
}
return -1;
}
}
void assetOpen(const char_t *path) {
assertNull(ASSET_ARCHIVE, "assetOpenFile: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetOpenFile: Entry is not NULL!");
assertStringValid(path, 1024, "assetOpenFile: Path is not valid!");
// Store path
strcpy(ASSET_PATH_CURRENT, path);
// Prepare data
ASSET_ARCHIVE = archive_read_new();
assertNotNull(ASSET_ARCHIVE, "assetOpenFile: Failed to create archive!");
// Set up the reader
// archive_read_support_filter_bzip2(ASSET_ARCHIVE);
archive_read_support_format_tar(ASSET_ARCHIVE);
// Open reader
archive_read_set_open_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_read_callback(ASSET_ARCHIVE, &assetArchiveRead);
archive_read_set_seek_callback(ASSET_ARCHIVE, &assetArchiveSeek);
archive_read_set_close_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_callback_data(ASSET_ARCHIVE, ASSET_ARCHIVE_BUFFER);
int32_t ret = archive_read_open1(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to open archive!");
// Iterate over each file.
while(archive_read_next_header(ASSET_ARCHIVE, &ASSET_ENTRY) == ARCHIVE_OK) {
const char_t *headerFile = (char_t*)archive_entry_pathname(ASSET_ENTRY);
if(strcmp(headerFile, ASSET_PATH_CURRENT) == 0) return;
int32_t ret = archive_read_data_skip(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to skip data!");
}
assertUnreachable("assetOpenFile: Failed to find file!");
}
size_t assetGetSize() {
assertNotNull(ASSET_ARCHIVE, "assetGetSize: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetGetSize: Entry is NULL!");
assertTrue(
archive_entry_size_is_set(ASSET_ENTRY),
"assetGetSize: Entry size is not set!"
);
size_t n = archive_entry_size(ASSET_ENTRY);
// Remnant when get size was doing some incorrect stuff.
// char_t path[2048];
// sprintf(
// path, "/home/yourwishes/htdocs/dusk/build/assets/%s", ASSET_PATH_CURRENT
// );
// FILE *temp = fopen(path, "rb");
// assertNotNull(temp, "assetGetSize: Failed to open temp file!");
// fseek(temp, 0, SEEK_END);
// size_t size = ftell(temp);
// assertTrue(size == n, "assetGetSize: Size is not equal!");
// fclose(temp);
return n;
}
size_t assetRead(uint8_t *buffer, size_t bufferSize) {
assertNotNull(ASSET_ARCHIVE, "assetRead: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetRead: Entry is NULL!");
assertNotNull(buffer, "assetRead: Buffer is NULL!");
assertTrue(bufferSize > 0, "assetRead: Buffer size must be greater than 0!");
ssize_t read = archive_read_data(ASSET_ARCHIVE, buffer, bufferSize);
if(read == ARCHIVE_FATAL) {
assertUnreachable(archive_error_string(ASSET_ARCHIVE));
}
assertTrue(read != ARCHIVE_RETRY, "assetRead: Failed to read data (RETRY)!");
assertTrue(read != ARCHIVE_WARN, "assetRead: Failed to read data (WARN)!");
return read;
}
void assetSkip(const size_t length) {
assertNotNull(ASSET_ARCHIVE, "assetSkip: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetSkip: Entry is NULL!");
assertTrue(length > 0, "assetSkip: Length must be greater than 0!");
// Asset archive does not support skipping, so we have to read and discard.
uint8_t buffer[1024];
size_t remaining = length;
do {
size_t toRead = mathMin(remaining, 1024);
size_t read = assetRead(buffer, toRead);
assertTrue(read == toRead, "assetSkip: Failed to skip data! (overskip?)");
remaining -= read;
} while(remaining > 0);
}
void assetClose() {
assertNotNull(ASSET_ARCHIVE, "assetClose: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetClose: Entry is NULL!");
int32_t ret = archive_read_free(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetClose: Failed to close archive!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
void assetDispose() {
assertNull(ASSET_ARCHIVE, "assetDestroy: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetDestroy: Entry is not NULL!");
int32_t result = fclose(ASSET_FILE);
assertTrue(result == 0, "assetDestroy: Failed to close asset file!");
}

73
src/dawn/asset/asset.h Normal file
View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Initializes the asset manager.
*/
void assetInit();
/**
* Opens an asset by its filename (within the asset archive). Asset paths should
* always use the unix forward slash '/' as a path separator.
*
* @param path The path to the asset within the archive.
*/
void assetOpen(const char_t *path);
/**
* Returns the size of the asset.
*
* @return The size of the asset.
*/
size_t assetGetSize();
/**
* Reads the asset into the buffer.
*
* @param buffer The buffer to read the asset into.
* @param bufferSize The size of the buffer.
* @return The amount of data read.
*/
size_t assetRead(uint8_t *buffer, size_t bufferSize);
/**
* Reads ahead in the buffer until either the end of the buffer, or the
* specified character is found. Return value will be -1 if the character was
* not found.
*
* Buffer can be NULL if you just want to skip ahead.
*
* Returned value will be either the amount of data read into the buffer, which
* excludes the extra 1 character that was read from the asset. If the character
* was not found, -1 will be returned.
*
* @param buffer Buffer to read into.
* @param c Character to read until.
* @param maxLength Maximum length to read.
* @return -1 if the character was not found, otherwise the amount of data read.
*/
size_t assetReadUntil(uint8_t *buffer, const char_t c, const size_t maxLength);
/**
* Skips ahead in the buffer by the specified length.
*
* @param length The length to skip ahead by.
*/
void assetSkip(const size_t length);
/**
* Closes the asset.
*/
void assetClose();
/**
* Destroys and cleans up the asset manager.
*/
void assetDispose();

View File

@ -0,0 +1,55 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/assetarchive.h"
#include "assert/assert.h"
#include "util/math.h"
FILE *ASSET_FILE;
struct archive *ASSET_ARCHIVE;
struct archive_entry *ASSET_ENTRY;
uint8_t ASSET_ARCHIVE_BUFFER[ASSET_BUFFER_SIZE];
char_t ASSET_PATH_CURRENT[ASSET_PATH_MAX];
ssize_t assetArchiveRead(
struct archive *archive,
void *data,
const void **buffer
) {
assertNotNull(archive, "assetArchiveRead: Archive is NULL!");
assertNotNull(data, "assetArchiveRead: Data is NULL!");
assertNotNull(buffer, "assetArchiveRead: Buffer is NULL!");
*buffer = data;
size_t read = fread(data, 1, ASSET_BUFFER_SIZE, ASSET_FILE);
if(ferror(ASSET_FILE)) return ARCHIVE_FATAL;
return read;
}
int64_t assetArchiveSeek(
struct archive *archive,
void *data,
int64_t offset,
int32_t whence
) {
assertNotNull(archive, "assetArchiveSeek: Archive is NULL!");
assertNotNull(data, "assetArchiveSeek: Data is NULL!");
assertTrue(offset > 0, "assetArchiveSeek: Offset must be greater than 0!");
int32_t ret = fseek(ASSET_FILE, offset, whence);
assertTrue(ret == 0, "assetArchiveSeek: Failed to seek!");
return ftell(ASSET_FILE);
}
int32_t assetArchiveOpen(struct archive *a, void *data) {
int32_t ret = fseek(ASSET_FILE, 0, SEEK_SET);
assertTrue(ret == 0, "assetArchiveOpen: Failed to seek to start of file!");
return ARCHIVE_OK;
}
int32_t assetArchiveClose(struct archive *a, void *data) {
return assetArchiveOpen(a, data);
}

View File

@ -0,0 +1,68 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/asset.h"
#include <archive.h>
#include <archive_entry.h>
#define ASSET_BUFFER_SIZE 32768
#define ASSET_PATH_MAX 1024
extern FILE *ASSET_FILE;
extern struct archive *ASSET_ARCHIVE;
extern struct archive_entry *ASSET_ENTRY;
extern uint8_t ASSET_ARCHIVE_BUFFER[ASSET_BUFFER_SIZE];
extern char_t ASSET_PATH_CURRENT[ASSET_PATH_MAX];
/**
* Internal read method provided to libarchive api.
*
* @param archive The archive to read from.
* @param data The data to read into.
* @param buffer The buffer to read from.
* @return The amount of data read.
*/
ssize_t assetArchiveRead(
struct archive *archive,
void *data,
const void **buffer
);
/**
* Internal seek method provided to libarchive api.
*
* @param archive The archive to seek in.
* @param data The data to seek in.
* @param offset Offset bytes to seek.
* @param whence Relative to whence to seek.
* @return The new position.
*/
int64_t assetArchiveSeek(
struct archive *archive,
void *data,
int64_t offset,
int32_t whence
);
/**
* Internal open method provided to libarchive api.
*
* @param archive The archive to open.
* @param data The data to open.
* @return The result of the open.
*/
int32_t assetArchiveOpen(struct archive *a, void *data);
/**
* Internal close method provided to libarchive api.
*
* @param archive The archive to close.
* @param data The data to close.
* @return The result of the close.
*/
int32_t assetArchiveClose(struct archive *a, void *data);

560
src/dawn/asset/assetjson.c Normal file
View File

@ -0,0 +1,560 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetjson.h"
#include "assert/assert.h"
#include "util/memory.h"
size_t assetJsonParse(const char_t *json, assetjson_t **out) {
size_t offset = assetJsonParseSub(json, out);
// We only expect whitespace or EOF here
char_t c;
size_t len = strlen(json);
while(offset <= len) {
c = json[offset];
if(c == '\0') break;
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
offset++;
continue;
}
assertUnreachable("Unexpected character found after JSON data.");
}
assertTrue(c == '\0', "Unexpected character found after JSON data.");
assertTrue(offset == len, "Unexpected character found after JSON data.");
return offset;
}
size_t assetJsonParseSub(
const char_t *json,
assetjson_t **out
) {
size_t offset = 0;
char_t c;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Read first character
c = json[offset];
switch(c) {
case '{':
offset += assetJsonParseAsObject(json + offset, out);
break;
case '[':
offset += assetJsonParseAsArray(json + offset, out);
break;
case '"':
offset += assetJsonParseAsString(json + offset, out);
break;
case '-':
case '0' ... '9':
case '.':
offset += assetJsonParseAsNumber(json + offset, out);
break;
case 't':
case 'f':
offset += assetJsonParseAsBoolean(json + offset, out);
break;
case 'n':
offset += assetJsonParseAsNull(json + offset, out);
break;
default:
assertUnreachable("Invalid JSON data type found.");
break;
}
return offset;
}
size_t assetJsonParseAsNull(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
// Read "null"
assertTrue(json[0] == 'n', "Expected NULL data type. (n0)");
assertTrue(json[1] == 'u', "Expected NULL data type. (u0)");
assertTrue(json[2] == 'l', "Expected NULL data type. (l0)");
assertTrue(json[3] == 'l', "Expected NULL data type. (l1)");
obj->type = ASSET_JSON_DATA_TYPE_NULL;
*out = obj;
return 4;
}
size_t assetJsonParseAsBoolean(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_BOOLEAN;
*out = obj;
if(json[0] == 't') {
// Read "true"
assertTrue(json[0] == 't', "Expected TRUE data type. (t0)");
assertTrue(json[1] == 'r', "Expected TRUE data type. (r0)");
assertTrue(json[2] == 'u', "Expected TRUE data type. (u0)");
assertTrue(json[3] == 'e', "Expected TRUE data type. (e0)");
obj->boolean = true;
return 4;
} else {
// Read "false"
assertTrue(json[0] == 'f', "Expected FALSE data type. (f0)");
assertTrue(json[1] == 'a', "Expected FALSE data type. (a0)");
assertTrue(json[2] == 'l', "Expected FALSE data type. (l0)");
assertTrue(json[3] == 's', "Expected FALSE data type. (s0)");
assertTrue(json[4] == 'e', "Expected FALSE data type. (e0)");
obj->boolean = false;
return 5;
}
}
size_t assetJsonParseAsString(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_STRING;
// For each char
size_t offset = 1;// Skip opening quote
size_t outOffset = 0;
char c;
bool_t inEscape = false;
size_t bufferSize = 2;
char_t *string = (char_t*)memoryAllocate(bufferSize * sizeof(char_t));
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of string.");
if(inEscape) {
inEscape = false;
switch(c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'u':
assertUnreachable("Unicode escape sequences are not supported.");
break;
default:
break;
}
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize * sizeof(char_t));
}
string[outOffset] = c;
offset++;
outOffset++;
continue;
}
if(c == '\\') {
inEscape = true;
offset++;
continue;
}
if(c == '"') break;
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize * sizeof(char_t));
}
string[outOffset] = c;
offset++;
outOffset++;
}
string[outOffset] = '\0';
outOffset++;
*out = obj;
obj->string = string;
return offset + 1;// For closing string quote
}
size_t assetJsonParseAsObject(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_OBJECT;
size_t bufferSize = 2;
char_t **keys = memoryAllocate(bufferSize * sizeof(char_t*));
assetjson_t **values = memoryAllocate(bufferSize * sizeof(assetjson_t*));
size_t length = 0;
// Skip whitespace
size_t offset = 1;// Skip opening bracket
char_t c;
while(true) {
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Only expect opening string or closing brace
if(c == '}') break;
assertTrue(c == '"', "Expected opening string for JSON object key.");
char_t *bufferKey;
// Skip "
offset++;
offset += assetJsonReadString(json + offset, &bufferKey);
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Only expect colon
assertTrue(c == ':', "Expected colon after JSON object key.");
offset++;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Parse sub
assetjson_t *value;
offset += assetJsonParseSub(json + offset, &value);
// Need to resize?
if(length >= bufferSize) {
bufferSize *= 2;
keys = memoryReallocate(keys, bufferSize * sizeof(char_t*));
values = memoryReallocate(values, bufferSize * sizeof(assetjson_t*));
}
keys[length] = bufferKey;
values[length] = value;
length++;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Expect either comma or closing bracket
assertTrue(
c == ',' || c == '}',
"Expected comma or closing bracket after JSON object value."
);
if(c == '}') break;
offset++;
}
obj->object.keys = keys;
obj->object.values = values;
obj->object.length = length;
*out = obj;
return offset + 1;// Skip closing bracket
}
size_t assetJsonParseAsArray(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_ARRAY;
size_t offset = 1;// Skip opening bracket
char_t c;
// Create array
size_t arraySize = 2;
obj->array.value = (assetjson_t**)memoryAllocate(
arraySize * sizeof(assetjson_t*)
);
obj->array.length = 0;
// Until closing bracket
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of JSON array.");
if(c == ']') break;
// Skip whitespace ONLY
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
offset++;
continue;
}
// Need to expand?
if(obj->array.length >= arraySize) {
arraySize *= 2;
obj->array.value = memoryReallocate(
obj->array.value, arraySize * sizeof(assetjson_t*)
);
}
// Parse sub
offset += assetJsonParseSub(
json + offset,
&obj->array.value[obj->array.length++]
);
// Skip whitespace ONLY
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// If comma, continue
if(c == ',') {
offset++;
continue;
}
// If closing bracket, break
if(c == ']') break;
// Else, error
assertUnreachable("Unexpected character found in JSON array.");
}
// End of array
*out = obj;
return offset + 1;// Skip closing bracket
}
size_t assetJsonParseAsNumber(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_NUMBER;
// For each char
size_t offset = 0;
size_t outOffset = 0;
char_t c;
size_t bufferSize = 2;
char_t *buffer = (char_t*)memoryAllocate(bufferSize * sizeof(char_t));
bool_t hasDecimal = false;
bool_t hasNumber = false;
// Read number
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of number.");
if(c == '-') {
// only accepted on first input
assertTrue(outOffset == 0, "Unexpected - after first digit");
} else if(c == '.') {
// only accepted once
assertTrue(!hasDecimal, "Unexpected . after first decimal");
hasDecimal = true;
if(!hasNumber) {
// If no number before decimal, add a 0
if(outOffset >= bufferSize) {
bufferSize *= 2;
buffer = memoryReallocate(buffer, bufferSize * sizeof(char_t));
}
buffer[outOffset] = '0';
outOffset++;
}
} else if(c >= '0' && c <= '9') {
hasNumber = true;
} else {
break;
}
// Need to expand?
if(outOffset >= bufferSize) {
bufferSize *= 2;
buffer = memoryReallocate(buffer, bufferSize * sizeof(char_t));
}
buffer[outOffset] = c;
offset++;
outOffset++;
}
// Seal the buffer, parse and cleanup
buffer[outOffset] = '\0';
obj->number = strtod(buffer, NULL);
memoryFree(buffer);
*out = obj;
return offset;
}
size_t assetJsonReadString(
const char_t *json,
char_t **buffer
) {
size_t offset = 0;
size_t outOffset = 0;
char_t c;
size_t bufferSize = 32;
char_t *string = (char_t*)memoryAllocate(sizeof(char_t) * bufferSize);
bool_t inEscape = false;
// For each char
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of string.");
if(inEscape) {
inEscape = false;
switch(c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'u':
assertUnreachable("Unicode escape sequences are not supported.");
break;
default:
break;
}
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize);
}
string[outOffset] = c;
offset++;
outOffset++;
continue;
}
if(c == '\\') {
inEscape = true;
offset++;
continue;
}
if(c == '"') break;
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize);
}
string[outOffset] = c;
offset++;
outOffset++;
}
string[outOffset] = '\0';
outOffset++;
*buffer = string;
return offset + 1;
}
assetjson_t * assetJsonGetObjectValue(assetjson_t *json, const char_t *key) {
assertTrue(json->type == ASSET_JSON_DATA_TYPE_OBJECT, "Expected JSON object.");
for(size_t i = 0; i < json->object.length; i++) {
if(strcmp(json->object.keys[i], key) == 0) {
return json->object.values[i];
}
}
return NULL;
}
void assetJsonDispose(assetjson_t *json) {
switch(json->type) {
case ASSET_JSON_DATA_TYPE_OBJECT:
for(size_t i = 0; i < json->object.length; i++) {
memoryFree(json->object.keys[i]);
assetJsonDispose(json->object.values[i]);
}
memoryFree(json->object.keys);
memoryFree(json->object.values);
break;
case ASSET_JSON_DATA_TYPE_ARRAY:
for(size_t i = 0; i < json->array.length; i++) {
assetJsonDispose(json->array.value[i]);
}
memoryFree(json->array.value);
break;
case ASSET_JSON_DATA_TYPE_STRING:
memoryFree(json->string);
break;
case ASSET_JSON_DATA_TYPE_NUMBER:
break;
case ASSET_JSON_DATA_TYPE_BOOLEAN:
break;
case ASSET_JSON_DATA_TYPE_NULL:
break;
}
memoryFree(json);
}

140
src/dawn/asset/assetjson.h Normal file
View File

@ -0,0 +1,140 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef enum {
ASSET_JSON_DATA_TYPE_OBJECT,
ASSET_JSON_DATA_TYPE_ARRAY,
ASSET_JSON_DATA_TYPE_STRING,
ASSET_JSON_DATA_TYPE_NUMBER,
ASSET_JSON_DATA_TYPE_BOOLEAN,
ASSET_JSON_DATA_TYPE_NULL
} assetjsondatatype_t;
typedef struct _assetjson_t assetjson_t;
typedef struct _assetjson_t {
assetjsondatatype_t type;
union {
struct {
char_t **keys;
assetjson_t **values;
size_t length;
} object;
struct {
assetjson_t **value;
size_t length;
} array;
double_t number;
char_t *string;
bool_t boolean;
};
} assetjson_t;
/**
* Parses a JSON string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParse(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a sub-object.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseSub(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a NULL value.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsNull(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a boolean value.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsBoolean(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as an object.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsObject(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as an array.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsArray(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsString(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsNumber(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonReadString(const char_t *json, char_t **out);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
assetjson_t *assetJsonGetObjectValue(assetjson_t *object, const char_t *key);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
void assetJsonDispose(assetjson_t *json);

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetlanguage.h"
#include "asset/asset.h"
#include "assert/assert.h"
#include "locale/language.h"
#include "util/memory.h"
void assetLanguageObjectLoad(
const char_t *key,
assetjson_t *json
) {
char_t tKey[LANGUAGE_STRING_KEY_LENGTH_MAX];
size_t keyLength = strlen(key);
strcpy(tKey, key);
if(keyLength > 0) {
tKey[keyLength] = '.';
keyLength++;
}
for(int32_t i = 0; i < json->object.length; i++) {
const char_t *subKey = json->object.keys[i];
assetjson_t *value = json->object.values[i];
strcpy(tKey + keyLength, subKey);
if(json->object.values[i]->type == ASSET_JSON_DATA_TYPE_OBJECT) {
assetLanguageObjectLoad(tKey, value);
continue;
}
if(json->object.values[i]->type == ASSET_JSON_DATA_TYPE_STRING) {
strcpy(LANGUAGE.keys[LANGUAGE.count], tKey);
strcpy(LANGUAGE.strings[LANGUAGE.count], value->string);
LANGUAGE.count++;
continue;
}
assertUnreachable("Language value is not a string or object!");
}
}
void assetLanguageLoad(const char_t *path) {
assertNotNull(path, "Path cannot be NULL.");
assetOpen(path);
size_t length = assetGetSize();
char_t *buffer = memoryAllocate(sizeof(char_t) * (length + 1));
buffer[length] = '\0';
size_t read = assetRead((uint8_t*)buffer, length);
assertTrue(read == length, "Failed to read language file!");
assetClose();
assetjson_t *json;
read = assetJsonParse(buffer, &json);
memoryFree(buffer);
assertTrue(
json->type == ASSET_JSON_DATA_TYPE_OBJECT,
"Language file is not an object!"
);
languageInit();
assetLanguageObjectLoad("", json);
assetJsonDispose(json);
}

View File

@ -0,0 +1,27 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/assetjson.h"
/**
* Loads a JSON object from the asset file.
*
* @param key The key to load.
* @param json The value to load into.
*/
void assetLanguageObjectLoad(
const char_t *key,
assetjson_t *json
);
/**
* Loads the language file from the specified path.
*
* @param path Path to the language file.
*/
void assetLanguageLoad(const char_t *path);

236
src/dawn/asset/assetmap.c Normal file
View File

@ -0,0 +1,236 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetmap.h"
#include "asset/asset.h"
#include "assert/assert.h"
#include "util/memory.h"
void assetMapLoadEntity(
assetjson_t *jEnt,
map_t *map
) {
int32_t x = (int32_t)assetJsonGetObjectValue(jEnt, "x")->number;
int32_t y = (int32_t)assetJsonGetObjectValue(jEnt, "y")->number;
entitytype_t type = (entitytype_t)assetJsonGetObjectValue(
jEnt, "type"
)->number;
entity_t *ent = mapEntityAdd(map);
entityInit(ent, type, map);
entityPositionSet(ent, x, y);
assetjson_t *val;
switch(type) {
case ENTITY_TYPE_NPC:
val = assetJsonGetObjectValue(jEnt, "name");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: NPC name is not a string!"
);
npcNameSet(&ent->npc, val->string);
}
val = assetJsonGetObjectValue(jEnt, "text");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: NPC text is not a string!"
);
npcTextSet(&ent->npc, val->string);
}
break;
case ENTITY_TYPE_SIGN:
val = assetJsonGetObjectValue(jEnt, "text");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextAppend(&ent->sign, val->string);
}
val = assetJsonGetObjectValue(jEnt, "texts");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Sign texts is not an array!"
);
assertTrue(
val->array.length <= SIGN_TEXT_COUNT_MAX,
"assetMapLoad: Too many sign texts!"
);
for(int32_t i = 0; i < val->array.length; i++) {
assetjson_t *subVal = val->array.value[i];
assertTrue(
subVal->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextAppend(&ent->sign, subVal->string);
}
}
break;
case ENTITY_TYPE_DOOR:
val = assetJsonGetObjectValue(jEnt, "door");
if(val != NULL) {
assetjson_t *door = assetJsonGetObjectValue(val, "x");
x = (int32_t)door->number;
assertTrue(
door->type == ASSET_JSON_DATA_TYPE_NUMBER,
"assetMapLoad: Door x is not a number!"
);
door = assetJsonGetObjectValue(val, "y");
y = (int32_t)door->number;
assertTrue(
door->type == ASSET_JSON_DATA_TYPE_NUMBER,
"assetMapLoad: Door y is not a number!"
);
door = assetJsonGetObjectValue(val, "direction");
entitydirection_t direction = ENTITY_DIRECTION_SOUTH;
if(door != NULL) {
direction = (entitydirection_t)(
assetJsonGetObjectValue(val, "direction")->number
);
}
door = assetJsonGetObjectValue(val, "map");
maplist_t list;
if(door == NULL) {
list = map->list;
} else if(door->type == ASSET_JSON_DATA_TYPE_STRING) {
list = mapListGet(door->string);
} else if(door->type == ASSET_JSON_DATA_TYPE_NUMBER) {
list = (maplist_t)door->number;
} else {
assertUnreachable("assetMapLoad: Door map not string or number!");
}
doorDestinationSet(&ent->door, x, y, direction, list);
}
break;
default:
break;
}
}
void assetMapLoad(
const char_t *path,
map_t *map
) {
assertNotNull(map, "assetMapLoad: Map is NULL!");
// Read in the string data.
assetOpen(path);
size_t length = assetGetSize();
char_t *buffer = memoryAllocate(sizeof(char_t) * (length + 1));
size_t read = assetRead((uint8_t*)buffer, length);
buffer[length] = '\0';
assertTrue(read == length, "assetMapLoad: Failed to read map data!");
assetClose();
// Begin parsing JSON data.
assetjson_t *json;
read = assetJsonParse(buffer, &json);
memoryFree(buffer);
assertTrue(
json->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Map data is not an object!"
);
int32_t width = (int32_t)assetJsonGetObjectValue(json, "width")->number;
int32_t height = (int32_t)assetJsonGetObjectValue(json, "height")->number;
assetjson_t *layers = assetJsonGetObjectValue(json, "layers");
assertTrue(
layers->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Layers is not an array!"
);
int32_t layerCount = layers->array.length;
assertTrue(layerCount == MAP_LAYERS_MAX, "assetMapLoad: No layers found!");
mapInit(map, mapListGet(path), width, height, layerCount);
// Load tile data.
for(int32_t i = 0; i < layerCount; i++) {
assetjson_t *layer = layers->array.value[i];
assertTrue(
layer->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Layer is not an object!"
);
assetjson_t *tiles = assetJsonGetObjectValue(layer, "tiles");
assertTrue(
tiles->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Tiles is not an array!"
);
assertTrue(
tiles->array.length == width * height,
"assetMapLoad: Tile count does not match map size!"
);
for(int32_t j = 0; j < width * height; j++) {
map->tiles[j] = (tile_t)tiles->array.value[j]->number;
}
}
// Load entity data
assetjson_t *entities = assetJsonGetObjectValue(json, "entities");
if(entities != NULL) {
assertTrue(
entities->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Entities is not an array!"
);
for(int32_t i = 0; i < entities->array.length; i++) {
assetjson_t *jEnt = entities->array.value[i];
assertTrue(
jEnt->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Entity is not an object!"
);
assetMapLoadEntity(jEnt, map);
}
}
// Load trigger data
assetjson_t *triggers = assetJsonGetObjectValue(json, "triggers");
if(triggers != NULL) {
assertTrue(
triggers->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Triggers is not an array!"
);
for(int32_t i = 0; i < triggers->array.length; i++) {
assetjson_t *jTrig = triggers->array.value[i];
assertTrue(
jTrig->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Trigger is not an object!"
);
int32_t x = (int32_t)assetJsonGetObjectValue(jTrig, "x")->number;
int32_t y = (int32_t)assetJsonGetObjectValue(jTrig, "y")->number;
int32_t width = (int32_t)assetJsonGetObjectValue(jTrig, "width")->number;
int32_t height = (int32_t)assetJsonGetObjectValue(
jTrig, "height"
)->number;
triggertype_t type = (triggertype_t)assetJsonGetObjectValue(
jTrig, "type"
)->number;
trigger_t *trigger = mapTriggerAdd(map);
triggerInit(trigger, type, x, y, width, height);
}
}
assetJsonDispose(json);
}

32
src/dawn/asset/assetmap.h Normal file
View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/world/map.h"
#include "asset/assetjson.h"
/**
* Loads an entity from the specified JSON object.
*
* @param jEnt JSON object to load the entity from.
* @param map Map to load the entity into.
*/
void assetMapLoadEntity(
assetjson_t *jEnt,
map_t *map
);
/**
* Loads a map from the specified path.
*
* @param path Path to the map file.
* @param map Map to load the data into.
*/
void assetMapLoad(
const char_t *path,
map_t *map
);

View File

@ -1,17 +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
JSONLoader.cpp
TrueTypeLoader.cpp
ShaderLoader.cpp
StringLoader.cpp
)
# Subdirs
add_subdirectory(scene)

View File

@ -1,43 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "JSONLoader.hpp"
using namespace Dawn;
const std::string JSONLoader::ASSET_TYPE = "json";
JSONLoader::JSONLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
loader(name),
state(JSONLoaderState::INITIAL)
{
this->typetest = this->getAssetType();
}
void JSONLoader::updateAsync() {
if(this->state != JSONLoaderState::INITIAL) return;
this->state = JSONLoaderState::LOADING_JSON;
std::string jsonContents = loader.getEntireContentsAsString();
this->data = json::parse(jsonContents);
this->state = JSONLoaderState::DONE;
this->loaded = true;
}
void JSONLoader::updateSync() {
}
std::string JSONLoader::getAssetType() const {
return JSONLoader::ASSET_TYPE;
}
JSONLoader::~JSONLoader() {
}

View File

@ -1,37 +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 JSONLoaderState {
INITIAL,
LOADING_JSON,
DONE
};
class JSONLoader : public AssetLoader {
protected:
AssetDataLoader loader;
enum JSONLoaderState state;
public:
const static std::string ASSET_TYPE;
json data;
JSONLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
~JSONLoader();
};
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "ShaderLoader.hpp"
#include "assert/assert.hpp"
#include "asset/AssetManager.hpp"
#include "game/Game.hpp"
using namespace Dawn;
const std::string ShaderLoader::ASSET_TYPE = "shader";
ShaderLoader::ShaderLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
state(ShaderLoaderState::INITIAL),
shader(std::make_shared<ShaderProgram>())
{
}
void ShaderLoader::updateAsync() {
}
void ShaderLoader::updateSync() {
if(state != ShaderLoaderState::INITIAL) return;
this->state = ShaderLoaderState::LOADING;
assertFalse(loaded, "ShaderLoader already loaded.");
// Shorthand.
auto sm = this->getAssetManager()->getGame()->shaderManager;
// Load the shader string
Slang::ComPtr<IBlob> diagnostics;
auto module = sm->session->loadModule(
this->name.c_str(),
diagnostics.writeRef()
);
shader->init(module, sm->session);
// Finished loading.
this->state = ShaderLoaderState::LOADED;
this->loaded = true;
}
std::string ShaderLoader::getAssetType() const {
return ShaderLoader::ASSET_TYPE;
}
std::shared_ptr<ShaderProgram> ShaderLoader::getShader() {
assertNotNull(shader, "ShaderLoader shader is null.");
return shader;
}
ShaderLoader::~ShaderLoader() {
shader = nullptr;
}

View File

@ -1,44 +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"
#include "display/shader/ShaderManager.hpp"
#include "display/shader/ShaderProgram.hpp"
namespace Dawn {
enum class ShaderLoaderState {
INITIAL,
LOADING,
LOADED
};
class ShaderLoader : public AssetLoader {
protected:
enum ShaderLoaderState state;
std::shared_ptr<ShaderProgram> shader;
public:
const static std::string ASSET_TYPE;
ShaderLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
/**
* Retreives the shader program for this loader.
*
* @return The shader program that this loader is managing.
*/
std::shared_ptr<ShaderProgram> getShader();
~ShaderLoader();
};
}

View File

@ -1,38 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "StringLoader.hpp"
using namespace Dawn;
const std::string StringLoader::ASSET_TYPE = "string";
StringLoader::StringLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
loader(name),
state(StringLoaderState::INITIAL)
{
}
void StringLoader::updateSync() {
}
void StringLoader::updateAsync() {
if(this->state != StringLoaderState::INITIAL) return;
this->state = StringLoaderState::LOADING_STRING;
this->data = this->loader.getEntireContentsAsString();
this->state = StringLoaderState::DONE;
this->loaded = true;
}
std::string StringLoader::getAssetType() const {
return StringLoader::ASSET_TYPE;
}
StringLoader::~StringLoader() {
}

View File

@ -1,36 +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 StringLoaderState {
INITIAL,
LOADING_STRING,
DONE
};
class StringLoader : public AssetLoader {
protected:
AssetDataLoader loader;
enum StringLoaderState state;
public:
const static std::string ASSET_TYPE;
std::string data;
StringLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
~StringLoader();
};
}

View File

@ -1,157 +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;
const std::string TextureLoader::ASSET_TYPE = "texture";
TextureLoader::TextureLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
loader(name),
state(TextureLoaderLoadState::INITIAL)
{
this->typetest = this->getAssetType();
texture = std::make_shared<Texture>();
}
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->texture, "Texture is null!");
assertNotNull(this->data, "Texture data is null!");
// Setup Texture
this->texture->setSize(
this->width,
this->height,
this->format,
TextureDataFormat::UNSIGNED_BYTE
);
this->texture->buffer(this->data);
// Free data buffer
delete[] this->data;
this->data = nullptr;
// Hand off and call done
this->state = TextureLoaderLoadState::SYNC_DONE;
this->loaded = true;
}
std::string TextureLoader::getAssetType() const {
return TextureLoader::ASSET_TYPE;
}
std::shared_ptr<Texture> TextureLoader::getTexture() {
return this->texture;
}
TextureLoader::~TextureLoader() {
if(this->data != nullptr) {
delete[] this->data;
this->data = nullptr;
}
this->texture = 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;
std::shared_ptr<Texture> texture;
public:
const static std::string ASSET_TYPE;
TextureLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const override;
/**
* Get the texture asset.
*
* @return Texture asset.
*/
std::shared_ptr<Texture> getTexture();
~TextureLoader();
};
}

View File

@ -1,107 +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;
const std::string TrueTypeLoader::ASSET_TYPE = "ttf";
TrueTypeLoader::TrueTypeLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
loader(name)
{
this->typetest = this->getAssetType();
// 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::string TrueTypeLoader::getAssetType() const {
return TrueTypeLoader::ASSET_TYPE;
}
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,53 +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:
const static std::string ASSET_TYPE;
TrueTypeLoader(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
void updateSync() override;
void updateAsync() override;
std::string getAssetType() const 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
);
~TrueTypeLoader();
};
}

View File

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

View File

@ -1,76 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "LoaderForSceneItems.hpp"
#include "asset/loader/TextureLoader.hpp"
#include "asset/loader/scene/PrefabLoader.hpp"
#include "asset/loader/ShaderLoader.hpp"
using namespace Dawn;
LoaderForSceneItems::LoaderForSceneItems(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
) :
AssetLoader(assetManager, name),
ctx(std::make_shared<SceneLoadContext>())
{
}
void LoaderForSceneItems::setupDependencies() {
assertNotNull(this->jsonLoader, "JSON Loader is NULL?");
assertNotNull(ctx, "SceneLoadContext is NULL?");
assertTrue(this->jsonLoader->loaded, "JSON loader not loaded?");
// Begin loading dependencies.
auto &data = this->jsonLoader->data;
if(data.contains("assets")) {
for(auto &asset : data["assets"].items()) {
auto &assetName = asset.key();
auto &assetData = asset.value();
assertTrue(assetData.contains("type"), "Asset missing type");
assertTrue(assetData.contains("path"), "Asset missing path");
auto type = assetData["type"].get<std::string>();
auto path = assetData["path"].get<std::string>();
// Is this asset already named?
if(ctx->assets.find(assetName) != ctx->assets.end()) {
// Check if path and type already the same.
auto &existing = ctx->assets[assetName];
assertTrue(
existing->name == path && existing->getAssetType() == type,
"Asset already exists with different path or type: %s",
assetName.c_str()
);
continue;
}
std::shared_ptr<AssetLoader> loader;
if(type == "texture") {
loader = getAssetManager()->get<TextureLoader>(path);
} else if(type == "json") {
loader = getAssetManager()->get<JSONLoader>(path);
} else if(type == "prefab") {
auto prefabLoader = getAssetManager()->get<PrefabLoader>(path);
prefabLoader->ctx->parent = ctx;
loader = prefabLoader;
} else if(type == "shader") {
loader = getAssetManager()->get<ShaderLoader>(path);
} else {
assertUnreachable("Unknown asset type: %s", type.c_str());
}
ctx->assets[assetName] = loader;
}
}
}
LoaderForSceneItems::~LoaderForSceneItems() {
jsonLoader = nullptr;
}

View File

@ -1,39 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "asset/loader/JSONLoader.hpp"
#include "SceneLoadContext.hpp"
namespace Dawn {
class LoaderForSceneitems;
class LoaderForSceneItems :
public AssetLoader,
public std::enable_shared_from_this<LoaderForSceneItems>
{
protected:
std::shared_ptr<JSONLoader> jsonLoader;
/**
* Loads the dependencies into the context for the data available in
* the jsonLoader.
*/
void setupDependencies();
public:
const std::shared_ptr<SceneLoadContext> ctx;
LoaderForSceneItems(
const std::shared_ptr<AssetManager> assetManager,
const std::string name
);
~LoaderForSceneItems();
friend class SceneLoader;
friend class PrefabLoader;
};
}

Some files were not shown because too many files have changed in this diff Show More