Added comments to source samples

This commit is contained in:
drmortalwombat 2022-01-01 12:39:54 +01:00
parent b9a1689dc6
commit 2d0f20cadc
20 changed files with 364 additions and 17 deletions

View File

@ -320,6 +320,7 @@ void rirq_sort(void)
rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i]]; rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i]];
npos++; npos++;
vic.raster = rasterIRQNext[nextIRQ] - 1;
} }
void rirq_start(void) void rirq_start(void)

View File

@ -3,29 +3,38 @@
#include <c64/memmap.h> #include <c64/memmap.h>
#include <conio.h> #include <conio.h>
// Address of hires buffer and color buffer
#define Screen ((char *)0xe000) #define Screen ((char *)0xe000)
#define Color ((char *)0xc800) #define Color ((char *)0xc800)
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Turn of the kernal ROM
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Switch VIC into hires mode
vic_setmode(VICM_HIRES, Color, Screen); vic_setmode(VICM_HIRES, Color, Screen);
// Clear the screen
memset(Screen, 0, 8000); memset(Screen, 0, 8000);
memset(Color, 0x10, 1000); memset(Color, 0x10, 1000);
// Loop over all pixels
int py, px; int py, px;
for(py=0; py<200; py++) for(py=0; py<200; py++)
{ {
for(px=0; px<320; px++) for(px=0; px<320; px++)
{ {
// Value in the complex plane
float xz = (float)px * (3.5 / 320.0)- 2.5; float xz = (float)px * (3.5 / 320.0)- 2.5;
float yz = (float)py * (2.0 / 200.0) - 1.0; float yz = (float)py * (2.0 / 200.0) - 1.0;
// Iterate up to 32 times
float x = 0.0, y = 0.0; float x = 0.0, y = 0.0;
int i; int i;
for(i=0; i<32; i++) for(i=0; i<32; i++)
@ -37,15 +46,19 @@ int main(void)
x = xt; x = xt;
} }
// Set a pixel if exceeds bound in less than 32 iterations
if (i < 32) if (i < 32)
Screen[320 * (py >> 3) + (py & 7) + (px & ~7)] |= 0x80 >> (px & 7); Screen[320 * (py >> 3) + (py & 7) + (px & ~7)] |= 0x80 >> (px & 7);
} }
} }
// Re-enable the kernal
mmap_set(MMAP_NO_BASIC); mmap_set(MMAP_NO_BASIC);
// Wait for key press
getch(); getch();
// Restore VIC state
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
return 0; return 0;

View File

