summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/gpu.c b/src/gpu.c
index 4cba190..8bc5721 100644
--- a/src/gpu.c
+++ b/src/gpu.c
@@ -17,6 +17,8 @@
*/
#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include "ta_sdl.h"
#include "window.h"
#include "files.h"
@@ -26,6 +28,32 @@
#define SPIRV_ENTRY_POINT "main"
+typedef enum ta_gpu_shape_type {
+ TA_GPU_SHAPE_FILLED_RECTANGLE,
+ TA_GPU_SHAPE_RECTANGLE,
+ TA_GPU_SHAPE_LINE,
+ TA_GPU_SHAPE_FILLED_CIRCLE,
+ TA_GPU_SHAPE_CIRCLE,
+ TA_GPU_SHAPE_FILLED_TRIANGLE,
+ TA_GPU_SHAPE_TRIANGLE,
+} ta_gpu_shape_type;
+
+typedef struct ta_gpu_shape {
+ ta_gpu_shape_type type;
+ float bounds[4];
+ float points[3][2];
+ float color[4];
+ float thickness;
+} ta_gpu_shape;
+
+typedef struct ta_gpu_shape_uniforms {
+ float bounds[4];
+ float points[3][4];
+ float viewport[4];
+ float color[4];
+ float params[4];
+} ta_gpu_shape_uniforms;
+
// NOTE: Does this formatting look good?
SDL_GPUDevice *ta_gpu_device;
SDL_GPUGraphicsPipeline *ta_gpu_text_pipeline;
@@ -33,6 +61,7 @@
SDL_GPUSampler *ta_gpu_text_sampler;
Uint32 ta_gpu_text_texture_width;
Uint32 ta_gpu_text_texture_height;
+static SDL_GPUGraphicsPipeline *ta_gpu_shape_pipeline;
static SDL_GPUTexture *ta_gpu_msaa_texture;
static SDL_GPUTexture *ta_gpu_depth_texture;
SDL_GPUSampleCount ta_gpu_sample_count = SDL_GPU_SAMPLECOUNT_8;
@@ -41,6 +70,9 @@ static Uint32 ta_gpu_msaa_texture_width;
static Uint32 ta_gpu_msaa_texture_height;
static SDL_GPUCommandBuffer *ta_gpu_command_buffer;
static SDL_GPUTexture *ta_gpu_swapchain_texture;
+static ta_gpu_shape *ta_gpu_shapes;
+static size_t ta_gpu_shape_count;
+static size_t ta_gpu_shape_capacity;
static void ta_gpu_resize_msaa_texture(SDL_GPUTextureFormat format) {
if (ta_gpu_msaa_texture_width == (Uint32)ta_window_width &&
@@ -140,6 +172,30 @@ void ta_gpu_init(void) {
SDL_ReleaseGPUShader(ta_gpu_device, vertex_shader);
SDL_ReleaseGPUShader(ta_gpu_device, fragment_shader);
+ vertex_shader = ta_gpu_load_shader(
+ ta_gpu_device,
+ file_shape_vert_slang_spv_start,
+ file_shape_vert_slang_spv_size,
+ SDL_GPU_SHADERSTAGE_VERTEX,
+ 0,
+ 1
+ );
+ fragment_shader = ta_gpu_load_shader(
+ ta_gpu_device,
+ file_shape_frag_slang_spv_start,
+ file_shape_frag_slang_spv_size,
+ SDL_GPU_SHADERSTAGE_FRAGMENT,
+ 0,
+ 1
+ );
+ pipeline_info.vertex_shader = vertex_shader;
+ pipeline_info.fragment_shader = fragment_shader;
+ pipeline_info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
+ pipeline_info.depth_stencil_state = (SDL_GPUDepthStencilState){ 0 };
+ ta_gpu_shape_pipeline = ta_sdl_create_gpu_graphics_pipeline(ta_gpu_device, &pipeline_info);
+ SDL_ReleaseGPUShader(ta_gpu_device, vertex_shader);
+ SDL_ReleaseGPUShader(ta_gpu_device, fragment_shader);
+
SDL_GPUSamplerCreateInfo sampler_info = {
.min_filter = SDL_GPU_FILTER_LINEAR,
.mag_filter = SDL_GPU_FILTER_LINEAR,
@@ -152,6 +208,7 @@ void ta_gpu_init(void) {
}
void ta_gpu_start_frame(void) {
+ ta_gpu_shape_count = 0;
ta_gpu_command_buffer = ta_sdl_acquire_gpu_command_buffer(ta_gpu_device);
ta_gpu_swapchain_texture = NULL;
ta_gpu_swapchain_format = SDL_GetGPUSwapchainTextureFormat(ta_gpu_device, ta_window);
@@ -162,6 +219,142 @@ void ta_gpu_start_frame(void) {
}
}
+static void ta_gpu_queue_shape(const ta_gpu_shape *shape) {
+ if (ta_gpu_shape_count == ta_gpu_shape_capacity) {
+ size_t next_capacity = ta_gpu_shape_capacity == 0 ? 64 : ta_gpu_shape_capacity * 2;
+ ta_gpu_shape *shapes = realloc(ta_gpu_shapes, next_capacity * sizeof(*shapes));
+ if (!shapes) {
+ return;
+ }
+ ta_gpu_shapes = shapes;
+ ta_gpu_shape_capacity = next_capacity;
+ }
+
+ ta_gpu_shapes[ta_gpu_shape_count++] = *shape;
+}
+
+static void ta_gpu_set_shape_color(float output[4], ta_color color) {
+ output[0] = (float)color.red / 255.0f;
+ output[1] = (float)color.green / 255.0f;
+ output[2] = (float)color.blue / 255.0f;
+ output[3] = (float)color.alpha / 255.0f;
+}
+
+void ta_gpu_draw_filled_rectangle(ta_color color, int x, int y, int width, int height) {
+ if (width <= 0 || height <= 0) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_FILLED_RECTANGLE
+ };
+ shape.bounds[0] = (float)x;
+ shape.bounds[1] = (float)y;
+ shape.bounds[2] = (float)width;
+ shape.bounds[3] = (float)height;
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+void ta_gpu_draw_rectangle(ta_color color, int x, int y, int width, int height, int thickness) {
+ if (width <= 0 || height <= 0 || thickness <= 0) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_RECTANGLE
+ };
+ shape.bounds[0] = (float)x;
+ shape.bounds[1] = (float)y;
+ shape.bounds[2] = (float)width;
+ shape.bounds[3] = (float)height;
+ shape.thickness = (float)thickness;
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+void ta_gpu_draw_line(ta_color color, int x1, int y1, int x2, int y2, int thickness) {
+ if (thickness <= 0 || (x1 == x2 && y1 == y2)) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_LINE
+ };
+ shape.points[0][0] = (float)x1;
+ shape.points[0][1] = (float)y1;
+ shape.points[1][0] = (float)x2;
+ shape.points[1][1] = (float)y2;
+ shape.thickness = (float)thickness;
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+void ta_gpu_draw_filled_circle(ta_color color, int x, int y, int radius) {
+ if (radius <= 0) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_FILLED_CIRCLE
+ };
+ shape.bounds[0] = (float)(x - radius);
+ shape.bounds[1] = (float)(y - radius);
+ shape.bounds[2] = (float)(radius * 2);
+ shape.bounds[3] = (float)(radius * 2);
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+void ta_gpu_draw_circle(ta_color color, int x, int y, int radius, int thickness) {
+ if (radius <= 0 || thickness <= 0) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_CIRCLE
+ };
+ shape.bounds[0] = (float)(x - radius);
+ shape.bounds[1] = (float)(y - radius);
+ shape.bounds[2] = (float)(radius * 2);
+ shape.bounds[3] = (float)(radius * 2);
+ shape.thickness = (float)thickness;
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+static void ta_gpu_set_triangle_points(ta_gpu_shape *shape, int x1, int y1, int x2, int y2, int x3, int y3) {
+ shape->points[0][0] = (float)x1;
+ shape->points[0][1] = (float)y1;
+ shape->points[1][0] = (float)x2;
+ shape->points[1][1] = (float)y2;
+ shape->points[2][0] = (float)x3;
+ shape->points[2][1] = (float)y3;
+}
+
+void ta_gpu_draw_filled_triangle(ta_color color, int x1, int y1, int x2, int y2, int x3, int y3) {
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_FILLED_TRIANGLE
+ };
+ ta_gpu_set_triangle_points(&shape, x1, y1, x2, y2, x3, y3);
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
+void ta_gpu_draw_triangle(ta_color color, int x1, int y1, int x2, int y2, int x3, int y3, int thickness) {
+ if (thickness <= 0) {
+ return;
+ }
+
+ ta_gpu_shape shape = {
+ .type = TA_GPU_SHAPE_TRIANGLE
+ };
+ ta_gpu_set_triangle_points(&shape, x1, y1, x2, y2, x3, y3);
+ shape.thickness = (float)thickness;
+ ta_gpu_set_shape_color(shape.color, color);
+ ta_gpu_queue_shape(&shape);
+}
+
void ta_gpu_end_frame(void) {
if (ta_gpu_swapchain_texture) {
ta_gpu_upload_text(ta_gpu_command_buffer);
@@ -197,6 +390,27 @@ void ta_gpu_end_frame(void) {
ta_text_render(ta_gpu_command_buffer, render_pass);
ta_screen_render(ta_gpu_command_buffer, render_pass);
+ SDL_BindGPUGraphicsPipeline(render_pass, ta_gpu_shape_pipeline);
+ for (size_t index = 0; index < ta_gpu_shape_count; index++) {
+ ta_gpu_shape *shape = &ta_gpu_shapes[index];
+ ta_gpu_shape_uniforms uniforms = {
+ 0
+ };
+ memcpy(uniforms.bounds, shape->bounds, sizeof(uniforms.bounds));
+ for (int point = 0; point < 3; point++) {
+ uniforms.points[point][0] = shape->points[point][0];
+ uniforms.points[point][1] = shape->points[point][1];
+ }
+ uniforms.viewport[0] = (float)ta_window_width;
+ uniforms.viewport[1] = (float)ta_window_height;
+ memcpy(uniforms.color, shape->color, sizeof(uniforms.color));
+ uniforms.params[0] = (float)shape->type;
+ uniforms.params[1] = shape->thickness;
+ SDL_PushGPUVertexUniformData(ta_gpu_command_buffer, 0, &uniforms, sizeof(uniforms));
+ SDL_PushGPUFragmentUniformData(ta_gpu_command_buffer, 0, &uniforms, sizeof(uniforms));
+ Uint32 vertex_count = shape->type == TA_GPU_SHAPE_FILLED_TRIANGLE ? 3 : shape->type == TA_GPU_SHAPE_TRIANGLE ? 18 : 6;
+ SDL_DrawGPUPrimitives(render_pass, vertex_count, 1, 0, 0);
+ }
SDL_EndGPURenderPass(render_pass);
}