Compare commits

..

1 Commits
main ... shmup

Author SHA1 Message Date
Sylvain PILLOT 3ff6008b9a double command space 2023-01-29 22:48:57 +01:00
22 changed files with 26 additions and 1025 deletions

2
.gitignore vendored
View File

@ -5,5 +5,3 @@
# Editor files
*.sublime-*
.vscode

View File

@ -1,3 +0,0 @@
{
"editor.fontSize": 12
}

View File

@ -1,8 +0,0 @@
Polygon shader
Filled polygon shader
Ellipse shader
Filled ellipse shader
Better font shader

View File

@ -35,11 +35,6 @@ if(AZUR_TOOLKIT_SDL AND AZUR_GRAPHICS_OPENGL)
DEPENDS gen_glsl.py ${ASSETS})
endif()
if(AZUR_TOOLKIT_GINT)
list(APPEND SOURCES
src/gint/init.cpp)
endif()
# gint rendering
if(AZUR_GRAPHICS_GINT_CG)
list(APPEND SOURCES
@ -72,15 +67,7 @@ if(AZUR_GRAPHICS_GINT_CG)
src/gint/shaders/image_p4_dye.c
# Triangle shader
src/gint/shaders/triangle.c
src/gint/shaders/triangle.S
# Line shader
src/gint/shaders/line.c
# Circle shader
src/gint/shaders/circle.c
src/gint/shaders/filledcircle.c
src/gint/shaders/poly.c
src/gint/shaders/filledpoly.c
)
src/gint/shaders/triangle.S)
endif()
add_library(azur STATIC ${SOURCES})

View File

@ -44,14 +44,6 @@
#cmakedefine AZUR_GRAPHICS_GINT_CG
/* CPU architecture (mostly useful for optimized SuperH stuff). */
/* Generic/unknown CPU architecture; only C code is used. */
#cmakedefine AZUR_ARCH_GENERIC
/* SH4AL-DSP for the fx-CG. */
#cmakedefine AZUR_ARCH_SH4ALDSP
/* Input/output settings on terminal. */
/* No terminal output entirely. */

View File

@ -205,21 +205,6 @@ void azrp_subimage(int x, int y, bopti_image_t const *image,
void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color);
/* azrp_line(): Draw a line with clipping to the screen resolution between point (x1,y1) and (x2,y2) */
void azrp_line( int x1, int y1, int x2, int y2, uint16_t color );
/* azrp_circle() : Draw a circle with clipping to the screen resolution with a center (xc,yc) and a radius rad */
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. */
@ -232,12 +217,6 @@ void azrp_shader_image_p8_configure(void);
void azrp_shader_image_p4_configure(void);
void azrp_shader_triangle_configure(void);
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

@ -1,98 +0,0 @@
#include <azur/azur.h>
#include <azur/log.h>
#include <gint/timer.h>
#include <gint/cpu.h>
int azur_init(char const *title, int window_width, int window_height)
{
(void)title;
(void)window_width;
(void)window_height;
return 0;
}
__attribute__((destructor))
void azur_quit(void)
{
}
//---
// Main loop setup
//---
/* Time spent in the main loop (seconds)
TODO: Handle ml_time (also in the SDL backend) */
static double ml_time = 0.0;
/* Timers for render and updates */
static int ml_timer_render = -1;
static int ml_timer_update = -1;
static int set_flag(volatile int *flag)
{
*flag = 1;
return TIMER_CONTINUE;
}
int azur_main_loop(
void (*render)(void), int render_fps,
int (*update)(void), int update_ups,
int flags)
{
volatile int render_tick = 1;
volatile int update_tick = 0;
bool started = false;
ml_timer_render = timer_configure(TIMER_ANY, 1000000 / render_fps,
GINT_CALL(set_flag, &render_tick));
if(ml_timer_render < 0) {
azlog(ERROR, "failed to create render timer\n");
return 1;
}
else {
timer_start(ml_timer_render);
}
if(!(flags & AZUR_MAIN_LOOP_TIED)) {
ml_timer_update = timer_configure(TIMER_ANY, 1000000 / update_ups,
GINT_CALL(set_flag, &update_tick));
if(ml_timer_update < 0) {
timer_stop(ml_timer_render);
azlog(ERROR, "failed to create render timer\n");
return 1;
}
else {
timer_start(ml_timer_update);
}
}
while(1) {
if(update_tick && !(flags & AZUR_MAIN_LOOP_TIED)) {
update_tick = 0;
if(update && update()) break;
}
if(render_tick) {
render_tick = 0;
/* Tied renders and updates */
if(started && (flags & AZUR_MAIN_LOOP_TIED)) {
if(update && update()) break;
}
if(render) render();
started = true;
}
sleep();
}
if(ml_timer_render >= 0) {
timer_stop(ml_timer_render);
ml_timer_render = 0;
}
if(ml_timer_update >= 0) {
timer_stop(ml_timer_update);
ml_timer_update = 0;
}
return 0;
}

