initial commit

This commit is contained in:
2026-07-18 20:34:55 +02:00
commit 59ad004c96
474 changed files with 226635 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
../../bin/oscar64 joycontrol.c
../../bin/oscar64 multiplexer.c -n
../../bin/oscar64 creditroll.c -n
../../bin/oscar64 -n sprmux32.c -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
../../bin/oscar64 -n sprmux64.c
+276
View File
@@ -0,0 +1,276 @@
#include <c64/vic.h>
#include <c64/rasterirq.h>
#include <c64/sprites.h>
#include <stdlib.h>
#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, 0x2c00, , , {spriteset} )
// everything beyond will be code, data, bss and heap to the end
#pragma region( main, 0x2c00, 0xa000, , , {code, data, bss, heap, stack} )
// spriteset at fixed location
#pragma data(spriteset)
char spriteset[64 * 48] = {0};
#pragma data(data)
char charset[32 * 8] = {
#embed "../resources/scifiglyph.bin"
};
const char * scrolltext[] = {
"This sample uses",
"six sprites",
"multiplexed six",
"times to provide",
"twelve lines of",
"text with eighteen",
"characters each",
"",
"each character is",
"extracted from a",
"custom font into a",
"new sprite and the",
"sprites are then",
"moved up the",
"screen",
"",
"interrupts are",
"used to switch the",
"sprite vertical",
"position and",
"graphics",
"data every two",
"character lines"
"",
"",
"",
"",
""
};
RIRQCode * spmux[6], final;
// Expand a line of source text into buffer centered
void readline(char * dp, char n)
{
const char * sp = scrolltext[n];
// Count number of characters
char s = 0;
while (sp[s])
s++;
// Left padding
char l = (18 - s) >> 1;
char i = 0;
while (i < l)
dp[i++] = ' ';
// Text in center
s = 0;
while (sp[s])
dp[i++] = sp[s++];
// Right padding
while (i < 18)
dp[i++] = ' ';
}
// Expand six characters into sprite
void expandline(const char * line, char sppos, char ty)
{
// Target position for first character
char * dp = spriteset + 64 * sppos + 3 * ty;
char xl = 0;
for(char x=0; x<6; x++)
{
// Source character data
const char * sp = charset + 8 * (line[x] & 0x1f);
// Copy eight rows
dp[ 0] = sp[0]; dp[ 3] = sp[1]; dp[ 6] = sp[2]; dp[ 9] = sp[3];
dp[12] = sp[4]; dp[15] = sp[5]; dp[18] = sp[6]; dp[21] = sp[7];
// Next character
dp++;
xl++;
// Advance to next sprite
if (xl == 3)
{
dp += 61;
xl = 0;
}
}
}
int main(void)
{
rirq_init(true);
spr_init(Screen);
// Vertical pixel offset
sbyte oy = 0;
// Index of top left sprite
char sy = 128;
// Loop over five rows of virtual sprites
for(char i=0; i<5; i++)
{
// Allocate large rirq command with 12 writes
RIRQCode * sp = rirq_alloc(12);
spmux[i] = sp;
// Six sprites per row
for(char x=0; x<6; x++)
{
// Vertical sprite position
rirq_write(sp, 2 * x + 0, &vic.spr_pos[x].y, 48 * (i + 1) + oy);
// Sprite graphic
rirq_write(sp, 2 * x + 1, Screen + 0x3f8 + x, sy + 1 + i);
}
// Place in list
rirq_set(i, 48 * i + 46 + oy, spmux[i]);
}
// Final irq at bottom of screen
rirq_build(&final, 0);
rirq_set(5, 250, &final);
// Placing top sprites
for(int x=0; x<6; x++)
spr_set(x, true, 40 + 48 * x, oy, 128, 1, false, true, true);
// Initial sort and start of processing
rirq_sort();
rirq_start();
// Buffer for single line
char line[20];
// Index into text to scroll
char lpos = 0;
for(;;)
{
// Wait for end of irq list
rirq_wait();
// Advance one pixel line
oy--;
if (oy < 0)
{
// Advance one row of sprites
oy += 48;
sy += 6;
if (sy == 128 + 36)
sy = 128;
}
// Update interrupt position
for(char i=0; i<5; i++)
{
int ty = 48 * i + 45 + oy;
// No interrupts below screen bottom
if (ty < 250)
rirq_move(i, ty);
else
rirq_clear(i);
}
// Sort list
rirq_sort();
// Reset row of top level sprites
char sty = sy;
for(int x=0; x<6; x++)
{
spr_move(x, 40 + 48 * x, oy);
spr_image(x, sty);
sty ++;
}
// Update write data in interrupt list
for(char i=0; i<5; i++)
{
RIRQCode * sp = spmux[i];
// Check sprite rotation
if (sty == 128 + 36)
sty = 128;
// Update vertical position and sprite data
char py = 48 * (i + 1) + oy;
for(char x=0; x<6; x++)
{
rirq_data(sp, 2 * x + 0, py);
rirq_data(sp, 2 * x + 1, sty);
sty ++;
}
}
// Expand next line of text into bottom row of
// sprites while invisible
switch (oy)
{
case 46:
case 42:
readline(line, lpos);
lpos++;
if (lpos == 27)
lpos = 0;
break;
case 45:
expandline(line + 0, sty - 6 - 128, 0);
break;
case 44:
expandline(line + 6, sty - 4 - 128, 0);
break;
case 43:
expandline(line + 12, sty - 2 - 128, 0);
break;
case 41:
expandline(line + 0, sty - 6 - 128, 12);
break;
case 40:
expandline(line + 6, sty - 4 - 128, 12);
break;
case 39:
expandline(line + 12, sty - 2 - 128, 12);
break;
}
}
return 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+52
View File
@@ -0,0 +1,52 @@
#include <c64/sprites.h>
#include <c64/joystick.h>
#include <string.h>
char spdata[] = {
#embed "../resources/friendlybear.bin"
};
int spx, spy;
#define SpriteData ((char *)0x0380)
int main(void)
{
// Copy the sprite data
memcpy(SpriteData, spdata, 128);
// Initialize the sprite system
spr_init((char*)0x0400);
// Center screen position
spx = 160;
spy = 100;
// Two sprites, one black in front hires and one multicolor in back
spr_set(0, true, spx, spy, 0x03c0 / 64, VCOL_BLACK, false, false, false);
spr_set(1, true, spx, spy, 0x0380 / 64, VCOL_ORANGE, true, false, false);
// Multicolor sprite colors
vic.spr_mcolor0 = VCOL_BROWN;
vic.spr_mcolor1 = VCOL_WHITE;
for(;;)
{
// Poll joytick
joy_poll(0);
// Change position according to joystick
spx += joyx[0];
spy += joyy[0];
// Move sprites on screen
spr_move(0, spx, spy);
spr_move(1, spx, spy);
// Wait for one frame iteration
vic_waitFrame();
}
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
call ..\..\bin\oscar64 joycontrol.c
call ..\..\bin\oscar64 multiplexer.c -n
call ..\..\bin\oscar64 creditroll.c -n
call ..\..\bin\oscar64 -n sprmux32.c -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
call ..\..\bin\oscar64 -n sprmux64.c
+14
View File
@@ -0,0 +1,14 @@
%.prg: %.c
@echo "Compiling sample file" $<
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
all: joycontrol.prg multiplexer.prg creditroll.prg sprmux32.prg sprmux64.prg
joycontrol.prg: joycontrol.c
@$(OSCAR64_CC) $<
sprmux32.prg: sprmux32.c
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -O2 -dVSPRITES_MAX=32 -dNUM_IRQS=28
clean:
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs
+90
View File
@@ -0,0 +1,90 @@
#include <c64/vic.h>
#include <c64/rasterirq.h>
#include <c64/sprites.h>
#include <math.h>
#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, 0x2800, , , {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)
char spriteset[2048] = {
#embed "../resources/digitsprites.bin"
};
#pragma data(data)
// sinus table for circular movement
int sintab[128];
int main(void)
{
// calculate sine table
for(int i=0; i<128; i++)
sintab[i] = (int)(70 * sin(i * PI / 64));
// enable raster interrupt via kernal path
rirq_init(true);
// initialize sprite multiplexer
vspr_init(Screen);
// initialize sprites
for(int i=0; i<16; i++)
{
vspr_set(i, 30 + 16 * i, 220 - 8 * i, (unsigned)&(spriteset[0]) / 64 + i, (i & 7) + 8);
}
// initial sort and update
vspr_sort();
vspr_update();
rirq_sort();
// start raster IRQ processing
rirq_start();
// animation loop
unsigned j = 0;
for(;;)
{
// move sprites around
char k = j >> 4;
for(char i=0; i<16; i++)
{
vspr_move(i, 200 + sintab[(j + 8 * i) & 127] + sintab[k & 127], 150 + sintab[(j + 8 * i + 32) & 127] + sintab[(k + 32) & 127]);
}
j++;
// sort virtual sprites by y position
vspr_sort();
// wait for raster IRQ to reach and of frame
rirq_wait();
// update sprites back to normal and set up raster IRQ for second set
vspr_update();
// sort raster IRQs
rirq_sort();
}
return 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

+126
View File
@@ -0,0 +1,126 @@
#include <c64/vic.h>
#include <c64/sprites.h>
#include <c64/rasterirq.h>
#include <c64/memmap.h>
#include <c64/cia.h>
static const sbyte sintab[256] = {
0, 2, 4, 7, 9, 11, 13, 15, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 55, 57, 59, 60,
62, 64, 65, 67, 68, 70, 71, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 85, 86, 87, 87, 88, 88, 89, 89, 89, 90, 90, 90, 90,
90, 90, 90, 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 85, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 72, 71, 70, 68, 67, 65, 64,
62, 60, 59, 57, 55, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 15, 13, 11, 9, 7, 4, 2,
0, -2, -4, -7, -9, -11, -13, -15, -18, -20, -22, -24, -26, -28, -30, -32, -34, -36, -38, -40, -42, -44, -46, -48, -50, -52, -54, -55, -57, -59, -60,
-62, -64, -65, -67, -68, -70, -71, -72, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -85, -86, -87, -87, -88, -88, -89, -89, -89, -90, -90, -90, -90,
-90, -90, -90, -90, -90, -89, -89, -89, -88, -88, -87, -87, -86, -85, -85, -84, -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -72, -71, -70, -68, -67, -65, -64,
-62, -60, -59, -57, -55, -54, -52, -50, -48, -46, -44, -42, -40, -38, -36, -34, -32, -30, -28, -26, -24, -22, -20, -18, -15, -13, -11, -9, -7, -4, -2
};
static const sbyte costab[256] = {
120, 120, 120, 120, 119, 119, 119, 118, 118, 117, 116, 116, 115, 114, 113, 112, 111, 110, 108, 107, 106, 104, 103, 101, 100, 98, 96, 95, 93, 91, 89, 87,
85, 83, 81, 78, 76, 74, 71, 69, 67, 64, 62, 59, 57, 54, 51, 49, 46, 43, 40, 38, 35, 32, 29, 26, 23, 21, 18, 15, 12, 9, 6, 3,
0, -3, -6, -9, -12, -15, -18, -21, -23, -26, -29, -32, -35, -38, -40, -43, -46, -49, -51, -54, -57, -59, -62, -64, -67, -69, -71, -74, -76, -78, -81, -83,
-85, -87, -89, -91, -93, -95, -96, -98, -100, -101, -103, -104, -106, -107, -108, -110, -111, -112, -113, -114, -115, -116, -116, -117, -118, -118, -119, -119, -119, -120, -120, -120,
-120, -120, -120, -120, -119, -119, -119, -118, -118, -117, -116, -116, -115, -114, -113, -112, -111, -110, -108, -107, -106, -104, -103, -101, -100, -98, -96, -95, -93, -91, -89, -87,
-85, -83, -81, -78, -76, -74, -71, -69, -67, -64, -62, -59, -57, -54, -51, -49, -46, -43, -40, -38, -35, -32, -29, -26, -23, -21, -18, -15, -12, -9, -6, -3,
0, 3, 6, 9, 12, 15, 18, 21, 23, 26, 29, 32, 35, 38, 40, 43, 46, 49, 51, 54, 57, 59, 62, 64, 67, 69, 71, 74, 76, 78, 81, 83,
85, 87, 89, 91, 93, 95, 96, 98, 100, 101, 103, 104, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 116, 117, 118, 118, 119, 119, 119, 120, 120, 120
};
#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, 0x2800, , , {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)
static const char spriteset[2048] = {
#embed "../resources/digitsprites.bin"
};
#pragma data(data)
int main(void)
{
// Disable interrupts while setting up
__asm { sei };
// Kill CIA interrupts
cia_init();
mmap_set(MMAP_NO_ROM);
// enable raster interrupt via direct path
rirq_init(false);
// initialize sprite multiplexer
vspr_init(Screen);
// initialize sprites
for(char i=0; i<32; i++)
{
vspr_set(i, 30 + 8 * i, 220 - 4 * i, (unsigned)&(spriteset[0]) / 64 + (i & 15), (i & 7) + 8);
}
// initial sort and update
vspr_sort();
vspr_update();
rirq_sort();
// start raster IRQ processing
rirq_start();
// Black screen
vic.color_border = 0;
vic.color_back = 0;
// animation loop
unsigned j = 0, t = 0;
unsigned k = 91;
for(;;)
{
// Use MSB as start position
j = t << 8;
// Unroll movement loop for performance
#pragma unroll(full)
for(char i=0; i<32; i++)
{
vspr_move(i, 170 + costab[((j >> 8) + 8 * i) & 255], 140 + sintab[(t + 8 * i) & 255]);
j += k;
}
// Advance animation
t+=3;
k++;
// sort virtual sprites by y position
vspr_sort();
// wait for raster IRQ to reach and of frame
rirq_wait();
// update sprites back to normal and set up raster IRQ for sprites 8 to 31
vspr_update();
// sort raster IRQs
rirq_sort();
}
return 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

+185
View File
@@ -0,0 +1,185 @@
#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;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB