GAME PROG

This commit is contained in:
2024-06-19 11:45:12 -05:00
parent fec8771c75
commit bba4a83240
85 changed files with 3687 additions and 27 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "lib/libarchive"]
path = lib/libarchive
url = https://github.com/libarchive/libarchive
[submodule "lib/boxer"]
path = lib/boxer
url = https://github.com/aaronmjacobs/Boxer

View File

@ -19,6 +19,9 @@ if(DAWN_BUILD_SYSTEM STREQUAL "linux")
add_subdirectory(freetype)
add_subdirectory(boxer)
target_compile_definitions(Boxer PRIVATE UNICODE)
elseif(DAWN_BUILD_SYSTEM STREQUAL "vita")
add_subdirectory(glm)

1
lib/boxer Submodule

Submodule lib/boxer added at 65e79c38f1

View File

@ -9,6 +9,7 @@ if(DAWN_BUILD_SYSTEM STREQUAL "linux")
add_subdirectory(dawnglfw)
add_subdirectory(dawnlinux)
add_subdirectory(dawnopengl)
add_subdirectory(dawnrpg)
elseif(DAWN_BUILD_SYSTEM STREQUAL "vita")
add_subdirectory(dawn)
add_subdirectory(dawnvita)

View File

@ -22,6 +22,12 @@ target_sources(${DAWN_TARGET_NAME}
)
# Subdirs
add_subdirectory(display)
add_subdirectory(error)
add_subdirectory(game)
add_subdirectory(locale)
add_subdirectory(scene)
add_subdirectory(util)
# Textures
# tool_texture(texture_test

View File

@ -6,8 +6,32 @@
*/
#pragma once
#include <iostream>
#include <cstdint>
#include <cstdarg>
typedef char char_t;
#define DAWN_GAME_NAME "Dawn"
#define DAWN_GAME_NAME_U8 u8"Dawn"
#include <vector>
#include <iostream>
#include <thread>
#include <map>
#include <array>
#include <memory>
#include <algorithm>
#include <sstream>
#include <string>
#include <functional>
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <float.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/matrix_decompose.hpp>
typedef char char_t;
typedef char8_t u8char_t;
typedef float float_t;
typedef double double_t;
typedef bool bool_t;

View File

@ -0,0 +1,16 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Color.cpp
RenderPipeline.cpp
RenderManager.cpp
)
# Subdirs
add_subdirectory(mesh)
add_subdirectory(shader)

View File

@ -0,0 +1,84 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Color.hpp"
#include "error/assert.hpp"
#include "util/string.hpp"
using namespace Dawn;
struct Color Color::fromString(const std::string str) {
// Convert to lowercase
auto lower = stringToLowercase(str);
if(stringIncludes(lower, "cornflower")) {
return COLOR_CORNFLOWER_BLUE;
} else if(stringIncludes(lower, "magenta")) {
return COLOR_MAGENTA;
} else if(stringIncludes(lower, "white")) {
return COLOR_WHITE;
} else if(stringIncludes(lower, "black")) {
return COLOR_BLACK;
} else if(stringIncludes(lower, "red")) {
return COLOR_RED;
} else if(stringIncludes(lower, "green")) {
return COLOR_GREEN;
} else if(stringIncludes(lower, "blue")) {
return COLOR_BLUE;
} else if(stringIncludes(lower, "transparent")) {
return COLOR_TRANSPARENT;
}
// Hex code?
if(lower[0] == '#') {
// Remove the hash
lower = lower.substr(1);
// Convert to RGB
if(lower.length() == 3) {
// Convert to 6 digit hex
lower = lower[0] + lower[0] + lower[1] + lower[1] + lower[2] + lower[2];
}
// Convert to RGB
return {
(float_t)std::stoi(lower.substr(0, 2), nullptr, 16) / 255.0f,
(float_t)std::stoi(lower.substr(2, 2), nullptr, 16) / 255.0f,
(float_t)std::stoi(lower.substr(4, 2), nullptr, 16) / 255.0f,
1.0f
};
}
// Split by comma
auto splitByComma = stringSplit(str, ",");
if(splitByComma.size() == 3) {
// RGB
return {
(float_t)std::stof(splitByComma[0]),
(float_t)std::stof(splitByComma[1]),
(float_t)std::stof(splitByComma[2]),
1.0f
};
} else if(splitByComma.size() == 4) {
// RGBA
return {
(float_t)std::stof(splitByComma[0]),
(float_t)std::stof(splitByComma[1]),
(float_t)std::stof(splitByComma[2]),
(float_t)std::stof(splitByComma[3])
};
}
// TODO: Parse other kinds of colors
assertUnreachable("Failed to find a color match for %s", str);
return {};
}

View File

@ -0,0 +1,89 @@
// 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 {
struct ColorU8 {
uint8_t r, g, b, a;
};
struct Color final {
/**
* Returns a color from a string.
*
* @param str String to parse.
* @return Color parsed.
*/
static struct Color fromString(const std::string str);
float_t r, g, b, a;
const struct Color& operator = (const struct Color &val) {
this->r = val.r;
this->g = val.g;
this->b = val.b;
this->a = val.a;
return *this;
}
struct Color operator * (const float_t &x) {
return {
r * x,
g * x,
b * x,
a * x
};
}
struct Color operator - (const struct Color &color) {
return {
r - color.r,
g - color.g,
b - color.b,
a - color.a
};
}
struct Color operator + (const struct Color &color) {
return {
r + color.r,
g + color.g,
b + color.b,
a + color.a
};
}
const bool_t operator == (const struct Color &other) {
return r == other.r && g == other.g && b == other.b && a == other.a;
}
operator struct ColorU8() const {
return {
(uint8_t)(r * 255),
(uint8_t)(g * 255),
(uint8_t)(b * 255),
(uint8_t)(a * 255)
};
}
};
#define COLOR_DEF(r,g,b,a) { r, g, b, a }
#define COLOR_WHITE COLOR_DEF(1.0f, 1.0f, 1.0f, 1.0f)
#define COLOR_RED COLOR_DEF(1.0f, 0, 0, 1.0f)
#define COLOR_GREEN COLOR_DEF(0, 1.0f, 0, 1.0f)
#define COLOR_BLUE COLOR_DEF(0, 0, 1.0f, 1.0f)
#define COLOR_BLACK COLOR_DEF(0, 0, 0, 1.0f)
#define COLOR_MAGENTA COLOR_DEF(1.0f, 0, 1.0f, 1.0f)
#define COLOR_DARK_GREY COLOR_DEF(0.2f, 0.2f, 0.2f, 1.0f)
#define COLOR_LIGHT_GREY COLOR_DEF(0.8f, 0.8f, 0.8f, 1.0f)
#define COLOR_CORNFLOWER_BLUE COLOR_DEF(0.4f, 0.6f, 0.9f, 1.0f)
#define COLOR_WHITE_TRANSPARENT COLOR_DEF(1.0f, 1.0f, 1.0f, 0.0f)
#define COLOR_BLACK_TRANSPARENT COLOR_DEF(0.0f, 0.0f, 0.0f, 0.0f)
#define COLOR_YELLOW COLOR_DEF(1.0f, 1.0f, 0.0f, 1.0f)
#define COLOR_CYAN COLOR_DEF(0.0f, 1.0f, 1.0f, 1.0f)
#define COLOR_TRANSPARENT COLOR_WHITE_TRANSPARENT
}

View File