View File

@ -30,7 +30,7 @@ static int commands_count=0, commands_length=0;
Rendering order is integer order. */
static uint32_t commands_array[AZRP_MAX_COMMANDS];
static GALIGNED(4) uint8_t commands_data[4*16384];
static GALIGNED(4) uint8_t commands_data[16384*2];
/* Array of shader programs and uniforms. */
static azrp_shader_t *shaders[AZRP_MAX_SHADERS] = { NULL };

View File

@ -1,141 +0,0 @@
#include <azur/gint/render.h>
uint8_t AZRP_SHADER_CIRCLE = -1;
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_circle;
AZRP_SHADER_CIRCLE = azrp_register_shader(azrp_shader_circle);
}
void azrp_shader_circle_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_CIRCLE, (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 256
struct command {
uint8_t shader_id;
uint16_t color;
uint8_t curr_frag;
uint16_t NbPixels[14]; // Nunmber of pixels in each fragment
uint16_t DataPixelsX[14*TABLE_WIDTH]; // 14 fragments each able to store as much pixels as width
uint16_t DataPixelsY[14*TABLE_WIDTH]; // 14 fragments each able to store as much pixels as width
};
void AddPixelCircle( int16_t xp, int16_t yp, struct command *cmd )
{
if (xp >= 0 && xp < azrp_width && yp >= 0 && yp < azrp_height)
{
uint8_t cfrag = yp / azrp_frag_height;
uint16_t nbpixinfrag = cmd->NbPixels[ cfrag ];
uint16_t index = cfrag * TABLE_WIDTH + nbpixinfrag;
cmd->DataPixelsX[ index ] = xp;
cmd->DataPixelsY[ index ] = yp & 15;
cmd->NbPixels[ cfrag ]++;
}
}
void azrp_circle(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;
cmd.shader_id = AZRP_SHADER_CIRCLE;
cmd.color = color;
cmd.curr_frag = frag_first;
// reset the point counters in each cell of the table
for( int i = 0; i < 14; i++ )
cmd.NbPixels[i]=0;
int x = 0;
int y = rad;
int m = 5 - 4*rad;
while (x <= y)
{
AddPixelCircle( xc+x, yc+y, &cmd );
AddPixelCircle( xc+y, yc+x, &cmd );
AddPixelCircle( xc-x, yc+y, &cmd );
AddPixelCircle( xc-y, yc+x, &cmd );
AddPixelCircle( xc+x, yc-y, &cmd );
AddPixelCircle( xc+y, yc-x, &cmd );
AddPixelCircle( xc-x, yc-y, &cmd );
AddPixelCircle( 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_circle( void *uniforms, void *comnd, void *fragment )
{
struct command *cmd = (struct command *) comnd;
uint16_t *frag = (uint16_t *) fragment;
uint16_t *taille = (uint16_t *) cmd->NbPixels;
uint16_t *DX = (uint16_t *) cmd->DataPixelsX;
uint16_t *DY = (uint16_t *) cmd->DataPixelsY;
uint16_t nbpix = taille[ cmd->curr_frag ];
int BaseAdress = cmd->curr_frag * TABLE_WIDTH;
for( int i = 0; i < nbpix; i++ )
{
uint16_t X = DX[ BaseAdress + i ];
uint16_t Y = DY[ BaseAdress + i ];
frag[ azrp_width * Y + X ] = cmd->color;
}
cmd->curr_frag++;
}

View File

@ -1,116 +0,0 @@
#include <azur/gint/render.h>
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);
}
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; }
//---
#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;
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;
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++;
}

View File