@ -3,10 +3,12 @@
#include <c64/memmap.h> #include <c64/memmap.h>
#include <conio.h> #include <conio.h>
// Address of hires buffer and color buffers
#define Screen ((char *)0xe000) #define Screen ((char *)0xe000)
#define Color ((char *)0xc800) #define Color ((char *)0xc800)
#define Color2 ((char *)0xd800) #define Color2 ((char *)0xd800)
// Bit patters for eight different color pairs
char colors[] = { char colors[] = {
0xff, 0xff, 0xff, 0xff,
0xee, 0xbb, 0xee, 0xbb,
@ -21,27 +23,35 @@ char colors[] = {
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Turn of the kernal ROM
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Switch VIC into multicolor bitmap mode
vic_setmode(VICM_HIRES_MC, Color, Screen); vic_setmode(VICM_HIRES_MC, Color, Screen);
// Clear the screen and set the colors
vic.color_back = 0x00; vic.color_back = 0x00;
memset(Screen, 0, 8000); memset(Screen, 0, 8000);
memset(Color, 0x27, 1000); memset(Color, 0x27, 1000);
memset(Color2, 0x03, 1000); memset(Color2, 0x03, 1000);
// Loop over all pixels
int py, px; int py, px;
for(py=0; py<100; py++) for(py=0; py<100; py++)
{ {
for(px=0; px<160; px++) for(px=0; px<160; px++)
{ {
// Value in the complex plane
float xz = (float)px * (3.5 / 160.0)- 2.5; float xz = (float)px * (3.5 / 160.0)- 2.5;
float yz = (float)py * (2.4 / 100.0) - 1.2; float yz = (float)py * (2.4 / 100.0) - 1.2;
// Iterate up to 32 times
float x = 0.0, y = 0.0; float x = 0.0, y = 0.0;
int i; int i;
for(i=0; i<32; i++) for(i=0; i<32; i++)
@ -55,20 +65,29 @@ int main(void)
if (i < 32) if (i < 32)
{ {
// Position on screen
char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (px & ~3); char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (px & ~3);
// Mask of pixels to change
char mask = 0xc0 >> (2 * (px & 3)); char mask = 0xc0 >> (2 * (px & 3));
// Get the two color patterns for upper and lower half
char c0 = colors[2 * (i & 7)], c1 = colors[2 * (i & 7) + 1]; char c0 = colors[2 * (i & 7)], c1 = colors[2 * (i & 7) + 1];
// Put the pixels into the image
dp[0] |= c0 & mask; dp[0] |= c0 & mask;
dp[1] |= c1 & mask; dp[1] |= c1 & mask;
} }
} }
} }
// Re-enable the kernal
mmap_set(MMAP_NO_BASIC); mmap_set(MMAP_NO_BASIC);
// Wait for key press
getch(); getch();
// Restore VIC state
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
return 0; return 0;

View File

@ -4,10 +4,12 @@
#include <conio.h> #include <conio.h>
#include <math.h> #include <math.h>
// Address of hires buffer and color buffers
#define Screen ((char *)0xe000) #define Screen ((char *)0xe000)
#define Color1 ((char *)0xc800) #define Color1 ((char *)0xc800)
#define Color2 ((char *)0xd800) #define Color2 ((char *)0xd800)
// Bit patters for two different color pairs and eight shades
byte colors[2][17] = byte colors[2][17] =
{ {
{0x00, {0x00,
@ -20,27 +22,37 @@ byte colors[2][17] =
} }
}; };
// Fill a vertical line x from py to ty with color c
void VLine(int x, int py, int ty, char c) void VLine(int x, int py, int ty, char c)
{ {
// Clip boundaries
if (py < 0) if (py < 0)
py = 0; py = 0;
if (ty > 100) if (ty > 100)
ty = 100; ty = 100;
// Check if there are pixel to draw
if (py < ty) if (py < ty)
{ {
// Calculate top address and mask
char mask = 0xc0 >> (2 * (x & 3)); char mask = 0xc0 >> (2 * (x & 3));
char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (x & ~3); char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (x & ~3);
// Get the two color patterns
char c0 = colors[0][c] & mask, c1 = colors[1][c] & mask; char c0 = colors[0][c] & mask, c1 = colors[1][c] & mask;
// Invert mask to cover the unchanged portion
mask = ~mask; mask = ~mask;
// Loop over all pixels
char h = ty - py; char h = ty - py;
while (h) while (h)
{ {
// Apply color to memory
dp[0] = (dp[0] & mask) | c0; dp[0] = (dp[0] & mask) | c0;
dp[1] = (dp[1] & mask) | c1; dp[1] = (dp[1] & mask) | c1;
// Two pixel lines down
dp += 2; dp += 2;
if (!((int)dp & 7)) if (!((int)dp & 7))
dp += 312; dp += 312;
@ -50,6 +62,7 @@ void VLine(int x, int py, int ty, char c)
} }
} }
// Iterate up to 32 iterations and return a smoothed height
float iter(float xz, float yz) float iter(float xz, float yz)
{ {
float x = 0.0, y = 0.0, r; float x = 0.0, y = 0.0, r;
@ -71,6 +84,7 @@ float iter(float xz, float yz)
return i - log(log(r)/log(64.0))/log(2.0) return i - log(log(r)/log(64.0))/log(2.0)
} }
// Calculate light with given new and old heights
int light(float hl, float hu, float h) int light(float hl, float hu, float h)
{ {
float dx = h - hl, dz = h - hu, dy = 0.1; float dx = h - hl, dz = h - hu, dy = 0.1;
@ -84,12 +98,16 @@ int light(float hl, float hu, float h)
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Turn of the kernal ROM
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Switch VIC into multicolor bitmap mode
vic_setmode(VICM_HIRES_MC, Color1, Screen); vic_setmode(VICM_HIRES_MC, Color1, Screen);
// Clear the screen and set the colors
vic.color_back = 0x00; vic.color_back = 0x00;
vic.color_border = 0x00; vic.color_border = 0x00;
@ -97,22 +115,28 @@ int main(void)
memset(Color1, 0x26, 1000); memset(Color1, 0x26, 1000);
memset(Color2, 0x0f, 1000); memset(Color2, 0x0f, 1000);
// Height of previous row, needed for lighting
float hl[200]; float hl[200];
// Rotation of complex plane
float w = -0.7; float w = -0.7;
float co = cos(w), si = sin(w); float co = cos(w), si = sin(w);
// Loop from left to right
for(int x=-1; x<160; x+= 1) for(int x=-1; x<160; x+= 1)
{ {
// Loop from far to nead
int py = 20; int py = 20;
float hu = 0; float hu = 0;
for(int y=1; y<200; y+= 1) for(int y=1; y<200; y+= 1)
{ {
// Inverse 3D projection
float fz = 2.0 / (float)y; float fz = 2.0 / (float)y;
float fx = (float)(x - 80) * fz / 100.0; float fx = (float)(x - 80) * fz / 100.0;
float mz = fz * 100.0 - 3.0, mx = fx * 100.0; float mz = fz * 100.0 - 3.0, mx = fx * 100.0;
// Rotation of the plane
float rx = mx * co - mz * si, rz = mx * si + mz * co; float rx = mx * co - mz * si, rz = mx * si + mz * co;
float dp = iter(rx, rz); float dp = iter(rx, rz);
float v = 2 * dp; float v = 2 * dp;
@ -120,20 +144,25 @@ int main(void)
float fy = 5.0 * pow(2.0, - v * 0.4); float fy = 5.0 * pow(2.0, - v * 0.4);
// Calculate light
int ni = light(hl[y], hu, fy); int ni = light(hl[y], hu, fy);
// Update left column
hl[y] = fy; hl[y] = fy;
hu = fy; hu = fy;
// Forward 3D projection
int ty = 20 + y / 2 + (int)(floor(fy / fz)); int ty = 20 + y / 2 + (int)(floor(fy / fz));
int c;
// color of pixel
int c;
if (dp != 32) if (dp != 32)
c = 1 + ni + 8 * ((int)floor(dp) & 1); c = 1 + ni + 8 * ((int)floor(dp) & 1);
else else
c = 0; c = 0;
// Draw line if not dummy left row
if (x >= 0) if (x >= 0)
VLine(x, py, ty, c); VLine(x, py, ty, c);
@ -141,10 +170,13 @@ int main(void)
} }
} }
// Re-enable the kernal
mmap_set(MMAP_NO_BASIC); mmap_set(MMAP_NO_BASIC);
// Wait for key press
getch(); getch();
// Restore VIC state
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
return 0; return 0;

View File

@ -3,18 +3,24 @@
int main(void) int main(void)
{ {
// Set name for file and open it on drive 9
krnio_setnam("@0:CHARS,P,R"); krnio_setnam("@0:CHARS,P,R");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Read bytes until failure
int ch, k = 0; int ch, k = 0;
while ((ch = krnio_getch(2)) >= 0) while ((ch = krnio_getch(2)) >= 0)
{ {
// Print the value of the byte
printf("%d : %d\n", k, ch) printf("%d : %d\n", k, ch)
k++; k++;
// Exit the loop if this was the last byte of the file
if (ch & 0x100) if (ch & 0x100)
break; break;
} }
// Close the file
krnio_close(2); krnio_close(2);
} }

View File

@ -3,12 +3,18 @@
int main(void) int main(void)
{ {
// Set name for file and open it with replace on drive 9
krnio_setnam("@0:CHARS,P,W"); krnio_setnam("@0:CHARS,P,W");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Write 128 bytes to the file, it would be more efficient
// to set the output channel with krnio_chkout() for the file and
// write the bytes using krnio_chrout()
for(char i=0; i<128; i++) for(char i=0; i<128; i++)
krnio_putch(2, i); krnio_putch(2, i);
// Close the file again
krnio_close(2); krnio_close(2);
} }

View File

@ -11,14 +11,18 @@ Score score[4];
int main(void) int main(void)
{ {
// Set name for file and open it on drive 9
krnio_setnam("HIGHSCORE,P,R"); krnio_setnam("HIGHSCORE,P,R");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Read the content of the file into the score arrayx
krnio_read(2, (char*)score, sizeof(score)); krnio_read(2, (char*)score, sizeof(score));
// Close the file
krnio_close(2); krnio_close(2);
} }
// Print the result to stdout
for(int i=0; i<4; i++) for(int i=0; i<4; i++)
{ {
printf("%s : %u\n", score[i].name, score[i].score); printf("%s : %u\n", score[i].name, score[i].score);

View File

@ -16,11 +16,14 @@ Score score[] = {
int main(void) int main(void)
{ {
// Set name for file and open it with replace on drive 9
krnio_setnam("@0:HIGHSCORE,P,W"); krnio_setnam("@0:HIGHSCORE,P,W");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Fill the file with the score array
krnio_write(2, (char*)score, sizeof(score)); krnio_write(2, (char*)score, sizeof(score));
// Close the file
krnio_close(2); krnio_close(2);
} }

View File

@ -12,27 +12,40 @@ Bitmap Screen;
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Initialize the display bitmap
bm_init(&Screen, ScreenMem, 40, 25); bm_init(&Screen, ScreenMem, 40, 25);
// Clear the color memory with ROM and IO disabled
mmap_set(MMAP_RAM); mmap_set(MMAP_RAM);
memset(ScreenMem, 0, 8000); memset(ScreenMem, 0, 8000);
memset(ColorMem, 0x70, 1000); memset(ColorMem, 0x70, 1000);
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Switch VIC to hires mode
vic_setmode(VICM_HIRES, ColorMem, ScreenMem); vic_setmode(VICM_HIRES, ColorMem, ScreenMem);
// Reenable the kernal rom
mmap_set(MMAP_ROM); mmap_set(MMAP_ROM);
// Set name for file and open it with replace on drive 9
krnio_setnam("TESTIMAGE,P,R"); krnio_setnam("TESTIMAGE,P,R");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Read the bitmap image in one go
krnio_read(2, ScreenMem, 8000); krnio_read(2, ScreenMem, 8000);
// Close the file
krnio_close(2); krnio_close(2);
} }
// Wait for a character
getchar(); getchar();
// Restore VIC
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
return 0; return 0;

View File

@ -13,27 +13,34 @@ char Buffer[200];
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Initialize the display bitmap and a brush
bm_init(&Screen, ScreenMem, 40, 25); bm_init(&Screen, ScreenMem, 40, 25);
bm_alloc(&Brush, 2, 2); bm_alloc(&Brush, 2, 2);
// Clear the color memory with ROM and IO disabled
mmap_set(MMAP_RAM); mmap_set(MMAP_RAM);
memset(ScreenMem, 0, 8000); memset(ScreenMem, 0, 8000);
memset(ColorMem, 0x70, 1000); memset(ColorMem, 0x70, 1000);
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Switch VIC to hires mode
vic_setmode(VICM_HIRES, ColorMem, ScreenMem); vic_setmode(VICM_HIRES, ColorMem, ScreenMem);
// Draw the brush
ClipRect crb = {0, 0, 16, 16}; ClipRect crb = {0, 0, 16, 16};
bm_fill(&Brush, 0); bm_fill(&Brush, 0);
bm_circle_fill(&Brush, &crb, 7, 7, 6, NineShadesOfGrey[8]); bm_circle_fill(&Brush, &crb, 7, 7, 6, NineShadesOfGrey[8]);
// Draw the main image
ClipRect crr = {0, 0, 320, 200}; ClipRect crr = {0, 0, 320, 200};
bm_circle_fill(&Screen, &crr, 160, 100, 90, NineShadesOfGrey[8]); bm_circle_fill(&Screen, &crr, 160, 100, 90, NineShadesOfGrey[8]);
bm_circle_fill(&Screen, &crr, 120, 80, 20, NineShadesOfGrey[0]); bm_circle_fill(&Screen, &crr, 120, 80, 20, NineShadesOfGrey[0]);
bm_circle_fill(&Screen, &crr, 200, 80, 20, NineShadesOfGrey[0]); bm_circle_fill(&Screen, &crr, 200, 80, 20, NineShadesOfGrey[0]);
// And a smile
for(int x=-40; x<=40; x+=4) for(int x=-40; x<=40; x+=4)
{ {
int y = bm_usqrt(50 * 50 - x * x); int y = bm_usqrt(50 * 50 - x * x);
@ -41,22 +48,32 @@ int main(void)
} }
// Reenable the kernal rom
mmap_set(MMAP_ROM); mmap_set(MMAP_ROM);
// Set name for file and open it with replace on drive 9
krnio_setnam("@0:TESTIMAGE,P,W"); krnio_setnam("@0:TESTIMAGE,P,W");
if (krnio_open(2, 9, 2)) if (krnio_open(2, 9, 2))
{ {
// Loop in chunks of 200 bytes
for(int i=0; i<8000; i+=200) for(int i=0; i<8000; i+=200)
{ {
// Disable ROM
mmap_set(MMAP_NO_ROM); mmap_set(MMAP_NO_ROM);
// Copy chunk into buffer
memcpy(Buffer, ScreenMem + i, 200); memcpy(Buffer, ScreenMem + i, 200);
// Reeable the ROM
mmap_set(MMAP_ROM); mmap_set(MMAP_ROM);
// Write the chunk to disk
krnio_write(2, Buffer, 200); krnio_write(2, Buffer, 200);
} }
// Close the file
krnio_close(2); krnio_close(2);
} }
// Restore the VIC
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
return 0; return 0;

View File

@ -2,25 +2,31 @@
#include <c64/rasterirq.h> #include <c64/rasterirq.h>
#include <conio.h> #include <conio.h>
// Prepare small 14 color bars and one IRQ for back to normal
RIRQCode bars[15]; RIRQCode bars[15];
int main(void) int main(void)
{ {
// initialize raster IRQ
rirq_init(true); rirq_init(true);
for(int i=0; i<15; i++) for(int i=0; i<15; i++)
{ {
// Build color change raster IRQ
rirq_build(bars + i, 2); rirq_build(bars + i, 2);
// Change border color
rirq_write(bars + i, 0, &vic.color_border, i); rirq_write(bars + i, 0, &vic.color_border, i);
// Change background color
rirq_write(bars + i, 1, &vic.color_back, i); rirq_write(bars + i, 1, &vic.color_back, i);
// Place it on screen
rirq_set(i, 80 + 8 * i, bars + i); rirq_set(i, 80 + 8 * i, bars + i);
} }
// Sort all raster IRQs
rirq_sort(); rirq_sort();
// Start raster IRQs
rirq_start(); rirq_start();
return 0; return 0;
} }

View File

@ -4,6 +4,8 @@
#include <math.h> #include <math.h>
#include <conio.h> #include <conio.h>
// Five raster IRQs for top and bottom of the two chasing bars, and the bottom
// of the screen
RIRQCode ftop, fbottom, btop, bbottom, final ; RIRQCode ftop, fbottom, btop, bbottom, final ;
char sintab[256]; char sintab[256];

View File

@ -8,26 +8,36 @@ char spdata[] = {
#embed "../resources/friendlybear.bin" #embed "../resources/friendlybear.bin"
}; };
// Raster IRQs for last line of screen and below
RIRQCode open, bottom; RIRQCode open, bottom;
int main(void) int main(void)
{ {
// initialize raster IRQ
rirq_init(true); rirq_init(true);
// Build open border raster IRQ
rirq_build(&open, 1); rirq_build(&open, 1);
// Reduce vertical screen size to fool VIC counter
rirq_write(&open, 0, &vic.ctrl1, VIC_CTRL1_DEN | 3); rirq_write(&open, 0, &vic.ctrl1, VIC_CTRL1_DEN | 3);
// Place it into the last line of the screen
rirq_set(0, 50 + 200 - 3, &open); rirq_set(0, 50 + 200 - 3, &open);
// Build switch to normal raster IRQ
rirq_build(&bottom, 1); rirq_build(&bottom, 1);
rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3 ); rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3 );
rirq_set(1, 50, &bottom); rirq_set(1, 50, &bottom);
// sort the raster IRQs
rirq_sort(); rirq_sort();
// start raster IRQ processing
rirq_start(); rirq_start();
// Copy the sprite data
memcpy((char *)0x0380, spdata, 128); memcpy((char *)0x0380, spdata, 128);
// Initialize sprites
*(char *)(0x7f8) = 0x03c0 / 64; *(char *)(0x7f8) = 0x03c0 / 64;
*(char *)(0x7f9) = 0x0380 / 64; *(char *)(0x7f9) = 0x0380 / 64;
*(char *)(0x7fa) = 0x03c0 / 64; *(char *)(0x7fa) = 0x03c0 / 64;
@ -52,6 +62,7 @@ int main(void)
for(;;) for(;;)
{ {
// Move sprites through all vertical positions
for(int i=0; i<255; i++) for(int i=0; i<255; i++)
{ {
vic_sprxy(0, 100, 1 * i); vic_sprxy(1, 100, 1 * i); vic_sprxy(0, 100, 1 * i); vic_sprxy(1, 100, 1 * i);

View File

@ -10,29 +10,44 @@ const char * Text =
S"CORPORIS, EOS? UNDE VERO ISTE QUIA? EAQUE EAQUE. IN. AUT ID " S"CORPORIS, EOS? UNDE VERO ISTE QUIA? EAQUE EAQUE. IN. AUT ID "
S"EXPEDITA ILLUM MOLESTIAS, "; S"EXPEDITA ILLUM MOLESTIAS, ";
// Raster interrupt command structure for change to scrolled and back
RIRQCode scroll, bottom; RIRQCode scroll, bottom;
int main(void) int main(void)
{ {
// initialize raster IRQ
rirq_init(true); rirq_init(true);
// Build switch to scroll line IRQ
rirq_build(&scroll, 1); rirq_build(&scroll, 1);
// Change control register two with this IRQ
rirq_write(&scroll, 0, &vic.ctrl2, 0); rirq_write(&scroll, 0, &vic.ctrl2, 0);
// Put it onto the scroll line
rirq_set(0, 50 + 24 * 8, &scroll); rirq_set(0, 50 + 24 * 8, &scroll);
// Build the switch to normal IRQ
rirq_build(&bottom, 1); rirq_build(&bottom, 1);
// re-enable left and right column and reset horizontal scroll
rirq_write(&bottom, 0, &vic.ctrl2, VIC_CTRL2_CSEL); rirq_write(&bottom, 0, &vic.ctrl2, VIC_CTRL2_CSEL);
// place this at the bottom
rirq_set(1, 250, &bottom); rirq_set(1, 250, &bottom);
// sort the raster IRQs
rirq_sort(); rirq_sort();
// start raster IRQ processing
rirq_start(); rirq_start();
// Loop through text
int x = 0; int x = 0;
for(;;) for(;;)
{ {
// wait for raster reaching bottom of screen
rirq_wait(); rirq_wait();
// Update raster IRQ for scroll line with new horizontal scroll offset
rirq_data(&scroll, 0, 7 - (x & 7)); rirq_data(&scroll, 0, 7 - (x & 7));
// Copy scrolled version of text when switching over char border
if ((x & 7) == 0) if ((x & 7) == 0)
memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40); memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40);
x++; x++;

View File

@ -4,6 +4,7 @@
byte font[2048]; byte font[2048];
// Copy the system font into local RAM for easy access
void copyFont(void) void copyFont(void)
{ {
mmap_set(MMAP_CHAR_ROM); mmap_set(MMAP_CHAR_ROM);
@ -13,15 +14,23 @@ void copyFont(void)
mmap_set(MMAP_ROM); mmap_set(MMAP_ROM);
} }
// Screen and color space
#define screen ((byte *)0x0400) #define screen ((byte *)0x0400)
#define color ((byte *)0xd800) #define color ((byte *)0xd800)
// Macro for easy access to screen space
#define sline(x, y) (screen + 40 * (y) + (x)) #define sline(x, y) (screen + 40 * (y) + (x))
// Start row for text
#define srow 5 #define srow 5
// Move the screen one character to the left
void scrollLeft(void) void scrollLeft(void)
{ {
// Loop horizontaly
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
{ {
// Unroll vetical loop 16 times
#assign y 0 #assign y 0
#repeat #repeat
sline(0, srow + y)[x] = sline(1, srow + y)[x]; sline(0, srow + y)[x] = sline(1, srow + y)[x];
@ -30,10 +39,13 @@ void scrollLeft(void)
} }
} }
// Expand one column of a glyph to the right most screen column
void expand(char c, byte f) void expand(char c, byte f)
{ {
// Address of glyph data
byte * fp = font + 8 * c; byte * fp = font + 8 * c;
// Unroll eight times for each byte in glyph data
#assign y 0 #assign y 0
#repeat #repeat
sline(39, srow + 2 * y + 0)[0] = sline(39, srow + 2 * y + 0)[0] =
@ -54,28 +66,36 @@ const char * text =
int main(void) int main(void)
{ {
// Install the IRQ trampoline
mmap_trampoline(); mmap_trampoline();
// Copy the font data
copyFont(); copyFont();
// Cleat the screen
memset(screen, 0x20, 1000); memset(screen, 0x20, 1000);
// Color bars
for(int i=0; i<16; i++) for(int i=0; i<16; i++)
memset(color + 40 * (srow + i), i + 1, 40); memset(color + 40 * (srow + i), i + 1, 40);
vic.color_back = VCOL_BLACK; vic.color_back = VCOL_BLACK;
vic.color_border = VCOL_BLACK; vic.color_border = VCOL_BLACK;
// Hide left and right column
vic.ctrl2 = 0; vic.ctrl2 = 0;
// Loop over text
int ci = 0; int ci = 0;
for(;;) for(;;)
{ {
// Loop over glyph from left to right
byte cf = 0x80; byte cf = 0x80;
while (cf) while (cf)
{ {
for(char i=0; i<2; i++) for(char i=0; i<2; i++)
{ {
// Pixel level scrolling
vic_waitBottom(); vic_waitBottom();
vic.ctrl2 = 4; vic.ctrl2 = 4;
vic_waitTop(); vic_waitTop();
@ -91,12 +111,16 @@ int main(void)
vic_waitBottom(); vic_waitBottom();
vic.ctrl2 = 6; vic.ctrl2 = 6;
// Crossing character border, now scroll and show new column
scrollLeft(); scrollLeft();
expand(text[ci], cf); expand(text[ci], cf);
} }
// Next glyph column
cf >>= 1; cf >>= 1;
} }
// Next character
ci++; ci++;
} }

View File

@ -4,11 +4,15 @@
#include <c64/joystick.h> #include <c64/joystick.h>
#include <stdlib.h> #include <stdlib.h>
// Screen and color space
#define Screen ((byte *)0x0400) #define Screen ((byte *)0x0400)
#define Color ((byte *)0xd800) #define Color ((byte *)0xd800)
// Macro for easy access to screen and color space
#define sline(x, y) (Screen + 40 * (y) + (x)) #define sline(x, y) (Screen + 40 * (y) + (x))
#define cline(x, y) (Color + 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] = static const char quad[4][4 * 4] =
{ {
{ {
@ -40,6 +44,7 @@ static const char quad[4][4 * 4] =
#pragma align(quad, 256) #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) void expandrow(char * dp, char * cp, const char * grid, char ly, char lx)
{ {
char hx = 0; char hx = 0;
@ -56,6 +61,7 @@ void expandrow(char * dp, char * cp, const char * grid, char ly, char lx)
} }
} }
// Expand a single column into an offscreen buffer
void expandcol(char * dp, char * cp, const char * grid, char ly, char lx) void expandcol(char * dp, char * cp, const char * grid, char ly, char lx)
{ {
for(char y=0; y<25; y++) for(char y=0; y<25; y++)
@ -71,25 +77,39 @@ void expandcol(char * dp, char * cp, const char * grid, char ly, char lx)
} }
} }
// Two split scroll for left, right and up
#define VSPLIT 12 #define VSPLIT 12
// Three split scroll for down. Downscrolling is more tricky because
// we have to copy towards the raster
#define VSPLIT 12 #define VSPLIT 12
#define VSPLIT2 20 #define VSPLIT2 20
// New line/column of screen and color data
char news[40], newc[40]; 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) void scroll_left(void)
{ {
// Wait for one frame
vic_waitTop(); vic_waitTop();
vic_waitBottom(); vic_waitBottom();
// Switch to offset 2, 4
vic.ctrl2 = 0x02; vic.ctrl2 = 0x02;
vic_waitTop(); vic_waitTop();
vic_waitBottom(); vic_waitBottom();
// Switch to offset 0, 4
vic.ctrl2 = 0x00; vic.ctrl2 = 0x00;
// Wait until bottom of section
vic_waitLine(50 + 8 * VSPLIT); vic_waitLine(50 + 8 * VSPLIT);
// Scroll upper section
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
{ {
#assign ty 0 #assign ty 0
@ -100,6 +120,7 @@ void scroll_left(void)
#until ty == VSPLIT #until ty == VSPLIT
} }
// Update column
#assign ty 0 #assign ty 0
#repeat #repeat
sline(0, ty)[39] = news[ty]; sline(0, ty)[39] = news[ty];
@ -107,9 +128,13 @@ void scroll_left(void)
#assign ty ty + 1 #assign ty ty + 1
#until ty == VSPLIT #until ty == VSPLIT
// Wait for bottom of visible screen
vic_waitBottom(); vic_waitBottom();
// Switch to offset 6, 4
vic.ctrl2 = 0x06; vic.ctrl2 = 0x06;
// Scroll lower part of the screen, while top is redrawn
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
{ {
#assign ty VSPLIT #assign ty VSPLIT
@ -120,6 +145,7 @@ void scroll_left(void)
#until ty == 25 #until ty == 25
} }
// Update new column
#assign ty VSPLIT #assign ty VSPLIT
#repeat #repeat
sline(0, ty)[39] = news[ty]; sline(0, ty)[39] = news[ty];
@ -127,11 +153,16 @@ void scroll_left(void)
#assign ty ty + 1 #assign ty ty + 1
#until ty == 25 #until ty == 25
// Wait for bottom
vic_waitBottom(); vic_waitBottom();
// Now back to 4, 4
vic.ctrl2 = 0x04 vic.ctrl2 = 0x04
} }
// Scroll one character right in two pixel increments
void scroll_right(void) void scroll_right(void)
{ {
vic_waitTop(); vic_waitTop();
@ -185,6 +216,8 @@ void scroll_right(void)
vic.ctrl2 = 0x04; vic.ctrl2 = 0x04;
} }
// Scroll one character up in two pixel increments
void scroll_up(void) void scroll_up(void)
{ {
vic_waitTop(); vic_waitTop();
@ -229,20 +262,36 @@ void scroll_up(void)
char tmp0[40], tmp1[40], tmp2[40], tmp3[40]; 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) void scroll_down(void)
{ {
// Wait one frame
vic_waitTop(); vic_waitTop();
vic_waitBottom(); vic_waitBottom();
// Save seam lines
for(char x=0; x<40; x++) for(char x=0; x<40; x++)
{ {
tmp0[x] = sline(0, VSPLIT)[x]; tmp0[x] = sline(0, VSPLIT)[x];
tmp1[x] = cline(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; vic.ctrl1 = 0x06 | VIC_CTRL1_DEN;
// Wait for bottom of top section
vic_waitLine(58 + 8 * VSPLIT); vic_waitLine(58 + 8 * VSPLIT);
// Scroll top section down and copy new column
for(char x=0; x<40; x++) for(char x=0; x<40; x++)
{ {
#assign ty VSPLIT #assign ty VSPLIT
@ -257,12 +306,12 @@ void scroll_down(void)
} }
// vic_waitBottom(); // vic_waitBottom();
// We have already reached the bottom, switch to 4, 0
vic.ctrl1 = 0x00 | VIC_CTRL1_DEN; vic.ctrl1 = 0x00 | VIC_CTRL1_DEN;
// Copy the second section, update the seam line from the buffer
for(char x=0; x<40; x++) for(char x=0; x<40; x++)
{ {
tmp2[x] = sline(0, VSPLIT2)[x];
tmp3[x] = cline(0, VSPLIT2)[x];
#assign ty VSPLIT2 #assign ty VSPLIT2
#repeat #repeat
@ -275,6 +324,7 @@ void scroll_down(void)
cline(0, ty)[x] = tmp1[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++) for(char x=0; x<40; x++)
{ {
#assign ty 24 #assign ty 24
@ -288,9 +338,11 @@ void scroll_down(void)
cline(0, ty)[x] = tmp3[x]; cline(0, ty)[x] = tmp3[x];
} }
// Switch to 4, 2
vic_waitBottom(); vic_waitBottom();
vic.ctrl1 = 0x02 | VIC_CTRL1_DEN; vic.ctrl1 = 0x02 | VIC_CTRL1_DEN;
// Switch to 4, 4
vic_waitTop(); vic_waitTop();
vic_waitBottom(); vic_waitBottom();
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN; vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
@ -302,11 +354,13 @@ char grid[16][16];
int main(void) int main(void)
{ {
// We need some more accurate timing for this, so kill the kernal IRQ
__asm __asm
{ {
sei sei
} }
// Init the grid
for(char y=0; y<16; y++) for(char y=0; y<16; y++)
{ {
for(char x=0; x<16; x++) for(char x=0; x<16; x++)
@ -317,6 +371,7 @@ int main(void)
char gridX = 0, gridY = 0; char gridX = 0, gridY = 0;
// Inital drwaing of the screen
char * dp = Screen, * cp = Color; char * dp = Screen, * cp = Color;
for(char y=0; y<25; y++) for(char y=0; y<25; y++)
{ {
@ -325,11 +380,18 @@ int main(void)
cp += 40; cp += 40;
} }
// setup initial scroll offset
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
vic.ctrl2 = 0x04
for(;;) for(;;)
{ {
// Check the joystick
joy_poll(1); joy_poll(1);
if (joyx[1] == 1) if (joyx[1] == 1)
{ {
// Move to the right
if (gridX < 24) if (gridX < 24)
{ {
gridX++; gridX++;
@ -339,6 +401,7 @@ int main(void)
} }
else if (joyx[1] == -1) else if (joyx[1] == -1)
{ {
// Move to the left
if (gridX > 0) if (gridX > 0)
{ {
gridX--; gridX--;
@ -348,6 +411,7 @@ int main(void)
} }
else if (joyy[1] == 1) else if (joyy[1] == 1)
{ {
// Move down
if (gridY < 39) if (gridY < 39)
{ {
gridY++; gridY++;
@ -357,6 +421,7 @@ int main(void)
} }
else if (joyy[1] == -1) else if (joyy[1] == -1)
{ {
// Move up
if (gridY > 0) if (gridY > 0)
{ {
gridY--; gridY--;

View File

@ -3,16 +3,22 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
// Screen and color space
#define screen ((byte *)0x0400) #define screen ((byte *)0x0400)
#define color ((byte *)0xd800) #define color ((byte *)0xd800)
// Macro for easy access to screen and color space
#define sline(x, y) (screen + 40 * (y) + (x)) #define sline(x, y) (screen + 40 * (y) + (x))
#define cline(x, y) (color + 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]; char rbuff[25], cbuff[25];
// Split into three scrolling sections to race the beam
#define SPLIT1 8 #define SPLIT1 8
#define SPLIT2 16 #define SPLIT2 16
// Scroll top section
void scrollLeft0(void) void scrollLeft0(void)
{ {
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
@ -32,6 +38,7 @@ void scrollLeft0(void)
#until y == SPLIT1 #until y == SPLIT1
} }
// Scroll bottom two sections
void scrollLeft1(void) void scrollLeft1(void)
{ {
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
@ -67,7 +74,7 @@ void scrollLeft1(void)
} }
// Prepare a new column with random data
void prepcol(void) void prepcol(void)
{ {
for(char i=0; i<25; i++) for(char i=0; i<25; i++)
@ -80,6 +87,7 @@ void prepcol(void)
int main(void) int main(void)
{ {
// Clear the screen
memset(screen, 0x20, 1000); memset(screen, 0x20, 1000);
memset(color, 7, 1000); memset(color, 7, 1000);
@ -90,24 +98,33 @@ int main(void)
for(;;) for(;;)
{ {
// Advance one pixel
x = (x + 1) & 7; x = (x + 1) & 7;
// If we will cross the character boundary, scroll the top section
if (x == 0) if (x == 0)
{ {
// Wait for raster reaching bottom of first section
vic_waitLine(50 + 8 * SPLIT1); vic_waitLine(50 + 8 * SPLIT1);
// Scroll first section
scrollLeft0(); scrollLeft0();
} }
// Wait for bottom of screen
vic_waitBottom(); vic_waitBottom();
// Update the pixel offset
vic.ctrl2 = (7 - x) & 7; vic.ctrl2 = (7 - x) & 7;
if (x == 0) if (x == 0)
{ {
// Scroll the bottom section if needed
scrollLeft1(); scrollLeft1();
} }
else else
{ {
// Update the new column somewhere in the middle of the character
if (x == 4) if (x == 4)
prepcol(); prepcol();
vic_waitTop(); vic_waitTop();

View File

@ -4,10 +4,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <c64/rasterirq.h> #include <c64/rasterirq.h>
// Screen and color space
#define screen ((byte *)0x0400) #define screen ((byte *)0x0400)
#define color ((byte *)0xd800) #define color ((byte *)0xd800)
// Macro for easy access to screen space
#define sline(x, y) (screen + 40 * (y) + (x)) #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] = static const char quad[4][4 * 4] =
{ {
{ {
@ -38,9 +42,11 @@ static const char quad[4][4 * 4] =
#pragma align(quad, 256) #pragma align(quad, 256)
// expand one row with column offset 0 into the grid
void expandrow0(char * dp, const char * grid, char ly) void expandrow0(char * dp, const char * grid, char ly)
{ {
char gi; char gi;
// unroll for each char in the row
#assign gx 0 #assign gx 0
#repeat #repeat
gi = grid[gx] | ly; gi = grid[gx] | ly;
@ -52,6 +58,8 @@ void expandrow0(char * dp, const char * grid, char ly)
#until gx == 10 #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) void expandrow1(char * dp, const char * grid, char ly)
{ {
char gi; char gi;
@ -72,6 +80,8 @@ void expandrow1(char * dp, const char * grid, char ly)
dp[39] = quad[0][gi]; 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) void expandrow2(char * dp, const char * grid, char ly)
{ {
char gi; char gi;
@ -92,6 +102,8 @@ void expandrow2(char * dp, const char * grid, char ly)
dp[39] = quad[1][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) void expandrow3(char * dp, const char * grid, char ly)
{ {
char gi; char gi;
@ -112,16 +124,24 @@ void expandrow3(char * dp, const char * grid, char ly)
dp[39] = quad[2][gi]; dp[39] = quad[2][gi];
} }
// expand the visibile portion of the screen at the
// given char offset into the tiles
void expand(char * dp, const char * grid, char px, char py) void expand(char * dp, const char * grid, char px, char py)
{ {
// remainder of position, offset into the tile
char ry = 4 * (py & 3); char ry = 4 * (py & 3);
char rx = px & 3; char rx = px & 3;
// target screen position
char * cdp = dp; char * cdp = dp;
const char * cgrid = grid + (px >> 2) + 16 * (py >> 2);
// 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++) for(char gy=0; gy<20; gy++)
{ {
// Update based on row (could be unrolled for inner groups of full tiles)
switch (rx) switch (rx)
{ {
case 0: case 0:
@ -137,28 +157,35 @@ void expand(char * dp, const char * grid, char px, char py)
expandrow3(cdp, cgrid, ry); expandrow3(cdp, cgrid, ry);
break; break;
} }
// Next row
cdp += 40; cdp += 40;
ry += 4; ry += 4;
// Next tile
if (ry == 16) if (ry == 16)
{ {
ry = 0; ry = 0;
cgrid += 16; cgrid += 32;
} }
} }
} }
char grid[16][16]; char grid[32][32];
#pragma align(grid, 256) #pragma align(grid, 256)
// Raster IRQs for split screen
RIRQCode blank, scroll, bottom; RIRQCode blank, scroll, bottom;
int main(void) int main(void)
{ {
for(char y=0; y<16; y++) // Init grid with random data
for(char y=0; y<32; y++)
{ {
for(char x=0; x<16; x++) for(char x=0; x<32; x++)
{ {
grid[y][x] = rand() & 3; grid[y][x] = rand() & 3;
} }
@ -166,18 +193,22 @@ int main(void)
vic.color_border = 0; vic.color_border = 0;
// Setup split screen
rirq_init(true); rirq_init(true);
// Blank display after top section
rirq_build(&blank, 1); rirq_build(&blank, 1);
rirq_write(&blank, 0, &vic.ctrl1, 0); rirq_write(&blank, 0, &vic.ctrl1, 0);
rirq_set(0, 46 + 5 * 8, &blank); rirq_set(0, 46 + 5 * 8, &blank);
// Setup scrolling area
rirq_build(&scroll, 3); rirq_build(&scroll, 3);
rirq_delay(&scroll, 10); rirq_delay(&scroll, 10);
rirq_write(&scroll, 1, &vic.ctrl1, VIC_CTRL1_DEN); rirq_write(&scroll, 1, &vic.ctrl1, VIC_CTRL1_DEN);
rirq_write(&scroll, 2, &vic.ctrl2, 0); rirq_write(&scroll, 2, &vic.ctrl2, 0);
rirq_set(1, 54 + 5 * 8, &scroll); rirq_set(1, 54 + 5 * 8, &scroll);
// Wait for bottom of screen
rirq_build(&bottom, 2); rirq_build(&bottom, 2);
rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL); rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL);
rirq_write(&bottom, 1, &vic.ctrl2, VIC_CTRL2_CSEL); rirq_write(&bottom, 1, &vic.ctrl2, VIC_CTRL2_CSEL);
@ -187,46 +218,59 @@ int main(void)
rirq_start(); rirq_start();
// Movement data
int py = 40 * 32, px = 40 * 32, dy = 0, dx = 0, ax = 0, ay = 0; int py = 40 * 32, px = 40 * 32, dy = 0, dx = 0, ax = 0, ay = 0;
for(;;) for(;;)
{ {
// Grid position using 13.5 fractions
int rx = px >> 5, ry = py >> 5; int rx = px >> 5, ry = py >> 5;
// Wait for next raster
vic.color_border++; vic.color_border++;
rirq_wait(); rirq_wait();
vic.color_border--; vic.color_border--;
// Update vertical scroll position
rirq_data(&blank, 0, ((7 - ry) & 7) | VIC_CTRL1_DEN | VIC_CTRL1_BMM | VIC_CTRL1_ECM); 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) if ((ry & 7) == 0)
rirq_data(&scroll, 0, 4); rirq_data(&scroll, 0, 4);
else else
rirq_data(&scroll, 0, 10); rirq_data(&scroll, 0, 10);
// Update vertical and horizontal scroll position
rirq_data(&scroll, 1, ((7 - ry) & 7) | VIC_CTRL1_DEN); rirq_data(&scroll, 1, ((7 - ry) & 7) | VIC_CTRL1_DEN);
rirq_data(&scroll, 2, (7 - rx) & 7); rirq_data(&scroll, 2, (7 - rx) & 7);
// Expand grid at current location
expand(screen + 200, &(grid[0][0]), rx >> 3, ry >> 3); expand(screen + 200, &(grid[0][0]), rx >> 3, ry >> 3);
// Update screen velocity using differential equation
dx += ax; dx += ax;
dy += ay; dy += ay;
// New force
if ((rand() & 127) == 0) if ((rand() & 127) == 0)
{ {
ax = (rand() & 63) - 32; ax = (rand() & 63) - 32;
ay = (rand() & 63) - 32; ay = (rand() & 63) - 32;
} }
// Some friction
dx -= (dx + 8) >> 4; dx -= (dx + 8) >> 4;
dy -= (dy + 8) >> 4; dy -= (dy + 8) >> 4;
// Update position reflect at borders
py += dy; py += dy;
if (py < 0 || py > 10 * 8 * 4 * 32) if (py < 0 || py > 26 * 8 * 4 * 32)
{ {
dy = -dy; dy = -dy;
py += dy; py += dy;
} }
px += dx; px += dx;
if (px < 0 || px > 6 * 8 * 4 * 32) if (px < 0 || px > 22 * 8 * 4 * 32)
{ {
dx = -dx; dx = -dx;
px += dx; px += dx;

View File

@ -3,14 +3,20 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
// Screen and color space
#define screen ((byte *)0x0400) #define screen ((byte *)0x0400)
#define color ((byte *)0xd800) #define color ((byte *)0xd800)
// Macro for easy access to screen space
#define sline(x, y) (screen + 40 * (y) + (x)) #define sline(x, y) (screen + 40 * (y) + (x))
// Column buffer for one prepared column of tunnel
char rbuff[25]; char rbuff[25];
// Copy the prepared tunnel column to screen
void expand(char x) void expand(char x)
{ {
// Unroll for each row
#assign y 0 #assign y 0
#repeat #repeat
sline(0, y)[x] = rbuff[y]; sline(0, y)[x] = rbuff[y];
@ -18,8 +24,13 @@ void expand(char x)
#until y == 25 #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) void scrollLeft(void)
{ {
// First 12 rows scroll left and copy new column
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
{ {
#assign y 0 #assign y 0
@ -34,6 +45,7 @@ void scrollLeft(void)
#assign y y + 1 #assign y y + 1
#until y == 12 #until y == 12
// Final 13 rows scroll left and copy new column
for(char x=0; x<39; x++) for(char x=0; x<39; x++)
{ {
#assign y 12 #assign y 12
@ -49,6 +61,10 @@ void scrollLeft(void)
#until y == 25 #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) void scrollRight(void)
{ {
for(char x=39; x>0; x--) for(char x=39; x>0; x--)
@ -80,19 +96,26 @@ void scrollRight(void)
#until y == 25 #until y == 25
} }
// Top and bottom row of the tunnel
char ytop[256], ybottom[256]; char ytop[256], ybottom[256];
// Prepare one column of the tunnel
void prepcol(char xi) void prepcol(char xi)
{ {
char yt, yb; char yt, yb;
signed char dyt, dyb; signed char dyt, dyb;
// Current height of top and bottom
yt = ytop[(char)(xi + 0)]; yt = ytop[(char)(xi + 0)];
yb = ybottom[(char)(xi + 0)]; yb = ybottom[(char)(xi + 0)];
// Height of column to the left for diagonal
dyt = yt - ytop[(char)(xi - 1)]; dyt = yt - ytop[(char)(xi - 1)];
dyb = yb - ybottom[(char)(xi - 1)]; dyb = yb - ybottom[(char)(xi - 1)];
// Fill top, center and bottom range
for(char i=0; i<yt; i++) for(char i=0; i<yt; i++)
rbuff[i] = 160; rbuff[i] = 160;
for(char i=yt; i<yb; i++) for(char i=yt; i<yb; i++)
@ -100,6 +123,7 @@ void prepcol(char xi)
for(char i=yb; i<25; i++) for(char i=yb; i<25; i++)
rbuff[i] = 160; rbuff[i] = 160;
// Select transitional characters based on slope
if (dyt < 0) if (dyt < 0)
rbuff[yt] = 105; rbuff[yt] = 105;
else if (dyt > 0) else if (dyt > 0)
@ -112,6 +136,7 @@ void prepcol(char xi)
} }
// Initialize tunnel with "random" data
void buildTunnel(void) void buildTunnel(void)
{ {
signed char yt = 1, yb = 24, dyt = 1, dyb = -1; signed char yt = 1, yb = 24, dyt = 1, dyb = -1;
@ -152,49 +177,64 @@ void buildTunnel(void)
int main(void) int main(void)
{ {
// Clear the screen
memset(screen, 0x20, 1000); memset(screen, 0x20, 1000);
memset(color, 7, 1000); memset(color, 7, 1000);
vic.color_back = VCOL_BLACK; vic.color_back = VCOL_BLACK;
vic.color_border = VCOL_BLACK; vic.color_border = VCOL_BLACK;
// Build tunnel
buildTunnel(); buildTunnel();
// Initial fill of screen
for(char i=0; i<40; i++) for(char i=0; i<40; i++)
{ {
prepcol(i); prepcol(i);
expand(i); expand(i);
} }
// Now start moving
int xpos = 0, dx = 0, ax = 1; int xpos = 0, dx = 0, ax = 1;
int xi = 0, pxi = 0; int xi = 0, pxi = 0;
for(;;) for(;;)
{ {
// Random change of direction
unsigned r = rand(); unsigned r = rand();
if ((r & 127) == 0) if ((r & 127) == 0)
ax = -ax; ax = -ax;
// Acceleration
dx += ax; dx += ax;
if (dx > 32) if (dx > 32)
dx = 32; dx = 32;
else if (dx < -32) else if (dx < -32)
dx = -32; dx = -32;
// Movement
xpos += dx; xpos += dx;
pxi = xi; pxi = xi;
xi = xpos >> 5; xi = xpos >> 5;
// Check if we cross a character boundary, and if so prepare
// the new column
if (pxi < xi) if (pxi < xi)
prepcol(xi + 39); prepcol(xi + 39);
else if (pxi > xi) else if (pxi > xi)
prepcol(xi + 0); prepcol(xi + 0);
// Wait one frame
vic_waitTop(); vic_waitTop();
vic_waitBottom(); vic_waitBottom();
// Update pixel level scrolling
vic.ctrl2 = (7 - (xpos >> 2)) & 7; vic.ctrl2 = (7 - (xpos >> 2)) & 7;
// Character level scrolling if needed
if (pxi < xi) if (pxi < xi)
scrollLeft(); scrollLeft();
else if (pxi > xi) else if (pxi > xi)

View File

@ -12,29 +12,38 @@ int spx, spy;
int main(void) int main(void)
{ {
// Copy the sprite data
memcpy(SpriteData, spdata, 128); memcpy(SpriteData, spdata, 128);
// Initalize the sprite system
spr_init((char*)0x0400); spr_init((char*)0x0400);
// Center screen position
spx = 160; spx = 160;
spy = 100; 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(0, true, spx, spy, 0x03c0 / 64, VCOL_BLACK, false, false, false);
spr_set(1, true, spx, spy, 0x0380 / 64, VCOL_ORANGE, true, 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_mcolor0 = VCOL_BROWN;
vic.spr_mcolor1 = VCOL_WHITE; vic.spr_mcolor1 = VCOL_WHITE;
for(;;) for(;;)
{ {
// Poll joytick
joy_poll(1); joy_poll(1);
// Change position according to joystick
spx += joyx[1]; spx += joyx[1];
spy += joyy[1]; spy += joyy[1];
// Move sprites on screen
spr_move(0, spx, spy); spr_move(0, spx, spy);
spr_move(1, spx, spy); spr_move(1, spx, spy);
// Wait for one frame iteration
vic_waitFrame(); vic_waitFrame();
} }