summaryrefslogtreecommitdiffhomepage
path: root/src/gfx
diff options
context:
space:
mode:
authorrealtradam <[email protected]>2023-06-04 02:35:00 -0400
committerrealtradam <[email protected]>2023-06-04 02:35:00 -0400
commit35558b39040d37c939bd68b56985d6cb5385a451 (patch)
treeb10516557ba530d96799a8c4bed94b7644938811 /src/gfx
parent856ce67eb21f64d86ecf6bb3651985f10e6236c3 (diff)
downloadRodeoKit-gfx-rewrite.tar.gz
RodeoKit-gfx-rewrite.zip
refactor to have graphics and windowing seperategfx-rewrite
Diffstat (limited to 'src/gfx')
-rw-r--r--src/gfx/irodeo_gfx.h30
-rw-r--r--src/gfx/irodeo_gfx_t.h49
-rw-r--r--src/gfx/rodeo_gfx.c732
3 files changed, 811 insertions, 0 deletions
diff --git a/src/gfx/irodeo_gfx.h b/src/gfx/irodeo_gfx.h
new file mode 100644
index 0000000..3acc49f
--- /dev/null
+++ b/src/gfx/irodeo_gfx.h
@@ -0,0 +1,30 @@
+
+// -- internal --
+// public
+#include "rodeo/common.h"
+// private
+#include "gfx/irodeo_gfx_t.h"
+
+// -- external --
+#include "bgfx/c99/bgfx.h"
+#include "stc/cstr.h"
+
+bgfx_shader_handle_t
+irodeo_gfx_shader_load(const cstr path);
+
+void
+irodeo_gfx_render_buffer_transient_alloc(void);
+
+void
+irodeo_gfx_frame_stall(void);
+
+#define \
+mrodeo_bgfx_vertex_layout_do(vertex_layout) \
+ mrodeo_defer_do( \
+ bgfx_vertex_layout_begin( \
+ vertex_layout, \
+ bgfx_get_renderer_type() \
+ ), \
+ bgfx_vertex_layout_end(vertex_layout) \
+ )
+
diff --git a/src/gfx/irodeo_gfx_t.h b/src/gfx/irodeo_gfx_t.h
new file mode 100644
index 0000000..7d9d1b7
--- /dev/null
+++ b/src/gfx/irodeo_gfx_t.h
@@ -0,0 +1,49 @@
+#pragma once
+
+// -- internal --
+// public
+#include "rodeo/gfx_t.h"
+
+// -- external --
+#include "bgfx/c99/bgfx.h"
+#define CGLM_FORCE_DEPTH_ZERO_TO_ONE
+#include "cglm/mat4.h"
+
+typedef uint16_t irodeo_index_type_t;
+
+typedef
+struct
+{
+ bgfx_vertex_layout_t vertex_layout;
+ //bgfx_dynamic_vertex_buffer_handle_t vertex_buffer_handle;
+ //bgfx_dynamic_index_buffer_handle_t index_buffer_handle;
+ bgfx_transient_vertex_buffer_t vertex_buffer_handle;
+ bgfx_transient_index_buffer_t index_buffer_handle;
+ rodeo_gfx_vertex_t *batched_vertices;
+ irodeo_index_type_t *batched_indices;
+ irodeo_index_type_t vertex_size;
+ irodeo_index_type_t index_count;
+ irodeo_index_type_t index_size;
+ //irodeo_index_type_t batched_indices[(mrodeo_vertex_size_max / 4) * 6];
+ rodeo_gfx_texture_2d_t default_texture;
+ bgfx_texture_handle_t *active_texture_p;
+ bgfx_shader_handle_t vertex_shader;
+ bgfx_shader_handle_t fragment_shader;
+ bgfx_program_handle_t program_shader;
+ bgfx_uniform_handle_t texture_uniforms[2];
+ mat4 view_matrix;
+ mat4 proj_matrix;
+ uint64_t frame_count;
+ uint32_t frame_limit;
+ uint32_t frame_start;
+ uint32_t frame_end;
+ float frame_time;
+}
+irodeo_gfx_state_t;
+
+struct
+irodeo_gfx_texture_internal
+{
+ bgfx_texture_handle_t texture_bgfx;
+};
+
diff --git a/src/gfx/rodeo_gfx.c b/src/gfx/rodeo_gfx.c
new file mode 100644
index 0000000..38dc145
--- /dev/null
+++ b/src/gfx/rodeo_gfx.c
@@ -0,0 +1,732 @@
+
+// -- internal --
+// public
+#include "rodeo.h" // TODO remove this
+#include "rodeo/gfx.h"
+#include "rodeo/window.h"
+#include "rodeo/log.h"
+// private
+#include "gfx/irodeo_gfx.h"
+#include "window/irodeo_window.h"
+#include "rodeo_config.h"
+
+// -- external --
+#include "bgfx/c99/bgfx.h"
+#define CGLM_FORCE_DEPTH_ZERO_TO_ONE
+#include "cglm/cglm.h"
+#include "SDL_image.h"
+#include "SDL.h" // used for timing, need to replace in this file with BGFX at some point
+
+static irodeo_gfx_state_t irodeo_gfx_state = {0};
+
+void
+rodeo_gfx_init(void)
+{
+
+#ifdef __EMSCRIPTEN__
+ bgfx_render_frame(-1);
+#endif
+
+ bgfx_platform_data_t pd = {0};
+ memset(&pd, 0, sizeof(bgfx_platform_data_t));
+
+#if !__EMSCRIPTEN__
+ // x11
+ pd.ndt = irodeo_window_wmi_get().info.x11.display;
+ pd.nwh = (void*)(uintptr_t)irodeo_window_wmi_get().info.x11.window;
+#else
+ // web
+ pd.nwh = (void*)"#canvas";
+#endif
+
+ bgfx_init_t init = {0};
+ bgfx_init_ctor(&init);
+ //init.type = BGFX_RENDERER_TYPE_COUNT; // auto determine renderer
+ init.type = BGFX_RENDERER_TYPE_OPENGL; // force opengl renderer
+ //SDL_GetWindowSize(irodeo_gfx_state.window, &irodeo_gfx_state.screen_width, &irodeo_gfx_state.screen_height);
+ init.resolution.width = rodeo_window_screen_height_get();
+ init.resolution.height = rodeo_window_screen_width_get();
+ init.resolution.reset = BGFX_RESET_VSYNC;
+ init.platformData = pd;
+ bgfx_init(&init);
+
+ bgfx_set_debug(BGFX_DEBUG_TEXT);
+
+ //bgfx_set_state(BGFX_STATE_CULL_CCW, 0);
+
+ //bgfx_dbg_text_clear(0x65, false);
+
+ bgfx_set_view_clear(
+ 0,
+ BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
+ 0x443355FF,
+ 1.0f,
+ 0
+ );
+ bgfx_set_view_rect(0, 0, 0, rodeo_window_screen_width_get(), rodeo_window_screen_height_get());
+
+ rodeo_log(rodeo_logLevel_info, "Setting up default render pipeline...");
+ // set up vertex layout
+ mrodeo_bgfx_vertex_layout_do(&irodeo_gfx_state.vertex_layout)
+ {
+ bgfx_vertex_layout_add(&irodeo_gfx_state.vertex_layout, BGFX_ATTRIB_POSITION, 3, BGFX_ATTRIB_TYPE_FLOAT, false, false);
+ bgfx_vertex_layout_add(&irodeo_gfx_state.vertex_layout, BGFX_ATTRIB_COLOR0, 4, BGFX_ATTRIB_TYPE_FLOAT, false, false);
+ bgfx_vertex_layout_add(&irodeo_gfx_state.vertex_layout, BGFX_ATTRIB_TEXCOORD0, 2, BGFX_ATTRIB_TYPE_FLOAT, false, false);
+ bgfx_vertex_layout_add(&irodeo_gfx_state.vertex_layout, BGFX_ATTRIB_TEXCOORD1, 1, BGFX_ATTRIB_TYPE_FLOAT, false, false);
+ }
+
+ // load shaders
+ cstr shader_path = cstr_lit("???");
+ switch(bgfx_get_renderer_type()) {
+ case BGFX_RENDERER_TYPE_NOOP:
+ rodeo_log(
+ rodeo_logLevel_error,
+ "BGFX failed to get determine an appropriate renderer"
+ );
+ exit(EXIT_FAILURE);
+ case BGFX_RENDERER_TYPE_OPENGLES:
+ cstr_assign(
+ &shader_path,
+ "shaders/100_es/"
+ );
+ break;
+ case BGFX_RENDERER_TYPE_VULKAN:
+ cstr_assign(
+ &shader_path,
+ "shaders/spirv/"
+ );
+ break;
+ case BGFX_RENDERER_TYPE_OPENGL:
+ cstr_assign(
+ &shader_path,
+ "shaders/opengl/"
+ );
+ break;
+ default:
+ rodeo_log(
+ rodeo_logLevel_error,
+ "No shaders implemented for BGFX renderer chosen"
+ );
+ exit(EXIT_FAILURE);
+ }
+ cstr vertex_shader_path = cstr_lit("simple.vertex.bin");
+ cstr fragment_shader_path = cstr_lit("simple.fragment.bin");
+
+ cstr_insert_s(
+ &vertex_shader_path,
+ 0,
+ shader_path
+ );
+ cstr_insert_s(
+ &fragment_shader_path,
+ 0,
+ shader_path
+ );
+
+ irodeo_gfx_state.vertex_shader = irodeo_gfx_shader_load(vertex_shader_path);
+ irodeo_gfx_state.fragment_shader = irodeo_gfx_shader_load(fragment_shader_path);
+ irodeo_gfx_state.program_shader = bgfx_create_program(
+ irodeo_gfx_state.vertex_shader,
+ irodeo_gfx_state.fragment_shader,
+ true
+ );
+ rodeo_log(
+ rodeo_logLevel_info,
+ "Default render pipeline finished setup"
+ );
+
+ //bgfx_texture_handle_t default_bgfx_texture = rodeo_texture_2d_create_default();
+
+ irodeo_gfx_state.default_texture.internal_texture = malloc(sizeof(irodeo_gfx_texture_internal_t));
+
+ // used for binding textures to shader uniforms
+ irodeo_gfx_state.texture_uniforms[0] = bgfx_create_uniform("default_texture", BGFX_UNIFORM_TYPE_SAMPLER, 1);
+ irodeo_gfx_state.texture_uniforms[1] = bgfx_create_uniform("texture_0", BGFX_UNIFORM_TYPE_SAMPLER, 1);
+
+ {
+ // represents 1 pixel sized white texture
+ const uint8_t default_texture_data[] = {
+ //red, blue, green, alpha
+ 0xff, 0xff, 0xff, 0xff,
+ };
+
+ irodeo_gfx_state.default_texture.internal_texture->texture_bgfx =
+ bgfx_create_texture_2d(
+ 1,
+ 1,
+ false,
+ 0,
+ BGFX_TEXTURE_FORMAT_RGBA8,
+ BGFX_SAMPLER_UVW_CLAMP | BGFX_SAMPLER_MAG_POINT,
+ bgfx_copy(
+ &default_texture_data,
+ sizeof(default_texture_data)
+ )
+ );
+ irodeo_gfx_state.default_texture.width = 1;
+ irodeo_gfx_state.default_texture.height = 1;
+
+ irodeo_gfx_state.active_texture_p = &irodeo_gfx_state.default_texture.internal_texture->texture_bgfx;
+ }
+
+ SDL_SetWindowResizable(irodeo_window_get(), true);
+
+ bgfx_reset(
+ (uint32_t)rodeo_window_screen_width_get(),
+ (uint32_t)rodeo_window_screen_height_get(),
+ //BGFX_RESET_MSAA_X16 | BGFX_RESET_MAXANISOTROPY,
+ BGFX_RESET_VSYNC,
+ BGFX_TEXTURE_FORMAT_COUNT
+ );
+
+ rodeo_random_seed_set(SDL_GetTicks64());
+
+ irodeo_gfx_state.frame_end = (uint32_t)SDL_GetPerformanceCounter();
+}
+
+void
+rodeo_gfx_deinit(void)
+{
+
+ free(irodeo_gfx_state.default_texture.internal_texture);
+
+ bgfx_destroy_program(irodeo_gfx_state.program_shader);
+ bgfx_shutdown();
+}
+
+void
+rodeo_gfx_frame_begin(void)
+{
+ //vec3 eye = {0.0f, 0.0f, -35.0f};
+ //vec3 center = {0.0f, 0.0f, 0.0f};
+ //vec3 up = {0, 1, 0};
+
+ //glm_lookat(eye, center, up, view);
+
+ glm_mat4_identity(irodeo_gfx_state.view_matrix);
+
+ //glm_perspective(glm_rad(60.f), 640.f / 480.f, 0.1f, 100.0f, proj);
+
+ // TODO: figure out if why 'zo' is correct
+ // but 'no' is incorrect
+ glm_ortho_rh_zo(
+ 0,
+ (float)rodeo_window_screen_width_get(),
+ (float)rodeo_window_screen_height_get(),
+ 0,
+ // near
+ -0.1f,
+ // far
+ 100.0f,
+ irodeo_gfx_state.proj_matrix
+ );
+
+ bgfx_set_view_transform(0, irodeo_gfx_state.view_matrix, irodeo_gfx_state.proj_matrix);
+ bgfx_set_view_rect(0, 0, 0, rodeo_window_screen_width_get(), rodeo_window_screen_height_get());
+ bgfx_touch(0);
+
+ irodeo_gfx_render_buffer_transient_alloc();
+
+ irodeo_gfx_state.frame_start = irodeo_gfx_state.frame_end;
+}
+
+void
+rodeo_gfx_frame_end(void)
+{
+ rodeo_gfx_renderer_flush();
+
+ bgfx_frame(false);
+
+ #ifndef __EMSCRIPTEN__
+ irodeo_gfx_frame_stall();
+ #endif
+ irodeo_gfx_state.frame_count += 1;
+ irodeo_gfx_state.frame_end = (uint32_t)SDL_GetPerformanceCounter();
+ //
+#ifndef __EMSCRIPTEN__
+ //irodeo_gfx_state.frame_time = ((float)(irodeo_gfx_state.frame_end - irodeo_gfx_state.frame_start) * 1000.0f / (float)SDL_GetPerformanceFrequency());
+ irodeo_gfx_state.frame_time = (1.0f/60.f) * 1000; //((float)(state.end_frame - state.start_frame) * 1000.0f / (float)SDL_GetPerformanceFrequency());
+#else
+ irodeo_gfx_state.frame_time = (1.0f/60.f) * 1000; //((float)(state.end_frame - state.start_frame) * 1000.0f / (float)SDL_GetPerformanceFrequency());
+#endif
+}
+
+float
+rodeo_gfx_frame_time_get(void)
+{
+ return irodeo_gfx_state.frame_time; //(float)bgfx_get_stats()->cpuTimeFrame;
+}
+
+float
+rodeo_gfx_frame_perSecond_get(void)
+{
+ return 1.0f / (rodeo_gfx_frame_time_get() / 1000.0f);
+}
+
+// measures how much time there is left in the remaining frame until
+// the frame target time is reached. If we surpassed the target time
+// then this will be negative
+float
+irodeo_gfx_frame_remaining_get(void)
+{
+ #ifdef __EMSCRIPTEN__
+ float target = 60.0f;
+ #else
+ float target = (float)rodeo_gfx_frame_limit_get();
+ #endif
+
+ float result = (1/target * 1000.0f) - ((float)(SDL_GetPerformanceCounter() - irodeo_gfx_state.frame_start) / (float)SDL_GetPerformanceFrequency() * 1000.0f);
+
+ return result;
+}
+
+
+// used internally at the end of every frame to fill for time
+// in order to reach the desired framerate
+void
+irodeo_gfx_frame_stall(void)
+{
+ // if no frame limit then run as fast as possible
+ if(rodeo_gfx_frame_limit_get() == 0)
+ {
+ return;
+ }
+
+ // sleep isnt perfectly accurate so we sleep for a slightly shorter
+ // amount of time
+ float stall_time = irodeo_gfx_frame_remaining_get();
+ if(stall_time > 0.0005)
+ {
+ SDL_Delay((uint32_t)(stall_time * 0.9995));
+ }
+
+ // then we spinlock for the small remaining amount of time
+ stall_time = irodeo_gfx_frame_remaining_get();
+ while(stall_time > 0.0005) {
+ stall_time = irodeo_gfx_frame_remaining_get();
+ }
+}
+
+void
+rodeo_gfx_renderer_flush(void)
+{
+ // set default texture
+ bgfx_set_texture(
+ 0,
+ irodeo_gfx_state.texture_uniforms[0],
+ rodeo_gfx_texture_2d_default_get()->internal_texture->texture_bgfx,
+ UINT32_MAX
+ );
+ if(irodeo_gfx_state.active_texture_p != NULL)
+ {
+ // set dynamic texture
+ bgfx_set_texture(
+ 1,
+ irodeo_gfx_state.texture_uniforms[1],
+ *irodeo_gfx_state.active_texture_p,
+ UINT32_MAX
+ );
+ }
+ else
+ {
+ // set to default if none exists
+ bgfx_set_texture(
+ 1,
+ irodeo_gfx_state.texture_uniforms[1],
+ rodeo_gfx_texture_2d_default_get()->internal_texture->texture_bgfx,
+ UINT32_MAX
+ );
+ }
+
+ if(irodeo_gfx_state.vertex_size > 0)
+ {
+ bgfx_set_state(
+ BGFX_STATE_CULL_CW |
+ BGFX_STATE_WRITE_RGB |
+ BGFX_STATE_WRITE_A |
+ //BGFX_STATE_DEPTH_TEST_LESS |
+ //BGFX_STATE_MSAA |
+ BGFX_STATE_BLEND_ALPHA,
+ 0
+ );
+
+ // upload remaining batched vertices
+ bgfx_set_transient_vertex_buffer(0, &irodeo_gfx_state.vertex_buffer_handle, 0, irodeo_gfx_state.vertex_size);
+ //const bgfx_memory_t* vbm = bgfx_copy(irodeo_gfx_state.batched_vertices, sizeof(rodeo_gfx_vertex_t) * irodeo_gfx_state.vertex_size);
+ //bgfx_update_dynamic_vertex_buffer(irodeo_gfx_state.vertex_buffer_handle, 0, vbm);
+
+ // upload remaining batched indices
+ bgfx_set_transient_index_buffer(&irodeo_gfx_state.index_buffer_handle, 0, irodeo_gfx_state.index_size);
+ //bgfx_set_dynamic_index_buffer(irodeo_gfx_state.index_buffer_handle, 0, irodeo_gfx_state.index_size);
+ //const bgfx_memory_t* ibm = bgfx_copy(irodeo_gfx_state.batched_indices, sizeof(uint16_t) * irodeo_gfx_state.index_size);
+ //bgfx_update_dynamic_index_buffer(irodeo_gfx_state.index_buffer_handle, 0, ibm);
+
+
+ // submit vertices & batches
+ bgfx_submit(0, irodeo_gfx_state.program_shader, 0, BGFX_DISCARD_NONE);
+
+ // reset arrays
+ irodeo_gfx_state.vertex_size = 0;
+ irodeo_gfx_state.index_size = 0;
+ irodeo_gfx_state.index_count = 0;
+
+ // allocate new buffers
+ irodeo_gfx_render_buffer_transient_alloc();
+ }
+ irodeo_gfx_state.active_texture_p = NULL;
+}
+
+const rodeo_gfx_texture_2d_t*
+rodeo_gfx_texture_2d_default_get(void)
+{
+ return &irodeo_gfx_state.default_texture;
+}
+
+rodeo_gfx_texture_2d_t
+rodeo_gfx_texture_2d_create_from_RGBA8(
+ const uint16_t width,
+ const uint16_t height,
+ const uint8_t memory[]
+)
+{
+ rodeo_gfx_texture_2d_t texture;
+ texture.internal_texture = malloc(sizeof(irodeo_gfx_texture_internal_t));
+ bgfx_copy(memory, (uint32_t)width * (uint32_t)height * sizeof(uint8_t) * 4);
+ texture.internal_texture->texture_bgfx =
+ bgfx_create_texture_2d(
+ width,
+ height,
+ false,
+ 0,
+ BGFX_TEXTURE_FORMAT_RGBA8,
+ BGFX_SAMPLER_UVW_CLAMP | BGFX_SAMPLER_MAG_POINT,
+ bgfx_copy(memory, (uint32_t)width * (uint32_t)height * sizeof(uint8_t) * 4)
+ );
+
+ texture.width = width;
+ texture.height = height;
+
+ return texture;
+}
+
+void
+rodeo_gfx_texture_2d_destroy(rodeo_gfx_texture_2d_t *texture)
+{
+ bgfx_destroy_texture(texture->internal_texture->texture_bgfx);
+ free(texture->internal_texture);
+}
+
+void
+rodeo_gfx_rectangle_draw(
+ const rodeo_rectangle_t *rectangle,
+ const rodeo_color_RGBAFloat_t *color
+)
+{
+ rodeo_gfx_texture_2d_draw(
+ rectangle,
+ NULL,
+ color,
+ NULL
+ );
+}
+
+void
+rodeo_gfx_texture_2d_draw(
+ // cant be NULL
+ const rodeo_rectangle_t *destination,
+ // default: entire texture
+ const rodeo_rectangle_t *source,
+ // default: white
+ const rodeo_color_RGBAFloat_t *color,
+ // default: default texture
+ const rodeo_gfx_texture_2d_t *texture
+)
+{
+ // whether to use default or custom texture
+ float texture_uniform_slot = 0.0;
+
+ rodeo_rectangle_t source_applied;
+ if(source != NULL && texture != NULL)
+ {
+ source_applied = (rodeo_rectangle_t){
+ .x = source->x / (float)texture->width,
+ .y = source->y / (float)texture->height,
+ .width = source->width / (float)texture->width,
+ .height = source->height / (float)texture->height,
+ };
+ }
+ else
+ {
+ source_applied = (rodeo_rectangle_t){
+ .x = 0.0f,
+ .y = 0.0f,
+ .width = 1.0f,
+ .height = 1.0f,
+ };
+ }
+
+ rodeo_color_RGBAFloat_t color_applied;
+ if(color != NULL)
+ {
+ color_applied = *color;
+ }
+ else
+ {
+ color_applied = (rodeo_color_RGBAFloat_t){
+ { 1.0f, 1.0f, 1.0f, 1.0f }
+ };
+ }
+
+ // if not using texture: use default instead
+ // otherwise check what current texture is active
+ // if none or the same: set it
+ // if different: flush and then set it
+ if(texture != NULL)
+ {
+ if(irodeo_gfx_state.active_texture_p != NULL)
+ {
+ if(&texture->internal_texture->texture_bgfx != irodeo_gfx_state.active_texture_p)
+ {
+ rodeo_gfx_renderer_flush();
+ }
+ }
+ texture_uniform_slot = 1.0;
+ irodeo_gfx_state.active_texture_p = &texture->internal_texture->texture_bgfx;
+ }
+
+
+ if(irodeo_gfx_state.vertex_size < mrodeo_vertex_size_max)
+ {
+ irodeo_gfx_state.batched_vertices[irodeo_gfx_state.vertex_size] =
+ (rodeo_gfx_vertex_t)
+ {
+ .x = destination->width + destination->x,
+ .y = destination->height + destination->y,
+ //.z = 0.0f,
+ .color = color_applied,
+ .texture_id = texture_uniform_slot,
+ .texture_x = source_applied.width + source_applied.x,
+ .texture_y = source_applied.height + source_applied.y,
+ };
+ irodeo_gfx_state.vertex_size += 1;
+ irodeo_gfx_state.batched_vertices[irodeo_gfx_state.vertex_size] =
+ (rodeo_gfx_vertex_t)
+ {
+ .x = destination->width + destination->x,
+ .y = destination->y,
+ //.z = 0.0f,
+ .color = color_applied,
+ .texture_id = texture_uniform_slot,
+ .texture_x = source_applied.width + source_applied.x,
+ .texture_y = source_applied.y,
+ };
+ irodeo_gfx_state.vertex_size += 1;
+ irodeo_gfx_state.batched_vertices[irodeo_gfx_state.vertex_size] =
+ (rodeo_gfx_vertex_t)
+ {
+ .x = destination->x,
+ .y = destination->y,
+ //.z = 0.0f,
+ .color = color_applied,
+ .texture_id = texture_uniform_slot,
+ .texture_x = source_applied.x,
+ .texture_y = source_applied.y,
+ };
+ irodeo_gfx_state.vertex_size += 1;
+ irodeo_gfx_state.batched_vertices[irodeo_gfx_state.vertex_size] =
+ (rodeo_gfx_vertex_t)
+ {
+ .x = destination->x,
+ .y = destination->height + destination->y,
+ //.z = 0.0f,
+ .color = color_applied,
+ .texture_id = texture_uniform_slot,
+ .texture_x = source_applied.x,
+ .texture_y = source_applied.height + source_applied.y,
+ };
+ irodeo_gfx_state.vertex_size += 1;
+
+ irodeo_index_type_t indices[] =
+ {
+ 0, 1, 3,
+ 1, 2, 3
+ //2, 1, 0,
+ //2, 3, 1
+ };
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[0];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[1];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[2];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[3];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[4];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.batched_indices[irodeo_gfx_state.index_size] = irodeo_gfx_state.index_count + indices[5];
+ irodeo_gfx_state.index_size += 1;
+ irodeo_gfx_state.index_count += 4;
+ }
+
+ if(irodeo_gfx_state.vertex_size >= mrodeo_vertex_size_max)
+ {
+ rodeo_gfx_renderer_flush();
+ }
+}
+
+rodeo_gfx_texture_2d_t
+rodeo_gfx_texture_2d_create_from_path(cstr path)
+{
+ // load image to surface
+ SDL_Surface *surface = IMG_Load(cstr_str(&path));
+ if(surface == NULL)
+ {
+ rodeo_log(
+ rodeo_logLevel_error,
+ "Loading texture from image failed: %s",
+ IMG_GetError()
+ );
+ return (rodeo_gfx_texture_2d_t){0};
+ }
+
+ // check and handle a color key for transparency
+ // not sure if I actually need this...
+ //uint32_t color_key;
+ //if(SDL_GetColorKey(surface, &color_key) == 0)
+ //{
+ // SDL_SetColorKey(surface, SDL_TRUE, color_key);
+ //}
+
+ // convert pixel format of surface into RGBA8
+ SDL_Surface *converted_surface =
+ SDL_ConvertSurfaceFormat(
+ surface,
+ // pixel format needs to be backwards
+ // of what bgfx uses for some reason
+ SDL_PIXELFORMAT_ABGR8888,
+ 0
+ );
+ if(converted_surface == NULL)
+ {
+ rodeo_log(
+ rodeo_logLevel_error,
+ "Converting image to RGBA8 while loading texture failed: %s",
+ SDL_GetError()
+ );
+ SDL_FreeSurface(surface);
+ return (rodeo_gfx_texture_2d_t){0};
+ }
+
+ // load the pixel data into our own texture
+ rodeo_gfx_texture_2d_t texture = rodeo_gfx_texture_2d_create_from_RGBA8(
+ (uint16_t)converted_surface->w,
+ (uint16_t)converted_surface->h,
+ converted_surface->pixels
+ );
+
+ SDL_FreeSurface(surface);
+ SDL_FreeSurface(converted_surface);
+
+ return texture;
+}
+
+uint64_t
+rodeo_gfx_frame_count_get(void)
+{
+ return irodeo_gfx_state.frame_count;
+}
+
+void
+rodeo_gfx_frame_limit_set(uint32_t limit)
+{
+ #ifdef __EMSCRIPTEN__
+ rodeo_log(
+ rodeo_logLevel_warning,
+ "Framerate limit cannot be set on web platform. Limit is enforced by platform to 60fps"
+ );
+ #else
+ irodeo_gfx_state.frame_limit = limit;
+ #endif
+}
+
+uint32_t
+rodeo_gfx_frame_limit_get(void)
+{
+ #ifdef __EMSCRIPTEN__
+ return 60;
+ #else
+ return irodeo_gfx_state.frame_limit;
+ #endif
+}
+
+cstr
+rodeo_gfx_renderer_name_get(void)
+{
+ return cstr_from(
+ bgfx_get_renderer_name(bgfx_get_renderer_type())
+ );
+}
+
+bgfx_shader_handle_t
+irodeo_gfx_shader_load(const cstr path)
+{
+ const char* path_cstr = cstr_str(&path);
+
+ FILE *file = fopen(path_cstr, "rb");
+
+ if(!file)
+ {
+ rodeo_log(
+ rodeo_logLevel_error,
+ "Shader file \"%s\" not found",
+ path_cstr
+ );
+ return (bgfx_shader_handle_t)BGFX_INVALID_HANDLE;
+ }
+
+ fseek(file, 0, SEEK_END);
+ int64_t file_size_temp = ftell(file);
+ if(file_size_temp < 0)
+ {
+ rodeo_log(
+ rodeo_logLevel_error,
+ "Failed to get current file position of given stream(ftell() error)"
+ );
+ exit(EXIT_FAILURE);
+ }
+ if((file_size_temp + 1) > UINT32_MAX)
+ {
+ rodeo_log(
+ rodeo_logLevel_error,
+ "File size larger then what bgfx can allocate"
+ );
+ exit(EXIT_FAILURE);
+ }
+ uint32_t file_size = (uint32_t)file_size_temp;
+ fseek(file, 0, SEEK_SET);
+
+
+ const bgfx_memory_t *mem = bgfx_alloc(file_size + 1);
+ fread(mem->data, 1, file_size, file);
+ mem->data[mem->size - 1] = '\0';
+ fclose(file);
+
+ bgfx_shader_handle_t shader = bgfx_create_shader(mem);
+ rodeo_log(
+ rodeo_logLevel_info,
+ "Shader loaded with idx: %"PRIu8"",
+ shader.idx
+ );
+
+ return shader;
+}
+
+void
+irodeo_gfx_render_buffer_transient_alloc(void)
+{
+ bgfx_alloc_transient_vertex_buffer(&irodeo_gfx_state.vertex_buffer_handle, mrodeo_vertex_size_max, &irodeo_gfx_state.vertex_layout);
+ bgfx_alloc_transient_index_buffer(&irodeo_gfx_state.index_buffer_handle, mrodeo_index_size_max, false);
+ irodeo_gfx_state.batched_vertices = (rodeo_gfx_vertex_t*)irodeo_gfx_state.vertex_buffer_handle.data;
+ irodeo_gfx_state.batched_indices = (irodeo_index_type_t*)irodeo_gfx_state.index_buffer_handle.data;
+}
+