186 lines
4.9 KiB
C
186 lines
4.9 KiB
C
#include <c64/vic.h>
|
|
#include <c64/rasterirq.h>
|
|
#include <c64/memmap.h>
|
|
#include <c64/cia.h>
|
|
|
|
static const sbyte costab[256] = {
|
|
30, 30, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, 28, 28, 27, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 23, 23, 22, 22,
|
|
21, 21, 20, 20, 19, 18, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10, 9, 9, 8, 7, 7, 6, 5, 4, 4, 3, 2, 1, 1,
|
|
0, -1, -1, -2, -3, -4, -4, -5, -6, -7, -7, -8, -9, -9, -10, -11, -11, -12, -13, -13, -14, -15, -15, -16, -17, -17, -18, -18, -19, -20, -20,
|
|
-21, -21, -22, -22, -23, -23, -24, -24, -25, -25, -25, -26, -26, -26, -27, -27, -27, -28, -28, -28, -28, -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -30, -30,
|
|
-30, -30, -30, -30, -30, -30, -30, -30, -29, -29, -29, -29, -29, -28, -28, -28, -28, -27, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -23, -23, -22, -22,
|
|
-21, -21, -20, -20, -19, -18, -18, -17, -17, -16, -15, -15, -14, -13, -13, -12, -11, -11, -10, -9, -9, -8, -7, -7, -6, -5, -4, -4, -3, -2, -1, -1,
|
|
0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 20,
|
|
21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30
|
|
};
|
|
|
|
#define Screen ((char *)0x400)
|
|
|
|
// make space until 0x2000 for code and data
|
|
|
|
#pragma region( lower, 0x0a00, 0x2000, , , {code, data} )
|
|
|
|
// then space for our sprite data
|
|
|
|
#pragma section( spriteset, 0)
|
|
|
|
#pragma region( spriteset, 0x2000, 0x2040, , , {spriteset} )
|
|
|
|
// everything beyond will be code, data, bss and heap to the end
|
|
|
|
#pragma region( main, 0x2800, 0xa000, , , {code, data, bss, heap, stack} )
|
|
|
|
|
|
// spriteset at fixed location
|
|
|
|
#pragma data(spriteset)
|
|
|
|
__export const char spriteset[64] = {
|
|
#embed "../resources/ballsprite.bin"
|
|
};
|
|
|
|
#pragma data(data)
|
|
|
|
// Control variables for the interrupt
|
|
|
|
char pphase; // global phase
|
|
char poffset; // phase offset for this row of sprites
|
|
char yoffset; // vertical offset for this row of sprites
|
|
|
|
// Interrupt routine switching to next row of sprites, invokes some lines after
|
|
// start of previous row
|
|
|
|
__interrupt void setspr(void)
|
|
{
|
|
// Switch vertical position first, will not take effect
|
|
// until after the current row of sprites is complete, so it
|
|
// is done first
|
|
#pragma unroll(full)
|
|
for(char i=0; i<8; i++)
|
|
vic.spr_pos[i].y = yoffset;
|
|
|
|
char phase = pphase + poffset; // Effective rotation phase for this row
|
|
int step = costab[phase]; // 30 * Cosine of phase for x step
|
|
int xpos0 = 172 - (step >> 1); // Half a step to the left
|
|
int xpos1 = 172 + (step >> 1); // Half a step to the right
|
|
|
|
// Table for xpositions
|
|
static unsigned xp[8];
|
|
|
|
// Calculate xpositions, four to the left and four to the right
|
|
#pragma unroll(full)
|
|
for(char i=0; i<4; i++)
|
|
{
|
|
xp[3 - i] = xpos0;
|
|
xp[i + 4] = xpos1;
|
|
|
|
// Stepping left and right
|
|
xpos0 -= step;
|
|
xpos1 += step;
|
|
}
|
|
|
|
// build highbyte for sprite pos
|
|
char xymask = 0;
|
|
if (phase & 0x80)
|
|
{
|
|
// put MSB into xymask bit
|
|
#pragma unroll(full)
|
|
for(char i=0; i<8; i++)
|
|
xymask = ((unsigned)xymask | (xp[i] & 0xff00)) >> 1;
|
|
}
|
|
else
|
|
{
|
|
// put MSB into xymask bit
|
|
#pragma unroll(full)
|
|
for(char i=0; i<8; i++)
|
|
xymask = ((unsigned)xymask | (xp[7 - i] & 0xff00)) >> 1;
|
|
}
|
|
|
|
|
|
// Wait for end of current sprite, xpos will take effect
|
|
// at start of line, so we need to patch it after the last
|
|
// pixel line has started
|
|
vic_waitLine(yoffset - 3);
|
|
|
|
// Left to right or right to left to get a matching z order
|
|
if (phase & 0x80)
|
|
{
|
|
// Update all sprite x LSB and color
|
|
#pragma unroll(full)
|
|
for(char i=0; i<8; i++)
|
|
{
|
|
vic.spr_pos[i].x = xp[i];
|
|
vic.spr_color[i] = VCOL_ORANGE + i;
|
|
}
|
|
|
|
// Update MSB
|
|
vic.spr_msbx = xymask;
|
|
}
|
|
else
|
|
{
|
|
// Update all sprite x LSB and color
|
|
#pragma unroll(full)
|
|
for(char i=0; i<8; i++)
|
|
{
|
|
vic.spr_pos[i].x = xp[7 - i];
|
|
vic.spr_color[i] = VCOL_ORANGE + (7 - i);
|
|
}
|
|
}
|
|
// Update MSB
|
|
vic.spr_msbx = xymask;
|
|
}
|
|
|
|
// Eight raster interrupts
|
|
RIRQCode spmux[8];
|
|
|
|
int main(void)
|
|
{
|
|
// Keep kernal alive
|
|
rirq_init(true);
|
|
|
|
// Setup sprite images
|
|
for(char i=0; i<8; i++)
|
|
Screen[0x03f8 + i] = 128;
|
|
|
|
// Remaining sprite registers
|
|
vic.spr_enable = 0xff;
|
|
vic.spr_multi = 0xff;
|
|
vic.spr_expand_x = 0x00;
|
|
vic.spr_expand_y = 0x00;
|
|
vic.spr_mcolor0 = VCOL_BLACK;
|
|
vic.spr_mcolor1 = VCOL_WHITE;
|
|
|
|
// Setup raster interrupts
|
|
for(char i=0; i<8; i++)
|
|
{
|
|
// Three operations per interrupt
|
|
rirq_build(spmux + i, 3);
|
|
// Store phase offset
|
|
rirq_write(spmux + i, 0, &poffset, 11 * i);
|
|
// Store vertical position
|
|
rirq_write(spmux + i, 1, &yoffset, 52 + 25 * i);
|
|
// Call sprite update function
|
|
rirq_call(spmux + i, 2, setspr);
|
|
|
|
// Place raster interrupt 16 lines before sprite start to
|
|
// give it enough time for processing
|
|
rirq_set(i, 36 + 25 * i, spmux + i);
|
|
}
|
|
|
|
// Sort interrupts and start processing
|
|
rirq_sort();
|
|
rirq_start();
|
|
|
|
// Forever
|
|
for(;;)
|
|
{
|
|
// Advance phase
|
|
pphase += 5;
|
|
|
|
// Wait for next frame
|
|
vic_waitFrame();
|
|
}
|
|
|
|
return 0;
|
|
}
|