124 lines
3.2 KiB
C++
124 lines
3.2 KiB
C++
#include <azur/gint/render.h>
|
|
|
|
uint8_t AZRP_SHADER_FILLEDCIRCLE = -1;
|
|
|
|
|
|
static void azrp_shader_filledcircle_configure(void) {
|
|
azrp_set_uniforms(AZRP_SHADER_FILLEDCIRCLE, (void *)azrp_width);
|
|
}
|
|
|
|
|
|
__attribute__((constructor)) static void register_shader(void) {
|
|
extern azrp_shader_t azrp_shader_filledcircle;
|
|
AZRP_SHADER_FILLEDCIRCLE = azrp_register_shader(azrp_shader_filledcircle, azrp_shader_filledcircle_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; }
|
|
|
|
//---
|
|
|
|
#define TABLE_WIDTH
|
|
|
|
struct command {
|
|
uint8_t shader_id;
|
|
uint16_t color;
|
|
uint8_t curr_frag;
|
|
int16_t DataFilling[2 * 224]; // Each line of the screen can have a xmin and
|
|
// a xmax value
|
|
};
|
|
|
|
void AddPixelFilledCircle(int16_t xpmin, int16_t xpmax, int16_t yp,
|
|
struct command *cmd) {
|
|
if (yp >= 0 && yp < azrp_height) {
|
|
if (xpmin >= 0)
|
|
cmd->DataFilling[2 * yp] = xpmin;
|
|
else
|
|
cmd->DataFilling[2 * yp] = 0;
|
|
|
|
if (xpmax < azrp_width)
|
|
cmd->DataFilling[2 * yp + 1] = xpmax;
|
|
else
|
|
cmd->DataFilling[2 * yp + 1] = azrp_width - 1;
|
|
}
|
|
}
|
|
|
|
void azrp_filledcircle(int xc, int yc, uint16_t rad, uint16_t color) {
|
|
prof_enter(azrp_perf_cmdgen);
|
|
|
|
int xmin = xc - rad;
|
|
int xmax = xc + rad;
|
|
int ymin = yc - rad;
|
|
int ymax = yc + rad;
|
|
|
|
// The circle is fully outside the screen
|
|
if ((xmax < 0) || (xmin >= azrp_width) || (ymax < 0) ||
|
|
(ymin >= azrp_height)) {
|
|
prof_leave(azrp_perf_cmdgen);
|
|
return;
|
|
}
|
|
|
|
int ytop = max(ymin, 0);
|
|
int ybot = min(ymax, azrp_height - 1);
|
|
|
|
int frag_first = ytop / azrp_frag_height;
|
|
int frag_last = ybot / azrp_frag_height;
|
|
int frag_count = frag_last - frag_first + 1;
|
|
|
|
struct command *cmd = (struct command *) azrp_new_command(sizeof *cmd, frag_first, frag_count);
|
|
if(!cmd) {
|
|
prof_leave(azrp_perf_cmdgen);
|
|
return;
|
|
}
|
|
|
|
cmd->shader_id = AZRP_SHADER_FILLEDCIRCLE;
|
|
cmd->color = color;
|
|
cmd->curr_frag = frag_first;
|
|
|
|
// reset the point counters in each cell of the table
|
|
for (int i = 0; i < 224; i++) {
|
|
cmd->DataFilling[2 * i] = -1; // reset with value equels -1
|
|
cmd->DataFilling[2 * i + 1] = -1; // reset with value equals -1
|
|
}
|
|
|
|
int x = 0;
|
|
int y = rad;
|
|
int m = 5 - 4 * rad;
|
|
|
|
while (x <= y) {
|
|
AddPixelFilledCircle(xc - x, xc + x, yc - y, cmd);
|
|
AddPixelFilledCircle(xc - y, xc + y, yc - x, cmd);
|
|
AddPixelFilledCircle(xc - x, xc + x, yc + y, cmd);
|
|
AddPixelFilledCircle(xc - y, xc + y, yc + x, cmd);
|
|
|
|
if (m > 0) {
|
|
y--;
|
|
m -= 8 * y;
|
|
}
|
|
x++;
|
|
m += 8 * x + 4;
|
|
}
|
|
|
|
prof_leave(azrp_perf_cmdgen);
|
|
}
|
|
|
|
void azrp_shader_filledcircle(void *uniforms, void *comnd, void *fragment) {
|
|
struct command *cmd = (struct command *)comnd;
|
|
uint16_t *frag = (uint16_t *)fragment;
|
|
|
|
int16_t *data = (int16_t *)cmd->DataFilling;
|
|
int BaseAdress = cmd->curr_frag * azrp_frag_height * 2;
|
|
|
|
for (int i = 0; i < azrp_frag_height; i++) {
|
|
int16_t Xmin = data[BaseAdress + 2 * i];
|
|
int16_t Xmax = data[BaseAdress + 2 * i + 1];
|
|
|
|
if (Xmin != -1 && Xmax != -1)
|
|
for (int j = Xmin; j <= Xmax; j++)
|
|
frag[azrp_width * i + j] = cmd->color;
|
|
}
|
|
|
|
cmd->curr_frag++;
|
|
} |