#include uint8_t AZRP_SHADER_TRIANGLE = -1; static void configure(void) { azrp_set_uniforms(AZRP_SHADER_TRIANGLE, (void *)azrp_width); } __attribute__((constructor)) static void register_shader(void) { extern azrp_shader_t azrp_shader_triangle; AZRP_SHADER_TRIANGLE = azrp_register_shader(azrp_shader_triangle, configure); configure(); } 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 total, including this fragment */ uint8_t height_total; /* Number of lines to render on the current fragment */ uint8_t height_frag; /* Rectangle along the x coordinates (x_max included) */ uint16_t x_min, x_max; /* Color */ uint16_t color; uint16_t _; /* Initial barycentric coordinates */ int u0, v0, w0; /* Variation of each coordinate for a movement in x */ int du_x, dv_x, dw_x; /* Variation of each coordinate for a movement in y while canceling rows' movements in x */ int du_row, dv_row, dw_row; }; 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))); if(min_x >= max_x || min_y >= max_y) { prof_leave(azrp_perf_cmdgen); return; } int frag_first, first_offset, frag_count; azrp_config_get_lines(min_y, max_y - min_y + 1, &frag_first, &first_offset, &frag_count); 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; /* Swap points 1 and 2 if the order of points is not left-handed */ if(edge_start(x1, y1, x2, y2, x3, y3) < 0) { int xt = x1; x1 = x2; x2 = xt; int yt = y1; y1 = y2; y2 = yt; } /* Vector products for barycentric coordinates */ cmd.u0 = edge_start(x2, y2, x3, y3, min_x, min_y); cmd.du_x = y3 - y2; int du_y = x2 - x3; cmd.v0 = edge_start(x3, y3, x1, y1, min_x, min_y); cmd.dv_x = y1 - y3; int dv_y = x3 - x1; cmd.w0 = edge_start(x1, y1, x2, y2, min_x, min_y); cmd.dw_x = y2 - y1; int dw_y = x1 - x2; int columns = max_x - min_x + 1; cmd.du_row = du_y - columns * cmd.du_x; cmd.dv_row = dv_y - columns * cmd.dv_x; cmd.dw_row = dw_y - columns * cmd.dw_x; azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count); prof_leave(azrp_perf_cmdgen); }