Initial commit

This commit is contained in:
Chewico 2026-10-04 20:47:34 +02:00
parent 18a4ac43e1
commit 9953bc13e9
25 changed files with 8503 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build/

13
CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.20)
project(MyEngine
VERSION 0.1
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(deerith_engine_core)
add_subdirectory(deerith_engine_client)
add_subdirectory(sandbox)

View File

@ -0,0 +1,36 @@
find_package(glfw3 REQUIRED)
find_package(OpenGL REQUIRED)
find_package(glm REQUIRED)
add_library(DeerithClient)
file(GLOB_RECURSE deerith_client_SOURCES
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
)
target_sources(DeerithClient
PRIVATE
${deerith_client_SOURCES}
)
target_include_directories(DeerithClient
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(DeerithClient
PUBLIC
DeerithCore
OpenGL::GL
glfw
glm::glm
)
add_custom_target(DeerithClientShaders ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/shaders
${CMAKE_CURRENT_BINARY_DIR}/shaders
)
add_dependencies(DeerithClient DeerithClientShaders)

View File

@ -0,0 +1,26 @@
#pragma once
#include <glm/glm.hpp>
namespace deerith
{
class Mesh2D
{
public:
Mesh2D(const glm::vec2 *vertices,
size_t vertex_size,
const unsigned int *indices,
size_t index_count);
void bind() const;
void draw() const;
~Mesh2D();
private:
unsigned int vao;
unsigned int vbo;
unsigned int ebo;
size_t index_count;
};
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <glm/glm.hpp>
namespace deerith
{
void define_primitive_viewspace(glm::vec2 start_viewspace, glm::vec2 end_viewspace);
void define_primitive_color(glm::vec4 color);
void draw_primitive_rectangle(glm::vec2 start, glm::vec2 end);
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "glm/glm.hpp"
#include "glm/mat4x4.hpp"
namespace deerith
{
class Shader
{
public:
unsigned int id;
Shader(const char *vertexPath, const char *fragmentPath);
void use() const;
void set_bool(const char *name, bool value) const;
void set_int(const char *name, int value) const;
void set_float(const char *name, float value) const;
void set_matrix(const char *name, const glm::mat4 &value);
void set_vec3(const char *name, const glm::vec3 &value);
void set_vec4(const char *name, const glm::vec4 &value);
};
}

View File

@ -0,0 +1,13 @@
#pragma once
namespace deerith
{
int init_window();
void shutdown_window();
// returns false if it must terminate
bool begin_window_display();
void finish_window_display();
int get_current_frame_id();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
#version 330 core
uniform vec4 uColor;
out vec4 FragColor;
void main()
{
FragColor = uColor;
}

View File

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPosition;
uniform mat4 uViewProjection;
uniform mat4 uTransform;
void main()
{
gl_Position = uViewProjection * uTransform * vec4(aPosition, 1.0);
}

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
#include <deerith/graphics/mesh.h>
#include <glad/gl.h>
deerith::Mesh2D::Mesh2D(
const glm::vec2 *vertices,
std::size_t vertex_count,
const unsigned int *indices,
std::size_t index_count)
: index_count(index_count)
{
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(
GL_ARRAY_BUFFER,
vertex_count * sizeof(glm::vec2),
vertices,
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
index_count * sizeof(unsigned int),
indices,
GL_STATIC_DRAW);
// Position: vec2
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(float),
nullptr);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
deerith::Mesh2D::~Mesh2D()
{
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
}
void deerith::Mesh2D::bind() const
{
glBindVertexArray(vao);
}
void deerith::Mesh2D::draw() const
{
glBindVertexArray(vao);
glDrawElements(
GL_TRIANGLES,
static_cast<GLsizei>(index_count),
GL_UNSIGNED_INT,
nullptr);
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "glm/glm.hpp"
namespace deerith
{
void init_primitives();
void shutdown_primitives();
const glm::vec2 rectangle_vertices[4] = {
glm::vec2(0, 0),
glm::vec2(1, 0),
glm::vec2(0, 1),
glm::vec2(1, 1),
};
const unsigned int rectangle_indices[6] = {
0, 2, 1,
1, 2, 3};
}

View File

@ -0,0 +1,78 @@
#include "primitive_internals.h"
#include "deerith/graphics/primitive.h"
#include "deerith/graphics/shader.h"
#include "deerith/graphics/mesh.h"
#include "glm/glm.hpp"
#include "glm/mat4x4.hpp"
#include "glm/ext/matrix_clip_space.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <deerith/core/log.h>
#include <memory>
#include <glad/gl.h>
namespace deerith
{
std::unique_ptr<Shader> primitive_shader;
std::unique_ptr<Mesh2D> primitive_rectangle_mesh;
}
void deerith::init_primitives()
{
primitive_shader = std::make_unique<Shader>(
"../deerith_engine_client/shaders/primitive.vert.glsl",
"../deerith_engine_client/shaders/primitive.frag.glsl");
primitive_rectangle_mesh = std::make_unique<Mesh2D>(rectangle_vertices, 4, rectangle_indices, 6);
}
void deerith::shutdown_primitives()
{
primitive_shader.release();
primitive_shader.reset();
primitive_rectangle_mesh.release();
primitive_rectangle_mesh.reset();
}
void deerith::define_primitive_viewspace(glm::vec2 start_viewspace, glm::vec2 end_viewspace)
{
float width = end_viewspace.x - start_viewspace.x;
float height = end_viewspace.y - start_viewspace.y;
deerith_client_assert(width > 0, "define_primitive_viewspace width must be > 0");
deerith_client_assert(height > 0, "define_primitive_viewspace height must be > 0");
glm::mat4 m_projection = glm::ortho(
start_viewspace.x,
end_viewspace.x,
start_viewspace.y,
end_viewspace.y,
-1.0f,
1.0f);
primitive_shader->set_matrix("uViewProjection", m_projection);
}
void deerith::define_primitive_color(glm::vec4 color)
{
primitive_shader->set_vec4("uColor", color);
}
void deerith::draw_primitive_rectangle(glm::vec2 start, glm::vec2 end)
{
float width = end.x - start.x;
float height = end.y - start.y;
deerith_client_assert(width > 0, "draw_primitive_rectangle width must be > 0");
deerith_client_assert(height > 0, "draw_primitive_rectangle height must be > 0");
glm::mat4 model = glm::translate(glm::mat4(1), glm::vec3(start.x, start.y, 0.0f));
model = glm::scale(model, glm::vec3(width, height, 1.0f));
primitive_shader->use();
primitive_shader->set_matrix("uTransform", model);
primitive_rectangle_mesh->draw();
}

View File

@ -0,0 +1,208 @@
#include "deerith/graphics/shader.h"
#include <glad/gl.h>
#include <glm/gtc/type_ptr.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
deerith::Shader::Shader(const char *vertexPath, const char *fragmentPath)
{
std::string vertexCode;
std::string fragmentCode;
std::ifstream vertexFile;
std::ifstream fragmentFile;
vertexFile.exceptions(
std::ifstream::failbit |
std::ifstream::badbit);
fragmentFile.exceptions(
std::ifstream::failbit |
std::ifstream::badbit);
try
{
vertexFile.open(vertexPath);
fragmentFile.open(fragmentPath);
std::stringstream vertexStream;
std::stringstream fragmentStream;
vertexStream << vertexFile.rdbuf();
fragmentStream << fragmentFile.rdbuf();
vertexFile.close();
fragmentFile.close();
vertexCode = vertexStream.str();
fragmentCode = fragmentStream.str();
}
catch (const std::ifstream::failure &e)
{
std::cerr
<< "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ\n"
<< e.what()
<< std::endl;
id = 0;
return;
}
const char *vertexSource = vertexCode.c_str();
const char *fragmentSource = fragmentCode.c_str();
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(
vertexShader,
1,
&vertexSource,
nullptr);
glCompileShader(vertexShader);
int success;
char infoLog[1024];
glGetShaderiv(
vertexShader,
GL_COMPILE_STATUS,
&success);
if (!success)
{
glGetShaderInfoLog(
vertexShader,
sizeof(infoLog),
nullptr,
infoLog);
std::cerr
<< "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n"
<< infoLog
<< std::endl;
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(
fragmentShader,
1,
&fragmentSource,
nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(
fragmentShader,
GL_COMPILE_STATUS,
&success);
if (!success)
{
glGetShaderInfoLog(
fragmentShader,
sizeof(infoLog),
nullptr,
infoLog);
std::cerr
<< "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"
<< infoLog
<< std::endl;
}
id = glCreateProgram();
glAttachShader(id, vertexShader);
glAttachShader(id, fragmentShader);
glLinkProgram(id);
glGetProgramiv(
id,
GL_LINK_STATUS,
&success);
if (!success)
{
glGetProgramInfoLog(
id,
sizeof(infoLog),
nullptr,
infoLog);
std::cerr
<< "ERROR::SHADER::PROGRAM::LINKING_FAILED\n"
<< infoLog
<< std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void deerith::Shader::use() const
{
glUseProgram(id);
}
void deerith::Shader::set_bool(const char *name, bool value) const
{
this->use();
glUniform1i(
glGetUniformLocation(id, name),
static_cast<int>(value));
}
void deerith::Shader::set_int(const char *name, int value) const
{
this->use();
glUniform1i(
glGetUniformLocation(id, name),
value);
}
void deerith::Shader::set_float(const char *name, float value) const
{
this->use();
glUniform1f(
glGetUniformLocation(id, name),
value);
}
void deerith::Shader::set_matrix(
const char *name,
const glm::mat4 &value)
{
this->use();
glUniformMatrix4fv(
glGetUniformLocation(id, name),
1,
GL_FALSE,
glm::value_ptr(value));
}
void deerith::Shader::set_vec3(
const char *name,
const glm::vec3 &value)
{
this->use();
glUniform3fv(
glGetUniformLocation(id, name),
1,
glm::value_ptr(value));
}
void deerith::Shader::set_vec4(
const char *name,
const glm::vec4 &value)
{
this->use();
glUniform4f(
glGetUniformLocation(id, name),
value.x, value.y, value.z, value.w);
}

View File

@ -0,0 +1,111 @@
#include "deerith/graphics/window.h"
#include "primitive_internals.h"
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <chrono>
#include <thread>
#include <iostream>
namespace deerith
{
GLFWwindow *window;
int frame_id = 0;
constexpr double TARGET_FRAME_TIME = 1.0 / 60.0;
std::chrono::steady_clock::time_point last_frame_time;
}
int deerith::init_window()
{
if (!glfwInit())
{
std::cerr << "Failed to initialize GLFW\n";
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(
1280,
720,
"Deerith",
nullptr,
nullptr);
if (!window)
{
std::cerr << "Failed to create GLFW window\n";
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
int version = gladLoadGL(glfwGetProcAddress);
if (version == 0)
{
std::cerr << "Failed to initialize GLAD\n";
glfwDestroyWindow(window);
glfwTerminate();
return -1;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
init_primitives();
return 0;
}
bool deerith::begin_window_display()
{
if (glfwWindowShouldClose(window))
{
return false;
}
glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
return true;
}
void deerith::finish_window_display()
{
using clock = std::chrono::steady_clock;
const auto now = clock::now();
const std::chrono::duration<double> elapsed = now - last_frame_time;
if (elapsed.count() < TARGET_FRAME_TIME)
{
std::this_thread::sleep_for(
std::chrono::duration<double>(
TARGET_FRAME_TIME - elapsed.count()));
}
frame_id++;
glfwSwapBuffers(window);
glfwPollEvents();
}
void deerith::shutdown_window()
{
shutdown_primitives();
glfwDestroyWindow(window);
glfwTerminate();
}
int deerith::get_current_frame_id()
{
return frame_id;
}

View File

@ -0,0 +1,25 @@
add_library(DeerithCore)
find_package(spdlog REQUIRED)
find_package(fmt REQUIRED)
file(GLOB_RECURSE DEERITH_CORE_SOURCES
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
)
target_sources(DeerithCore
PRIVATE
${DEERITH_CORE_SOURCES}
)
target_include_directories(DeerithCore
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(DeerithCore
PUBLIC
spdlog::spdlog
fmt::fmt
)

View File

@ -0,0 +1,7 @@
#pragma once
namespace deerith
{
int init_deerith_core();
void shutdown_deerith_core();
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
namespace deerith
{
spdlog::logger *get_core_logger();
spdlog::logger *get_graphics_logger();
} // namespace deerith
#define deerith_core_trace(...) deerith::get_core_logger()->trace(__VA_ARGS__)
#define deerith_core_info(...) deerith::get_core_logger()->info(__VA_ARGS__)
#define deerith_core_warn(...) deerith::get_core_logger()->warn(__VA_ARGS__)
#define deerith_core_error(...) deerith::get_core_logger()->error(__VA_ARGS__)
#define deerith_client_trace(...) deerith::get_graphics_logger()->trace(__VA_ARGS__)
#define deerith_client_info(...) deerith::get_graphics_logger()->info(__VA_ARGS__)
#define deerith_client_warn(...) deerith::get_graphics_logger()->warn(__VA_ARGS__)
#define deerith_client_error(...) deerith::get_graphics_logger()->error(__VA_ARGS__)
#define deerith_core_assert(condition, ...) \
if (!(condition)) \
{ \
deerith::get_core_logger()->error(__VA_ARGS__); \
__builtin_trap(); \
}
#define deerith_client_assert(condition, ...) \
if (!(condition)) \
{ \
deerith::get_graphics_logger()->error(__VA_ARGS__); \
__builtin_trap(); \
}

View File

@ -0,0 +1,14 @@
#include "deerith/core/core.h"
#include "internal.h"
int deerith::init_deerith_core()
{
init_log();
return 0;
}
void deerith::shutdown_deerith_core()
{
shutdown_log();
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace deerith
{
void init_log();
void shutdown_log();
}

View File

@ -0,0 +1,40 @@
#include "deerith/core/log.h"
#include "internal.h"
#include <memory>
namespace deerith
{
std::shared_ptr<spdlog::logger> core_logger;
std::shared_ptr<spdlog::logger> graphics_logger;
}
void deerith::init_log()
{
spdlog::set_pattern("%^[%T] %n: %v%$");
core_logger = spdlog::stdout_color_mt("core");
graphics_logger = spdlog::stdout_color_mt("graphics");
core_logger->set_level(spdlog::level::level_enum::trace);
graphics_logger->set_level(spdlog::level::level_enum::trace);
}
void deerith::shutdown_log()
{
core_logger.reset();
graphics_logger.reset();
spdlog::drop_all();
}
spdlog::logger *deerith::get_core_logger()
{
return core_logger.get();
}
spdlog::logger *deerith::get_graphics_logger()
{
return graphics_logger.get();
}

8
sandbox/CMakeLists.txt Normal file
View File

@ -0,0 +1,8 @@
add_executable(Sandbox
src/main.cpp
)
target_link_libraries(Sandbox
PRIVATE
DeerithClient
)

37
sandbox/src/main.cpp Normal file
View File

@ -0,0 +1,37 @@
#include <deerith/graphics/window.h>
#include <deerith/graphics/primitive.h>
#include <deerith/core/core.h>
#include <iostream>
#include <math.h>
#include "deerith/core/log.h"
int main(int args_count, const char **args)
{
deerith::init_deerith_core();
deerith_core_trace("{}", args[0]);
int init_result = deerith::init_window();
if (init_result != 0)
{
return init_result;
}
while (deerith::begin_window_display())
{
deerith::define_primitive_viewspace(glm::vec2(0, 0), glm::vec2(1, 1));
deerith::define_primitive_color(glm::vec4(0.9f, 0, 0, 1));
deerith::draw_primitive_rectangle(glm::vec2(0, 0), glm::vec2(0.5f, 1));
deerith::define_primitive_color(glm::vec4(0.2f, 0.4f, (deerith::get_current_frame_id() % 100) / 100.0f, 1));
deerith::draw_primitive_rectangle(glm::vec2(0.5, 0), glm::vec2(1, 0.5f));
deerith::finish_window_display();
}
deerith::shutdown_window();
deerith::shutdown_deerith_core();
return 0;
}