@ -0,0 +1,117 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/Color.hpp"
namespace Dawn {
enum class TextureFormat {
R = 1,
RG = 2,
RGB = 3,
RGBA = 4
};
enum class TextureWrapMode {
REPEAT = 0,
MIRRORED_REPEAT = 1,
CLAMP_TO_EDGE = 2,
CLAMP_TO_BORDER = 3
};
enum class TextureFilterMode {
NEAREST = 0,
LINEAR = 1
};
enum class TextureDataFormat {
UNSIGNED_BYTE = sizeof(uint8_t),
FLOAT = sizeof(float_t)
};
class ITexture {
public:
enum TextureWrapMode wrapModeX = TextureWrapMode::REPEAT;
enum TextureWrapMode wrapModeY = TextureWrapMode::REPEAT;
enum TextureFilterMode filterModeMin = TextureFilterMode::NEAREST;
enum TextureFilterMode filterModeMag = TextureFilterMode::NEAREST;
enum TextureFilterMode mipMapFilterModeMin = TextureFilterMode::NEAREST;
enum TextureFilterMode mipMapFilterModeMag = TextureFilterMode::NEAREST;
/**
* Returns the width of the texture.
*
* @return Width of the texture.
*/
virtual int32_t getWidth() = 0;
/**
* Returns the height of the texture.
*
* @return Height of the texture.
*/
virtual int32_t getHeight() = 0;
/**
* Initializes a texture.
*
* @param width Width of the texture (in pixels).
* @param height Height of the texture (in pixels).
* @param format Data format of the texture to use.
* @param dataFormat Data format of the texture to use.
*/
virtual void setSize(
const int32_t width,
const int32_t height,
const enum TextureFormat format,
const enum TextureDataFormat dataFormat
) = 0;
/**
* Returns true only when the texture has been loaded, sized and put on
* the gpu for rendering.
*
* @return True if ready, otherwise false.
*/
virtual bool_t isReady() = 0;
/**
* Buffer pixel data onto the GPU. Pixel buffering is rather costly so
* avoid doing this too often.
*
* @param pixels Array of pixels you're trying to buffer.
*/
virtual void buffer(const struct ColorU8 pixels[]) = 0;
/**
* Buffer pixel data onto the GPU. Pixel buffering is rather costly so
* avoid doing this too often.
*
* @param pixels Array of pixels you're trying to buffer.
*/
virtual void buffer(const struct Color pixels[]) = 0;
/**
* Buffer pixel data onto the GPU. Pixel buffering is rather costly so
* avoid doing this too often.
*
* @param pixels Array of pixels you're trying to buffer.
*/
virtual void buffer(const uint8_t pixels[]) = 0;
/**
* Binds the texture to the given slot (for use by the shaders).
*
* @param slot Slot to bind to.
*/
virtual void bind(const uint8_t slot) = 0;
/**
* Disposes of the texture.
*/
virtual ~ITexture() {
}
};
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "RenderManager.hpp"
#include "game/Game.hpp"
using namespace Dawn;
RenderManager::RenderManager() :
renderPipeline(),
shaderManager()
{
}
void RenderManager::init(const Game &game) {
backBuffer = std::make_shared<BackBuffer>();
backBuffer->setClearColor(COLOR_CORNFLOWER_BLUE);
}
void RenderManager::update(const Game &game) {
backBuffer->bind();
backBuffer->clear(RENDER_TARGET_CLEAR_COLOR | RENDER_TARGET_CLEAR_DEPTH);
}
std::shared_ptr<BackBuffer> RenderManager::getBackBufferRenderTarget() {
return backBuffer;
}
RenderManager::~RenderManager() {
}

View File

@ -1,13 +1,56 @@
// Copyright (c) 2024 Dominic Masters
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
#include "display/RenderTarget.hpp"
#include "display/RenderPipeline.hpp"
#include "display/shader/ShaderManager.hpp"
#include "display/BackBuffer.hpp"
namespace Dawn {
class Game;
class RenderManager {
private:
std::shared_ptr<BackBuffer> backBuffer = nullptr;
public:
}
RenderPipeline renderPipeline;
ShaderManager shaderManager;
/**
* Creates a render manager.
*/
RenderManager();
/**
* Initializes the render manager, called by the game during the initial
* set up of the engine.
*
* @param game Game that requested the render manager to initialize.
*/
void init(const Game &game);
/**
* Performs an update/tick of the render manager. This would be the game
* asking the RenderManager to do the rendering.
*/
void update(const Game &game);
/**
* Returns the back buffer render target. This is the render target that
* is used to render to the screen.
*
* @return The back buffer render target.
*/
std::shared_ptr<BackBuffer> getBackBufferRenderTarget();
/**
* Destroys the render manager.
*/
~RenderManager();
};
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "error/assert.hpp"
#include "RenderPipeline.hpp"
#include "game/Game.hpp"
using namespace Dawn;
RenderPipeline::RenderPipeline() {
}
RenderPipeline::~RenderPipeline() {
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class RenderPipeline {
public:
/**
* Creates a new RenderPipeline.
*/
RenderPipeline();
/**
* Destroys the RenderPipeline.
*/
virtual ~RenderPipeline();
};
}

View File

@ -0,0 +1,71 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "event/Event.hpp"
#define RENDER_TARGET_CLEAR_COLOR (1 << 0)
#define RENDER_TARGET_CLEAR_DEPTH (1 << 1)
namespace Dawn {
class RenderTarget {
public:
Event<float_t, float_t> onResize;
/**
* Return the width of the render target.
*
* @return The width of the render target.
*/
virtual float_t getWidth() = 0;
/**
* Return the height of the render target.
*
* @return The height of the render target.
*/
virtual float_t getHeight() = 0;
/**
* Returns the scale (as in pixel density) of the render target. This is
* typically 1.0f, but on high DPI displays this may be 2.0f or higher.
*
* @return The scale of the render target.
*/
virtual float_t getScale() = 0;
/**
* Sets the clear color of the render target when the clear method for
* the color buffer is requested.
*
* @param color Color to use for the clear operation.
*/
virtual void setClearColor(const struct Color color) = 0;
/**
* Request the existing data in the render target to be cleared out. We
* typically assume the render target can support multiple buffer types,
* so you can opt to only clear certain buffer types.
*
* @param clearFlags Flags to request what is going to be cleared.
*/
virtual void clear(const int32_t clearFlags) = 0;
/**
* Bind the render target for rendering to. The proceeding render requests
* will want to render to this render target directly. In future I may
* see if we can have multiple render targets bound at once to make this
* operation perform faster.
*/
virtual void bind() = 0;
/**
* Destroys the render target.
*/
virtual ~RenderTarget() {
}
};
}

View File

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

View File

@ -0,0 +1,70 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "CubeMesh.hpp"
using namespace Dawn;
void CubeMesh::buffer(
const std::shared_ptr<Mesh> mesh,
const glm::vec3 pos,
const glm::vec3 size,
const int32_t verticeStart,
const int32_t indiceStart
) {
glm::vec3 positions[CUBE_VERTICE_COUNT] = {
pos,
glm::vec3(pos.x+size.x, pos.y, pos.z),
glm::vec3(pos.x, pos.y+size.y, pos.z),
glm::vec3(pos.x+size.x, pos.y+size.y, pos.z),
glm::vec3(pos.x, pos.y, pos.z+size.z),
glm::vec3(pos.x+size.x, pos.y, pos.z+size.z),
glm::vec3(pos.x, pos.y+size.y, pos.z+size.z),
pos + size
};
glm::vec2 coordinates[CUBE_VERTICE_COUNT] = {
glm::vec2(0, 0),
glm::vec2(1, 0),
glm::vec2(0, 1),
glm::vec2(1, 1),
glm::vec2(0, 0),
glm::vec2(1, 0),
glm::vec2(0, 1),
glm::vec2(1, 1)
};
int32_t indices[CUBE_INDICE_COUNT] = {
// Back
verticeStart, verticeStart + 1, verticeStart + 3,
verticeStart, verticeStart + 2, verticeStart + 3,
// Right
verticeStart + 1, verticeStart + 5, verticeStart + 7,
verticeStart + 1, verticeStart + 3, verticeStart + 7,
// Left
verticeStart + 4, verticeStart, verticeStart + 2,
verticeStart + 4, verticeStart + 6, verticeStart + 2,
// Front
verticeStart + 5, verticeStart + 4, verticeStart + 6,
verticeStart + 5, verticeStart + 7, verticeStart + 6,
// Top
verticeStart + 7, verticeStart + 2, verticeStart + 6,
verticeStart + 7, verticeStart + 3, verticeStart + 2,
// Bottom
verticeStart + 1, verticeStart, verticeStart + 4,
verticeStart + 1, verticeStart + 4, verticeStart + 5
};
mesh->bufferPositions(verticeStart, positions, CUBE_VERTICE_COUNT);
mesh->bufferCoordinates(verticeStart, coordinates, CUBE_VERTICE_COUNT);
mesh->bufferIndices(indiceStart, indices, CUBE_INDICE_COUNT);
}

View File

@ -0,0 +1,30 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/mesh/Mesh.hpp"
#define CUBE_VERTICE_COUNT 8
#define CUBE_INDICE_COUNT 36
namespace Dawn {
class CubeMesh {
public:
/**
* Buffers cube mesh vertices and indices into the given mesh.
*
* @param size The size of the cube.
* @param verticeStart The starting index of the vertices.
* @param indiceStart The starting index of the indices.
*/
static void buffer(
const std::shared_ptr<Mesh> mesh,
const glm::vec3 pos,
const glm::vec3 size,
const int32_t verticeStart,
const int32_t indiceStart
);
};
}

View File

@ -0,0 +1,102 @@
// 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 {
enum MeshDrawMode {
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLE_FAN,
LINES,
POINTS
// LINE_STRIP,
};
class IMesh {
protected:
/** How many vertices are in the mesh */
int32_t verticeCount = -1;
/** How many indices are in the mesh */
int32_t indiceCount = -1;
public:
/**
* Create a new set of buffers for the mesh to use.
*
* @param verticeCount How many Vertices will this buffer support.
* @param indiceCount How many Indices will this buffer support.
*/
virtual void createBuffers(
const int32_t verticeCount,
const int32_t indiceCount
) = 0;
/**
* Cleanup the buffers on a given mesh. This is useful if you intend to
* expand the count of vertices your mesh supports.
*/
virtual void disposeBuffers() = 0;
/**
* Write vertice positions to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param vertices Array of positions to write.
* @param len How many positions are in the array.
*/
virtual void bufferPositions(
const int32_t pos,
const glm::vec3 positions[],
const int32_t len
) = 0;
/**
* Write vertice coordinates to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param coordinates Array of coordinates to write.
* @param len How many coordinates are in the array.
*/
virtual void bufferCoordinates(
const int32_t pos,
const glm::vec2 coordinates[],
const int32_t len
) = 0;
/**
* Write indices to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param indices Array of indices to write.
* @param len How many indices are in the array.
*/
virtual void bufferIndices(
const int32_t pos,
const int32_t indices[],
const int32_t len
) = 0;
/**
* Draw a primitive. Primitives are drawn by their indices.
*
* @param drawMode Which drawing mode to use to draw the primitive.
* @param start Start indice (index) to draw.
* @param count Count of indices to draw. Use -1 to draw all.
*/
virtual void draw(
const enum MeshDrawMode drawMode,
const int32_t start,
const int32_t count
) = 0;
/**
* Cleanup a previously initiated mesh.
*/
virtual ~IMesh() {
}
};
}

View File

@ -0,0 +1,72 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "QuadMesh.hpp"
using namespace Dawn;
void QuadMesh::buffer(
const std::shared_ptr<Mesh> mesh,
const glm::vec4 positions,
const glm::vec4 coordinates,
const int32_t verticeStart,
const int32_t indiceStart,
const float_t depth
) {
glm::vec3 vertices[QUAD_VERTICE_COUNT] = {
glm::vec3(positions.x, positions.y, depth),
glm::vec3(positions.z, positions.y, depth),
glm::vec3(positions.x, positions.w, depth),
glm::vec3(positions.z, positions.w, depth)
};
glm::vec2 coords[QUAD_VERTICE_COUNT] = {
glm::vec2(coordinates.x, coordinates.y),
glm::vec2(coordinates.z, coordinates.y),
glm::vec2(coordinates.x, coordinates.w),
glm::vec2(coordinates.z, coordinates.w)
};
int32_t indices[QUAD_INDICE_COUNT] = {
verticeStart, verticeStart + 1, verticeStart + 3,
verticeStart, verticeStart + 2, verticeStart + 3
};
mesh->bufferPositions(verticeStart, vertices, QUAD_VERTICE_COUNT);
mesh->bufferCoordinates(verticeStart, coords, QUAD_VERTICE_COUNT);
mesh->bufferIndices(indiceStart, indices, QUAD_INDICE_COUNT);
}
void QuadMesh::bufferWithIndex(
const std::shared_ptr<Mesh> mesh,
const glm::vec4 positions,
const glm::vec4 coordinates,
const int32_t verticeStart,
const int32_t indiceStart,
const int32_t indexOffset
) {
glm::vec3 vertices[QUAD_VERTICE_COUNT] = {
glm::vec3(positions.x, positions.y, indexOffset),
glm::vec3(positions.z, positions.y, indexOffset + 1),
glm::vec3(positions.x, positions.w, indexOffset + 2),
glm::vec3(positions.z, positions.w, indexOffset + 3)
};
glm::vec2 coords[QUAD_VERTICE_COUNT] = {
glm::vec2(coordinates.x, coordinates.y),
glm::vec2(coordinates.z, coordinates.y),
glm::vec2(coordinates.x, coordinates.w),
glm::vec2(coordinates.z, coordinates.w)
};
int32_t indices[QUAD_INDICE_COUNT] = {
verticeStart, verticeStart + 1, verticeStart + 3,
verticeStart, verticeStart + 2, verticeStart + 3
};
mesh->bufferPositions(verticeStart, vertices, QUAD_VERTICE_COUNT);
mesh->bufferCoordinates(verticeStart, coords, QUAD_VERTICE_COUNT);
mesh->bufferIndices(indiceStart, indices, QUAD_INDICE_COUNT);
}

View File

@ -0,0 +1,55 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/mesh/Mesh.hpp"
#define QUAD_VERTICE_COUNT 4
#define QUAD_INDICE_COUNT 6
namespace Dawn {
class QuadMesh {
public:
/**
* Buffers quad mesh vertices and indices into the given mesh.
*
* @param mesh The mesh to buffer into.
* @param positions The positions of the vertices.
* @param coordinates The coordinates of the vertices.
* @param verticeStart The starting index of the vertices.
* @param indiceStart The starting index of the indices.
* @param depth The depth of the vertices (Z coordinate).
*/
static void buffer(
const std::shared_ptr<Mesh> mesh,
const glm::vec4 positions,
const glm::vec4 coordinates,
const int32_t verticeStart,
const int32_t indiceStart,
const float_t depth = 0.0f
);
/**
* Buffers quad mesh vertices and indices into the given mesh. This will
* store the index of the vertice in the Z component, allowing you to find
* which vertex ID you are rendering in your shader.
*
* @param mesh The mesh to buffer into.
* @param positions The positions of the vertices.
* @param coordinates The coordinates of the vertices.
* @param verticeStart The starting index of the vertices.
* @param indiceStart The starting index of the indices.
* @param indexOffset The offset to add to the index of each vertex.
*/
static void bufferWithIndex(
const std::shared_ptr<Mesh> mesh,
const glm::vec4 positions,
const glm::vec4 coordinates,
const int32_t verticeStart,
const int32_t indiceStart,
const int32_t indexOffset = 0
);
};
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/mesh/Mesh.hpp"
namespace Dawn {
class IRenderPass {
public:
std::shared_ptr<Mesh> mesh;
/**
* Binds the shader for this render pass.
*/
virtual void bind() = 0;
/**
* Sets the data for this render pass to the shader.
*/
virtual void setData() = 0;
/**
* Uploads the data to the GPU.
*/
virtual void upload() = 0;
/**
* Draws the mesh for this render pass.
*/
virtual void draw() = 0;
/**
* Cleans up the render pass.
*/
virtual ~IRenderPass() {
}
};
}

View File

@ -0,0 +1,94 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "game/Game.hpp"
#include "display/pass/IRenderPass.hpp"
#include "display/shader/Shader.hpp"
#include "display/Texture.hpp"
#include "component/display/MeshRenderer.hpp"
namespace Dawn {
template<class S, typename D>
class RenderPass : public IRenderPass {
private:
std::shared_ptr<S> shader;
const std::unordered_map<
shadertexturebinding_t, std::shared_ptr<Texture>
> textures;
std::shared_ptr<Mesh> mesh;
const enum MeshDrawMode drawMode;
const int32_t indiceStart;
const int32_t indiceCount;
const D data;
public:
/**
* Constructs a new RenderPass.
*
* @param self Self component instance that is creating this render pass.
* @param d The data to use for this render pass.
* @param mesh The mesh to use for this render pass.
* @param drawMode The draw mode to use for this render pass.
* @param indiceStart The indice to start drawing from.
* @param indiceCount The number of indices to draw.
*/
RenderPass(
SceneComponent &self,
const D d,
const std::unordered_map<
shadertexturebinding_t, std::shared_ptr<Texture>
> textures,
const std::shared_ptr<Mesh> mesh,
const enum MeshDrawMode drawMode,
const int32_t indiceStart,
const int32_t indiceCount
) :
data(d),
textures(textures),
mesh(mesh),
drawMode(drawMode),
indiceStart(indiceStart),
indiceCount(indiceCount)
{
//Get the shader
shader = (
self.getGame()->renderHost.shaderManager.getShader<S>()
);
assertNotNull(shader, "Shader cannot be null!");
// Need mesh?
if(!this->mesh) {
auto meshRenderer = self.getItem()->getComponent<MeshRenderer>();
if(meshRenderer) this->mesh = meshRenderer->mesh;
}
}
void bind() override {
shader->bind();
}
void setData() override {
shader->setData(data);
}
void upload() override {
for(auto &pair : textures) {
if(!pair.second->isReady()) continue;
pair.second->bind(pair.first);
}
shader->upload();
}
void draw() override {
if(mesh) {
mesh->draw(drawMode, indiceStart, indiceCount);
}
}
~RenderPass() override {
}
};
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "game/Game.hpp"
#include "scene/Scene.hpp"
#include "component/display/Camera.hpp"
namespace Dawn {
struct RenderPassContext {
std::shared_ptr<Game> game;
std::shared_ptr<Scene> scene;
std::shared_ptr<Camera> camera;
std::shared_ptr<RenderTarget> renderTarget;
};
}

View File

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

View File

@ -0,0 +1,46 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "display/shader/Shader.hpp"
#include "error/assert.hpp"
#include "display/Color.hpp"
#include "display/Texture.hpp"
using namespace Dawn;
size_t shaderParameterTypeGetSize(const enum ShaderParameterType type) {
switch(type) {
case ShaderParameterType::VEC2:
return sizeof(glm::vec2);
case ShaderParameterType::VEC3:
return sizeof(glm::vec3);
case ShaderParameterType::VEC4:
return sizeof(glm::vec4);
case ShaderParameterType::MAT3:
return sizeof(glm::mat3);
case ShaderParameterType::MAT4:
return sizeof(glm::mat4);
case ShaderParameterType::COLOR:
return sizeof(struct Color);
case ShaderParameterType::FLOAT:
return sizeof(float);
case ShaderParameterType::INT:
return sizeof(int32_t);
case ShaderParameterType::TEXTURE:
return sizeof(shadertexturebinding_t);
default:
assertUnreachable("Unknown ShaderParameterType");
return 0;
}
}

View File

@ -0,0 +1,86 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
enum class ShaderParameterType {
VEC2,
VEC3,
VEC4,
MAT3,
MAT4,
COLOR,
FLOAT,
INT,
TEXTURE,
BOOLEAN
};
class IShaderBase {
public:
virtual ~IShaderBase() {
}
};
template<typename T>
class IShader : public IShaderBase {
protected:
T data;
public:
/**
* Returns the currently uploaded data on the Shader.
*
* @return The uploaded data.
*/
T getData() {
return data;
}
/**
* Sets the entire data to be uploaded.
*
* @param data Data to be uploaded.
*/
void setData(const T data) {
this->data = data;
}
/**
* Initializes the shader, this needs to be called before the shader can
* be used.
*/
virtual void init() = 0;
/**
* Binds the shader as the current one, does not upload any data, somewhat
* relies on something else uploading the data.
*/
virtual void bind() = 0;
/**
* Uploads the data to the GPU.
*/
virtual void upload() = 0;
/**
* Disposes of the shader.
*/
virtual ~IShader() {
}
};
}
/**
* Returns the size of the ShaderParameterType.
*
* @param type The type to get the size of.
* @return Size of the type.
*/
size_t shaderParameterTypeGetSize(const enum Dawn::ShaderParameterType type);

View File

@ -0,0 +1,18 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "IShaderStage.hpp"
using namespace Dawn;
IShaderStage::IShaderStage(const enum ShaderStageType type) :
type(type)
{
}
IShaderStage::~IShaderStage() {
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
enum class ShaderStageType {
VERTEX,
FRAGMENT,
// COMPUTE
};
class IShaderStage {
public:
const enum ShaderStageType type;
/**
* Constructs a new Shader Stage.
*
* @param type Type of shader stage.
*/
IShaderStage(const enum ShaderStageType type);
/**
* Destroy the IShaderStage object
*/
virtual ~IShaderStage();
};
}

View File

@ -0,0 +1,45 @@
// 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 {
class ShaderManager {
private:
std::vector<std::shared_ptr<IShaderBase>> shaders;
public:
/**
* Retreives an instance of the shader from the shader manager. If the
* shader does not exist it will be created.
*
* @tparam T Type of shader to retreive.
* @return Shader instance.
*/
template<class T>
std::shared_ptr<T> getShader() {
auto itShaders = shaders.begin();
while(itShaders != shaders.end()) {
// auto shader = itShaders->lock();
// if(!shader) {
// itShaders = shaders.erase(itShaders);
// continue;
// }
// std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(shader);
auto shader = *itShaders;
std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(shader);
if(casted) return casted;
itShaders++;
}
auto newShader = std::make_shared<T>();
shaders.push_back(newShader);
newShader->init();
return newShader;
}
};
}

View File

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

View File

@ -5,12 +5,21 @@
#include "assert.hpp"
void assertTrue(bool condition, const char_t *message, ...) {
if (!condition) {
void assertTrueImplement(
const char *file,
const int32_t line,
const char *func,
const bool_t result,
const char *message,
...
) {
if(!result) {
va_list args;
va_start(args, message);
fprintf(stderr, "Assertion failed in %s:%d (%s): ", file, line, func);
vfprintf(stderr, message, args);
fprintf(stderr, "\n");
va_end(args);
exit(EXIT_FAILURE);
exit(1);
}
}

View File

@ -1,17 +1,115 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.hpp"
/**
* Asserts a statement to be true, if not true a failed assertion is thrown
* and a program halt is requested.
* Asserts that a given statement must evaluate to true or the assertion fails
* and the game will close semi-gracefully.
*
* @param condition The condition to assert.
* @param message Message to display if assertion is false.
* @param ...args Arguments to format the message with. (Sprintf)
* @param file String filename of the file that has the assertion.
* @param line Integer line number within the file that the assertion is on.
* @param func Called function that has the assertion.
* @param result The statement that must equate to true.
* @param message Message (sprintf format) to send to the stdout.
* @param ... Varargs of the sprintf arguments.
*/
static void assertTrue(bool condition, const char_t *message, ...);
void assertTrueImplement(
const char *file,
const int32_t line,
const char *func,
const bool_t result,
const char *message,
...
);
/**
* Asserts that a statement must be true in order for the assertion to not cause
* an error. Basically this is a throw statement in disguise.
*
* @param statement Statement of the assertion.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertTrue(...) assertTrueImplement( \
__FILE__, __LINE__, __func__, __VA_ARGS__ \
)
/**
* Asserts that a statement must be false in order for the assertion to not
* cause an error.
*
* @param statement Statement of the assertion.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertFalse(x, ...) assertTrue(!(x), __VA_ARGS__)
/**
* Asserts that a specified piece of code should be entirely unreachable.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertUnreachable(...) assertTrue(false, __VA_ARGS__)
/**
* Asserts that a given pointer is not null.
* @param x Pointer to check.
* @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__)
/**
* Asserts that a given pointer is null.
* @param x Pointer to check.
* @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 value has a specific flag turned off.
*
* @param value Value to check.
* @param flag Flag 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 assertFlagOff(value, flag, ...) assertTrue( \
(value & flag) == 0, __VA_ARGS__ \
)
/**
* Asserts that a given value has a specific flag turned on.
*
* @param value Value to check.
* @param flag Flag 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 assertFlagOn(value, flag, ...) assertTrue( \
(value & flag) == flag, __VA_ARGS__ \
)
/**
* Asserts that the current code is deprecated and should not be used anymore.
* @deprecated
*/
#define assertDeprecated(...) assertUnreachable(__VA_ARGS__)

22
src/dawn/error/error.hpp Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
/**
* Shows an error message box on the host device. This method should be blocking
* and should not return until the user has acknowledged the error.
*
* @param message Message to display.
*/
void errorMessageBox(const std::u8string &message);
/**
* Logs an error message to the host device.
*
* @param message Message to log.
*/
void errorLog(const std::string &message);

View File

@ -0,0 +1,141 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
namespace Dawn {
enum class CustomEventResult {
NOTHING,
REMOVE,
INVOKE,
INVOKE_AND_REMOVE
};
template<
typename InternalData,
typename InternalListenerData,
typename ListenerArgument,
typename ...InvokeArgs
>
class CustomEvent {
private:
int32_t nextId = 0;
std::unordered_map<
int32_t,
std::pair<InternalListenerData, std::function<void(InvokeArgs...)>>
> listeners;
protected:
InternalData internalData;
/**
* Custom event filter. Decides whether or not the event should be emitted
* to the listener.
*
* @param listenerData Data for this listener.
* @param args The arguments to pass to the listeners.
* @return The result of the filter.
*/
virtual enum CustomEventResult shouldEmit(
const InternalListenerData &listenerData,
const InvokeArgs... args
) = 0;
/**
* Transform the arguments for listener data when the listener is first
* subscribed.
*
* @param argument The argument to transform.
* @return The transformed argument into an internal data format.
*/
virtual InternalListenerData transformData(
const ListenerArgument &argument
) = 0;
/**
* Transform the data for listener data after the event has been emitted.
*
* @param internalData The internal data to transform.
* @return Updated/Transformed internal data.
*/
virtual InternalListenerData transformDataAfterEmit(
const InternalListenerData &internalData
) {
return internalData;
}
public:
/**
* Emits the event.
* @param args The arguments to pass to the listeners.
*/
void emit(InvokeArgs... args) {
auto copy = listeners;
for(auto &pair : copy) {
// Check emit test.
auto result = this->shouldEmit(
pair.second.first,
args...
);
if(
result == CustomEventResult::INVOKE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
pair.second.second(args...);
}
if(
result == CustomEventResult::REMOVE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
listeners.erase(pair.first);
continue;
}
if(
result == CustomEventResult::INVOKE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
// Update the internal data.
listeners[pair.first].first = transformDataAfterEmit(
pair.second.first
);
}
}
}
/**
* Listens to the event.
*
* @param data Listener data to use.
* @param listener The listener to add.
* @returns A function that can be called to remove the listener.
*/
std::function<void()> listen(
const ListenerArgument &data,
const std::function<void(InvokeArgs...)> listener
) {
int32_t id = nextId++;
auto pair = std::make_pair(
transformData(data),
listener
);
listeners[id] = pair;
return [this, id]() {
listeners.erase(id);
};
}
/**
* Destroys the custom event.
*/
virtual ~CustomEvent() {
listeners.clear();
}
};
}

57
src/dawn/event/Event.hpp Normal file
View File

@ -0,0 +1,57 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
template<typename ...A>
class Event {
private:
int32_t nextId = 0;
std::map<int32_t, std::function<void(A...)>> listeners;
public:
/**
* Constructs a new Event.
*/
Event() {
}
/**
* Emits the event.
* @param args The arguments to pass to the listeners.
*/
void emit(A ...args) {
auto copy = listeners;
for(auto &pair : copy) {
pair.second(args...);
}
}
/**
* Listens to the event.
* @param listener The listener to add.
* @returns A function that can be called to remove the listener.
*/
std::function<void()> listen(
const std::function<void(A...)> listener
) {
int32_t id = nextId++;
listeners[id] = listener;
return [this, id]() {
listeners.erase(id);
};
}
/**
* Destroys the event.
*/
virtual ~Event() {
listeners.clear();
}
};
}

View File

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

34
src/dawn/game/Game.cpp Normal file
View File

@ -0,0 +1,34 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Game.hpp"
using namespace Dawn;
Game::Game() :
renderManager()
{
}
std::shared_ptr<Scene> Game::getCurrentScene() {
return currentScene;
}
void Game::setCurrentScene(std::shared_ptr<Scene> scene) {
currentScene = scene;
}
void Game::init() {
renderManager.init(*this);
}
void Game::update() {
renderManager.update(*this);
}
Game::~Game() {
}

View File

@ -5,10 +5,18 @@
#pragma once
#include "dawn.hpp"
#include "display/RenderManager.hpp"
namespace Dawn {
class Game {
class Scene;
class Game : std::enable_shared_from_this<Game> {
private:
std::shared_ptr<Scene> currentScene;
public:
RenderManager renderManager;
/**
* Constructs a new instance of Game, the class majorily responsible for
* handling all internal dawn functions outside of platform-centric things
@ -16,6 +24,30 @@ namespace Dawn {
*/
Game();
/**
* Gets the current scene.
*
* @return The current scene.
*/
std::shared_ptr<Scene> getCurrentScene();
/**
* Sets the current scene to the provided scene.
*
* @param scene The scene to set as the current scene.
*/
void setCurrentScene(std::shared_ptr<Scene> scene);
/**
* Initializes the game and all sub managers used by game.
*/
void init();
/**
* Updates the game and all sub managers used by game.
*/
void update();
/**
* Deloads game and all sub managers used by game.
*/

View File

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

View File

@ -0,0 +1,15 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Language.hpp"
using namespace Dawn;
std::u8string Language::get(
const char_t key[],
const std::pair<std::string, std::u8string> &args
) {
return u8"Some language string 👍";
}

View File

@ -0,0 +1,24 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class Language {
public:
/**
* Gets a language string from the language definition set.
*
* @param key The key to look up in the language file.
* @param args A pair of strings to replace in the language string.
* @return The language string.
*/
static std::u8string get(
const char_t key[],
const std::pair<std::string, std::u8string> &args = std::make_pair("", u8"")
);
};
}

View File

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

16
src/dawn/scene/Scene.cpp Normal file
View File

@ -0,0 +1,16 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Scene.hpp"
using namespace Dawn;
Scene::Scene() {
}
Scene::~Scene() {
}

22
src/dawn/scene/Scene.hpp Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class Scene {
public:
/**
* Scene Constructor.
*/
Scene();
/**
* Scene Destructor.
*/
~Scene();
};
}

View File

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

35
src/dawn/util/string.cpp Normal file
View File

@ -0,0 +1,35 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "string.hpp"
bool_t stringIncludes(
const std::string &haystack,
const std::string &needle
) {
return haystack.find(needle) != std::string::npos;
}
std::string stringToLowercase(const std::string &str) {
std::string lower = str;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
return lower;
}
std::vector<std::string> stringSplit(
const std::string &str,
const std::string &delim
) {
std::vector<std::string> parts;
size_t start = 0;
size_t end = str.find(delim);
while(end != std::string::npos) {
parts.push_back(str.substr(start, end - start));
start = end + delim.length();
end = str.find(delim, start);
}
parts.push_back(str.substr(start, end));
return parts;
}

36
src/dawn/util/string.hpp Normal file
View File

@ -0,0 +1,36 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
/**
* Returns true if the haystack string includes the needle string.
* @param haystack The string to search in.
* @param needle The string to search for.
* @return True if the needle is found in the haystack.
*/
bool_t stringIncludes(
const std::string &haystack,
const std::string &needle
);
/**
* Converts a string to lowercase.
* @param str The string to convert.
* @return The lowercase version of the string.
*/
std::string stringToLowercase(const std::string &str);
/**
* Splits a string by a delimiter.
* @param str The string to split.
* @param delim The delimiter to split by.
* @return A vector of strings split by the delimiter.
*/
std::vector<std::string> stringSplit(
const std::string &str,
const std::string &delim
);

View File

@ -9,6 +9,7 @@ target_link_libraries(${DAWN_TARGET_NAME}
glfw
glad
archive_static
Boxer
)
# Includes
@ -24,4 +25,6 @@ target_sources(${DAWN_TARGET_NAME}
# input.c
)
# Subdirs
# Subdirs
add_subdirectory(error)
add_subdirectory(host)

View File

@ -0,0 +1,7 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include <glad/glad.h>

View File

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

View File

@ -0,0 +1,27 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "error/error.hpp"
#include <boxer/boxer.h>
void errorMessageBox(const std::u8string &message) {
std::string titleStr = DAWN_GAME_NAME;
std::string messageStr = (
message.length() > 0 ?
std::string(message.cbegin(), message.cend()) :
std::string()
);
boxer::show(
messageStr.c_str(),
titleStr.c_str(),
boxer::Style::Error,
boxer::Buttons::Quit
);
}
void errorLog(const std::string &message) {
std::cerr << message << std::endl;
}

View File

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

View File

@ -0,0 +1,150 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "DawnGLFWHost.hpp"
#include "error/error.hpp"
#include "locale/Language.hpp"
#include "error/erroropengl.hpp"
using namespace Dawn;
DawnGLFWHost::DawnGLFWHost() {
}
DawnGLFWInitResult DawnGLFWHost::init(
const int32_t argc, const char_t **argv
) {
if(!glfwInit()) {
errorLog("GLFW failed to initialize.");
errorMessageBox(Language::get("glfw.error.glfw_init"));
return DawnGLFWInitResult::GLFW_INIT_FAILED;
}
// Setup window hints
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, false);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
// Create window
this->window = glfwCreateWindow(
DAWN_GLFW_WIDTH_DEFAULT,
DAWN_GLFW_HEIGHT_DEFAULT,
DAWN_GAME_NAME,
NULL,
NULL
);
if(this->window == nullptr) {
errorLog("GLFW failed to create window.");
errorMessageBox(Language::get("glfw.error.window_create"));
glfwTerminate();
return DawnGLFWInitResult::WINDOW_CREATE_FAILED;
}
// Set back pointer
glfwSetWindowUserPointer(this->window, this);
// Load GLAD
glfwMakeContextCurrent(this->window);
glfwSwapInterval(1);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
try {
errorCheckOpenGL();
} catch(const std::runtime_error &e) {
errorLog(e.what());
errorMessageBox(Language::get("glfw.error.opengl_error"));
glfwTerminate();
return DawnGLFWInitResult::GLAD_GL_CHECK_FAILED;
}
// Override the defaults
int32_t fbWidth, fbHeight;
glfwGetFramebufferSize(this->window, &fbWidth, &fbHeight);
glfwGetWindowSize(this->window, &this->windowWidth, &this->windowHeight);
try {
errorCheckOpenGL();
} catch(const std::runtime_error &e) {
errorLog(e.what());
errorMessageBox(Language::get("glfw.error.opengl_error"));
glfwTerminate();
return DawnGLFWInitResult::GLAD_GL_CHECK_FAILED;
}
if(
fbWidth == 0 ||
fbHeight == 0 ||
this->windowWidth == 0 ||
this->windowHeight == 0
) {
errorLog(
"GLFW Returned incorrect size: " +
std::to_string(fbWidth) + "x" + std::to_string(fbHeight) + " / " +
std::to_string(windowWidth) + "x" + std::to_string(windowHeight)
);
errorMessageBox(Language::get("glfw.error.viewport_size"));
glfwTerminate();
return DawnGLFWInitResult::VIEWPORT_SIZE_FAILED;
}
// Init Game
this->game = std::make_shared<Game>();
this->game->init();
auto backBuffer = this->game->renderManager.getBackBufferRenderTarget();
backBuffer->setSize((float_t)fbWidth, (float_t)fbHeight);
// Set up callbacks
glfwSetFramebufferSizeCallback(this->window, [](
GLFWwindow *window,
int32_t width,
int32_t height
) {
auto host = (DawnGLFWHost*)glfwGetWindowUserPointer(window);
if(host == nullptr) return;
host->windowWidth = width;
host->windowHeight = height;
auto backBuffer = host->game->renderManager.getBackBufferRenderTarget();
backBuffer->setSize((float_t)width, (float_t)height);
});
return DawnGLFWInitResult::SUCCESS;
}
void DawnGLFWHost::start() {
double_t time, newTime;
float_t fDelta;
int32_t updateResult;
// Main Render Loop
time = 0.0f;
while(!glfwWindowShouldClose(this->window)) {
// Determine the delta.
newTime = glfwGetTime();
fDelta = (float_t)(newTime - time);
time = newTime;
// Update the game
this->game->update();
// Update GLFW
glfwSwapBuffers(this->window);
glfwPollEvents();
}
this->game = nullptr;
}
DawnGLFWHost::~DawnGLFWHost() {
this->game = nullptr;
// Terminate GLFW
if(this->window != nullptr) {
glfwDestroyWindow(this->window);
glfwTerminate();
}
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnopengl.hpp"
#include "dawn.hpp"
#include <GLFW/glfw3.h>
#include "game/Game.hpp"
#define DAWN_GLFW_WIDTH_DEFAULT 800
#define DAWN_GLFW_HEIGHT_DEFAULT 600
namespace Dawn {
enum class DawnGLFWInitResult {
SUCCESS = 0,
GLFW_INIT_FAILED = 1,
WINDOW_CREATE_FAILED = 2,
GLAD_GL_CHECK_FAILED = 3,
VIEWPORT_SIZE_FAILED = 4
};
class DawnGLFWHost {
private:
GLFWwindow *window;
int32_t windowWidth, windowHeight;
std::shared_ptr<Game> game;
public:
/**
* Creates a new GLFW Host.
*/
DawnGLFWHost();
/**
* Initializes the GLFW Host.
*
* @param argc The number of arguments.
* @param argv The arguments.
*/
DawnGLFWInitResult init(const int32_t argc, const char_t **argv);
/**
* Starts the GLFW Host, called after the GLFW Host has been initialized.
*/
void start();
/**
* Destroys the GLFW Host.
*/
~DawnGLFWHost();
};
}

View File

@ -6,8 +6,14 @@
*/
#include "main.hpp"
#include "host/DawnGLFWHost.hpp"
using namespace Dawn;
int32_t main(const int32_t argc, const char_t **argv) {
std::shared_ptr<DawnGLFWHost> host = std::make_shared<DawnGLFWHost>();
host->init(argc, argv);
host->start();
int32_t main(int32_t argc, char_t **argv) {
std::cout << "Hello C++" << std::endl;
return 0;
}

View File

@ -15,4 +15,4 @@
* @param argv The arguments passed to the program.
* @return The exit code of the program.
*/
int32_t main(int32_t argc, char_t **argv);
int32_t main(const int32_t argc, const char_t **argv);

View File

@ -10,5 +10,5 @@ target_include_directories(${DAWN_TARGET_NAME}
)
# Subdirs
# add_subdirectory(assert)
# add_subdirectory(display)
add_subdirectory(error)
add_subdirectory(display)

View File

@ -0,0 +1,68 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "dawnopengl.hpp"
#include "error/assert.hpp"
#include "error/assertgl.hpp"
#include "BackBuffer.hpp"
using namespace Dawn;
BackBuffer::BackBuffer() {
}
float_t BackBuffer::getScale() {
return this->scale;
}
float_t BackBuffer::getWidth() {
return this->width;
}
float_t BackBuffer::getHeight() {
return this->height;
}
void BackBuffer::setSize(
const float_t width,
const float_t height
) {
if(this->width == width && this->height == height) return;
// Fixes a new bug that it seems GLFW has introduced.
this->width = width == 0 ? 1 : width;
this->height = height == 0 ? 1 : height;
onResize.emit(this->width, this->height);
}
void BackBuffer::setClearColor(const struct Color color) {
this->clearColor = color;
}
void BackBuffer::clear(const int32_t clearFlags) {
glClearColor(clearColor.r, clearColor.g, clearColor.b, 1.0f);
assertNoGLError();
GLbitfield mask = 0;
if((clearFlags & RENDER_TARGET_CLEAR_COLOR) == RENDER_TARGET_CLEAR_COLOR) {
mask |= GL_COLOR_BUFFER_BIT;
}
if((clearFlags & RENDER_TARGET_CLEAR_DEPTH) == RENDER_TARGET_CLEAR_DEPTH) {
mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(mask);
assertNoGLError();
}
void BackBuffer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
assertNoGLError();
glViewport(0, 0, (GLsizei)this->width, (GLsizei)this->height);
assertNoGLError();
}

View File

@ -0,0 +1,44 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/Color.hpp"
#include "display/RenderTarget.hpp"
namespace Dawn {
class BackBuffer final : public RenderTarget {
private:
float_t width = 1;
float_t height = 1;
struct Color clearColor = COLOR_CORNFLOWER_BLUE;
public:
float_t scale = 1.0f;
/**
* Construct the back buffer render target.
*/
BackBuffer();
float_t getScale() override;
float_t getWidth() override;
float_t getHeight() override;
void setClearColor(const struct Color color) override;
void clear(const int32_t) override;
void bind() override;
/**
* Requests to modify the viewport directly. This is mostly to be called
* by whatever is setting the window/display resolution, so that the
* backbuffer can keep track of what the viewport size is. This should
* also be DPI aware, e.g. "4k @ 2xDPI, resulting in a 1080p equiv" should
* still call this method with 3840, 2160.
*
* @param width New width of the back buffer.
* @param height New height of the back buffer.
*/
void setSize(const float_t width, const float_t height);
};
}

View File

@ -0,0 +1,15 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
BackBuffer.cpp
Texture.cpp
)
# Subdirs
add_subdirectory(mesh)
add_subdirectory(shader)

View File

@ -0,0 +1,213 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "error/assert.hpp"
#include "error/assertgl.hpp"
#include "Texture.hpp"
using namespace Dawn;
void Texture::bind(const uint8_t slot) {
assertTrue(this->id != -1, "Texture is not ready!");
glActiveTexture(GL_TEXTURE0 + slot);
assertNoGLError();
glBindTexture(GL_TEXTURE_2D, this->id);
assertNoGLError();
this->updateTextureProperties();
}
int32_t Texture::getWidth() {
return this->width;
}
int32_t Texture::getHeight() {
return this->height;
}
bool_t Texture::isReady() {
return this->id != -1;
}
void Texture::setSize(
const int32_t width,
const int32_t height,
const enum TextureFormat format,
const enum TextureDataFormat dataFormat
) {
if(this->id != -1) {
glDeleteTextures(1, &this->id);
assertNoGLError();
this->id = -1;
}
int32_t maxSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
assertTrue(width > 0 && width <= maxSize, "Width is out of bounds!");
assertTrue(height > 0 && height <= maxSize, "Height is out of bounds!");
this->width = width;
this->height = height;
this->format = format;
this->dataFormat = dataFormat;
glGenTextures(1, &this->id);
assertNoGLError();
if(this->id <= 0) assertUnreachable("Texture generation failed!");
// Initialize the texture to blank
glActiveTexture(GL_TEXTURE0);
assertNoGLError();
this->bufferRaw(NULL);
}
// bool_t Texture::isReady() {
// return this->id != -1;
// }
void Texture::updateTextureProperties() {
auto setWrapMode = [](GLenum axis, enum TextureWrapMode wm) {
switch(wm) {
case TextureWrapMode::REPEAT:
glTexParameteri(GL_TEXTURE_2D, axis, GL_REPEAT);
break;
case TextureWrapMode::MIRRORED_REPEAT:
glTexParameteri(GL_TEXTURE_2D, axis, GL_MIRRORED_REPEAT);
break;
case TextureWrapMode::CLAMP_TO_EDGE:
glTexParameteri(GL_TEXTURE_2D, axis, GL_CLAMP_TO_EDGE);
break;
case TextureWrapMode::CLAMP_TO_BORDER:
glTexParameteri(GL_TEXTURE_2D, axis, GL_CLAMP_TO_BORDER);
break;
default:
assertUnreachable("Unknown wrap mode!");
}
assertNoGLError();
};
setWrapMode(GL_TEXTURE_WRAP_S, this->wrapModeX);
setWrapMode(GL_TEXTURE_WRAP_T, this->wrapModeY);
auto setFilterMode = [](
GLenum minMag,
enum TextureFilterMode filter,
enum TextureFilterMode mapFilterMode
) {
switch(filter) {
case TextureFilterMode::NEAREST: {
glTexParameteri(GL_TEXTURE_2D, minMag, GL_NEAREST);
break;
}
case TextureFilterMode::LINEAR: {
glTexParameteri(GL_TEXTURE_2D, minMag, GL_LINEAR);
break;
}
default: {
assertUnreachable("Unknown filter mode!");
}
}
assertNoGLError();
};
setFilterMode(
GL_TEXTURE_MIN_FILTER, this->filterModeMin, this->mipMapFilterModeMin
);
setFilterMode(
GL_TEXTURE_MAG_FILTER, this->filterModeMag, this->mipMapFilterModeMag
);
}
void Texture::bufferRaw(const void *data) {
assertTrue(this->id != -1, "Texture is not ready!");
GLenum format;
switch(this->format) {
case TextureFormat::R:
format = GL_RED;
break;
case TextureFormat::RG:
format = GL_RG;
break;
case TextureFormat::RGB:
format = GL_RGB;
break;
case TextureFormat::RGBA:
format = GL_RGBA;
break;
default:
assertUnreachable("Unknown texture format!");
}
GLenum dataFormat;
switch(this->dataFormat) {
case TextureDataFormat::UNSIGNED_BYTE:
dataFormat = GL_UNSIGNED_BYTE;
break;
case TextureDataFormat::FLOAT:
dataFormat = GL_FLOAT;
break;
default:
assertUnreachable("Unknown texture data format!");
}
glBindTexture(GL_TEXTURE_2D, this->id);
assertNoGLError();
glTexImage2D(
GL_TEXTURE_2D, 0, format,
this->width, this->height,
0, format, dataFormat, data
);
assertNoGLError();
glGenerateMipmap(GL_TEXTURE_2D);
assertNoGLError();
}
void Texture::buffer(const struct ColorU8 pixels[]) {
assertTrue(
this->dataFormat == TextureDataFormat::UNSIGNED_BYTE,
"Texture data format must be unsigned byte!"
);
this->bufferRaw((void*)pixels);
}
void Texture::buffer(const struct Color pixels[]) {
std::cout << "Correct buffer" << std::endl;
assertTrue(
this->dataFormat == TextureDataFormat::FLOAT,
"Texture data format must be float!"
);
assertTrue(
this->format == TextureFormat::RGBA,
"Texture format must be RGBA!"
);
this->bufferRaw((void*)pixels);
}
void Texture::buffer(const uint8_t pixels[]) {
assertTrue(
this->dataFormat == TextureDataFormat::UNSIGNED_BYTE,
"Texture data format must be unsigned byte!"
);
this->bufferRaw((void*)pixels);
}
Texture::~Texture() {
if(this->id != -1) {
glDeleteTextures(1, &this->id);
assertNoGLError();
}
}

View File

@ -0,0 +1,43 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnopengl.hpp"
#include "display/ITexture.hpp"
namespace Dawn {
class TextureRenderTarget;
typedef GLuint textureslot_t;
class Texture : public ITexture {
private:
int32_t width = -1;
int32_t height = -1;
GLuint id = -1;
enum TextureFormat format;
enum TextureDataFormat dataFormat;
void updateTextureProperties();
void bufferRaw(const void *data);
public:
int32_t getWidth() override;
int32_t getHeight() override;
void setSize(
const int32_t width,
const int32_t height,
const enum TextureFormat format,
const enum TextureDataFormat dataForat
) override;
bool_t isReady() override;
void buffer(const struct ColorU8 pixels[]) override;
void buffer(const struct Color pixels[]);
void buffer(const uint8_t pixels[]) override;
void bind(const uint8_t slot) override;
~Texture();
};
}

View File

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

View File

@ -0,0 +1,257 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "error/assert.hpp"
#include "error/assertgl.hpp"
#include "display/mesh/Mesh.hpp"
using namespace Dawn;
void Mesh::createBuffers(
const int32_t verticeCount,
const int32_t indiceCount
) {
assertTrue(verticeCount > 0, "Vertice count must be greater than zero.");
assertTrue(indiceCount > 0, "Indice count must be greater than zero.");
// Can we re-use the buffers?
if(
verticeCount <= this->verticeCount &&
indiceCount <= this->indiceCount
) return;
this->disposeBuffers();
this->verticeCount = verticeCount;
this->indiceCount = indiceCount;
auto sizePos = sizeof(glm::vec3) * verticeCount;
auto sizeInds = sizeof(int32_t) * indiceCount;
auto sizeCoords = sizeof(glm::vec2) * verticeCount;
// Generate vertex array, I don't think I need to do this tbh.
glGenVertexArrays(1, &this->vertexArray);
assertNoGLError();
glBindVertexArray(this->vertexArray);
assertNoGLError();
// Create some buffers, one for the vertex data, one for the indices
GLuint buffer[2];
glGenBuffers(2, buffer);
assertNoGLError();
this->vertexBuffer = buffer[0];
if(this->vertexBuffer < 0) assertUnreachable("Can't make vertex buffer");
this->indexBuffer = buffer[1];
if(this->indexBuffer < 0) assertUnreachable("Can't make index buffer");
// Buffer an empty set of data then buffer each component
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer);
assertNoGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuffer);
assertNoGLError();
glBufferData(GL_ARRAY_BUFFER, sizePos+sizeCoords, 0, GL_DYNAMIC_DRAW);
assertNoGLError();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeInds, 0, GL_DYNAMIC_DRAW);
assertNoGLError();
// Setup the attrib pointers
size_t offset = 0;
glVertexAttribPointer(
0, sizeof(glm::vec3) / sizeof(float_t),
GL_FLOAT, GL_FALSE,
0, (void *)offset
);
assertNoGLError();
glEnableVertexAttribArray(0);
assertNoGLError();
offset += sizePos;
glVertexAttribPointer(
1, sizeof(glm::vec2) / sizeof(float_t),
GL_FLOAT, GL_FALSE,
0, (void *)offset
);
assertNoGLError();
glEnableVertexAttribArray(1);
assertNoGLError();
}
void Mesh::disposeBuffers() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
assertNoGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
assertNoGLError();
if(this->vertexBuffer != -1) {
glDeleteBuffers(1, &this->vertexBuffer);
assertNoGLError();
this->vertexBuffer = -1;
this->verticeCount = -1;
}
if(this->indexBuffer != -1) {
glDeleteBuffers(1, &this->indexBuffer);
assertNoGLError();
this->indexBuffer = -1;
this->indiceCount = -1;
}
if(this->vertexArray) {
glDeleteVertexArrays(1, &this->vertexArray);
assertNoGLError();
this->vertexArray = -1;
}
}
void Mesh::bufferPositions(
const int32_t pos,
const glm::vec3 positions[],
const int32_t len
) {
assertNotNull(positions, "Positions cannot be null");
assertTrue(pos >= 0 && pos < verticeCount, "Position must be within range");
assertTrue(pos+len <= verticeCount, "Position + Length must be within range");
assertTrue(len > 0, "Length must be greater than zero");
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
assertNoGLError();
glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(glm::vec3) * pos,
sizeof(glm::vec3) * len,
(void*)positions
);
assertNoGLError();
}
void Mesh::bufferCoordinates(
const int32_t pos,
const glm::vec2 coordinates[],
const int32_t len
) {
assertNotNull(coordinates, "Coordinates cannot be null");
assertTrue(pos >= 0 && pos < verticeCount, "Position must be within range");
assertTrue(pos+len <= verticeCount, "Position + Length must be within range");
assertTrue(len > 0, "Length must be greater than zero");
auto offsetCoordinates = (
(sizeof(glm::vec3) * this->verticeCount) +
(sizeof(glm::vec2) * pos)
);
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer);
assertNoGLError();
glBufferSubData(
GL_ARRAY_BUFFER,
offsetCoordinates,
sizeof(glm::vec2) * len,
(void*)coordinates
);
assertNoGLError();
}
void Mesh::bufferIndices(
const int32_t pos,
const int32_t indices[],
const int32_t len
) {
assertNotNull(indices, "Indices cannot be null");
assertTrue(pos >= 0 && pos < indiceCount, "Position must be within range");
assertTrue(pos+len <= indiceCount, "Position + Length must be within range");
assertTrue(len > 0, "Length must be greater than zero");
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
assertNoGLError();
glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(int32_t) * pos,
sizeof(int32_t) * len,
(void*)indices
);
assertNoGLError();
}
void Mesh::draw(
const enum MeshDrawMode drawMode,
const int32_t start,
const int32_t count
) {
if(
count == 0 ||
this->vertexBuffer == -1 ||
this->indexBuffer == -1
) return;
int32_t drawCount = count;
if(count == -1) drawCount = this->indiceCount;
// Re-Bind the buffers
glBindVertexArray(this->vertexArray);
assertNoGLError();
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuffer);
assertNoGLError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuffer);
assertNoGLError();
// Re-Calculate the attrib pointers.
size_t offset = 0;
glVertexAttribPointer(
0, sizeof(glm::vec3) / sizeof(float_t),
GL_FLOAT, GL_FALSE,
0, (void *)offset
);
assertNoGLError();
glEnableVertexAttribArray(0);
assertNoGLError();
offset += sizeof(glm::vec3) * this->verticeCount;
glVertexAttribPointer(
1, sizeof(glm::vec2) / sizeof(float_t),
GL_FLOAT, GL_FALSE,
0, (void *)offset
);
assertNoGLError();
glEnableVertexAttribArray(1);
assertNoGLError();
GLuint glDrawMode;
switch(drawMode) {
case MeshDrawMode::TRIANGLES:
glDrawMode = GL_TRIANGLES;
break;
case MeshDrawMode::TRIANGLE_STRIP:
glDrawMode = GL_TRIANGLE_STRIP;
break;
case MeshDrawMode::TRIANGLE_FAN:
glDrawMode = GL_TRIANGLE_FAN;
break;
case MeshDrawMode::LINES:
glDrawMode = GL_LINES;
break;
case MeshDrawMode::POINTS:
glDrawMode = GL_POINTS;
break;
default:
assertUnreachable("Unsupported draw mode");
}
// Render the elements.
glDrawElements(
glDrawMode,
drawCount,
GL_UNSIGNED_INT,
(void *)(sizeof(int32_t) * start)
);
assertNoGLError();
}
Mesh::~Mesh() {
this->disposeBuffers();
}

View File

@ -0,0 +1,51 @@
// 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/mesh/IMesh.hpp"
namespace Dawn {
class Mesh : public IMesh {
protected:
GLuint vertexBuffer = -1;
GLuint indexBuffer = -1;
GLuint vertexArray = -1;
public:
void createBuffers(
const int32_t verticeCount,
const int32_t indiceCount
) override;
void disposeBuffers() override;
void bufferPositions(
const int32_t pos,
const glm::vec3 positions[],
const int32_t len
) override;
void bufferCoordinates(
const int32_t pos,
const glm::vec2 coordinates[],
const int32_t len
) override;
void bufferIndices(
const int32_t pos,
const int32_t indices[],
const int32_t len
) override;
void draw(
const enum MeshDrawMode drawMode,
const int32_t start,
const int32_t count
) override;
~Mesh();
};
}

View File

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

View File

@ -0,0 +1,8 @@
// 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

@ -0,0 +1,238 @@
// 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 "error/assert.hpp"
#include "error/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.");
// 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

@ -0,0 +1,20 @@
// 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

@ -0,0 +1,33 @@
// 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

@ -0,0 +1,69 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "error/assertgl.hpp"
#include "error/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();
// 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

@ -0,0 +1,28 @@
// 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

@ -0,0 +1,95 @@
// 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.
*/
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

@ -0,0 +1,100 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "display/shader/SimpleTexturedShader.hpp"
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;
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"
"out vec2 o_TextCoord;\n"
"void main() {\n"
"gl_Position = u_Projection * u_View * u_Model * vec4(aPos, 1.0);\n"
"o_TextCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
"}"
);
fragment = std::make_shared<ShaderStage>(
ShaderStageType::FRAGMENT,
"#version 330 core\n"
"in vec2 o_TextCoord;\n"
"out vec4 o_Color;\n"
"uniform vec4 u_Color;\n"
"uniform bool u_HasTexture;\n"
"uniform sampler2D u_Texture;\n"
"void main() {\n"
"if(u_HasTexture) {\n"
"o_Color = texture(u_Texture, o_TextCoord) * u_Color;\n"
"} else {\n"
"o_Color = u_Color;"
"}\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_Color",
&rel->color,
ShaderParameterType::COLOR
));
parameters.push_back(ShaderParameter(
"u_HasTexture",
&rel->hasTexture,
ShaderParameterType::BOOLEAN
));
parameters.push_back(ShaderParameter(
"u_Texture",
&rel->texture,
ShaderParameterType::TEXTURE
));
}

View File

@ -0,0 +1,29 @@
// 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 SimpleTexturedShaderData {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
struct Color color = COLOR_WHITE;
bool hasTexture = false;
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

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