@ -1,162 +0,0 @@
#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

@ -1,202 +0,0 @@
#include <azur/gint/render.h>
uint8_t AZRP_SHADER_LINE = -1;
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_line;
AZRP_SHADER_LINE = azrp_register_shader(azrp_shader_line);
}
void azrp_shader_line_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_LINE, (void *)azrp_width);
}
//---
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;
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;
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
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;
}

View File

@ -1,15 +0,0 @@
#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);
}

View File

@ -134,8 +134,7 @@ SDL_Window *azur_sdl_window(void)
// Main loop setup
//---
/* Time spent in the main loop (seconds)
TODO: Handle ml_time (also in the gint backend) */
/* Time spent in the main loop (seconds) */
static double ml_time = 0.0;
/* In emscripten, callbacks are void/void, vsync is always ON, and the

View File

@ -7,31 +7,15 @@
include(CTest)
set(SOURCES
src/num.cpp
add_library(num STATIC
src/str.cpp)
if(DEFINED AZUR_ARCH_GENERIC)
set(LIBNUM_ARCH_GENERIC TRUE)
elseif(DEFINED AZUR_ARCH_SH4ALDSP)
set(LIBNUM_ARCH_SH4ALDSP TRUE)
list(APPEND SOURCES
src/sh4aldsp/div_i32_i16_i16.s)
endif()
configure_file(include/num/config.h.in num/config.h)
add_library(num STATIC ${SOURCES})
target_include_directories(num PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_BINARY_DIR}")
target_include_directories(num PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Library file: libnum.a
install(TARGETS num DESTINATION ${LIBDIR})
# Headers: num/config.h and num/*.h
# Headers: azur/*.h
install(DIRECTORY include/ DESTINATION ${INCDIR})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/num/config.h"
DESTINATION ${INCDIR}/num)
#---
# Unit tests

View File

@ -1,15 +0,0 @@
//---------------------------------------------------------------------------//
// ," /\ ", Azur: A game engine for CASIO fx-CG and PC //
// | _/__\_ | Designed by Lephe' and the Planète Casio community. //
// "._`\/'_." License: MIT <https://opensource.org/licenses/MIT> //
//---------------------------------------------------------------------------//
// num.config: Compile-time configuration options
#pragma once
/* CPU architecture. */
/* Generic/unknown CPU architecture; only C code is used. */
#cmakedefine LIBNUM_ARCH_GENERIC
/* SH4AL-DSP for the fx-CG. */
#cmakedefine LIBNUM_ARCH_SH4ALDSP

View File

