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
+128
View File
@@ -0,0 +1,128 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
byte font[2048];
// Copy the system font into local RAM for easy access
void copyFont(void)
{
mmap_set(MMAP_CHAR_ROM);
memcpy(font, (byte *)0xd800, 2048);
mmap_set(MMAP_ROM);
}
// Single row of screen has 40 characters
typedef char ScreenRow[40];
// Screen and color space
ScreenRow * const screen = (ScreenRow *)0x0400;
ScreenRow * const color = (ScreenRow *)0xd800;
// Start row for text
#define srow 5
// Move the screen one character to the left
void scrollLeft(void)
{
// Loop horizontally
for(char x=0; x<39; x++)
{
// Unroll vertical loop 16 times
#pragma unroll(full)
for(char y=0; y<16; y++)
{
screen[srow + y][x] = screen[srow + y][x + 1];
}
}
}
// Expand one column of a glyph to the right most screen column
void expand(char c, byte f)
{
// Address of glyph data
byte * fp = font + 8 * c;
// Unroll eight times for each byte in glyph data
//#pragma unroll(full)
for(char y=0; y<8; y++)
{
char t = (fp[y] & f) ? 160 : 32;
screen[srow + 2 * y + 0][39] = t;
screen[srow + 2 * y + 1][39] = t;
}
}
const char * text =
s"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt "
s"ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo "
s"dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit "
s"amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor "
s"invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam "
s"et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
int main(void)
{
// Install the IRQ trampoline
mmap_trampoline();
// Copy the font data
copyFont();
// Cleat the screen
memset(screen, 0x20, 1000);
// Color bars
for(int i=0; i<16; i++)
memset(color[srow + i], i + 1, 40);
vic.color_back = VCOL_BLACK;
vic.color_border = VCOL_BLACK;
// Hide left and right column
vic.ctrl2 = 0;
// Loop over text
int ci = 0;
for(;;)
{
// Loop over glyph from left to right
byte cf = 0x80;
while (cf)
{
for(char i=0; i<2; i++)
{
// Pixel level scrolling
vic_waitBottom();
vic.ctrl2 = 4;
vic_waitTop();
vic_waitBottom();
vic.ctrl2 = 2;
vic_waitTop();
vic_waitBottom();
vic.ctrl2 = 0;
vic_waitTop();
vic_waitBottom();
vic.ctrl2 = 6;
// Crossing character border, now scroll and show new column
scrollLeft();
expand(text[ci], cf);
}
// Next glyph column
cf >>= 1;
}
// Next character
ci++;
}
return 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
../../bin/oscar64 bigfont.c -n
../../bin/oscar64 tunnel.c -n
../../bin/oscar64 grid2d.c -n
../../bin/oscar64 colorram.c -n
../../bin/oscar64 cgrid8way.c -n
+435
View File
@@ -0,0 +1,435 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <c64/joystick.h>
#include <stdlib.h>
// Screen and color space
#define Screen ((byte *)0x0400)
#define Color ((byte *)0xd800)
// Macro for easy access to screen and color space
#define sline(x, y) (Screen + 40 * (y) + (x))
#define cline(x, y) (Color + 40 * (y) + (x))
// Tile data, each column has four rows of four tiles
static const char quad[4][4 * 4] =
{
{
0x20, 0x55, 0x6c, 0x4e,
0x20, 0x5d, 0xe1, 0x65,
0x20, 0x5d, 0xe1, 0x65,
0x20, 0x4a, 0x7c, 0x4d,
},
{
0x20, 0x40, 0x62, 0x77,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x40, 0xe2, 0x6f,
},
{
0x20, 0x40, 0x62, 0x77,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x40, 0xe2, 0x6f,
},
{
0x20, 0x49, 0x7b, 0x4d,
0x20, 0x5d, 0x61, 0x6a,
0x20, 0x5d, 0x61, 0x6a,
0x20, 0x4b, 0x7e, 0x4e,
}
};
#pragma align(quad, 256)
// Expand a single row into an offscreen buffer
void expandrow(char * dp, char * cp, const char * grid, char ly, char lx)
{
char hx = 0;
for(char x=0; x<40; x++)
{
dp[x] = quad[lx][ly + grid[hx]];
cp[x] = grid[hx];
lx++;
if (lx == 4)
{
lx = 0;
hx++;
}
}
}
// Expand a single column into an offscreen buffer
void expandcol(char * dp, char * cp, const char * grid, char ly, char lx)
{
for(char y=0; y<25; y++)
{
dp[y] = quad[lx][ly + grid[0]];
cp[y] = grid[0];
ly += 4;
if (ly == 16)
{
grid += 16;
ly = 0;
}
}
}
// Two split scroll for left, right and up
#define VSPLIT 12
// Three split scroll for down. Downscrolling is more tricky because
// we have to copy towards the raster
#define VSPLIT 12
#define VSPLIT2 20
// New line/column of screen and color data
char news[40], newc[40];
// All scroll routines start with a pixel offset of 4, 4
// Scroll one character left in two pixel increments
void scroll_left(void)
{
// Wait for one frame
vic_waitTop();
vic_waitBottom();
// Switch to offset 2, 4
vic.ctrl2 = 0x02;
vic_waitTop();
vic_waitBottom();
// Switch to offset 0, 4
vic.ctrl2 = 0x00;
// Wait until bottom of section
vic_waitLine(50 + 8 * VSPLIT);
// Scroll upper section
for(char x=0; x<39; x++)
{
#assign ty 0
#repeat
sline(0, ty)[x] = sline(1, ty)[x];
cline(0, ty)[x] = cline(1, ty)[x];
#assign ty ty + 1
#until ty == VSPLIT
}
// Update column
#assign ty 0
#repeat
sline(0, ty)[39] = news[ty];
cline(0, ty)[39] = newc[ty];
#assign ty ty + 1
#until ty == VSPLIT
// Wait for bottom of visible screen
vic_waitBottom();
// Switch to offset 6, 4
vic.ctrl2 = 0x06;
// Scroll lower part of the screen, while top is redrawn
for(char x=0; x<39; x++)
{
#assign ty VSPLIT
#repeat
sline(0, ty)[x] = sline(1, ty)[x];
cline(0, ty)[x] = cline(1, ty)[x];
#assign ty ty + 1
#until ty == 25
}
// Update new column
#assign ty VSPLIT
#repeat
sline(0, ty)[39] = news[ty];
cline(0, ty)[39] = newc[ty];
#assign ty ty + 1
#until ty == 25
// Wait for bottom
vic_waitBottom();
// Now back to 4, 4
vic.ctrl2 = 0x04;
}
// Scroll one character right in two pixel increments
void scroll_right(void)
{
vic_waitTop();
vic_waitBottom();
vic.ctrl2 = 0x06;
vic_waitLine(50 + 8 * VSPLIT);
for(char x=39; x>0; x--)
{
#assign ty 0
#repeat
sline(0, ty)[x] = sline(-1, ty)[x];
cline(0, ty)[x] = cline(-1, ty)[x];
#assign ty ty + 1
#until ty == VSPLIT
}
#assign ty 0
#repeat
sline(0, ty)[0] = news[ty];
cline(0, ty)[0] = newc[ty];
#assign ty ty + 1
#until ty == VSPLIT
vic_waitBottom();
vic.ctrl2 = 0x00;
for(char x=39; x>0; x--)
{
#assign ty VSPLIT
#repeat
sline(0, ty)[x] = sline(-1, ty)[x];
cline(0, ty)[x] = cline(-1, ty)[x];
#assign ty ty + 1
#until ty == 25
}
#assign ty VSPLIT
#repeat
sline(0, ty)[0] = news[ty];
cline(0, ty)[0] = newc[ty];
#assign ty ty + 1
#until ty == 25
vic_waitBottom();
vic.ctrl2 = 0x02;
vic_waitTop();
vic_waitBottom();
vic.ctrl2 = 0x04;
}
// Scroll one character up in two pixel increments
void scroll_up(void)
{
vic_waitTop();
vic_waitBottom();
vic.ctrl1 = 0x02 | VIC_CTRL1_DEN;
vic_waitTop();
vic_waitBottom();
vic.ctrl1 = 0x00 | VIC_CTRL1_DEN;
vic_waitLine(50 + 8 * VSPLIT);
for(char x=0; x<40; x++)
{
#assign ty 0
#repeat
sline(0, ty)[x] = sline(0, ty + 1)[x];
cline(0, ty)[x] = cline(0, ty + 1)[x];
#assign ty ty + 1
#until ty == VSPLIT
}
vic_waitBottom();
vic.ctrl1 = 0x06 | VIC_CTRL1_DEN;
for(char x=0; x<40; x++)
{
#assign ty VSPLIT
#repeat
sline(0, ty)[x] = sline(0, ty + 1)[x];
cline(0, ty)[x] = cline(0, ty + 1)[x];
#assign ty ty + 1
#until ty == 24
sline(0, ty)[x] = news[x];
cline(0, ty)[x] = newc[x];
}
vic_waitBottom();
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
}
char tmp0[40], tmp1[40], tmp2[40], tmp3[40];
// Scroll one character down in two pixel increments. This is more tricky than
// the other three cases, because we have to work towards the beam because
// we have to copy backwards in memory.
//
// The scroll is split into three sections, the seam rows are saved into
// intermediate arrays, so we can copy the top section first and the bottom
// section last, and stay ahead of the beam.
void scroll_down(void)
{
// Wait one frame
vic_waitTop();
vic_waitBottom();
// Save seam lines
for(char x=0; x<40; x++)
{
tmp0[x] = sline(0, VSPLIT)[x];
tmp1[x] = cline(0, VSPLIT)[x];
tmp2[x] = sline(0, VSPLIT2)[x];
tmp3[x] = cline(0, VSPLIT2)[x];
}
// Now switch to 4, 6
vic.ctrl1 = 0x06 | VIC_CTRL1_DEN;
// Wait for bottom of top section
vic_waitLine(58 + 8 * VSPLIT);
// Scroll top section down and copy new column
for(char x=0; x<40; x++)
{
#assign ty VSPLIT
#repeat
sline(0, ty)[x] = sline(0, ty - 1)[x];
cline(0, ty)[x] = cline(0, ty - 1)[x];
#assign ty ty - 1
#until ty == 0
sline(0, ty)[x] = news[x];
cline(0, ty)[x] = newc[x];
}
// vic_waitBottom();
// We have already reached the bottom, switch to 4, 0
vic.ctrl1 = 0x00 | VIC_CTRL1_DEN;
// Copy the second section, update the seam line from the buffer
for(char x=0; x<40; x++)
{
#assign ty VSPLIT2
#repeat
sline(0, ty)[x] = sline(0, ty - 1)[x];
cline(0, ty)[x] = cline(0, ty - 1)[x];
#assign ty ty - 1
#until ty == VSPLIT + 1
sline(0, ty)[x] = tmp0[x];
cline(0, ty)[x] = tmp1[x];
}
// Copy the third section, update the seam line from the buffer
for(char x=0; x<40; x++)
{
#assign ty 24
#repeat
sline(0, ty)[x] = sline(0, ty - 1)[x];
cline(0, ty)[x] = cline(0, ty - 1)[x];
#assign ty ty - 1
#until ty == VSPLIT2 + 1
sline(0, ty)[x] = tmp2[x];
cline(0, ty)[x] = tmp3[x];
}
// Switch to 4, 2
vic_waitBottom();
vic.ctrl1 = 0x02 | VIC_CTRL1_DEN;
// Switch to 4, 4
vic_waitTop();
vic_waitBottom();
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
}
char grid[16][16];
#pragma align(grid, 256)
int main(void)
{
// We need some more accurate timing for this, so kill the kernal IRQ
__asm
{
sei
}
// Init the grid
for(char y=0; y<16; y++)
{
for(char x=0; x<16; x++)
{
grid[y][x] = rand() & 3;
}
}
char gridX = 0, gridY = 0;
// Initial drawing of the screen
char * dp = Screen, * cp = Color;
for(char y=0; y<25; y++)
{
expandrow(dp, cp, &(grid[y >> 2][0]), 4 * (y & 3), 0);
dp += 40;
cp += 40;
}
// setup initial scroll offset
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
vic.ctrl2 = 0x04;
for(;;)
{
// Check the joystick
joy_poll(0);
if (joyx[0] == 1)
{
// Move to the right
if (gridX < 24)
{
gridX++;
expandcol(news, newc, &(grid[gridY >> 2][(gridX + 39) >> 2]), 4 * (gridY & 3), (gridX + 39) & 3);
scroll_left();
}
}
else if (joyx[0] == -1)
{
// Move to the left
if (gridX > 0)
{
gridX--;
expandcol(news, newc, &(grid[gridY >> 2][gridX >> 2]), 4 * (gridY & 3), gridX & 3);
scroll_right();
}
}
else if (joyy[0] == 1)
{
// Move down
if (gridY < 39)
{
gridY++;
expandrow(news, newc, &(grid[(gridY + 24) >> 2][gridX >> 2]), 4 * ((gridY + 24) & 3), gridX & 3);
scroll_up();
}
}
else if (joyy[0] == -1)
{
// Move up
if (gridY > 0)
{
gridY--;
expandrow(news, newc, &(grid[gridY >> 2][gridX >> 2]), 4 * (gridY & 3), gridX & 3);
scroll_down();
}
}
}
return 0;
}
+138
View File
@@ -0,0 +1,138 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
// Screen and color space
#define screen ((byte *)0x0400)
#define color ((byte *)0xd800)
// Macro for easy access to screen and color space
#define sline(x, y) (screen + 40 * (y) + (x))
#define cline(x, y) (color + 40 * (y) + (x))
// Column buffer for one prepared column of screen and color data
char rbuff[25], cbuff[25];
// Split into three scrolling sections to race the beam
#define SPLIT1 8
#define SPLIT2 16
// Scroll top section
void scrollLeft0(void)
{
for(char x=0; x<39; x++)
{
#pragma unroll(full)
for(char y=0; y<SPLIT1; y++)
{
sline(0, y)[x] = sline(1, y)[x];
cline(0, y)[x] = cline(1, y)[x];
}
}
#pragma unroll(full)
for(char y=0; y<SPLIT1; y++)
{
sline(0, y)[39] = rbuff[y];
cline(0, y)[39] = cbuff[y];
}
}
// Scroll bottom two sections
void scrollLeft1(void)
{
for(char x=0; x<39; x++)
{
#pragma unroll(full)
for(char y=SPLIT1; y<SPLIT2; y++)
{
sline(0, y)[x] = sline(1, y)[x];
cline(0, y)[x] = cline(1, y)[x];
}
}
#pragma unroll(full)
for(char y=SPLIT1; y<SPLIT2; y++)
{
sline(0, y)[39] = rbuff[y];
cline(0, y)[39] = cbuff[y];
}
for(char x=0; x<39; x++)
{
#pragma unroll(full)
for(char y=SPLIT2; y<25; y++)
{
sline(0, y)[x] = sline(1, y)[x];
cline(0, y)[x] = cline(1, y)[x];
}
}
#pragma unroll(full)
for(char y=SPLIT2; y<25; y++)
{
sline(0, y)[39] = rbuff[y];
cline(0, y)[39] = cbuff[y];
}
}
// Prepare a new column with random data
void prepcol(void)
{
for(char i=0; i<25; i++)
{
unsigned r = rand();
cbuff[i] = r & 15;
rbuff[i] = (r & 16) ? 102 : 160;
}
}
int main(void)
{
// Clear the screen
memset(screen, 0x20, 1000);
memset(color, 7, 1000);
vic.color_back = VCOL_BLACK;
vic.color_border = VCOL_BLACK;
char x = 0;
for(;;)
{
// Advance one pixel
x = (x + 1) & 7;
// If we will cross the character boundary, scroll the top section
if (x == 0)
{
// Wait for raster reaching bottom of first section
vic_waitLine(50 + 8 * SPLIT1);
// Scroll first section
scrollLeft0();
}
// Wait for bottom of screen
vic_waitBottom();
// Update the pixel offset
vic.ctrl2 = (7 - x) & 7;
if (x == 0)
{
// Scroll the bottom section if needed
scrollLeft1();
}
else
{
// Update the new column somewhere in the middle of the character
if (x == 4)
prepcol();
vic_waitTop();
}
}
return 0;
}
+282
View File
@@ -0,0 +1,282 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
#include <c64/rasterirq.h>
// Screen and color space
#define screen ((byte *)0x0400)
#define color ((byte *)0xd800)
// Macro for easy access to screen space
#define sline(x, y) (screen + 40 * (y) + (x))
// Tile data, each column has four rows of four tiles
static const char quad[4][4 * 4] =
{
{
0x20, 0x55, 0x6c, 0x4e,
0x20, 0x5d, 0xe1, 0x65,
0x20, 0x5d, 0xe1, 0x65,
0x20, 0x4a, 0x7c, 0x4d,
},
{
0x20, 0x40, 0x62, 0x77,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x40, 0xe2, 0x6f,
},
{
0x20, 0x40, 0x62, 0x77,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x20, 0xa0, 0x20,
0x20, 0x40, 0xe2, 0x6f,
},
{
0x20, 0x49, 0x7b, 0x4d,
0x20, 0x5d, 0x61, 0x6a,
0x20, 0x5d, 0x61, 0x6a,
0x20, 0x4b, 0x7e, 0x4e,
}
};
#pragma align(quad, 256)
// expand one row with column offset 0 into the grid
void expandrow0(char * dp, const char * grid, char ly)
{
char gi;
// unroll for each char in the row
#assign gx 0
#repeat
gi = grid[gx] | ly;
dp[4 * gx + 0] = quad[0][gi];
dp[4 * gx + 1] = quad[1][gi];
dp[4 * gx + 2] = quad[2][gi];
dp[4 * gx + 3] = quad[3][gi];
#assign gx gx + 1
#until gx == 10
}
// expand one row with column offset 1 into the grid, so three
// chars from the first tile and one char from the last
void expandrow1(char * dp, const char * grid, char ly)
{
char gi;
gi = grid[0] | ly;
dp[0] = quad[1][gi];
dp[1] = quad[2][gi];
dp[2] = quad[3][gi];
#assign gx 0
#repeat
gi = grid[gx + 1] | ly;
dp[4 * gx + 3] = quad[0][gi];
dp[4 * gx + 4] = quad[1][gi];
dp[4 * gx + 5] = quad[2][gi];
dp[4 * gx + 6] = quad[3][gi];
#assign gx gx + 1
#until gx == 9
gi = grid[10] | ly;
dp[39] = quad[0][gi];
}
// expand one row with column offset 2 into the grid, so two
// chars from the first tile and two chars from the last
void expandrow2(char * dp, const char * grid, char ly)
{
char gi;
gi = grid[0] | ly;
dp[0] = quad[2][gi];
dp[1] = quad[3][gi];
#assign gx 0
#repeat
gi = grid[gx + 1] | ly;
dp[4 * gx + 2] = quad[0][gi];
dp[4 * gx + 3] = quad[1][gi];
dp[4 * gx + 4] = quad[2][gi];
dp[4 * gx + 5] = quad[3][gi];
#assign gx gx + 1
#until gx == 9
gi = grid[10] | ly;
dp[38] = quad[0][gi];
dp[39] = quad[1][gi];
}
// expand one row with column offset 3 into the grid, so one
// char from the first tile and trhee chars from the last
void expandrow3(char * dp, const char * grid, char ly)
{
char gi;
gi = grid[0] | ly;
dp[0] = quad[3][gi];
#assign gx 0
#repeat
gi = grid[gx + 1] | ly;
dp[4 * gx + 1] = quad[0][gi];
dp[4 * gx + 2] = quad[1][gi];
dp[4 * gx + 3] = quad[2][gi];
dp[4 * gx + 4] = quad[3][gi];
#assign gx gx + 1
#until gx == 9
gi = grid[10] | ly;
dp[37] = quad[0][gi];
dp[38] = quad[1][gi];
dp[39] = quad[2][gi];
}
// expand the visible portion of the screen at the
// given char offset into the tiles
void expand(char * dp, const char * grid, char px, char py)
{
// remainder of position, offset into the tile
char ry = 4 * (py & 3);
char rx = px & 3;
// target screen position
char * cdp = dp;
// pointer to grid offset for top lest tile visible
const char * cgrid = grid + (px >> 2) + 32 * (py >> 2);
// Loop over all visible screen rows
for(char gy=0; gy<20; gy++)
{
// Update based on row (could be unrolled for inner groups of full tiles)
switch (rx)
{
case 0:
expandrow0(cdp, cgrid, ry);
break;
case 1:
expandrow1(cdp, cgrid, ry);
break;
case 2:
expandrow2(cdp, cgrid, ry);
break;
default:
expandrow3(cdp, cgrid, ry);
break;
}
// Next row
cdp += 40;
ry += 4;
// Next tile
if (ry == 16)
{
ry = 0;
cgrid += 32;
}
}
}
char grid[32][32];
#pragma align(grid, 256)
// Raster IRQs for split screen
RIRQCode blank, scroll, bottom;
int main(void)
{
// Init grid with random data
for(char y=0; y<32; y++)
{
for(char x=0; x<32; x++)
{
grid[y][x] = rand() & 3;
}
}
vic.color_border = 0;
// Setup split screen
rirq_init(true);
// Blank display after top section
rirq_build(&blank, 1);
rirq_write(&blank, 0, &vic.ctrl1, 0);
rirq_set(0, 46 + 5 * 8, &blank);
// Setup scrolling area
rirq_build(&scroll, 3);
rirq_delay(&scroll, 10);
rirq_write(&scroll, 1, &vic.ctrl1, VIC_CTRL1_DEN);
rirq_write(&scroll, 2, &vic.ctrl2, 0);
rirq_set(1, 54 + 5 * 8, &scroll);
// Wait for bottom of screen
rirq_build(&bottom, 2);
rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL);
rirq_write(&bottom, 1, &vic.ctrl2, VIC_CTRL2_CSEL);
rirq_set(2, 250, &bottom);
rirq_sort();
rirq_start();
// Movement data
int py = 40 * 32, px = 40 * 32, dy = 0, dx = 0, ax = 0, ay = 0;
for(;;)
{
// Grid position using 13.5 fractions
int rx = px >> 5, ry = py >> 5;
// Wait for next raster
vic.color_border++;
rirq_wait();
vic.color_border--;
// Update vertical scroll position
rirq_data(&blank, 0, ((7 - ry) & 7) | VIC_CTRL1_DEN | VIC_CTRL1_BMM | VIC_CTRL1_ECM);
// Dynamic wait based on vertical scroll position to counter bad lines
if ((ry & 7) == 0)
rirq_data(&scroll, 0, 4);
else
rirq_data(&scroll, 0, 10);
// Update vertical and horizontal scroll position
rirq_data(&scroll, 1, ((7 - ry) & 7) | VIC_CTRL1_DEN);
rirq_data(&scroll, 2, (7 - rx) & 7);
// Expand grid at current location
expand(screen + 200, &(grid[0][0]), rx >> 3, ry >> 3);
// Update screen velocity using differential equation
dx += ax;
dy += ay;
// New force
if ((rand() & 63) == 0)
{
ax = (rand() & 63) - 32;
ay = (rand() & 63) - 32;
}
// Some friction
dx -= (dx + 8) >> 4;
dy -= (dy + 8) >> 4;
// Update position reflect at borders
py += dy;
if (py < 0 || py > 26 * 8 * 4 * 32)
{
dy = -dy;
py += dy;
}
px += dx;
if (px < 0 || px > 22 * 8 * 4 * 32)
{
dx = -dx;
px += dx;
}
}
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
call ..\..\bin\oscar64 bigfont.c -n
call ..\..\bin\oscar64 tunnel.c -n
call ..\..\bin\oscar64 grid2d.c -n
call ..\..\bin\oscar64 colorram.c -n
call ..\..\bin\oscar64 cgrid8way.c -n
+8
View File
@@ -0,0 +1,8 @@
%.prg: %.c
@echo "Compiling sample file" $<
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
all: bigfont.prg tunnel.prg grid2d.prg colorram.prg cgrid8way.prg
clean:
@$(RM) *.asm *.int *.lbl *.map *.prg
+246
View File
@@ -0,0 +1,246 @@
#include <c64/vic.h>
#include <c64/memmap.h>
#include <string.h>
#include <stdlib.h>
// Screen and color space
#define screen ((byte *)0x0400)
#define color ((byte *)0xd800)
// Macro for easy access to screen space
#define sline(x, y) (screen + 40 * (y) + (x))
// Column buffer for one prepared column of tunnel
char rbuff[25];
// Copy the prepared tunnel column to screen
void expand(char x)
{
// Unroll for each row
#assign y 0
#repeat
sline(0, y)[x] = rbuff[y];
#assign y y + 1
#until y == 25
}
// Scrolling left, copying new column. This is split into two
// unrolled sections so the update of the new column can race the
// beam
void scrollLeft(void)
{
// First 12 rows scroll left and copy new column
for(char x=0; x<39; x++)
{
#assign y 0
#repeat
sline(0, y)[x] = sline(1, y)[x];
#assign y y + 1
#until y == 12
}
#assign y 0
#repeat
sline(0, y)[39] = rbuff[y];
#assign y y + 1
#until y == 12
// Final 13 rows scroll left and copy new column
for(char x=0; x<39; x++)
{
#assign y 12
#repeat
sline(0, y)[x] = sline(1, y)[x];
#assign y y + 1
#until y == 25
}
#assign y 12
#repeat
sline(0, y)[39] = rbuff[y];
#assign y y + 1
#until y == 25
}
// Scrolling right, copying new column. This is split into two
// unrolled sections so the update of the new column can race the
// beam
void scrollRight(void)
{
for(char x=39; x>0; x--)
{
#assign y 0
#repeat
sline(0, y)[x] = sline(-1, y)[x];
#assign y y + 1
#until y == 12
}
#assign y 0
#repeat
sline(0, y)[0] = rbuff[y];
#assign y y + 1
#until y == 12
for(char x=39; x>0; x--)
{
#assign y 12
#repeat
sline(0, y)[x] = sline(-1, y)[x];
#assign y y + 1
#until y == 25
}
#assign y 12
#repeat
sline(0, y)[0] = rbuff[y];
#assign y y + 1
#until y == 25
}
// Top and bottom row of the tunnel
char ytop[256], ybottom[256];
// Prepare one column of the tunnel
void prepcol(char xi)
{
char yt, yb;
signed char dyt, dyb;
// Current height of top and bottom
yt = ytop[(char)(xi + 0)];
yb = ybottom[(char)(xi + 0)];
// Height of column to the left for diagonal
dyt = yt - ytop[(char)(xi - 1)];
dyb = yb - ybottom[(char)(xi - 1)];
// Fill top, center and bottom range
for(char i=0; i<yt; i++)
rbuff[i] = 160;
for(char i=yt; i<yb; i++)
rbuff[i] = 32;
for(char i=yb; i<25; i++)
rbuff[i] = 160;
// Select transitional characters based on slope
if (dyt < 0)
rbuff[yt] = 105;
else if (dyt > 0)
rbuff[yt - 1] = 95;
if (dyb < 0)
rbuff[yb] = 233;
else if (dyb > 0)
rbuff[yb - 1] = 223;
}
// Initialize tunnel with "random" data
void buildTunnel(void)
{
signed char yt = 1, yb = 24, dyt = 1, dyb = -1;
for(int i=0; i<256; i++)
{
unsigned r = rand();
if (!(r & 0x00e0))
dyt = -dyt;
if (!(r & 0xe000))
dyb = -dyb;
yt += dyt;
yb += dyb;
if (yt < 0)
{
yt = 0;
dyt = 1;
}
if (yb > 25)
{
yb = 25;
dyb = -1;
}
ytop[i] = yt;
ybottom[i] = yb;
if (yt + 5 > yb)
{
dyt = -1;
dyb = 1;
}
}
}
int main(void)
{
// Clear the screen
memset(screen, 0x20, 1000);
memset(color, 7, 1000);
vic.color_back = VCOL_BLACK;
vic.color_border = VCOL_BLACK;
// Build tunnel
buildTunnel();
// Initial fill of screen
for(char i=0; i<40; i++)
{
prepcol(i);
expand(i);
}
// Now start moving
int xpos = 0, dx = 0, ax = 1;
int xi = 0, pxi = 0;
for(;;)
{
// Random change of direction
unsigned r = rand();
if ((r & 127) == 0)
ax = -ax;
// Acceleration
dx += ax;
if (dx > 32)
dx = 32;
else if (dx < -32)
dx = -32;
// Movement
xpos += dx;
pxi = xi;
xi = xpos >> 5;
// Check if we cross a character boundary, and if so prepare
// the new column
if (pxi < xi)
prepcol(xi + 39);
else if (pxi > xi)
prepcol(xi + 0);
// Wait one frame
vic_waitTop();
vic_waitBottom();
// Update pixel level scrolling
vic.ctrl2 = (7 - (xpos >> 2)) & 7;
// Character level scrolling if needed
if (pxi < xi)
scrollLeft();
else if (pxi > xi)
scrollRight();
}
return 0;
}