212 lines
5.1 KiB
C++
212 lines
5.1 KiB
C++
|
#include <azur/gint/render.h>
|
||
|
|
||
|
uint8_t AZRP_SHADER_LINE = -1;
|
||
|
|
||
|
|
||
|
static void azrp_shader_line_configure(void)
|
||
|
{
|
||
|
azrp_set_uniforms(AZRP_SHADER_LINE, (void *)azrp_width);
|
||
|
}
|
||
|
|
||
|
|
||
|
__attribute__((constructor))
|
||
|
static void register_shader(void)
|
||
|
{
|
||
|
extern azrp_shader_t azrp_shader_line;
|
||
|
AZRP_SHADER_LINE = azrp_register_shader(azrp_shader_line, azrp_shader_line_configure );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//---
|
||
|
|
||
|
struct command {
|
||
|
uint8_t shader_id;
|
||
|
uint16_t color;
|
||
|
uint16_t curr_y;
|
||
|
uint16_t curr_x;
|
||
|
int16_t dx, dy, sx, sy;
|
||
|
int16_t cumul;
|
||
|
int16_t i;
|
||
|
};
|
||
|
|
||
|
int ABS( int x1 )
|
||
|
{
|
||
|
if (x1 >= 0) return x1;
|
||
|
else return (-1 * x1);
|
||
|
}
|
||
|
|
||
|
int SGN( int x1 )
|
||
|
{
|
||
|
if (x1 > 0) return 1;
|
||
|
else if (x1 == 0) return 0;
|
||
|
else return -1;
|
||
|
}
|
||
|
|
||
|
void azrp_line(int xA, int yA, int xB, int yB, uint16_t color)
|
||
|
{
|
||
|
prof_enter(azrp_perf_cmdgen);
|
||
|
|
||
|
//clipping algorithm as per "Another Simple but Faster Method for 2D Line Clipping"
|
||
|
//from Dimitrios Matthes and Vasileios Drakopoulos
|
||
|
//International Journal of Computer Graphics & Animation (IJCGA) Vol.9, No.1/2/3, July 2019
|
||
|
|
||
|
int xmin = 0;
|
||
|
int xmax = azrp_width-1;
|
||
|
int ymin = 0;
|
||
|
int ymax = azrp_height-1;
|
||
|
|
||
|
//step 1 line are fully out of the screen
|
||
|
if ((xA<xmin && xB<xmin) || (xA>xmax && xB>xmax) || (yA<ymin && yB<ymin) || (yA>ymax && yB>ymax)) {
|
||
|
prof_leave(azrp_perf_cmdgen);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int x1, x2, y1, y2;
|
||
|
|
||
|
// step 1.5 - specific to Azur fragment approach
|
||
|
// we swap to always start with the point on top as the fragment are updated from top to bottom
|
||
|
// (x1,y1) is the most top point and (x2,y2) is the most bottom point (rankig as per y values only
|
||
|
if (yA <= yB) {
|
||
|
x1 = xA; y1 = yA;
|
||
|
x2 = xB; y2 = yB;
|
||
|
}
|
||
|
else {
|
||
|
x1 = xB; y1 = yB;
|
||
|
x2 = xA; y2 = yA;
|
||
|
}
|
||
|
|
||
|
//step 2 line clipping within the box (xmin,ymin) --> (xmax,ymax)
|
||
|
int x[2];
|
||
|
int y[2];
|
||
|
|
||
|
x[0] = x1; x[1] = x2;
|
||
|
y[0] = y1; y[1] = y2;
|
||
|
|
||
|
|
||
|
for(int i=0; i<2; i++) {
|
||
|
if (x[i] < xmin) {
|
||
|
x[i] = xmin; y[i] = ((y2-y1) * (xmin-x1)) / (x2-x1) + y1;
|
||
|
}
|
||
|
else if (x[i] > xmax) {
|
||
|
x[i] = xmax; y[i] = ((y2-y1) * (xmax-x1)) / (x2-x1) + y1;
|
||
|
}
|
||
|
|
||
|
if (y[i] < ymin) {
|
||
|
x[i] = ((x2-x1) * (ymin-y1)) / (y2-y1) + x1; y[i] = ymin;
|
||
|
}
|
||
|
else if (y[i] > ymax) {
|
||
|
x[i] = ((x2-x1) * (ymax-y1)) / (y2-y1) + x1; y[i] = ymax;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if((x[0] < xmin && x[1] < xmin) || (x[0] > xmax && x[1] > xmax)) {
|
||
|
prof_leave(azrp_perf_cmdgen);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
x1 = x[0];
|
||
|
y1 = y[0];
|
||
|
x2 = x[1];
|
||
|
y2 = y[1];
|
||
|
|
||
|
int frag_first = y1 / azrp_frag_height;
|
||
|
int frag_last = y2 / 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_LINE;
|
||
|
cmd->color = color;
|
||
|
|
||
|
cmd->curr_x = x1;
|
||
|
cmd->curr_y = y1 & 15;
|
||
|
|
||
|
cmd->dx = ABS(x2-x1);
|
||
|
cmd->sx = SGN(x2-x1);
|
||
|
|
||
|
cmd->dy = ABS(y2-y1);
|
||
|
cmd->sy = SGN(y2-y1);
|
||
|
|
||
|
cmd->i = 0;
|
||
|
cmd->cumul = (cmd->dx >= cmd->dy) ? cmd->dx/2 : cmd->dy/2;
|
||
|
|
||
|
prof_leave(azrp_perf_cmdgen);
|
||
|
}
|
||
|
|
||
|
void azrp_shader_line( void *uniforms, void *comnd, void *fragment )
|
||
|
{
|
||
|
struct command *cmd = (struct command *) comnd;
|
||
|
uint16_t *frag = (uint16_t *) fragment;
|
||
|
|
||
|
frag[ azrp_width * cmd->curr_y + cmd->curr_x ] = cmd->color;
|
||
|
|
||
|
int i;
|
||
|
|
||
|
if (cmd->dy == 0)
|
||
|
{
|
||
|
for( i = cmd->i; i < cmd->dx ; i++ )
|
||
|
{
|
||
|
cmd->curr_x += cmd->sx;
|
||
|
frag[ azrp_width * cmd->curr_y + cmd->curr_x ] = cmd->color;
|
||
|
}
|
||
|
}
|
||
|
else if (cmd->dx == 0)
|
||
|
{
|
||
|
for( i = cmd->i; i < cmd->dy ; i++ )
|
||
|
{
|
||
|
cmd->curr_y += cmd->sy;
|
||
|
|
||
|
// if curr_y=16, this means we are changing to next fragment
|
||
|
if (cmd->curr_y == azrp_frag_height) break;
|
||
|
|
||
|
frag[ azrp_width * cmd->curr_y + cmd->curr_x ] = cmd->color;
|
||
|
}
|
||
|
}
|
||
|
else if (cmd->dx >= cmd->dy)
|
||
|
{
|
||
|
for( i = cmd->i; i < cmd->dx; i++ )
|
||
|
{
|
||
|
cmd->curr_x += cmd->sx;
|
||
|
cmd->cumul += cmd->dy;
|
||
|
if (cmd->cumul > cmd->dx)
|
||
|
{
|
||
|
cmd->cumul -= cmd->dx;
|
||
|
cmd->curr_y += cmd->sy;
|
||
|
}
|
||
|
// if curr_y=16, this means we are changing to next fragment
|
||
|
if (cmd->curr_y == azrp_frag_height ) break;
|
||
|
|
||
|
frag[ azrp_width * cmd->curr_y + cmd->curr_x ] = cmd->color;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i = cmd->i; i < cmd->dy; i++ )
|
||
|
{
|
||
|
cmd->curr_y += cmd->sy;
|
||
|
cmd->cumul += cmd->dx;
|
||
|
if (cmd->cumul > cmd->dy)
|
||
|
{
|
||
|
cmd->cumul -= cmd->dy;
|
||
|
cmd->curr_x += cmd->sx;
|
||
|
}
|
||
|
|
||
|
// if curr_y=16, this means we are changing to next fragment
|
||
|
if (cmd->curr_y == azrp_frag_height) break;
|
||
|
|
||
|
frag[ azrp_width * cmd->curr_y + cmd->curr_x ] = cmd->color;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cmd->curr_y = cmd->curr_y & 15;
|
||
|
|
||
|
cmd->i = i+1;
|
||
|
}
|