From 8badb9f9cc42a6231bd759f3d3cad97bb92e8bb9 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 20 Aug 2022 11:49:21 +0200 Subject: [PATCH] azrp: add very basic triangle shader --- azur/CMakeLists.txt | 5 +- azur/include/azur/gint/render.h | 3 + azur/src/gint/shaders/triangle.S | 1 + azur/src/gint/shaders/triangle.c | 132 +++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 azur/src/gint/shaders/triangle.S create mode 100644 azur/src/gint/shaders/triangle.c diff --git a/azur/CMakeLists.txt b/azur/CMakeLists.txt index 8d6ce40..39a1ffd 100644 --- a/azur/CMakeLists.txt +++ b/azur/CMakeLists.txt @@ -64,7 +64,10 @@ if(AZUR_GRAPHICS_GINT_CG) src/gint/shaders/image_p4.c src/gint/shaders/image_p4_effect.c src/gint/shaders/image_p4_swapcolor.c - src/gint/shaders/image_p4_dye.c) + src/gint/shaders/image_p4_dye.c + # Triangle shader + src/gint/shaders/triangle.c + src/gint/shaders/triangle.S) endif() add_library(azur STATIC ${SOURCES}) diff --git a/azur/include/azur/gint/render.h b/azur/include/azur/gint/render.h index 794f06e..8557f14 100644 --- a/azur/include/azur/gint/render.h +++ b/azur/include/azur/gint/render.h @@ -201,6 +201,8 @@ void azrp_image(int x, int y, bopti_image_t const *image); void azrp_subimage(int x, int y, bopti_image_t const *image, int left, int top, int width, int height, int flags); +void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color); + /* See below for more detailed image functions. Dynamic effects are provided with the same naming convention as gint. */ @@ -211,6 +213,7 @@ void azrp_shader_clear_configure(void); void azrp_shader_image_rgb16_configure(void); void azrp_shader_image_p8_configure(void); void azrp_shader_image_p4_configure(void); +void azrp_shader_triangle_configure(void); //--- // Performance indicators diff --git a/azur/src/gint/shaders/triangle.S b/azur/src/gint/shaders/triangle.S new file mode 100644 index 0000000..3c3684c --- /dev/null +++ b/azur/src/gint/shaders/triangle.S @@ -0,0 +1 @@ +/* empty for now */ diff --git a/azur/src/gint/shaders/triangle.c b/azur/src/gint/shaders/triangle.c new file mode 100644 index 0000000..31b3ce0 --- /dev/null +++ b/azur/src/gint/shaders/triangle.c @@ -0,0 +1,132 @@ +#include + +uint8_t AZRP_SHADER_TRIANGLE = -1; + +__attribute__((constructor)) +static void register_shader(void) +{ + extern azrp_shader_t azrp_shader_triangle; + AZRP_SHADER_TRIANGLE = azrp_register_shader(azrp_shader_triangle); +} + +void azrp_shader_triangle_configure(void) +{ + azrp_set_uniforms(AZRP_SHADER_TRIANGLE, (void *)azrp_width); +} + +static int min(int x, int y) +{ + return (x < y) ? x : y; +} +static int max(int x, int y) +{ + return (x > y) ? x : y; +} + +//--- + +struct command { + uint8_t shader_id; + /* Local y coordinate of the first line in the fragment */ + uint8_t y; + /* Number of lines to render on the current fragment */ + uint8_t height_frag; + /* Numebr of lines to render total, includnig this fragment */ + uint8_t height_total; + /* Rectangle along the x coordinates (x_max included) */ + uint16_t x_min, x_max; + /* Color */ + uint16_t color; + /* Initial barycentric coordinates */ + int u0, v0, w0; + /* Variation of each coordinate for a movement in x/y */ + int du_x, dv_x, dw_x; + int du_y, dv_y, dw_y; +}; + +//--- + +// TODO: Write in assembler +void azrp_shader_triangle(void *uniforms0, void *command0, void *fragment0) +{ + int width = (int)uniforms0; + struct command *cmd = command0; + uint16_t *frag = fragment0; + + frag += cmd->x_min + width * cmd->y; + + int u, v, w; + + for(int y = 0; y < cmd->height_frag; y++) { + u = cmd->u0; + v = cmd->v0; + w = cmd->w0; + + for(int x = cmd->x_min; x <= cmd->x_max; x++) { + if((u | v | w) > 0) { + frag[x] = cmd->color; + } + + u += cmd->du_x; + v += cmd->dv_x; + w += cmd->dw_x; + } + + frag += width; + cmd->u0 += cmd->du_y; + cmd->v0 += cmd->dv_y; + cmd->w0 += cmd->dw_y; + } + + /* Prepare next fragment */ + cmd->y = 0; + cmd->height_total -= cmd->height_frag; + cmd->height_frag = min(azrp_frag_height, cmd->height_total); +} + +//--- + +static int edge_start(int x1, int y1, int x2, int y2, int px, int py) +{ + return (y2 - y1) * (px - x1) - (x2 - x1) * (py - y1); +} +void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color) +{ + prof_enter(azrp_perf_cmdgen); + + /* Find a rectangle containing the triangle */ + int min_x = max(0, min(x1, min(x2, x3))); + int max_x = min(azrp_width-1, max(x1, max(x2, x3))); + int min_y = max(0, min(y1, min(y2, y3))); + int max_y = min(azrp_height-1, max(y1, max(y2, y3))); + + /* TODO: Have a proper way to do optimized-division by azrp_frag_height + TODO: Also account for first-fragment offset */ + int frag_first = min_y >> 4; + int frag_last = max_y >> 4; + int frag_count = frag_last - frag_first + 1; + int first_offset = min_y & 15; + + struct command cmd; + cmd.shader_id = AZRP_SHADER_TRIANGLE; + cmd.y = first_offset; + cmd.height_total = max_y - min_y + 1; + cmd.height_frag = min(cmd.height_total, azrp_frag_height - cmd.y); + cmd.x_min = min_x; + cmd.x_max = max_x; + cmd.color = color; + + /* Vector products for barycentric coordinates */ + cmd.u0 = edge_start(x2, y2, x3, y3, min_x, min_y); + cmd.du_x = y3 - y2; + cmd.du_y = x2 - x3; + cmd.v0 = edge_start(x3, y3, x1, y1, min_x, min_y); + cmd.dv_x = y1 - y3; + cmd.dv_y = x3 - x1; + cmd.w0 = edge_start(x1, y1, x2, y2, min_x, min_y); + cmd.dw_x = y2 - y1; + cmd.dw_y = x1 - x2; + + azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count); + prof_leave(azrp_perf_cmdgen); +}