added azrp_poly() and azrp_filledpoly() shaders

This commit is contained in:
Sylvain PILLOT 2023-05-26 18:14:57 +02:00
parent 69a7ece6f9
commit 1719aa0714
5 changed files with 275 additions and 106 deletions

View File

@ -78,6 +78,8 @@ if(AZUR_GRAPHICS_GINT_CG)
# Circle shader
src/gint/shaders/circle.c
src/gint/shaders/filledcircle.c
src/gint/shaders/poly.c
src/gint/shaders/filledpoly.c
)
endif()

View File

@ -214,6 +214,12 @@ void azrp_circle( int xc, int yx, uint16_t rad, uint16_t color );
/* azrp_filledcircle() : Draw a filled circle with clipping to the screen resolution with a center (xc,yc) and a radius rad */
void azrp_filledcircle( int xc, int yx, uint16_t rad, uint16_t color );
/* azrp_poly() : Draw a polygon with clipping*/
void azrp_poly(int *x, int *y, int nb_vertices, uint16_t color);
/* azrp_filledpoly() : Draw a filled polygon with clipping*/
void azrp_filledpoly(int *x, int *y, int nb_vertices, uint16_t color);
/* See below for more detailed image functions. Dynamic effects are provided
with the same naming convention as gint. */
@ -230,6 +236,7 @@ void azrp_shader_line_configure(void);
void azrp_shader_circle_configure(void);
void azrp_shader_filledcircle_configure(void);
void azrp_shader_filledpoly_configure(void);
//---
// Performance indicators

View File

@ -2,132 +2,115 @@
uint8_t AZRP_SHADER_FILLEDCIRCLE = -1;
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_filledcircle;
AZRP_SHADER_FILLEDCIRCLE = azrp_register_shader(azrp_shader_filledcircle);
__attribute__((constructor)) static void register_shader(void) {
extern azrp_shader_t azrp_shader_filledcircle;
AZRP_SHADER_FILLEDCIRCLE = azrp_register_shader(azrp_shader_filledcircle);
}
void azrp_shader_filledcircle_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_FILLEDCIRCLE, (void *)azrp_width);
void azrp_shader_filledcircle_configure(void) {
azrp_set_uniforms(AZRP_SHADER_FILLEDCIRCLE, (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;
}
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
#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
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;
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;
}
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);
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;
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;
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;
}
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
// 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;
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;
}
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
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;
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;
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;
}
for (int i = 0; i < azrp_frag_height; i++) {
int16_t Xmin = data[BaseAdress + 2 * i];
int16_t Xmax = data[BaseAdress + 2 * i + 1];
cmd->curr_frag++;
if (Xmin != -1 && Xmax != -1)
for (int j = Xmin; j <= Xmax; j++)
frag[azrp_width * i + j] = cmd->color;
}
cmd->curr_frag++;
}

View File

@ -0,0 +1,162 @@
#include <azur/gint/render.h>
uint8_t AZRP_SHADER_FILLEDPOLY = -1;
__attribute__((constructor)) static void register_shader(void) {
extern azrp_shader_t azrp_shader_filledpoly;
AZRP_SHADER_FILLEDPOLY = azrp_register_shader(azrp_shader_filledpoly);
}
void azrp_shader_filledpoly_configure(void) {
azrp_set_uniforms(AZRP_SHADER_FILLEDPOLY, (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; }
//---
#define TABLE_WIDTH
struct command {
uint8_t shader_id;
uint16_t color;
uint8_t curr_frag;
int16_t xmin[224];
int16_t xmax[224];
uint8_t empty[224];
};
void AddPixelFilledPoly(int16_t xpmin, int16_t xpmax, int16_t yp,
struct command *cmd) {
if (yp >= 0 && yp < azrp_height) {
if (xpmin >= 0)
cmd->xmin[yp] = xpmin;
else
cmd->xmin[yp] = 0;
if (xpmax < azrp_width)
cmd->xmax[yp] = xpmax;
else
cmd->xmax[yp] = azrp_width - 1;
}
}
void azrp_filledpoly(int *x, int *y, int nb_vertices, uint16_t color) {
prof_enter(azrp_perf_cmdgen);
int i, ymin, ymax, xmin2, xmax2, *xmin, *xmax;
char *empty;
if(nb_vertices < 3) {
prof_leave(azrp_perf_cmdgen);
return;
}
ymin = ymax = y[0];
xmin2 = xmax2 = x[0];
for(i=0 ; i<nb_vertices ; i++) {
if(y[i] < ymin) ymin = y[i];
if(y[i] > ymax) ymax = y[i];
if(x[i] < xmin2) xmin2 = x[i];
if(x[i] > xmax2) xmax2 = x[i];
}
// The polygon is fully outside the screen
if ((xmax2 < 0) || (xmin2 >= azrp_width) || (ymax < 0) ||
(ymin >= azrp_height)) {
prof_leave(azrp_perf_cmdgen);
return;
}
xmin = malloc((ymax-ymin+1)*sizeof(int));
xmax = malloc((ymax-ymin+1)*sizeof(int));
empty = malloc(ymax-ymin+1);
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;
cmd.shader_id = AZRP_SHADER_FILLEDPOLY;
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.xmin[i] = -1; // reset with value equels -1
cmd.xmax[i] = -1; // reset with value equals -1
}
if(xmin && xmax && empty) {
for(i=0 ; i<ymax-ymin+1 ; i++) empty[i] = 1;
for(i=0 ; i<nb_vertices ; i++) {
int j, px, py, dx, dy, sx, sy, cumul;
px = x[i];
py = y[i];
dx = x[(i+1)%nb_vertices]-px;
dy = y[(i+1)%nb_vertices]-py;
sx = (dx > 0) ? 1 : -1;
sy = (dy > 0) ? 1 : -1;
dx = (dx > 0) ? dx : -dx;
dy = (dy > 0) ? dy : -dy;
if(empty[py-ymin]) xmax[py-ymin]=xmin[py-ymin]=px, empty[py-ymin]=0; else xmax[py-ymin]=px;
if(dx > dy) {
cumul = dx >> 1;
for(j=1 ; j<dx ; j++) {
px += sx;
cumul += dy;
if(cumul > dx) cumul -= dx, py += sy;
if(empty[py-ymin]) xmax[py-ymin]=xmin[py-ymin]=px, empty[py-ymin]=0; else xmax[py-ymin]=px;
}
} else {
cumul = dy >> 1;
for(j=1 ; j<dy ; j++) {
py += sy;
cumul += dx;
if(cumul > dy) cumul -= dy, px += sx;
if(empty[py-ymin]) xmax[py-ymin]=xmin[py-ymin]=px, empty[py-ymin]=0; else xmax[py-ymin]=px;
}
}
}
for(i=0 ; i<ymax-ymin+1 ; i++)
AddPixelFilledPoly(xmin[i], xmax[i], ymin+i, &cmd);
}
free(xmin);
free(xmax);
free(empty);
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
prof_leave(azrp_perf_cmdgen);
}
void azrp_shader_filledpoly(void *uniforms, void *comnd, void *fragment) {
struct command *cmd = (struct command *)comnd;
uint16_t *frag = (uint16_t *)fragment;
int16_t *Xmindata = (int16_t *)cmd->xmin;
int16_t *Xmaxdata = (int16_t *)cmd->xmax;
int BaseAdress = cmd->curr_frag * azrp_frag_height;
for (int i = 0; i < azrp_frag_height; i++)
{
int16_t Xmin = Xmindata[BaseAdress + i];
int16_t Xmax = Xmaxdata[BaseAdress + i];
if (Xmin != -1 && Xmax != -1)
if (Xmin<=Xmax)
for (int j = Xmin; j <= Xmax; j++) frag[azrp_width * i + j] = cmd->color;
else
for (int j = Xmax; j <= Xmin; j++) frag[azrp_width * i + j] = cmd->color;
}
cmd->curr_frag++;
}

View File

@ -0,0 +1,15 @@
#include <azur/gint/render.h>
void azrp_poly(int *x, int *y, int nb_vertices, uint16_t color) {
prof_enter(azrp_perf_cmdgen);
for( int i=0 ; i<nb_vertices ; i++) {
int px = x[i];
int py = y[i];
int px2 = x[(i+1)%nb_vertices];
int py2 = y[(i+1)%nb_vertices];
azrp_line( px, py, px2, py2, color );
}
prof_leave(azrp_perf_cmdgen);
}