oscar64/include/c64/sprites.c

347 lines
6.1 KiB
C

#include "sprites.h"
#include "rasterirq.h"
static volatile char * vspriteScreen;
#ifdef VSPRITE_BSS
#pragma bss(VSPRITE_BSS)
#endif
void spr_init(char * screen)
{
vspriteScreen = screen + 0x3f8;
}
void spr_set(char sp, bool show, int xpos, int ypos, char image, char color, bool multi, bool xexpand, bool yexpand)
{
__assume (sp < 8);
char m = 1 << sp;
if (show)
vic.spr_enable |= m;
else
vic.spr_enable &= ~m;
if (multi)
vic.spr_multi |= m;
else
vic.spr_multi &= ~m;
if (xexpand)
vic.spr_expand_x |= m;
else
vic.spr_expand_x &= ~m;
if (yexpand)
vic.spr_expand_y |= m;
else
vic.spr_expand_y &= ~m;
vic.spr_pos[sp].y = ypos;
vic.spr_pos[sp].x = xpos & 0xff;
if (xpos & 0x100)
vic.spr_msbx |= m;
else
vic.spr_msbx &= ~m;
vspriteScreen[sp] = image;
vic.spr_color[sp] = color;
}
void spr_show(char sp, bool show)
{
__assume (sp < 8);
if (show)
vic.spr_enable |= 1 << sp;
else
vic.spr_enable &= ~(1 << sp);
}
void spr_move(char sp, int xpos, int ypos)
{
__assume (sp < 8);
vic.spr_pos[sp].y = ypos;
vic.spr_pos[sp].x = xpos & 0xff;
if (xpos & 0x100)
vic.spr_msbx |= 1 << sp;
else
vic.spr_msbx &= ~(1 << sp);
}
void spr_move16(char sp, int xpos, int ypos)
{
__assume (sp < 8);
if (ypos < 0 || ypos >= 256 || xpos < 0 || xpos >= 384)
xpos = 384;
vic.spr_pos[sp].y = ypos;
vic.spr_pos[sp].x = xpos & 0xff;
if (xpos & 0x100)
vic.spr_msbx |= 1 << sp;
else
vic.spr_msbx &= ~(1 << sp);
}
int spr_posx(char sp)
{
return vic.spr_pos[sp].x | ((vic.spr_msbx & (1 << sp)) ? 256 : 0);
}
int spr_posy(char sp)
{
return vic.spr_pos[sp].y;
}
void spr_image(char sp, char image)
{
__assume (sp < 8);
vspriteScreen[sp] = image;
}
void spr_color(char sp, char color)
{
__assume (sp < 8);
vic.spr_color[sp] = color;
}
void spr_expand(char sp, bool xexpand, bool yexpand)
{
__assume (sp < 8);
char m = 1 << sp;
if (xexpand)
vic.spr_expand_x |= m;
else
vic.spr_expand_x &= ~m;
if (yexpand)
vic.spr_expand_y |= m;
else
vic.spr_expand_y &= ~m;
}
static char vspriteYLow[VSPRITES_MAX], vspriteXLow[VSPRITES_MAX], vspriteXHigh[VSPRITES_MAX];
static char vspriteImage[VSPRITES_MAX], vspriteColor[VSPRITES_MAX];
static char spriteOrder[VSPRITES_MAX], spriteYPos[VSPRITES_MAX + 1];
static RIRQCode spirq[VSPRITES_MAX - 8], synch;
void vspr_init(char * screen)
{
vspriteScreen = screen + 0x3f8;
vic.spr_expand_x = 0;
vic.spr_expand_y = 0;
vic.spr_enable = 0xff;
for(int i=0; i<VSPRITES_MAX - 8; i++)
{
#ifdef VSPRITE_REVERSE
int j = (i & 7) ^ 7;
#else
int j = i & 7;
#endif
rirq_build(spirq + i, 5);
rirq_write(spirq + i, 0, &vic.spr_color[j], 0);
rirq_write(spirq + i, 1, &vic.spr_pos[j].x, 0);
rirq_write(spirq + i, 2, &vic.spr_pos[j].y, 0);
rirq_write(spirq + i, 3, &vspriteScreen[j], 0);
rirq_write(spirq + i, 4, &vic.spr_msbx, 0);
rirq_set(i, 80 + 4 * i, spirq + i);
}
rirq_build(&synch, 0);
rirq_set(VSPRITES_MAX - 8, 250, &synch);
for(int i=0; i<VSPRITES_MAX; i++)
{
spriteOrder[i] = i;
vspriteYLow[i] = 0xff;
}
}
void vspr_shutdown(void)
{
for(int i=0; i<VSPRITES_MAX - 7; i++)
rirq_clear(i);
}
void vspr_screen(char * screen)
{
vspriteScreen = screen + 0x3f8;
char hi = (unsigned)vspriteScreen >> 8;
#pragma unroll(8)
for(int i=0; i<VSPRITES_MAX - 8; i++)
rirq_addrhi(spirq + i, 3, hi);
}
#pragma native(vspr_init)
void vspr_set(char sp, int xpos, int ypos, char image, char color)
{
char yp = (char)ypos;
if ((ypos & 0xff00 ) || (xpos & 0xfe00))
yp = 0xff;
vspriteYLow[sp] = yp;
vspriteXLow[sp] = (char)xpos;
vspriteXHigh[sp] = (char)(xpos >> 8);
vspriteImage[sp] = image;
vspriteColor[sp] = color;
}
#pragma native(vspr_set)
void vspr_move(char sp, int xpos, int ypos)
{
char yp = (char)ypos;
if ((ypos & 0xff00 ) || (xpos & 0xfe00))
yp = 0xff;
vspriteYLow[sp] = yp;
vspriteXLow[sp] = (char)xpos;
vspriteXHigh[sp] = (char)(xpos >> 8);
}
void vspr_movex(char sp, int xpos)
{
vspriteXLow[sp] = (char)xpos;
vspriteXHigh[sp] = (char)(xpos >> 8);
}
void vspr_movey(char sp, int ypos)
{
char yp = (char)ypos;
if (ypos & 0xff00)
yp = 0xff;
vspriteYLow[sp] = yp;
}
void vspr_image(char sp, char image)
{
vspriteImage[sp] = image;
}
void vspr_color(char sp, char color)
{
vspriteColor[sp] = color;
}
void vspr_hide(char sp)
{
vspriteYLow[sp] = 0xff;
}
void vspr_sort(void)
{
byte rm = vspriteYLow[spriteOrder[0]];
spriteYPos[1] = rm;
for(char i = 1; i<VSPRITES_MAX; i++)
{
byte ri = spriteOrder[i];
byte rr = vspriteYLow[ri];
if (rr < rm)
{
byte j = i, rj = rm;
do {
spriteYPos[j + 1] = rj;
spriteOrder[j] = spriteOrder[j - 1];
rj = spriteYPos[j - 1];
j--;
} while (rr < rj);
spriteOrder[j] = ri;
spriteYPos[j + 1] = rr;
}
else
{
spriteYPos[i + 1] = rr;
rm = rr;
}
}
}
#pragma native(vspr_sort)
void vspr_update(void)
{
char xymask = 0;
volatile char * vsprs = vspriteScreen;
// char sypos[VSPRITES_MAX];
#pragma unroll(full)
for(char ui=0; ui<8; ui++)
{
byte ri = spriteOrder[ui];
#ifdef VSPRITE_REVERSE
char uj = ui ^ 7;
#else
char uj = ui;
#endif
vic.spr_color[uj] = vspriteColor[ri];
vsprs[uj] = vspriteImage[ri];
#ifdef VSPRITE_REVERSE
xymask = (xymask << 1) | (vspriteXHigh[ri] & 1);
#else
xymask = ((unsigned)xymask | (vspriteXHigh[ri] << 8)) >> 1;
#endif
vic.spr_pos[uj].x = vspriteXLow[ri];
vic.spr_pos[uj].y = spriteYPos[ui + 1];
// sypos[ui] = vspriteYLow[ri];
}
vic.spr_msbx = xymask;
#pragma unroll(full)
bool done = false;
for(char ti=0; ti<VSPRITES_MAX - 8; ti++)
{
if (!done && spriteYPos[ti + 9] < 250)
{
byte ri = spriteOrder[ti + 8];
rirq_move(ti, spriteYPos[ti + 1] + 23);
#ifdef VSPRITE_REVERSE
char m = 0x80 >> (ti & 7);
#else
char m = 1 << (ti & 7);
#endif
xymask |= m;
if (!(vspriteXHigh[ri] & 1))
xymask ^= m;
rirq_data(spirq + ti, 2, spriteYPos[ti + 9]);
rirq_data(spirq + ti, 0, vspriteColor[ri]);
rirq_data(spirq + ti, 1, vspriteXLow[ri]);
rirq_data(spirq + ti, 3, vspriteImage[ri]);
rirq_data(spirq + ti, 4, xymask);
// spriteYPos[ti + 9] = vspriteYLow[ri];
}
else
{
rirq_clear(ti);
done = true;
}
}
}
#pragma native(vspr_update)