diff options
Diffstat (limited to 'src/rendering')
| -rw-r--r-- | src/rendering/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/platform.h | 57 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/platform_glfw.h | 32 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/rendering.h | 288 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/window.h | 53 | ||||
| -rw-r--r-- | src/rendering/src/gl.c | 281 | ||||
| -rw-r--r-- | src/rendering/src/platform_glfw.c | 232 | ||||
| -rw-r--r-- | src/rendering/src/rendering.c | 696 | ||||
| -rw-r--r-- | src/rendering/src/window.c | 83 |
9 files changed, 0 insertions, 1755 deletions
diff --git a/src/rendering/CMakeLists.txt b/src/rendering/CMakeLists.txt deleted file mode 100644 index f3f4710..0000000 --- a/src/rendering/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -add_library(daw_rendering - src/gl.c - src/rendering.c - src/window.c - src/platform_glfw.c - ${GLAD_HEADER} - ) - -add_custom_command( - OUTPUT ${GLAD_HEADER} - COMMAND - glad - --api gl:core=4.6 - --out-path ${CMAKE_BINARY_DIR} - --reproducible - c - --header-only - --mx - ) - -set_property(SOURCE src/window.c APPEND PROPERTY OBJECT_DEPENDS ${GLAD_HEADER}) -set_property(SOURCE src/rendering.c APPEND PROPERTY OBJECT_DEPENDS ${GLAD_HEADER}) - -target_compile_options(daw_rendering PUBLIC ${BUILD_OPTS}) -target_include_directories(daw_rendering PRIVATE - ${DAW_INCLUDE_DIRS} - ${GLFW_INCLUDE_DIR} -) -target_link_libraries(daw_rendering PRIVATE - OpenGL::GL - cglm - glfw -) diff --git a/src/rendering/include/engine/rendering/platform.h b/src/rendering/include/engine/rendering/platform.h deleted file mode 100644 index ea51c47..0000000 --- a/src/rendering/include/engine/rendering/platform.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef PLATFORM_H -#define PLATFORM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <cglm/ivec2.h> - -#include <engine/core/types.h> -// TODO: We only need the window once all the garbage in Instance is cleaned up. -#include <engine/core/platform.h> -#include <engine/rendering/window.h> - -#define DAW_WINDOW_VSYNC (1 << 0) -#define DAW_WINDOW_FULLSCREEN (1 << 1) -#define DAW_WINDOW_RESIZEABLE (1 << 2) - -// Whether or not it is clever to force API consistency using a struct like this -// can be debated, at the time of writing it seemed like a smart idea. - -// Platform libraries must implement a struct Platform: -struct Platform { - /* Initialize a window for the given platform. The rendering backend should - * also be initialized here. - * Parameters: - * const char* title: window title. - * ivec2 windowsize: the size in pixels for the new window. - * const u32 flags: window flags, such as static size and fullscreen. - * The flags are platform agnostic and needs to be - * converted to the specific library - * Returns: - * A pointer to a struct Window, NULL on error. - */ - Window* (*window_init)(const char *restrict title, ivec2 windowsize, const u32 flags); - - /* Destroy, close, and free up resources related to the window and the - * platform library specific resources. - */ - void (*window_destroy)(Window *restrict w); - - /* Resize the given window. Resize callbacks are handled by the wrapper - * implementation. - */ - void (*window_resize)(Window *restrict window, int width, int height); - - /* Return true if the platform has ordered the window to exit. */ - bool (*window_should_close)(Window *restrict w); - - /* Poll events on the window from the operating system. */ - void (*window_poll)(void); -}; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/rendering/include/engine/rendering/platform_glfw.h b/src/rendering/include/engine/rendering/platform_glfw.h deleted file mode 100644 index 949968d..0000000 --- a/src/rendering/include/engine/rendering/platform_glfw.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef ENGINE_RENDERING_PLATFORM_GLFW_H -#define ENGINE_RENDERING_PLATFORM_GLFW_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <cglm/ivec2.h> - -#include <engine/core/types.h> -#include <engine/rendering/platform.h> -#include <engine/rendering/window.h> - -Window* window_init_glfw(const char *restrict windowtitle, ivec2 windowsize, const u32 flags); -void window_destroy_glfw(Window *restrict w); -void window_resize_glfw(Window *restrict window, int width, int height); -bool window_should_close_glfw(Window *restrict window); -void window_poll_glfw(void); - -const struct Platform Platform_GLFW = { - .window_init = window_init_glfw, - .window_destroy = window_destroy_glfw, - .window_resize = window_resize_glfw, - .window_should_close = window_should_close_glfw, - .window_poll = window_poll_glfw, -}; - -#ifdef __cplusplus -} -#endif -#endif - diff --git a/src/rendering/include/engine/rendering/rendering.h b/src/rendering/include/engine/rendering/rendering.h deleted file mode 100644 index a996257..0000000 --- a/src/rendering/include/engine/rendering/rendering.h +++ /dev/null @@ -1,288 +0,0 @@ -#ifndef ENGINE_RENDERING_RENDERING_H -#define ENGINE_RENDERING_RENDERING_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <engine/core/types.h> -#include <engine/rendering/window.h> - -#include <cglm/ivec2.h> - -/* Definitions */ -#define RGBA(_r, _g, _b, _a) ((Engine_color){.r = _r, .g = _g, .b = _b, .a = _a}) -#define RGB(_r, _g, _b) RGBA(_r, _g, _b, 0xFF) - -/* Types */ -/* TODO: Cleanup these types. */ -typedef struct { - u8 r; - u8 g; - u8 b; - u8 a; -} Engine_color; - -typedef struct { - /* Maybe implement types, such as `atlas` (default), `standalone`, or - * something idk. */ - u32 id; - i32 width; - i32 height; -} Texture; - -typedef struct { - u32 texture_id; - ivec2 coord; -} Sprite; - -typedef enum { - Shader_Error, - - Shader_Program, - Shader_Vertex, - Shader_Tessellation, - Shader_Geometry, - Shader_Fragment, - Shader_Compute, -} ShaderType; - -typedef struct { - /* Shader proram */ - ShaderType type; - u32 program; -} Shader; - -typedef struct { - vec3 position; - vec3 size; - mat4 rotation; -} Transform; - -typedef enum { - ShaderBufferFlag_none = 0x00, - - // First 3 bytes describe the access frequency. - ShaderBuffer_AccessFrequency_stream = 0b0000000000001, // 1 - ShaderBuffer_AccessFrequency_static = 0b0000000000010, // 2 - ShaderBuffer_AccessFrequency_dynamic = 0b0000000000011, // 3 - - // Next 3 bytes describe the access type. - ShaderBuffer_AccessType_draw = 0b0000000001000, // 8 - ShaderBuffer_AccessType_read = 0b0000000010000, // 16 - ShaderBuffer_AccessType_copy = 0b0000000011000, // 24 - - // Next 3 bytes describe the buffer type - ShaderBuffer_Type_vertexData = 0b0000001000000, // 64 - ShaderBuffer_Type_vertexPosition = 0b0000010000000, // 128 - ShaderBuffer_Type_vertexIndex = 0b0000011000000, // 192 - - // Next 4 bytes are designated for the data type - ShaderBuffer_DataType_nil = 0b0001000000000, // 512 - - ShaderBuffer_DataType_f32 = 0b0010000000000, // 1024 - ShaderBuffer_DataType_f64 = 0b0011000000000, // 1536 - - ShaderBuffer_DataType_i8 = 0b0100000000000, // 2048 - ShaderBuffer_DataType_i16 = 0b0101000000000, // 2560 - ShaderBuffer_DataType_i32 = 0b0110000000000, // 3072 - ShaderBuffer_DataType_i64 = 0b0111000000000, // 3584 - - ShaderBuffer_DataType_u8 = 0b1000000000000, // 4096 - ShaderBuffer_DataType_u16 = 0b1001000000000, // 4608 - ShaderBuffer_DataType_u32 = 0b1010000000000, // 5120 - ShaderBuffer_DataType_u64 = 0b1011000000000, // 5632 -} ShaderBufferFlag; - -typedef struct { - // The backend ID, ie. glGenBuffer(numBufferObjects, &this->buffername) - u32 buffername; - // Array, access, and data, type. - u32 buffertype; - // Buffer size of `data`. To get the size of the actual data, size_elem * count - usize size; - // Number of elements - usize count; - // components per generic vertex attribute (ie, 3 for RGB, 2 for UV) - usize components; - // size of each element - usize size_elem; - // Pointer to the data - void* data; -} ShaderBuffer; - -// SHADERBUFFER_NEW is a constructor that takes the -// * type T, as one of f32, f64, i8, i16, i32, i64, u8, u16, u32, or u64. -// * COUNT, number of elements in the buffer -// * COMPONENTS, number of elements to be grouped together, ie. 3 for a vec3. -// * DATA, the buffer (it is pointed to automatically) -// * FLAGS, are low-level GL flags that hints the access frequency, the access -// type, and what buffer type it is, such as "data" or an index buffer. -#define SHADERBUFFER_NEW(T, COUNT, COMPONENTS, DATA, FLAGS) \ - (ShaderBuffer){ \ - .buffername = 0, \ - .buffertype = ShaderBuffer_DataType_##T | FLAGS, \ - .size = COUNT * sizeof(T), \ - .count = COUNT, \ - .components = COMPONENTS, \ - .size_elem = sizeof(T), \ - .data = DATA, \ - } - -typedef struct { - /* Shader proram */ - Shader shader; - /* Vertex Array Object */ - u32 vao; - - /* MVP (a uniform from the shader). - * This could also probably be generalized */ - i32 mvp; - - // The texture ID, glBindTextures(target, &this->texture) - u32 texture; - - // Number of buffers - usize buffer_len; - - // The vertex buffer is also just a buffer - ShaderBuffer* buffer; -} RenderObject; - -typedef struct { - // Index of the model in the RenderBatch models buffer - usize model_idx; - // The transformation of the model - Transform transform; -} BatchModelInstance; - -typedef struct { - // Size of models buffer - usize msize; - // number of models in the `models` buffer - usize mcount; - // Pointers to original models in this batch - RenderObject **models; - - // Size of instance buffer - usize inst_size; - // number of instances in the `instances` buffer - usize inst_count; - // Pointers to original models in this batch - BatchModelInstance *instances; - - // The rendered destination object - RenderObject renderobj; -} RenderBatch; - -typedef enum { - Camera_Perspective, - Camera_Orthogonal, -} CameraType; - -typedef struct { - /* Position of the camera in world-space. */ - vec3 pos; - - /* The viewing direction of the camera, relative to the camera. */ - vec3 dir; - - /* Perspective matrix. Initialize with r_perspective_ortho or r_perspective. */ - /* Alternatively, use `glm_perspective` or `glm_ortho`. */ - mat4 per; - - /* Used to re-calculate the perspective matrix when resizing the window */ - CameraType type; - /* Yes, could use a singular "f32 arg", but this is more extendable in the - * future. */ - union { - struct {f32 fov;} perspective; - struct {f32 sz;} orthogonal; - } parameters; - -} Camera; - -usize ShaderBufferDataType_size(u16 flags); - -ShaderBufferFlag ShaderBuffer_get_access_frequency(u64 flags); -ShaderBufferFlag ShaderBuffer_get_access_type(u64 flags); -ShaderBufferFlag ShaderBuffer_get_type(u64 flags); -ShaderBufferFlag ShaderBuffer_get_data_type(u64 flags); - -/* Conversion to GL types */ -u32 ShaderBuffer_get_gl_type(u64 flags); -u32 ShaderBuffer_get_gl_accesstype(u64 flags); -u32 ShaderBuffer_get_gl_datatype(u64 flags); - -/* Rendering functions */ -void render_begin(Window* w); -void render_present(Window* w); -void drawcall_reset(void); -void render(Window* w); - -/* Misc */ -void r_perspective(f32 fov, Camera *c); -void r_perspective_ortho(f32 sz, Camera *c); - -void r_set_camera(Camera* c); -void r_reset_camera(Camera* c); - -//void window_size_callback(GLFWwindow* window, i32 width, i32 height); - -void engine_draw_sprite(Sprite* s, ivec2* pos, f32 scale); -void engine_draw_sprite_ex(Sprite* s, ivec2* pos, f32 scale, - Engine_color colormod); -void engine_draw_model(RenderObject* o, vec3 pos); - -Sprite sprite_new(u64 tid, u8 coord); - -typedef enum { - RenderDrawCallType_Text, - RenderDrawCallType_Sprite, - RenderDrawCallType_Model, -} RenderDrawCallType; - -typedef struct { - RenderDrawCallType type; - union { - void* data; - struct { - Sprite* sprite; - i32 x; - i32 y; - f32 scale; - } sprite; - struct { - RenderObject* model; - vec3 pos; - f32 scale; - } model; - } data; -} RenderDrawCall; - -// TODO make all the shader buffers a list - -RenderObject RenderObject_new( - Shader* shader, - u32 texture, - ShaderBuffer *restrict buffers, usize num_buffers); - -int renderbatch_new(RenderBatch* renderbatch, usize count); -i32 renderbatch_add(RenderBatch* renderbatch, RenderObject* obj, Transform* t); -void renderbatch_transform(RenderBatch* renderbatch, usize obj_idx, Transform* t); -int renderbatch_refresh(RenderBatch* renderbatch); - -Shader compile_shader(const char* file_path, const ShaderType shader_type); -Shader compose_shader(Shader *shaders, usize shaders_len); -void shaders_delete(Shader* shader, usize shader_len); - -u32 ComposeShader(u32 *shaders, usize shaders_len); - -ShaderType guess_shadertype_from_filename(const char *restrict fname); - -Texture createTextureFromImageData(unsigned char* image_data, i32 width, i32 height, u8 components); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/rendering/include/engine/rendering/window.h b/src/rendering/include/engine/rendering/window.h deleted file mode 100644 index a964b38..0000000 --- a/src/rendering/include/engine/rendering/window.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef WINDOW_H -#define WINDOW_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <cglm/ivec2.h> - -#include <engine/core/types.h> -#include <engine/ctrl/input.h> - -#ifndef ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS -extern u64 (*get_time)(void); -#endif - -typedef enum { - WINDOW_FRAMEWORK_NONE = 0, - WINDOW_FRAMEWORK_GLFW, -} Window_framework; - -typedef enum { - WINDOW_RENDERER_NONE = 0, - WINDOW_RENDERER_OPENGL, -} Window_renderer; - -typedef struct { - // Specifies the framwork & renderer combo used. - Window_framework framework; - Window_renderer renderer; - - // Window *buffer* size, in pixels. - ivec2 windowsize; - - // These are used differently depending on the framework / renderer combo. - // Subject to change to a union of backend-dependent structs - void* window; - void* context; - - /* The ctrl is probably the only sensible thing in this struct. */ - usize bindings_sz; - usize bindings_len; - i_ctx** bindings; -} Window; - -Window* Window_new(const char *restrict title, Window_framework framework, Window_renderer renderer, ivec2 size, u32 flags); - -void get_mousepos(double *x, double *y); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/rendering/src/gl.c b/src/rendering/src/gl.c deleted file mode 100644 index 920518f..0000000 --- a/src/rendering/src/gl.c +++ /dev/null @@ -1,281 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <glad/gl.h> - -#include <engine/core/types.h> -#include <engine/core/logging.h> - -#include <engine/rendering/rendering.h> -#include <engine/core/platform.h> -#include <engine/engine.h> - -extern Instance* GLOBAL_PLATFORM; - -const char* ShaderType_str[] = { - [Shader_Error] = "Shader_Error", - [Shader_Program] = "Shader_Program", - [Shader_Vertex] = "Shader_Vertex", - [Shader_Tessellation] = "Shader_Tessellation", - [Shader_Geometry] = "Shader_Geometry", - [Shader_Fragment] = "Shader_Fragment", - [Shader_Compute] = "Shader_Compute", -}; - -Shader compile_shader(const char* file_path, const ShaderType shader_type) { - u32 shaderID = 0; - GLenum shadertype = GL_INVALID_ENUM; - - i32 Result = GL_FALSE; - i32 infolog_len; - - char* source = NULL; - FILE* file = NULL; - - const GladGLContext* gl = GLOBAL_PLATFORM->window->context; - - if (file_path == NULL) { - WARN("Empty path to shader"); - return (Shader){.program = 0, .type = Shader_Error}; - } - - switch (shader_type) { - case Shader_Vertex: - shadertype = GL_VERTEX_SHADER; - break; - case Shader_Fragment: - shadertype = GL_FRAGMENT_SHADER; - break; - default: break; - } - - file = fopen(file_path, "r"); - - shaderID = gl->CreateShader(shadertype); - LOG("CREATED SHADER ID %d", shaderID); - - if(file != NULL) { - const usize size = f_get_sz(file); - - source = calloc((usize)size + 1, sizeof(char)); - - // Assume the whole file is successfully read - fread(source, sizeof(char), (usize)size, file); - - fclose(file); - } else { - ERROR("Cannot open \"" TERM_COLOR_YELLOW "%s" TERM_COLOR_RESET"\".", file_path); - return (Shader){.program = 0, .type = Shader_Error}; - } - - // Compile shader - INFO("Compiling shader \"" TERM_COLOR_YELLOW "%s" TERM_COLOR_RESET"\".", file_path); - char const* src_ptr = source; - gl->ShaderSource(shaderID, 1, &src_ptr , NULL); - gl->CompileShader(shaderID); - - // Check shader - gl->GetShaderiv(shaderID, GL_COMPILE_STATUS, &Result); - gl->GetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &infolog_len); - if ( infolog_len > 0 ) { - char* msg = calloc((usize)infolog_len + 1, sizeof(char)); - gl->GetShaderInfoLog(shaderID, infolog_len, NULL, msg); - ERROR("Failed to compile shader: " TERM_COLOR_YELLOW "%s" TERM_COLOR_RESET, msg); - free(msg); - } - - free(source); - - return (Shader){.program = shaderID, .type = shader_type}; -} - - -// http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/ -u32 load_shaders( - const GladGLContext* gl, - const char* vertex_file_path, - const char* fragment_file_path) { - - i32 Result = GL_FALSE; - i32 infolog_len; - - // Create the shaders - const Shader vertexShader = compile_shader(vertex_file_path, Shader_Vertex); - const Shader fragmentShader = compile_shader(fragment_file_path, Shader_Fragment); - - // Link the program - INFO("Linking program"); - u32 ProgramID = gl->CreateProgram(); - - if (vertex_file_path != NULL) gl->AttachShader(ProgramID, vertexShader.program); - if (fragment_file_path != NULL) gl->AttachShader(ProgramID, fragmentShader.program); - - gl->LinkProgram(ProgramID); - - // Check the program - gl->GetProgramiv(ProgramID, GL_LINK_STATUS, &Result); - gl->GetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &infolog_len); - if ( infolog_len > 0 ){ - char* msg = calloc((usize)infolog_len + 1, sizeof(char)); - gl->GetShaderInfoLog(ProgramID, infolog_len, NULL, msg); - ERROR("Compiling shader: " TERM_COLOR_YELLOW "%s" TERM_COLOR_RESET, msg); - free(msg); - } - - gl->DetachShader(ProgramID, vertexShader.program); - gl->DetachShader(ProgramID, fragmentShader.program); - - //gl->DeleteShader(vertexShader.program); - //gl->DeleteShader(fragmentShader.program); - - return ProgramID; -} - -/* Returns a shader program */ -Shader compose_shader(Shader *shaders, usize shaders_len) { - const GladGLContext* gl = GLOBAL_PLATFORM->window->context; - i32 Result = GL_FALSE; - - if (shaders_len == 0) { - ERROR("No shaders provided!"); - return (Shader){.program = 0, .type = Shader_Error}; - } - - u32 prog = gl->CreateProgram(); - - if (prog == 0) { - ERROR("Failed to create program!"); - return (Shader){.program = 0, .type = Shader_Error}; - } - - for (usize i = 0; i < shaders_len; i++) { - gl->AttachShader(prog, shaders[i].program); - INFO("Attaching shader %d to %d", shaders[i].program, prog); - } - - gl->LinkProgram(prog); - - // Check the program - gl->GetProgramiv(prog, GL_LINK_STATUS, &Result); - if (Result != GL_TRUE) { - // Get the size of the log - i32 log_len = 0; - i32 msg_len = 0; - gl->GetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_len); - char* msg = calloc((usize)log_len + 1, sizeof(char)); - - // Copy the log message(s) - gl->GetProgramInfoLog(prog, log_len, &msg_len, msg); - - ERROR("(Compose) Compiling shader:\n" TERM_COLOR_YELLOW "%s" TERM_COLOR_RESET "\n", msg); - free(msg); - } - - for (usize i = 0; i < shaders_len; i++) { - gl->DetachShader(prog, shaders[i].program); - } - - return (Shader){.program = prog, .type = Shader_Program}; -} - -/* Free up resources associated with `shader` */ -void shaders_delete(Shader* shader, usize shader_len) { - const GladGLContext* gl = GLOBAL_PLATFORM->window->context; - - for (usize i = 0; i < shader_len; i++) { - gl->DeleteShader(shader[i].program); - } -} - -GLenum ShaderBuffer_get_gl_access(u64 flags) { - const ShaderBufferFlag access = ShaderBuffer_get_access_type(flags); - - switch(flags & 0b111) { - case ShaderBuffer_AccessFrequency_stream: - switch(access) { - case ShaderBuffer_AccessType_draw: return GL_STREAM_DRAW; - case ShaderBuffer_AccessType_read: return GL_STREAM_READ; - case ShaderBuffer_AccessType_copy: return GL_STREAM_COPY; - default: return GL_STREAM_DRAW; - } - case ShaderBuffer_AccessFrequency_static: - switch(access) { - case ShaderBuffer_AccessType_draw: return GL_STATIC_DRAW; - case ShaderBuffer_AccessType_read: return GL_STATIC_READ; - case ShaderBuffer_AccessType_copy: return GL_STATIC_COPY; - default: return GL_STATIC_DRAW; - } - case ShaderBuffer_AccessFrequency_dynamic: - switch(access) { - case ShaderBuffer_AccessType_draw: return GL_DYNAMIC_DRAW; - case ShaderBuffer_AccessType_read: return GL_DYNAMIC_READ; - case ShaderBuffer_AccessType_copy: return GL_DYNAMIC_COPY; - default: return GL_DYNAMIC_DRAW; - } - default: return GL_STATIC_DRAW; - } -} - -RenderObject RenderObject_new( - Shader* shader, - u32 texture, - ShaderBuffer *restrict buffers, usize num_buffers) { - - GladGLContext *gl = GLOBAL_PLATFORM->window->context; - RenderObject o; - - gl->GenVertexArrays(1, &(o.vao)); - gl->BindVertexArray(o.vao); - - /* For each buffer in the shader, */ - /* The shader should be generalied, */ - for (usize i = 0; i < num_buffers; i++) { - const usize sz = buffers[i].size_elem * buffers[i].count; - const u32 b_gl_type = ShaderBuffer_get_gl_type(buffers[i].buffertype); - - gl->GenBuffers(1, &(buffers[i].buffername)); - gl->BindBuffer(b_gl_type, buffers[i].buffername); - gl->BufferData(b_gl_type, (isize)sz, buffers[i].data, ShaderBuffer_get_gl_accesstype(buffers[i].buffertype)); - } - - o.shader = *shader; - o.texture = texture; - o.buffer = buffers; - o.buffer_len = num_buffers; - o.mvp = gl->GetUniformLocation(o.shader.program, "MVP"); - - // It is very much a non-issue if we don't find the model view projection in - // the shader. In fact, it is removed from a shader program if it is not used. - // TODO: Add common uniforms, should be a list of strings (uniform name) & - // their locations (i32), such as - // * mouse coords, - // * time, - // * delta time, - // * modelviewprojection, - // * window size. - // These should be added to the RenderObject, if found. - - // if (o.mvp == -1) { - // WARN("Unable to find \"MVP\" input in shader program"); - //} - - gl->BindVertexArray(0); - - - return o; -} - -ShaderType guess_shadertype_from_filename(const char *restrict fname) { - const usize path_len = strlen(fname); - - if (path_len <= 4) { - ERROR("Unable to determine shader type from suffix! (%s)", fname); - return Shader_Error; - } - - if (!strncmp(".vert", &fname[path_len - 5], 5)) { return Shader_Vertex; } - if (!strncmp(".frag", &fname[path_len - 5], 5)) { return Shader_Fragment; } - - return Shader_Error; -} diff --git a/src/rendering/src/platform_glfw.c b/src/rendering/src/platform_glfw.c deleted file mode 100644 index 47638e2..0000000 --- a/src/rendering/src/platform_glfw.c +++ /dev/null @@ -1,232 +0,0 @@ -// Required for OpenGL rendering backend -#define GLAD_GL_IMPLEMENTATION -#include <glad/gl.h> -#undef GLAD_GL_IMPLEMENTATION - -// TODO: import vulkan thingymajig once I get around to it. -// TODO: move OpenGL initialization code at some point - -#undef GLFW_INCLUDE_NONE -#include <GLFW/glfw3.h> - -#include <engine/core/logging.h> - -#include <engine/rendering/platform.h> - -static void window_resize_callback(GLFWwindow *restrict window, int width, int height); -static void framebuffer_resize_callback(GLFWwindow *restrict window, int width, int height); -static void glfw_err_callback(int code, const char* description); -static void render_init_opengl(Window *restrict w, const u32 flags); -static void window_size(GLFWwindow *restrict w, ivec2 *restrict dst); - - -Window* window_init_glfw(const char *restrict windowtitle, ivec2 windowsize, const u32 flags) { - Window* ret = NULL; - GLFWwindow* window = NULL; - - glfwSetErrorCallback(&glfw_err_callback); - - INFO_("initializing glfw..."); - if (glfwInit() == GLFW_FALSE) { - const char *desc; - int code = glfwGetError(&desc); - ERROR("failed to initialize glfw [%d]: %s\n", code, *desc); - exit(EXIT_FAILURE); - } else - printf("ok\n"); - - - INFO_("initializing window..."); - //glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - if (!(flags & DAW_WINDOW_RESIZEABLE)) { - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - } - - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); - glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); - - glfwWindowHint(GLFW_SAMPLES, 0); // Disable anti aliasing - - // Use a modern opengl version - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); - - // Lean and mean - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - -#ifdef __APPLE__ - // To make MacOS happy; should not be needed - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - - /* "On Wayland specifically, you need to swap the buffers - * once of a window for it to become visible." */ - { - GLFWmonitor* mon = NULL; - if (flags & DAW_WINDOW_FULLSCREEN) mon = glfwGetPrimaryMonitor(); - - window = glfwCreateWindow(windowsize[0], windowsize[1], windowtitle, mon, NULL); - } - - if (window == NULL) { - ERROR("Failed to create GLFW window!\n"); - const char *desc; - int code = glfwGetError(&desc); - ERROR("failed to initialize glfw window [%d]: %s\n", code, desc); - exit(EXIT_FAILURE); - } else - printf("ok\n"); - - // Setup callbacks - glfwSetFramebufferSizeCallback(window, framebuffer_resize_callback); - glfwSetWindowSizeCallback(window, window_resize_callback); - glfwSetKeyCallback(window, (GLFWkeyfun)key_callback); - - // Create the window datastructure - ret = (Window*)calloc(1, sizeof(Window)); - ret->framework = WINDOW_FRAMEWORK_GLFW; - ret->renderer = WINDOW_RENDERER_NONE; - ret->window = window; - /* Last parameter is used for the renderer */ - ret->context = NULL; - - { - ivec2 wsize; - vec2 wscaling; - glfwGetWindowContentScale(window, &wscaling[0], &wscaling[1]); - glfwGetWindowSize(window, &wsize[0], &wsize[1]); - - ret->windowsize[0] = (i32)((f32)wsize[0] * wscaling[0]); - ret->windowsize[1] = (i32)((f32)wsize[1] * wscaling[1]); - - INFO("WINDOW CONTENT SCALING: %.2f x %.2f", wscaling[0], wscaling[1]); - INFO("WINDOW SIZE: %d x %d -> %d x %d", wsize[0], wsize[1], ret->windowsize[0], ret->windowsize[1]); - } - - // TODO: set this to `ret` once all the garbage is moved to `struct Window` - glfwSetWindowUserPointer(window, (void*)ret); - - render_init_opengl(ret, flags); - - return ret; -} - -void window_destroy_glfw(Window *restrict w) { - glfwDestroyWindow(w->window); - w->window = NULL; - - // If we ever do multi-window support, we need to make sure this is the last - // window before terminating - glfwTerminate(); - - switch(w->renderer) { - case WINDOW_RENDERER_OPENGL: - // Missing unloader function in glad MX library - free(w->context); - w->context = NULL; - break; - default: - ERROR("Destroying unknown renderer type."); - } -} - -void window_resize_glfw(Window *restrict window, int width, int height) { - window_resize_callback(window->window, width, height); - framebuffer_resize_callback(window->window, width, height); -} - -bool window_should_close_glfw(Window *restrict window) { - return glfwWindowShouldClose(window->window); -} - -void window_poll_glfw(void) { - glfwPollEvents(); -} - -// Helper function implementations -static void window_resize_callback(GLFWwindow* window, int width, int height) { - (void)width; (void)height; - Window* w = glfwGetWindowUserPointer(window); - glfwSwapBuffers(window); - if (w != NULL) { - const GladGLContext* gl = w->context; - gl->Finish(); - } -} - -static void framebuffer_resize_callback(GLFWwindow* window, int width, int height) { - (void)width; (void)height; - Window* w = glfwGetWindowUserPointer(window); - if (w != NULL) { - const GladGLContext* gl = w->context; - //TODO: Move the camera to window->renderer - //Camera* c = w->cam; - gl->Viewport(0,0, width, height); - w->windowsize[0] = width; - w->windowsize[1] = height; - - //r_reset_camera(c); - } -} - -static void glfw_err_callback(int code, const char* description) { - ERROR("glfw [%d]: %s\n", code, description); - // Terminate? - exit(EXIT_FAILURE); -} - -static void render_init_opengl(Window *restrict w, const u32 flags) { - if (w->renderer != WINDOW_RENDERER_NONE || w->context != NULL) { - ERROR("Window already initialized with a renderer!"); - return; - } - - // This is GLFW specific - glfwMakeContextCurrent(w->window); - - GladGLContext* ctx = (GladGLContext*)malloc(sizeof(GladGLContext)); - if (!ctx) { - ERROR("Failed to allocate memory for context"); - } - - int version = gladLoadGLContext(ctx, glfwGetProcAddress); - INFO("Loaded OpenGL %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)); - - if (ctx == NULL) { - ERROR("Failed to create glad context"); - exit(EXIT_FAILURE); - } - - if (flags & DAW_WINDOW_VSYNC) { - glfwSwapInterval(1); - } else { - glfwSwapInterval(0); - } - - - ctx->Viewport(0, 0, w->windowsize[0], w->windowsize[1]); - -#ifdef _DEBUG - ctx->ClearColor((float)0x10 / 255.f, (float)0x0a / 255.f, (float)0x33 / 255.f, 0.f); -#else - ctx->ClearColor(0x0, 0x0, 0x0, 0.f); -#endif - - // Make sure faces closest to the camera are drawn on-top of faces that are - // further away - ctx->Enable(GL_DEPTH_TEST); - ctx->DepthFunc(GL_LESS); - - w->context = ctx; - w->renderer = WINDOW_RENDERER_OPENGL; -} - -static void window_size(GLFWwindow *restrict w, ivec2 *restrict dst) { - ivec2 wsize; - vec2 wscaling; - glfwGetWindowContentScale(w, &wscaling[0], &wscaling[1]); - glfwGetWindowSize(w, &wsize[0], &wsize[1]); - - *dst[0] = (i32)((f32)wsize[0] * wscaling[0]); - *dst[1] = (i32)((f32)wsize[1] * wscaling[1]); -} diff --git a/src/rendering/src/rendering.c b/src/rendering/src/rendering.c deleted file mode 100644 index 8932cfc..0000000 --- a/src/rendering/src/rendering.c +++ /dev/null @@ -1,696 +0,0 @@ -#include <stdio.h> -#include <string.h> - -#include <glad/gl.h> -#include <GLFW/glfw3.h> -#include <cglm/cam.h> -#include <cglm/vec2.h> -#include <cglm/mat4.h> - - -#include <engine/engine.h> -#include <engine/utils.h> -#include <engine/rendering/rendering.h> - - -/* Extern globals */ -extern Instance* GLOBAL_PLATFORM; - -/* Globals */ -#define drawcall_limit (64 * 1024) -RenderDrawCall drawcalls[drawcall_limit]; -i32 drawcall_len = 0; - -usize -ShaderBufferDataType_size(u16 flags) { - const ShaderBufferFlag t = ShaderBuffer_get_data_type(flags); - switch (t) { - case ShaderBuffer_DataType_nil: return 0; - case ShaderBuffer_DataType_f32: return sizeof(f32); - case ShaderBuffer_DataType_f64: return sizeof(f64); - case ShaderBuffer_DataType_i8: return sizeof(i8); - case ShaderBuffer_DataType_i16: return sizeof(i16); - case ShaderBuffer_DataType_i32: return sizeof(i32); - case ShaderBuffer_DataType_i64: return sizeof(i64); - case ShaderBuffer_DataType_u8: return sizeof(u8); - case ShaderBuffer_DataType_u16: return sizeof(u16); - case ShaderBuffer_DataType_u32: return sizeof(u32); - case ShaderBuffer_DataType_u64: return sizeof(u64); - default: return 0; - } -} - -ShaderBufferFlag ShaderBuffer_get_access_frequency(u64 flags) { return flags & (0b111 << 0); } -ShaderBufferFlag ShaderBuffer_get_access_type(u64 flags) { return flags & (0b111 << 3); } -ShaderBufferFlag ShaderBuffer_get_type(u64 flags) { return flags & (0b111 << 6); } -ShaderBufferFlag ShaderBuffer_get_data_type(u64 flags) { return flags & (0b1111 << 9); } - -u32 ShaderBuffer_get_gl_type(u64 flags) { - switch(ShaderBuffer_get_type(flags)) { - case ShaderBuffer_Type_vertexData: - return GL_ARRAY_BUFFER; - case ShaderBuffer_Type_vertexPosition: - return GL_ARRAY_BUFFER; - case ShaderBuffer_Type_vertexIndex: - return GL_ELEMENT_ARRAY_BUFFER; - default: - return GL_ARRAY_BUFFER; - } -} - - -u32 ShaderBuffer_get_gl_accesstype(u64 flags) { - switch (ShaderBuffer_get_access_frequency(flags)) { - case ShaderBuffer_AccessFrequency_stream: - switch (ShaderBuffer_get_access_type(flags)) { - case ShaderBuffer_AccessType_draw: return GL_STREAM_DRAW; - case ShaderBuffer_AccessType_read: return GL_STREAM_READ; - case ShaderBuffer_AccessType_copy: return GL_STREAM_COPY; - default: return 0; - } - - case ShaderBuffer_AccessFrequency_static: - switch (ShaderBuffer_get_access_type(flags)) { - case ShaderBuffer_AccessType_draw: return GL_STATIC_DRAW; - case ShaderBuffer_AccessType_read: return GL_STATIC_READ; - case ShaderBuffer_AccessType_copy: return GL_STATIC_COPY; - default: return 0; - } - case ShaderBuffer_AccessFrequency_dynamic: - switch (ShaderBuffer_get_access_type(flags)) { - case ShaderBuffer_AccessType_draw: return GL_DYNAMIC_DRAW; - case ShaderBuffer_AccessType_read: return GL_DYNAMIC_READ; - case ShaderBuffer_AccessType_copy: return GL_DYNAMIC_COPY; - default: return 0; - } - default: return 0; - } -} - -ShaderBufferFlag ShaderBuffer_get_gl_datatype(u64 flags) { - switch (ShaderBuffer_get_data_type(flags)) { - case ShaderBuffer_DataType_nil: return GL_NONE; - - case ShaderBuffer_DataType_f32: return GL_FLOAT; - case ShaderBuffer_DataType_f64: return GL_DOUBLE; - - case ShaderBuffer_DataType_i8: return GL_BYTE; - case ShaderBuffer_DataType_i16: return GL_SHORT; - case ShaderBuffer_DataType_i32: return GL_INT; - case ShaderBuffer_DataType_i64: return GL_INT64_ARB; - - case ShaderBuffer_DataType_u8: return GL_UNSIGNED_BYTE; - case ShaderBuffer_DataType_u16: return GL_UNSIGNED_SHORT; - case ShaderBuffer_DataType_u32: return GL_UNSIGNED_INT; - case ShaderBuffer_DataType_u64: return GL_UNSIGNED_INT64_ARB; - - default: return GL_NONE; - } -} - -// `RenderBatch` is used for batch rendering. The struct is used as a -// "management" parent structure to keep track of multiple `RenderObject`s that -// are put into a final `RenderObject` to render. -// `RenderObject`s are copied to the internal `models` array, to which the -// pointer to the copied RenderObject is returned, or NULL if an error occurred. -// If changes are made to a render object the batch should be refreshed. -// Renderbatches assumes that all buffer layouts are the same. - -// renderbatch_new: Create a new render batch with space for `count` models. -int renderbatch_new(RenderBatch* renderbatch, usize count) { - /* TODO: Make it such that you can add identical models with different - * transforms, so you instead of relying on renderobject[n] to copy to the - * renderobject we have something like - * - * model { - * renderobj_idx // index in renderobj[n] that this model represents - * transform { - * size; - * pos; - * rotation; - * }; - * }; - * - * For this to work we will likely need to extend the shaderbuffer struct to - * also hold what type of data the buffer contains, s.t. we can apply the - * transformation to only geometry data. - * - * We'll therefore have both data type and buffer type stored somehow, - * maybe like we did the ShaderBufferDataType. - * TODO: Also use shaderbuffertype. - * */ - if (renderbatch == NULL) { - ERROR("renderbatch was null!"); - return -1; - } - - usize numisnstances = count; - - if (count == 0) { - // Just allocate enough for a couple hundred - count = 256; - numisnstances = count * 4; - } - - - renderbatch->msize = sizeof(RenderObject) * count; - renderbatch->mcount = 0; - renderbatch->inst_size = sizeof(BatchModelInstance) * numisnstances; - renderbatch->inst_count = 0; - renderbatch->models = (RenderObject**)calloc(count, sizeof(RenderObject*)); - - if (renderbatch->models == NULL) { - ERROR("Failed to allocate %lu size of bytes for models array!", sizeof(RenderObject*) * count); - return -1; - } - - renderbatch->instances = (BatchModelInstance*)calloc(numisnstances, sizeof(BatchModelInstance)); - - if (renderbatch->instances == NULL) { - ERROR("Failed to allocate %lu size of bytes for batch instances array!", sizeof(BatchModelInstance) * numisnstances); - return -1; - } - - memset(&(renderbatch->renderobj), 0, sizeof(RenderObject)); - - return 0; -} - -// Appends the data in src onto dst. More space for `data` is allocated if -// necessary, in which case a pointer to the new ShaderBuffer is returned. -ShaderBuffer* shaderbuffer_cat(ShaderBuffer* dst, ShaderBuffer *restrict src) { - if (dst == NULL) { - ERROR("dst is null"); - } - else if (src == NULL) { - ERROR("src is null"); - } - - if (ShaderBuffer_get_data_type(dst->buffertype) != ShaderBuffer_get_data_type(src->buffertype)) { - ERROR("Failed to concatenate shader buffers, incompatible datatypes: %d != %d", dst->buffertype, src->buffertype); - } - if (dst->components != src->components) { - ERROR("Failed to concatenate shader buffers, incompatible number of components: %d != %d", dst->components, src->components); - } - - // Assume that we single-handedly control the pointer to the data, copy and - // free the stuff. - - // Verify the size - const usize sz_src = src->size_elem * src->count; - const usize sz_dst = dst->size_elem * dst->count; - if (dst->data == NULL || sz_dst + sz_src >= dst->size) { - const usize sz_new = (1 + ((sz_src + sz_dst) / 4096)) * 4096; - // Resize dst size - dst->data = realloc(dst->data, sz_new); - dst->size = sz_new; - } - - memcpy(dst->data + sz_dst, src->data, sz_src); - - dst->count += src->count; - - return dst; -} - -// Add a render object to the render batch. -i32 renderbatch_add(RenderBatch* renderbatch, RenderObject* obj, Transform* t) { - // Check if its a valid renderbatch - if (renderbatch == NULL) { - ERROR("renderbatch was null!"); - return -1; - } - - // Check whether we have initialized models & instance memory - if (renderbatch->models == NULL) { - const usize sz = 8 * sizeof(RenderObject*); - renderbatch->models = calloc(8, sizeof(RenderObject*)); - renderbatch->msize = sz; - renderbatch->mcount = 0; - } - - if (renderbatch->instances == NULL) { - // Allocate enough for 4 times the models - const usize modelbufsz = renderbatch->msize / sizeof(RenderObject*); - const usize sz = 4 * modelbufsz * sizeof(BatchModelInstance); - renderbatch->instances = calloc(4 * modelbufsz, sizeof(BatchModelInstance)); - renderbatch->inst_size = sz; - renderbatch->inst_count = 0; - } - - // The index of the model - isize model_idx = -1; - - // Find the model, to check if it already exists - for (usize i = 0; i < renderbatch->mcount; i++) { - // Compare the model pointers - if (obj == renderbatch->models[i]) { - model_idx = (isize)i; - break; - } - } - - // Model doesn't exist, add it - if (-1 == model_idx) { - // Check if there's room enough - if ((1 + renderbatch->mcount) * sizeof(RenderObject*) > renderbatch->msize) { - // Realloc if necessary - const usize sz = renderbatch->msize * 2; - renderbatch->models = realloc(renderbatch->models, sz); - renderbatch->msize = sz; - } - - // If this is the first model, we want to copy the renderobj, and - // shaderbuffer parameters. - if (renderbatch->mcount == 0) { - // Shader, VAO, modelviewprojection, and texture, are set when the shaderobj - // is actually created with RenderObject_new later. - // The number of buffers should be the same. - //renderbatch->renderobj.shader = obj->shader; - //renderbatch->renderobj.texture = obj->texture; - - renderbatch->renderobj.buffer_len = obj->buffer_len; - if (renderbatch->renderobj.buffer == NULL) { - renderbatch->renderobj.buffer = calloc(obj->buffer_len, sizeof(ShaderBuffer)); - } else { - ERROR("RenderObj buffer is already initialized!"); - return -1; - } - - // Copy each buffers parameters - for (usize i = 0; i < renderbatch->renderobj.buffer_len; i++) { - renderbatch->renderobj.buffer[i].buffername = 0; - renderbatch->renderobj.buffer[i].buffertype = obj->buffer[i].buffertype; - // Size and count should be zero - - renderbatch->renderobj.buffer[i].components = obj->buffer[i].components; - renderbatch->renderobj.buffer[i].size_elem = obj->buffer[i].size_elem; - // Data should also be null - } - } - - //// Only concatenate the buffers once we refresh - //for (usize i = 0; i < renderbatch->renderobj.buffer_len; i++) { - // shaderbuffer_cat(&renderbatch->renderobj.buffer[i], &obj->buffer[i]); - //} - - model_idx = (isize)renderbatch->mcount; - renderbatch->models[renderbatch->mcount++] = obj; - } - - // Create batch instance - // Check if there's room enough - if ((1 + renderbatch->inst_count) * sizeof(BatchModelInstance) > renderbatch->inst_size) { - // Realloc if necessary - const usize sz = renderbatch->inst_size * 2; - renderbatch->instances = realloc(renderbatch->instances, sz); - renderbatch->inst_size = sz; - } - - BatchModelInstance inst = { - .model_idx = (usize)model_idx, - .transform = *t, - }; - - // Add it to the batch - renderbatch->instances[renderbatch->inst_count++] = inst; - - // Return instance index - return (i32)renderbatch->inst_count - 1; -} - -void renderbatch_transform(RenderBatch* renderbatch, usize obj_idx, Transform* t) { - // TODO: Combine transformation, ie. pos' += pos, etc. - const usize m = renderbatch->instances[obj_idx].model_idx; - const RenderObject* model = renderbatch->models[m]; - renderbatch->instances[obj_idx].transform = *t; - - if(renderbatch->inst_count < obj_idx) { - ERROR("renderbatch_transform: object index is outside range!"); - return; - } - /* TODO: Update the model data, we might need to - * 0. Iteratively go through each renderobj buffer, to find a vertexPosition - * buffer, - * 1. Calculate the models start index in the renderobj, - * 2. Apply transformation to the model in the renderobj buffer. - * */ - usize b; - for (b = 0; b < renderbatch->renderobj.buffer_len; b++) { - if (ShaderBuffer_Type_vertexPosition != ShaderBuffer_get_type(renderbatch->renderobj.buffer[b].buffertype) - || ShaderBuffer_DataType_f32 != ShaderBuffer_get_data_type(renderbatch->renderobj.buffer[b].buffertype)) { - continue; - } - } - - usize offset = 0; - for (usize i = 0; i < obj_idx; i++) { - const usize idx = renderbatch->instances[i].model_idx; - offset += renderbatch->models[idx]->buffer->size_elem - * renderbatch->models[idx]->buffer->count; - } - - float *data = renderbatch->renderobj.buffer[b].data; - data = &data[offset]; - const usize len = model->buffer[b].count; - - Transform tt = renderbatch->instances[obj_idx].transform; - if (model->buffer[b].components == 2) { - for (usize v = 0; v < len; v += 2) { - // scale - // rotate - // offset - glm_vec2_add(&data[v], tt.position, &data[v]); - } - } - else if (model->buffer[b].components == 3) { - for (usize v = 0; v < len; v += 3) { - // scale - // rotate - // offset - glm_vec3_add(&data[v], tt.position, &data[v]); - } - } -} - -// renderbatch_refresh: Copy all instances/models in the renderbatch to the -// batchs' model. -int renderbatch_refresh(RenderBatch* renderbatch) { - const usize bufs = renderbatch->renderobj.buffer_len; - usize *offsets = calloc(bufs, sizeof(usize)); - - // Reset renderobj buffers - for (usize b = 0; b < renderbatch->renderobj.buffer_len; b++) { - // Zero the old data - renderbatch->renderobj.buffer[b].count = 0; - memset(renderbatch->renderobj.buffer[b].data, 0, renderbatch->renderobj.buffer[b].size); - } - - // Copy the instances models buffers, and vertex position buffers with translations applied - for (usize i = 0; i < renderbatch->inst_count; i++) { - const usize m = renderbatch->instances[i].model_idx; - const RenderObject* model = renderbatch->models[m]; - Transform t = renderbatch->instances[i].transform; - - for (usize b = 0; b < renderbatch->renderobj.buffer_len; b++) { - shaderbuffer_cat(&renderbatch->renderobj.buffer[b], &model->buffer[b]); - - if (ShaderBuffer_Type_vertexPosition == ShaderBuffer_get_type(renderbatch->renderobj.buffer[b].buffertype)) { - if (ShaderBuffer_DataType_f32 != ShaderBuffer_get_data_type(renderbatch->renderobj.buffer[b].buffertype)) { - WARN("Buffer data type is not f32, skipping transformation..."); - continue; - } - // Apply transformation in renderbatch buffer-memory - - float *data = renderbatch->renderobj.buffer[b].data; - const usize len = model->buffer[b].count; - // Data points to the start of the model in renderobj - data = &data[renderbatch->renderobj.buffer[b].count - len]; - - if (model->buffer[b].components == 2) { - for (usize v = 0; v < len; v += 2) { - // scale - // rotate - // offset - glm_vec2_add(&data[v], t.position, &data[v]); - } - } - else if (model->buffer[b].components == 3) { - for (usize v = 0; v < len; v += 3) { - // scale - // rotate - // offset - glm_vec3_add(&data[v], t.position, &data[v]); - } - } - } - } - } - - free(offsets); - return 0; -} - - -/* Implementations */ - -/* Clear the screen, - * To be used inbetween draw calls */ -void render_begin(Window* w) { - glfwMakeContextCurrent(w->window); - ((GladGLContext*)(w->context))->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void render_present(Window* w) { - /* This is GL specific, TODO: move the GL-specific code elsewhere. Maybe make - * this whole present GL specific? assign it as a fn ptr in the Window struct? */ - GladGLContext *restrict gl = w->context; - Camera c = *GLOBAL_PLATFORM->cam; - - mat4 view; // view - vec3 angle; // viewing angle / direction of the camera - mat4 camera_matrix; - - glm_vec3_sub(c.pos, c.dir, angle); - glm_lookat(c.pos, angle, GLM_YUP, view); - glm_mat4_mul(c.per, view, camera_matrix); - - for (i32 drawcall_idx = 0; drawcall_idx < drawcall_len; drawcall_idx++) { - RenderDrawCall dc = drawcalls[drawcall_idx]; - switch (dc.type) { - case RenderDrawCallType_Sprite: { - // TODO render a quad - } break; - - case RenderDrawCallType_Model: { - - // bind shader program - // - set uniforms - // bind vertex array - // bind index buffer - - - RenderObject* o = dc.data.model.model; - vec3 pos; - glm_vec3_copy(dc.data.model.pos, pos); - - gl->UseProgram(o->shader.program); - // TODO: Use texture atlas - gl->ActiveTexture(GL_TEXTURE0); - gl->BindTexture(GL_TEXTURE_2D, o->texture); - - { - mat4 model = GLM_MAT4_IDENTITY_INIT; - mat4 modelviewprojection; - - model[3][0] = pos[0]; - model[3][1] = pos[1]; - model[3][2] = pos[2]; - - // modelviewprojection = p * view * model - glm_mat4_mul(model, camera_matrix, modelviewprojection); - - // TODO: Do this only once during initialization - gl->UniformMatrix4fv(o->mvp, 1, GL_FALSE, &modelviewprojection[0][0]); - } - - // TODO the buffers need to be abstracted a bit more - gl->BindVertexArray(o->vao); - - ShaderBuffer* ibo = NULL; - for (usize i = 0; i < o->buffer_len; i++) { - const u32 b_gl_type = ShaderBuffer_get_gl_type(o->buffer[i].buffertype); - if (b_gl_type == GL_ELEMENT_ARRAY_BUFFER) { - ibo = &o->buffer[i]; - } - - gl->EnableVertexAttribArray((u32)i); - gl->BindBuffer(b_gl_type, o->buffer[i].buffername); - gl->VertexAttribPointer( - // index of the attribute - (u32)i, - // number of component - (i32)o->buffer[i].components, - // type - ShaderBuffer_get_gl_datatype(o->buffer[i].buffertype), - // normalized? - GL_FALSE, - // stride - 0, - // array buffer offset - (void*)0 - ); - } - - // Draw the model ! - const i32 sz = (i32)(o->buffer->count * o->buffer->size_elem); - if (ibo) { - gl->DrawElements( - GL_TRIANGLES, - (i32)ibo->count, - ShaderBuffer_get_gl_datatype(ibo->buffertype), - (void*)0 - ); - } else { - // Starting from vertex 0; 3 vertices total -> 1 triangle - gl->DrawArrays(GL_TRIANGLES, 0, sz); - } - - for (u32 i = 0; i < o->buffer_len; i++) { - gl->DisableVertexAttribArray(i); - } - - gl->BindVertexArray(0); - - //if (i == 8) { - // printf("\r obj: %.3f", (double)(get_time() - t) * 1000.); - //} - } break; - default: - break; - } - } - - drawcall_len = 0; - - glfwSwapBuffers(w->window); -} - -void drawcall_reset(void) { - drawcall_len = 0; - memset(drawcalls, 0, sizeof(RenderDrawCall) * drawcall_limit); -} - -void r_perspective(f32 fov, Camera *c) { - const f32 ratio = (f32)GLOBAL_PLATFORM->window->windowsize[0] - / (f32)GLOBAL_PLATFORM->window->windowsize[1]; - - c->type = Camera_Perspective; - c->parameters.perspective.fov = fov; - - glm_perspective(glm_rad(fov), ratio, 0.1f, 100.0f, c->per); -} - -void r_perspective_ortho(f32 sz, Camera *c) { - const f32 ratio = (f32)GLOBAL_PLATFORM->window->windowsize[0] - / (f32)GLOBAL_PLATFORM->window->windowsize[1]; - - c->type = Camera_Orthogonal; - c->parameters.orthogonal.sz = sz; - - glm_ortho(-sz * ratio, sz * ratio, -sz, sz, -sz * 10.f, sz * 10.f, c->per); -} - -void r_set_camera(Camera* c) { - GLOBAL_PLATFORM->cam = c; -} - - -void r_reset_camera(Camera* c) { - if (c->type == Camera_Perspective) { - r_perspective(c->parameters.perspective.fov, c); - } - else if (c->type == Camera_Orthogonal) { - r_perspective_ortho(c->parameters.orthogonal.sz, c); - } -} - -void engine_draw_sprite(Sprite* s, ivec2* pos, f32 scale) { - if (drawcall_len + 1 >= drawcall_limit) return; -#ifdef _DEBUG - if (s == NULL) __asm__("int3;"); -#endif - drawcalls[drawcall_len++] = - (RenderDrawCall){.type = RenderDrawCallType_Sprite, - .data.sprite = { - .sprite = s, - .x = *pos[0], - .y = *pos[1], - .scale = scale, - //.mod = {0xFF, 0xFF, 0xFF, 0xFF}, - }}; -} - -void engine_draw_sprite_ex(Sprite* s, ivec2* pos, f32 scale, - Engine_color colormod) { - if (drawcall_len + 1 >= drawcall_limit) return; -#ifdef _DEBUG - if (s == NULL) __asm__("int3;"); -#endif - drawcalls[drawcall_len++] = (RenderDrawCall){ - .type = RenderDrawCallType_Sprite, - .data.sprite = { - .sprite = s, - .x = *pos[0], - .y = *pos[1], - .scale = scale, - //.mod = {colormod.r, colormod.g, colormod.b, colormod.a}, - }}; -} - -void engine_draw_model(RenderObject* o, vec3 pos) { - if (drawcall_len + 1 >= drawcall_limit) return; -#ifdef _DEBUG - if (o == NULL) __asm__("int3;"); -#endif - RenderDrawCall dc = { - .type = RenderDrawCallType_Model, - .data.model = { - .model = o, - .scale = 1.f, - }}; - - - glm_vec3_copy(pos, dc.data.model.pos); - - drawcalls[drawcall_len++] = dc; -} - -Sprite sprite_new(u64 tid, u8 coord) { - const i32 ts = 16; - // FIXME; used to be - //((struct Resources*)GLOBAL_PLATFORM->data)->textures[tid]->tilesize; - return (Sprite){ - .texture_id = (u32)tid, - { - ts * (coord & 0x0F), - ts * ((coord & 0xF0) >> 4), - }}; -} - -Texture createTextureFromImageData(unsigned char* image_data, i32 width, i32 height, u8 components) { - Window* restrict w = GLOBAL_PLATFORM->window; - Texture t; - t.width = width; - t.height = height; - - if (w->renderer != WINDOW_RENDERER_OPENGL) { - ERROR("createTextureFromImageData not implemented for chosen renderer!"); - return (Texture){.id = 0, .width = 0, .height = 0}; - } - - const GladGLContext* gl = w->context; - - gl->GenTextures(1, &t.id); - gl->BindTexture(GL_TEXTURE_2D, t.id); - u32 err = gl->GetError(); - if (err) { - ERROR("Failed to bind texture from image data!"); - } - - /* TODO: Support more formats than rgb and rgba, such as gray, gray/alpha, etc.*/ - u32 format = GL_RGB; - if (components == 4) format = GL_RGBA; - - /* TODO: Don't force internal format to RGB */ - - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, - GL_UNSIGNED_BYTE, image_data); - - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - gl->BindTexture(GL_TEXTURE_2D, 0); - - return t; -} diff --git a/src/rendering/src/window.c b/src/rendering/src/window.c deleted file mode 100644 index d761543..0000000 --- a/src/rendering/src/window.c +++ /dev/null @@ -1,83 +0,0 @@ -#include <time.h> - -/* TODO: REMOVE THIS INCLUSION */ -#include <engine/engine.h> - -#include <engine/core/types.h> -#include <engine/core/logging.h> - -#define ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS -#include <engine/rendering/window.h> -#undef ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS - -#include <engine/rendering/platform_glfw.h> - -#include <glad/gl.h> - -#undef GLFW_INCLUDE_NONE -#include <GLFW/glfw3.h> - -#include <cglm/ivec2.h> - -extern Instance* GLOBAL_PLATFORM; - -static inline u64 platform_get_time_usec(void) { - struct timespec t; - int res = clock_gettime(CLOCK_MONOTONIC, &t); - if (res != 0) { - // TODO: Check errno - WARN("Failed to get system time"); - } - return (u64)(t.tv_sec * 1000000 + t.tv_nsec / 1000); -} - -/* wrapper to get time in ms */ -u64 (*get_time)(void) = platform_get_time_usec; - - -#define DAW_WINDOW_VSYNC (1 << 0) -#define DAW_WINDOW_FULLSCREEN (1 << 1) -#define DAW_WINDOW_RESIZEABLE (1 << 2) - -// Wrapper to get a specific window and set up related structures. -Window* Window_new(const char *restrict title, Window_framework framework, Window_renderer renderer, ivec2 size, u32 flags) { - Window* w = NULL; - - switch (framework) { - case WINDOW_FRAMEWORK_GLFW: - switch (renderer) { - case WINDOW_RENDERER_OPENGL: - /* For now, pass instance as NULL, fix it once all the necessary bs is - * out of struct Instance */ - w = Platform_GLFW.window_init(title, size, flags); - - w->bindings = NULL; - w->bindings_sz = 0; - w->bindings_len = 0; - - /// TODO - //w->cam = &default_camera; - return w; - break; - default: - ERROR("Unsupported renderer."); - } - break; - default: - ERROR("Unsupported framework."); - } - return NULL; -} - -void get_mousepos(double *x, double *y) { - Window* w = GLOBAL_PLATFORM->window; - - switch(w->framework) { - case WINDOW_FRAMEWORK_GLFW: - glfwGetCursorPos(GLOBAL_PLATFORM->window->window, x, y); - break; - default: - ERROR("get_mouse_pos not implemented for chosen framework."); - } - -} |