View File

@ -0,0 +1,59 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assertgl.hpp"
#include "error/assert.hpp"
#include "dawnopengl.hpp"
void assertNotGLErrorCheck(const char *file, int32_t line) {
GLenum errorCode;
std::string fileString = file;
std::string error = "GL Error";
int32_t errorCount = 0;
while((errorCode = glGetError()) != GL_NO_ERROR) {
errorCount++;
switch (errorCode) {
case GL_INVALID_ENUM:
error += "\nINVALID_ENUM";
break;
case GL_INVALID_VALUE:
error += "\nINVALID_VALUE";
break;
case GL_INVALID_OPERATION:
error += "\nINVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
error += "\nSTACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
error += "\nSTACK_UNDERFLOW";
break;
case GL_OUT_OF_MEMORY:
error += "\nOUT_OF_MEMORY";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
error += "\nINVALID_FRAMEBUFFER_OPERATION";
break;
default:
error += "\nUNKNOWN GL ERROR ERROR";
break;
}
error += " (" + std::to_string(errorCode) + ")";
}
if(errorCount != 0) {
error += "\n" + std::string(file) + " (" + std::to_string(line) + ")";
assertUnreachable(error.c_str());
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
/**
* Asserts that there are no OpenGL errors.
*
* @param file The file the assertion is being made in.
* @param line The line the assertion is being made in.
*/
void assertNotGLErrorCheck(const char *file, int32_t line);
/**
* Asserts that there are no OpenGL errors.
*/
#define assertNoGLError() assertNotGLErrorCheck(__FILE__, __LINE__)

View File

@ -0,0 +1,56 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "erroropengl.hpp"
void errorCheckOpenGL() {
std::stringstream buffer;
GLenum errorCode;
int32_t errorCount = 0;
while((errorCode = glGetError()) != GL_NO_ERROR) {
errorCount++;
switch (errorCode) {
case GL_INVALID_ENUM:
buffer << "INVALID_ENUM" << std::endl;
break;
case GL_INVALID_VALUE:
buffer << "INVALID_VALUE" << std::endl;
break;
case GL_INVALID_OPERATION:
buffer << "INVALID_OPERATION" << std::endl;
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
buffer << "INVALID_FRAMEBUFFER_OPERATION" << std::endl;
break;
case GL_OUT_OF_MEMORY:
buffer << "OUT_OF_MEMORY" << std::endl;
break;
case GL_STACK_UNDERFLOW:
buffer << "STACK_UNDERFLOW" << std::endl;
break;
case GL_STACK_OVERFLOW:
buffer << "STACK_OVERFLOW" << std::endl;
break;
default:
buffer << "UNKNOWN" << std::endl;
break;
}
buffer << "(Error Code: " << errorCode << ")" << std::endl;
}
if(errorCount > 0) {
throw std::runtime_error("OpenGL Error(s) Found: " + buffer.str());
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
#include "dawnopengl.hpp"
/**
* Checks for OpenGL errors. Throws an exception if an error is found.
*/
void errorCheckOpenGL();

View File

@ -0,0 +1,21 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Libraries
# Includes
target_include_directories(${DAWN_TARGET_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
)
# Subdirs
add_subdirectory(scene)

View File

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

View File

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

View File

@ -0,0 +1,13 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/Scene.hpp"
namespace Dawn {
class RPGScene : public Scene {
public:
};
}