diff options
| -rw-r--r-- | src/daw.c | 29 | ||||
| -rw-r--r-- | src/include/daw/rendering.h | 107 | ||||
| -rw-r--r-- | src/include/daw/window.h | 20 | ||||
| -rw-r--r-- | src/rendering.c | 63 | ||||
| -rw-r--r-- | src/window.c | 121 |
5 files changed, 315 insertions, 25 deletions
@@ -171,9 +171,24 @@ i32 engine_run(Instance* p, StateType initial_state, void* state_arg) { StateType state = initial_state; + Window* w = p->window; + { u64 state_init_time = get_time(); State_init(state, mem, state_arg); + if (!w->render_targets) { + // Create only 1 additional framebuffer, in addition to the default + // one. This is used to render a texture that is represented as a quad + // on the default framebuffer. + FramebufferParameters p[] = { + {.num_attached_buffers = 1, {200,200}}, + }; + u32 t[] = { + BUFFERPARAMETER_SET_PARAMETER(BUFFERPARAMETER_SET_TYPE(0, BufferType_texture), BUFFERPARAMETER_TEXTURE_2D) + }; + window_init_renderstack(w, 1, 1, p, t); + w->render_targets->cam[0] = default_camera; + } INFO("Initializing state \"%s\" took %.1fns", StateTypeStr[state], (get_time() - state_init_time)); } @@ -222,12 +237,26 @@ i32 engine_run(Instance* p, StateType initial_state, void* state_arg) { // Reset camera to default camera p->cam = &default_camera; + free(w->render_targets); state = next_state; update_func = State_updateFunc(state); { u64 state_init_time = get_time(); State_init(state, mem, retval); + if (!w->render_targets) { + // Create only 1 additional framebuffer, in addition to the default + // one. This is used to render a texture that is represented as a quad + // on the default framebuffer. + FramebufferParameters p[] = { + {.num_attached_buffers = 1, {200,200}}, + }; + u32 t[] = { + BUFFERPARAMETER_SET_PARAMETER(BUFFERPARAMETER_SET_TYPE(0, BufferType_texture), BUFFERPARAMETER_TEXTURE_2D) + }; + window_init_renderstack(w, 1, 1, p, t); + w->render_targets->cam[0] = default_camera; + } INFO("Initializing state \"%s\" took %.1fns", StateTypeStr[state], (get_time() - state_init_time)); } diff --git a/src/include/daw/rendering.h b/src/include/daw/rendering.h index 9c4b647..17d3728 100644 --- a/src/include/daw/rendering.h +++ b/src/include/daw/rendering.h @@ -204,15 +204,16 @@ u32 ShaderBuffer_get_gl_accesstype(u64 flags); u32 ShaderBuffer_get_gl_datatype(u64 flags); /* Misc */ -void r_perspective(f32 fov, Camera *c); -void r_perspective_ortho(f32 sz, Camera *c); +void r_perspective(Camera *c, f32 fov, ivec2 windowsize); +void r_perspective_ortho(Camera *c, f32 sz, ivec2 windowsize); void r_set_camera(Camera* c); -void r_reset_camera(Camera* c); +void r_reset_camera(Camera* c, ivec2 windowsize); //void window_size_callback(GLFWwindow* window, i32 width, i32 height); -void engine_draw_model(RenderObject* o, vec3 pos); +// 3D positional coordinates and scale in last element of `pos` +void engine_draw_model(RenderObject* o, vec4 pos); typedef struct { vec3 pos; @@ -220,7 +221,89 @@ typedef struct { RenderObject* model; } RenderDrawCall; -// TODO make all the shader buffers a list +typedef enum { + BufferType_frame = 1, + BufferType_texture = 2, + BufferType_render = 3, + BufferType_buffer = 4, + +} BufferType; + +// Buffer parameter: Frame buffer +// Buffer parameter: Texture buffer +#define BUFFERPARAMETER_TEXTURE_1D 1 +#define BUFFERPARAMETER_TEXTURE_2D 2 +#define BUFFERPARAMETER_TEXTURE_3D 3 +#define BUFFERPARAMETER_TEXTURE_4D 4 + +#define BUFFERPARAMETER_TEXTURE_FMT_RGBA8 (1 << 4) +#define BUFFERPARAMETER_TEXTURE_FMT_SRGB8 (2 << 4) +#define BUFFERPARAMETER_TEXTURE_FMT_SRGBA8 (3 << 4) + +//TODO: texture formats + +// Buffer parameter: Buffer buffer +#define BUFFERPARAMETER_BUFFER_DEPTH 1 +#define BUFFERPARAMETER_BUFFER_STENCIL 2 + +// `buffer_definition` has the first 4 bits for the type, +#define BUFFERPARAMETER_MASK_TYPE ((1 << 4) - 1) +// next 16 bits for the type-specific parameters +#define BUFFERPARAMETER_MASK_PARAMETER (((1 << 16) - 1) << 4) + +#define BUFFERPARAMETER_GET_TYPE(bufferparam) \ + (BufferType)(bufferparam & BUFFERPARAMETER_MASK_TYPE) +#define BUFFERPARAMETER_GET_PARAMETER(bufferparam) \ + ((bufferparam & BUFFERPARAMETER_MASK_TYPE) >> 4) + +#define BUFFERPARAMETER_SET_TYPE(bufferparam, type) \ + (BufferType)((bufferparam & ~BUFFERPARAMETER_MASK_TYPE) | type) +#define BUFFERPARAMETER_SET_PARAMETER(bufferparam, param) \ + ((bufferparam & ~BUFFERPARAMETER_MASK_PARAMETER) | (param << 4)) + +typedef struct { + i32 num_attached_buffers; + ivec4 dimensions; // All objects attached to a framebuffer (in OpenGL) must have same size +} FramebufferParameters; + +// A render target takes a bunch of drawcalls, and renders it to a texture. +// TODO: user runs "init" for their rendertarget(s) "stack", possibly using some +// predefined macro "DEFAULT_RENDERTARGETS". Requires user to specify number of lights et. al. +typedef struct { + // glFrameBuffer + usize framebuffer_len; + + // glTexture / glRenderBuffer / glBuffer / glWhatever + usize buffer_len; + + u32 *framebuffer; + u32 *buffer; + + // Number of buffers attached to each of the framebuffers. Used to iteratively + // get all buffers by summing the previous sizes to get the first buffer + // associated with the current. + FramebufferParameters *framebuffer_parameters; + + // Stores per-buffer type, and type-specific parameters. + u32 *buffer_parameters; + + // One cam per framebuffer + Camera *cam; + + //// Called when window is resized with new width and height. Set to NULL to + //// skip changing texture_size. Comparable to glViewport. + //// This function can be heavy due to it destroying and re-creating framebuffers. + //// Which requires me to store the parameters that they we're created with. + //void (**framebuffer_size_callback)(ivec2*,ivec2); + + //// Called when window is resized. Calls the respective texture_size_callback function at + //// the same index if not null. The camera resize callback function is then + //// called with the new dimensions of the texture. + //// Set to NULL to skip changing the camera size/perspective. + void (**camera_reset_callback)(Camera*,ivec2); +} RenderTargets; + +void r_camera_reset_default(Camera* c, ivec2 windowsize); RenderObject RenderObject_new( Shader* shader, @@ -242,6 +325,20 @@ ShaderType guess_shadertype_from_filename(const char *restrict fname); Texture createTextureFromImageData(unsigned char* image_data, i32 width, i32 height, u8 components); +void r_create_framebuffers(void* restrict ctx, u32* restrict framebuffer_array, usize num_targets); +void r_destroy_framebuffers(void* restrict ctx, u32* restrict framebuffer_array, usize num_targets); +void r_create_textures(void *restrict ctx, u32* restrict texture_array, u32* restrict texture_types, ivec4* restrict texture_sizes, usize num_targets); +void r_destroy_textures(void *restrict ctx, u32* textures, usize num_textures); + +void r_init_renderstack( + usize num_fbuf, usize num_buf, + FramebufferParameters *restrict fb_params, + u32 *restrict buffer_params + ); + +//static void r_create_renderbuffers(GladGLContext* restrict ctx, u32* restrict renderbuffer_array, u32* restrict renderbuffer_types, ivec2* restrict renderbuffer_sizes, usize num_targets); + + #ifdef __cplusplus } #endif diff --git a/src/include/daw/window.h b/src/include/daw/window.h index f445860..44ea1fa 100644 --- a/src/include/daw/window.h +++ b/src/include/daw/window.h @@ -12,6 +12,10 @@ extern "C" { #include <daw/rendering.h> +#define DAW_WINDOW_VSYNC (1 << 0) +#define DAW_WINDOW_FULLSCREEN (1 << 1) +#define DAW_WINDOW_RESIZEABLE (1 << 2) + typedef enum { WINDOW_FRAMEWORK_NONE = 0, WINDOW_FRAMEWORK_GLFW, @@ -39,11 +43,13 @@ typedef struct { usize bindings_sz; usize bindings_len; i_ctx** bindings; -} Window; -#define DAW_WINDOW_VSYNC (1 << 0) -#define DAW_WINDOW_FULLSCREEN (1 << 1) -#define DAW_WINDOW_RESIZEABLE (1 << 2) + /* The first element in the stack is the one presented to the screen. This is + * usually used for post-processing effects and can depend on previous + * RenderTextures. Use cases vary from shadowmapping, secondary in-game + * cameras, and UI. */ + RenderTargets *render_targets; +} Window; // 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. @@ -97,6 +103,12 @@ void render_present(Window* w); void window_reset_drawing(void); void render(Window* w); +void window_init_renderstack(Window *restrict w, + usize num_fbuf, usize num_buf, + FramebufferParameters *restrict fb_params, + u32 *restrict buffer_params + ); + void get_mousepos(double *x, double *y); void window_get_size(ivec2* dst); diff --git a/src/rendering.c b/src/rendering.c index 25ee1fd..76df988 100644 --- a/src/rendering.c +++ b/src/rendering.c @@ -551,9 +551,8 @@ void window_reset_drawing(void) { 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]; +void r_perspective(Camera *c, f32 fov, ivec2 windowsize) { + const f32 ratio = (f32)windowsize[0] / (f32)windowsize[1]; c->type = Camera_Perspective; c->parameters.perspective.fov = fov; @@ -561,9 +560,8 @@ void r_perspective(f32 fov, Camera *c) { 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]; +void r_perspective_ortho(Camera *c, f32 sz, ivec2 windowsize) { + const f32 ratio = (f32)windowsize[0] / (f32)windowsize[1]; c->type = Camera_Orthogonal; c->parameters.orthogonal.sz = sz; @@ -576,24 +574,24 @@ void r_set_camera(Camera* c) { } -void r_reset_camera(Camera* c) { +void r_reset_camera(Camera* c, ivec2 windowsize) { if (c->type == Camera_Perspective) { - r_perspective(c->parameters.perspective.fov, c); + r_perspective(c, c->parameters.perspective.fov, windowsize); } else if (c->type == Camera_Orthogonal) { - r_perspective_ortho(c->parameters.orthogonal.sz, c); + r_perspective_ortho(c, c->parameters.orthogonal.sz, windowsize); } } -void engine_draw_model(RenderObject* o, vec3 pos) { +void engine_draw_model(RenderObject* o, vec4 pos) { if (drawcall_len + 1 >= drawcall_limit) return; #ifdef _DEBUG if (o == NULL) __asm__("int3;"); #endif RenderDrawCall dc = { .model = o, - .scale = 1.f, + .scale = pos[3], }; glm_vec3_copy(pos, dc.pos); @@ -669,3 +667,46 @@ Texture createTextureFromImageData(unsigned char* image_data, i32 width, i32 hei return t; } + +void r_init_renderstack( + usize num_fbuf, usize num_buf, + FramebufferParameters *restrict fb_params, + u32 *restrict buffer_params + ) { + window_init_renderstack(GLOBAL_PLATFORM->window, num_fbuf, num_buf, fb_params, buffer_params); +} + +void r_create_framebuffers(void* restrict ctx, u32* restrict framebuffer_array, + usize num_targets) { + const GladGLContext* gl = (GladGLContext*)ctx; + + gl->CreateFramebuffers(num_targets, framebuffer_array); +} + +void r_destroy_framebuffers(void* restrict ctx, u32* restrict framebuffer_array, + usize num_targets) { + const GladGLContext* gl = (GladGLContext*)ctx; + + gl->DeleteFramebuffers(num_targets, framebuffer_array); +} + +void r_create_textures(void* restrict ctx, u32* restrict texture_array, + u32* restrict texture_types, + ivec4* restrict texture_size, usize num_targets) { + const GladGLContext* gl = (GladGLContext*)ctx; + + gl->CreateTextures(GL_TEXTURE_2D, num_targets, texture_array); + + for (usize i = 0; i < num_targets; i++) { + ASSERT("SWITCH CASE ON BUFFER DIMENSIONALITY"); + ASSERT("SWITCH CASE ON TEXTURE DATA TYPE"); + gl->TextureStorage2D(texture_array[i], 1, texture_types[i], *texture_size[0], *texture_size[1]); + gl->TextureParameteri(texture_array[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->TextureParameteri(texture_array[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } +} + +void r_destroy_textures(void *restrict ctx, u32* textures, usize num_textures) { + const GladGLContext* gl = (GladGLContext*)ctx; + gl->DeleteTextures(num_textures, textures); +} diff --git a/src/window.c b/src/window.c index fc688b7..9702a7f 100644 --- a/src/window.c +++ b/src/window.c @@ -10,8 +10,6 @@ #include <daw/window.h> #undef ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS -#include <glad/gl.h> - #undef GLFW_INCLUDE_NONE #include <GLFW/glfw3.h> @@ -50,14 +48,13 @@ Window* Window_new(const struct Platform* p, const char *restrict title, Window_ * out of struct Instance */ w = p->window_init(title, size, flags); + // Manually reset bindings et. al. w->bindings = NULL; w->bindings_sz = 0; w->bindings_len = 0; - /// TODO - //w->cam = &default_camera; + w->render_targets = NULL; return w; - break; default: ERROR("Unsupported renderer."); } @@ -68,6 +65,38 @@ Window* Window_new(const struct Platform* p, const char *restrict title, Window_ return NULL; } + +void window_reset_cameras(Window* w, RenderTargets* restrict targets) { + // Question, would it be better to check both callbacks and continue early, + // instead of resizing the texture first, then check the camera callback? + for (usize i = 0; i < targets->framebuffer_len; i++) { + //if (targets->framebuffer_size_callback[i] == NULL) continue; + + //ivec2 newsz; + //targets->framebuffer_size_callback[i](&newsz, w->windowsize); + + // Destroy & Create framebuffers (and related buffers?) + + if (targets->camera_reset_callback[i] == NULL) continue; + (*targets->camera_reset_callback)(&targets->cam[i], w->windowsize); + } +} + +//void window_reset_texture_sizes(Window* w, RenderTargets* restrict targets) { +// // Question, would it be more efficient to just wipe all of them at once +// // instead of doing this? Not all are necessarily deleted. +// for (usize i = 0; i < targets->texture_len; i++) { +// if (targets->framebuffer_size_callback[i] == NULL) continue; +// +// ivec2 newsz; +// targets->framebuffer_size_callback[i](&newsz, w->windowsize); +// +// r_destroy_framebuffers(w->context, targets->framebuffer, 1); +// r_create_framebuffers(w->context, &targets->framebuffer[i], &targets->framebuffer_parameters[i].framebuffer_type, &newsz, 1); +// } +//} + + void get_mousepos(double *x, double *y) { Window* w = GLOBAL_PLATFORM->window; @@ -84,3 +113,85 @@ void get_mousepos(double *x, double *y) { void window_get_size(ivec2* dst) { glm_ivec2_copy(GLOBAL_PLATFORM->window->windowsize, *dst); } + + +// Assume framebuffer_len and texture_len is already set +void window_init_renderstack(Window *restrict w, + usize num_fbuf, usize num_buf, + FramebufferParameters *restrict fb_params, + u32 *restrict buffer_params + ) { + + ASSERT(w != NULL); + ASSERT(fb_params != NULL); + ASSERT(buffer_params != NULL); + + RenderTargets *t = NULL; + void* allocation = malloc( + sizeof(RenderTargets) + + sizeof(*t->framebuffer) * num_fbuf + + sizeof(*t->buffer) * num_buf + + sizeof(*t->framebuffer_parameters) * num_fbuf + + sizeof(*t->buffer_parameters) * num_buf + + sizeof(*t->cam) * num_fbuf + // TODO: callbacks + ); + +#define ADVANCE_PTR(target, count)\ + t->target = (void*)((u64)allocation + acc); \ + acc += sizeof(*t->target) * count + + t = allocation; + + t->framebuffer_len = num_fbuf; + t->buffer_len = num_buf; + + u64 acc = sizeof(RenderTargets); + ADVANCE_PTR(framebuffer, num_fbuf); + ADVANCE_PTR(buffer, num_buf); + ADVANCE_PTR(framebuffer_parameters, num_fbuf); + ADVANCE_PTR(buffer_parameters, num_buf); + ADVANCE_PTR(cam, num_fbuf); + // TODO: callbacks +#undef ADVANCE_PTR + + memcpy(t->framebuffer_parameters, fb_params, sizeof(*t->framebuffer_parameters) * num_fbuf); + memcpy(t->buffer_parameters, buffer_params, sizeof(*t->buffer_parameters) * num_buf); + + // Iteratively set up each framebuffer and framebuffer-attached objects + usize buffer_offset = 0; + for (usize fb_idx = 0; fb_idx < num_fbuf; fb_idx++) { + FramebufferParameters *p = &t->framebuffer_parameters[fb_idx]; + // Check everything is a texture, cuz rn. we don't support anything else + for (isize buffer_idx = 0; buffer_idx < p->num_attached_buffers; buffer_idx++) { + ASSERT(BUFFERPARAMETER_GET_TYPE(t->buffer_parameters[buffer_idx + buffer_offset]) == BufferType_texture); + } + r_create_textures(w->context, &t->buffer[buffer_offset], + &t->buffer_parameters[buffer_offset], + &t->framebuffer_parameters[fb_idx].dimensions, + t->framebuffer_parameters[fb_idx].num_attached_buffers); + //if (BUFFERPARAMETER_GET_TYPE(buffer_params[i]) != BufferType_texture) continue; + //u32 texture_type = BUFFERPARAMETER_GET_PARAMETER(buffer_params[i]); + + //usize span = 0; + //while ( + // (i + span < targets->buffer_len) && + // (BUFFERPARAMETER_GET_TYPE(buffer_params[i + span]) == BufferType_texture) && + // (buffer_params[i + span].buffer_param & 3) == textureType + //) { + // span++; + //} + //if (span == 0) continue; + //r_create_textures(w->context, &targets->buffer[i], texture_type, texturesizes, span); + } + //r_create_renderbuffers(c, targets->renderbuffer, renderbuffertypes, renderbuffersizes, targets->renderbuffer_len); + // Skip `texture` (??) + + w->render_targets = t; +} + + +void window_free_renderstack(RenderTargets *restrict t) { + // Everything is in the same buffer anyways + free(t->framebuffer); +} |