@ -48,8 +48,9 @@
#pragma once
#include <num/primitives.h>
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include <concepts>
@ -116,15 +117,9 @@ struct num8
v %= other.v;
return *this;
}
inline constexpr num8 ifloor() {
return 0;
}
inline constexpr num8 floor() {
return num8(0);
}
inline constexpr num8 iceil() {
return v != 0;
}
/* Warning: num8::ceil() always overflows! */
inline constexpr num8 ceil() {
return num8(0);
@ -137,19 +132,19 @@ struct num8
/* Comparisons with int */
inline constexpr bool operator==(int const &i) const {
inline constexpr bool operator==(int const &i) {
return (v | i) == 0;
}
inline constexpr bool operator<(int const &i) const {
inline constexpr bool operator<(int const &i) {
return i >= 1;
}
inline constexpr bool operator>=(int const &i) const {
inline constexpr bool operator>=(int const &i) {
return i <= 0;
}
inline constexpr bool operator<=(int const &i) const {
inline constexpr bool operator<=(int const &i) {
return i + !v > 0;
}
inline constexpr bool operator>(int const &i) const {
inline constexpr bool operator>(int const &i) {
return i + !v <= 0;
}
@ -200,9 +195,6 @@ struct num16
/* num16 x num16 -> num32 multiplication
This is efficiently implemented with a muls.w instruction. */
static constexpr num32 dmul(num16 const &x, num16 const &y);
/* num16 / num16 -> num16 division for positive numbers
This bypasses some sign tests, which saves a bit of time. */
static constexpr num16 div_positive(num16 const &x, num16 const &y);
/* Basic arithmetic */
@ -218,25 +210,19 @@ struct num16
v = (v * other.v) / 256;
return *this;
}
inline num16 &operator/=(num16 const &other) {
v = prim::div_i32_i16_i16(v * 256, other.v);
inline constexpr num16 &operator/=(num16 const &other) {
v = (v * 256) / other.v;
return *this;
}
inline constexpr num16 &operator%=(num16 const &other) {
v %= other.v;
return *this;
}
inline constexpr int ifloor() {
return v >> 8;
}
inline constexpr num16 floor() {
num16 x;
x.v = v & 0xff00;
return x;
}
inline constexpr int iceil() {
return (v + 0xff) >> 8;
}
inline constexpr num16 ceil() {
num16 x;
x.v = ((v - 1) | 0xff) + 1;
@ -250,22 +236,22 @@ struct num16
/* Comparisons with int */
inline constexpr bool operator==(int const &i) const {
inline constexpr bool operator==(int const &i) {
return (int16_t)i == i && (i << 8) == v;
}
inline constexpr bool operator<(int const &i) const {
inline constexpr bool operator<(int const &i) {
return (v >> 8) < i;
}
inline constexpr bool operator>=(int const &i) const {
inline constexpr bool operator>=(int const &i) {
return (v >> 8) >= i;
}
/* Unfortunately the branchless version for this test is expressed in terms
of `v`, not `i`, so it does not simplify well when `i` is known. In that
case, writing eg. `x > num16(0)` is faster than `x > 0`. */
inline constexpr bool operator<=(int const &i) const {
inline constexpr bool operator<=(int const &i) {
return (v >> 8) + ((v & 0xff) != 0) <= i;
}
inline constexpr bool operator>(int const &i) const {
inline constexpr bool operator>(int const &i) {
return (v >> 8) + ((v & 0xff) != 0) > i;
}
@ -344,17 +330,11 @@ struct num32
v %= other.v;
return *this;
}
inline constexpr int ifloor() {
return v >> 16;
}
inline constexpr num32 floor() {
num32 x;
x.v = v & 0xffff0000;
return x;
}
inline constexpr int iceil() {
return (v + 0xffff) >> 16;
}
inline constexpr num32 ceil() {
num32 x;
x.v = ((v - 1) | 0xffff) + 1;
@ -365,23 +345,22 @@ struct num32
x.v = v & 0xffff;
return x;
}
num32 sqrt() const;
/* Comparisons with int */
inline constexpr bool operator==(int const &i) const {
inline constexpr bool operator==(int const &i) {
return (int16_t)i == i && (i << 16) == v;
}
inline constexpr bool operator<(int const &i) const {
inline constexpr bool operator<(int const &i) {
return (v >> 16) < i;
}
inline constexpr bool operator>=(int const &i) const {
inline constexpr bool operator>=(int const &i) {
return (v >> 16) >= i;
}
inline constexpr bool operator<=(int const &i) const {
inline constexpr bool operator<=(int const &i) {
return (v >> 16) + ((v & 0xffff) != 0) <= i;
}
inline constexpr bool operator>(int const &i) const {
inline constexpr bool operator>(int const &i) {
return (v >> 16) + ((v & 0xffff) != 0) > i;
}
@ -468,17 +447,11 @@ struct num64
v %= other.v;
return *this;
}
inline constexpr int ifloor() {
return v >> 32;
}
inline constexpr num64 floor() {
num64 x;
x.v = v & 0xffffffff00000000ull;
return x;
}
inline constexpr int iceil() {
return (v >> 32) + ((uint32_t)v != 0);
}
inline constexpr num64 ceil() {
num64 x;
x.v = ((v - 1) | 0xffffffffull) + 1;
@ -596,26 +569,6 @@ inline constexpr T operator-(T const &op) {
return T(0) - op;
}
/* Internal minima, maxima and clamp */
template<typename T> requires(is_num<T>)
inline constexpr T min(T const &left, T const &right)
{
return (left < right) ? left : right;
}
template<typename T> requires(is_num<T>)
inline constexpr T max(T const &left, T const &right)
{
return (left > right) ? left : right;
}
template<typename T> requires(is_num<T>)
inline constexpr T clamp(T const &val, T const &lower, T const &upper)
{
return max(lower, min(val, upper));
}
/* Other specific operations */
inline constexpr num32 num16::dmul(num16 const &x, num16 const &y)
@ -625,13 +578,6 @@ inline constexpr num32 num16::dmul(num16 const &x, num16 const &y)
return n;
}
inline constexpr num16 num16::div_positive(num16 const &x, num16 const &y)
{
num16 r;
r.v = ((uint32_t)(uint16_t)x.v << 8) / (uint16_t)y.v;
return r;
}
inline constexpr num64 num32::dmul(num32 const &x, num32 const &y)
{
num64 n;
@ -639,12 +585,4 @@ inline constexpr num64 num32::dmul(num32 const &x, num32 const &y)
return n;
}
/* Floor modulo. We provide an optimized version for constants, which optimizes
away the main condition. */
template<typename T> requires(is_num<T>)
inline constexpr T modf(T const &x, T const &y) {
T r = x % y;
return (r.v && (r.v ^ y.v) < 0) ? r + y : r;
}
} /* namespace libnum */

View File

@ -1,37 +0,0 @@
//---------------------------------------------------------------------------//
// ," /\ ", Azur: A game engine for CASIO fx-CG and PC //
// | _/__\_ | Designed by Lephe' and the Planète Casio community. //
// "._`\/'_." License: MIT <https://opensource.org/licenses/MIT> //
//---------------------------------------------------------------------------//
// num.primitives: Platform-specific optimized primitives
//
// This header provides a generic interface to optimized primitives such as
// unusual-size divisions. These are used in libnum functions for a performance
// boost.
//
// The following functions are defined:
// - div_X_Y_Z: Division of an X by a Y with a result of type Z (where X,Y,Z is
// a signed integer type iN or an unsigned integer type uN)
//---
#pragma once
#include <num/config.h>
#include <cstdint>
namespace libnum::prim {
#ifdef LIBNUM_ARCH_SH4ALDSP
extern int div_i32_i16_i16(int32_t num, int16_t denum);
#else
static inline constexpr int div_i32_i16_i16(int32_t num, int16_t denum)
{
return num / denum;
}
#endif
} /* namespace libnum::prim */

View File

@ -189,10 +189,6 @@ inline constexpr vec<T,N> operator*(T const &lhs, vec<T,N> rhs) {
rhs[i] *= lhs;
return rhs;
}
template<typename T, int N>
inline constexpr vec<T,N> operator/(vec<T,N> lhs, T const &rhs) {
return lhs /= rhs;
}
/* Comparisons */

View File

@ -1,21 +0,0 @@
#include <num/num.h>
using namespace libnum;
/* Integer square root (rather slow) */
static int64_t sqrtll(int64_t n)
{
if(n < 4)
return (n > 0);
int64_t low_bound = sqrtll(n / 4) * 2;
int64_t high_bound = low_bound + 1;
return (high_bound * high_bound <= n) ? high_bound : low_bound;
}
num32 num32::sqrt() const
{
num32 r;
r.v = sqrtll((int64_t)v << 16);
return r;
}

View File

@ -1,54 +0,0 @@
# --------------------------------------------------------------------------- #
# ," /\ ", Azur: A game engine for CASIO fx-CG and PC #
# | _/__\_ | Designed by Lephe' and the Planète Casio community. #
# "._`\/'_." License: MIT <https://opensource.org/licenses/MIT> #
# --------------------------------------------------------------------------- #
# SH4AL-DSP optimized i32 / i16 -> i16 division.
#
# This simply uses the CPU's ability to divide without rotation for 16 bit
# divisors without all the boilerplate than libgcc's __sdivisi3 requires since
# it assumes 32-bit inputs. Used for num16 division.
# ---
.global __ZN6libnum4prim15div_i32_i16_i16Els
# libnum::prim::div_i32_i16_i16(long, short)
__ZN6libnum4prim15div_i32_i16_i16Els:
shll16 r5
mov #0, r2
mov r4, r3
rotcl r3
subc r2, r4
div0s r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
div1 r5, r4
exts.w r4, r4
rotcl r4
addc r2, r4
rts
exts.w r4, r0

View File

@ -306,7 +306,7 @@ class ExprParser:
return decorate
def binaryOpsRight(ctor, ops):
return binaryOps(ctor, ops, rassoc=True)
return binaryOpsRight(ctor, ops, rassoc=True)
def unaryOps(ctor, ops, assoc=True):
def decorate(f):