From 2d0f20cadc69f88961b690f377cef38d8cd7a7b8 Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sat, 1 Jan 2022 12:39:54 +0100 Subject: [PATCH] Added comments to source samples --- include/c64/rasterirq.c | 1 + samples/fractals/mbhires.c | 13 +++++++ samples/fractals/mbmulti.c | 21 +++++++++- samples/fractals/mbmulti3d.c | 38 ++++++++++++++++-- samples/kernalio/charread.c | 6 +++ samples/kernalio/charwrite.c | 6 +++ samples/kernalio/fileread.c | 4 ++ samples/kernalio/filewrite.c | 5 ++- samples/kernalio/hiresread.c | 13 +++++++ samples/kernalio/hireswrite.c | 17 ++++++++ samples/rasterirq/colorbars.c | 10 ++++- samples/rasterirq/movingbars.c | 2 + samples/rasterirq/openborder.c | 11 ++++++ samples/rasterirq/textcrawler.c | 15 +++++++ samples/scrolling/bigfont.c | 24 ++++++++++++ samples/scrolling/cgrid8way.c | 69 ++++++++++++++++++++++++++++++++- samples/scrolling/colorram.c | 19 ++++++++- samples/scrolling/grid2d.c | 58 +++++++++++++++++++++++---- samples/scrolling/tunnel.c | 40 +++++++++++++++++++ samples/sprites/joycontrol.c | 9 +++++ 20 files changed, 364 insertions(+), 17 deletions(-) diff --git a/include/c64/rasterirq.c b/include/c64/rasterirq.c index 5643093..ea6f1e6 100644 --- a/include/c64/rasterirq.c +++ b/include/c64/rasterirq.c @@ -320,6 +320,7 @@ void rirq_sort(void) rasterIRQNext[i] = rasterIRQRows[rasterIRQIndex[i]]; npos++; + vic.raster = rasterIRQNext[nextIRQ] - 1; } void rirq_start(void) diff --git a/samples/fractals/mbhires.c b/samples/fractals/mbhires.c index 60f2fef..0e6bd1e 100644 --- a/samples/fractals/mbhires.c +++ b/samples/fractals/mbhires.c @@ -3,29 +3,38 @@ #include #include +// Address of hires buffer and color buffer #define Screen ((char *)0xe000) #define Color ((char *)0xc800) int main(void) { + // Install the IRQ trampoline mmap_trampoline(); + // Turn of the kernal ROM mmap_set(MMAP_NO_ROM); + // Switch VIC into hires mode vic_setmode(VICM_HIRES, Color, Screen); + // Clear the screen memset(Screen, 0, 8000); memset(Color, 0x10, 1000); + // Loop over all pixels int py, px; for(py=0; py<200; py++) { for(px=0; px<320; px++) { + // Value in the complex plane + float xz = (float)px * (3.5 / 320.0)- 2.5; float yz = (float)py * (2.0 / 200.0) - 1.0; + // Iterate up to 32 times float x = 0.0, y = 0.0; int i; for(i=0; i<32; i++) @@ -37,15 +46,19 @@ int main(void) x = xt; } + // Set a pixel if exceeds bound in less than 32 iterations if (i < 32) Screen[320 * (py >> 3) + (py & 7) + (px & ~7)] |= 0x80 >> (px & 7); } } + // Re-enable the kernal mmap_set(MMAP_NO_BASIC); + // Wait for key press getch(); + // Restore VIC state vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); return 0; diff --git a/samples/fractals/mbmulti.c b/samples/fractals/mbmulti.c index 82f78e9..270a7be 100644 --- a/samples/fractals/mbmulti.c +++ b/samples/fractals/mbmulti.c @@ -3,10 +3,12 @@ #include #include +// Address of hires buffer and color buffers #define Screen ((char *)0xe000) #define Color ((char *)0xc800) #define Color2 ((char *)0xd800) +// Bit patters for eight different color pairs char colors[] = { 0xff, 0xff, 0xee, 0xbb, @@ -21,27 +23,35 @@ char colors[] = { int main(void) { + // Install the IRQ trampoline mmap_trampoline(); + // Turn of the kernal ROM mmap_set(MMAP_NO_ROM); + // Switch VIC into multicolor bitmap mode vic_setmode(VICM_HIRES_MC, Color, Screen); + // Clear the screen and set the colors vic.color_back = 0x00; memset(Screen, 0, 8000); memset(Color, 0x27, 1000); memset(Color2, 0x03, 1000); + // Loop over all pixels int py, px; for(py=0; py<100; py++) { for(px=0; px<160; px++) { + // Value in the complex plane + float xz = (float)px * (3.5 / 160.0)- 2.5; float yz = (float)py * (2.4 / 100.0) - 1.2; + // Iterate up to 32 times float x = 0.0, y = 0.0; int i; for(i=0; i<32; i++) @@ -55,21 +65,30 @@ int main(void) if (i < 32) { + // Position on screen char * dp = Screen + 320 * (py >> 2) + 2 * (py & 3) + 2 * (px & ~3); + + // Mask of pixels to change 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]; + + // Put the pixels into the image dp[0] |= c0 & mask; dp[1] |= c1 & mask; } } } + // Re-enable the kernal mmap_set(MMAP_NO_BASIC); + // Wait for key press getch(); + // Restore VIC state vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); - + return 0; } diff --git a/samples/fractals/mbmulti3d.c b/samples/fractals/mbmulti3d.c index a956c4c..78ccb6b 100644 --- a/samples/fractals/mbmulti3d.c +++ b/samples/fractals/mbmulti3d.c @@ -4,10 +4,12 @@ #include #include +// Address of hires buffer and color buffers #define Screen ((char *)0xe000) #define Color1 ((char *)0xc800) #define Color2 ((char *)0xd800) +// Bit patters for two different color pairs and eight shades byte colors[2][17] = { {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) { + // Clip boundaries if (py < 0) py = 0; if (ty > 100) ty = 100; + // Check if there are pixel to draw if (py < ty) { + // Calculate top address and mask char mask = 0xc0 >> (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; + + // Invert mask to cover the unchanged portion mask = ~mask; + + // Loop over all pixels char h = ty - py; while (h) { + // Apply color to memory dp[0] = (dp[0] & mask) | c0; dp[1] = (dp[1] & mask) | c1; + // Two pixel lines down dp += 2; if (!((int)dp & 7)) 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 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) } +// Calculate light with given new and old heights int light(float hl, float hu, float h) { float dx = h - hl, dz = h - hu, dy = 0.1; @@ -84,35 +98,45 @@ int light(float hl, float hu, float h) int main(void) { + // Install the IRQ trampoline mmap_trampoline(); + // Turn of the kernal ROM mmap_set(MMAP_NO_ROM); + // Switch VIC into multicolor bitmap mode vic_setmode(VICM_HIRES_MC, Color1, Screen); + // Clear the screen and set the colors vic.color_back = 0x00; vic.color_border = 0x00; memset(Screen, 0, 8000); memset(Color1, 0x26, 1000); memset(Color2, 0x0f, 1000); - + + // Height of previous row, needed for lighting float hl[200]; + // Rotation of complex plane float w = -0.7; float co = cos(w), si = sin(w); + // Loop from left to right for(int x=-1; x<160; x+= 1) { + // Loop from far to nead int py = 20; float hu = 0; for(int y=1; y<200; y+= 1) { + // Inverse 3D projection float fz = 2.0 / (float)y; float fx = (float)(x - 80) * fz / 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 dp = iter(rx, rz); float v = 2 * dp; @@ -120,20 +144,25 @@ int main(void) float fy = 5.0 * pow(2.0, - v * 0.4); + // Calculate light int ni = light(hl[y], hu, fy); + // Update left column hl[y] = fy; hu = fy; + // Forward 3D projection int ty = 20 + y / 2 + (int)(floor(fy / fz)); - int c; + // color of pixel + int c; if (dp != 32) c = 1 + ni + 8 * ((int)floor(dp) & 1); else c = 0; + // Draw line if not dummy left row if (x >= 0) VLine(x, py, ty, c); @@ -141,10 +170,13 @@ int main(void) } } + // Re-enable the kernal mmap_set(MMAP_NO_BASIC); + // Wait for key press getch(); + // Restore VIC state vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); return 0; diff --git a/samples/kernalio/charread.c b/samples/kernalio/charread.c index d723946..eb5072a 100644 --- a/samples/kernalio/charread.c +++ b/samples/kernalio/charread.c @@ -3,18 +3,24 @@ int main(void) { + // Set name for file and open it on drive 9 krnio_setnam("@0:CHARS,P,R"); if (krnio_open(2, 9, 2)) { + // Read bytes until failure int ch, k = 0; while ((ch = krnio_getch(2)) >= 0) { + // Print the value of the byte printf("%d : %d\n", k, ch) k++; + + // Exit the loop if this was the last byte of the file if (ch & 0x100) break; } + // Close the file krnio_close(2); } diff --git a/samples/kernalio/charwrite.c b/samples/kernalio/charwrite.c index 63e682f..0cc3a82 100644 --- a/samples/kernalio/charwrite.c +++ b/samples/kernalio/charwrite.c @@ -3,12 +3,18 @@ int main(void) { + // Set name for file and open it with replace on drive 9 krnio_setnam("@0:CHARS,P,W"); 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++) krnio_putch(2, i); + // Close the file again krnio_close(2); } diff --git a/samples/kernalio/fileread.c b/samples/kernalio/fileread.c index 9d058ed..7425cef 100644 --- a/samples/kernalio/fileread.c +++ b/samples/kernalio/fileread.c @@ -11,14 +11,18 @@ Score score[4]; int main(void) { + // Set name for file and open it on drive 9 krnio_setnam("HIGHSCORE,P,R"); if (krnio_open(2, 9, 2)) { + // Read the content of the file into the score arrayx krnio_read(2, (char*)score, sizeof(score)); + // Close the file krnio_close(2); } + // Print the result to stdout for(int i=0; i<4; i++) { printf("%s : %u\n", score[i].name, score[i].score); diff --git a/samples/kernalio/filewrite.c b/samples/kernalio/filewrite.c index 58147d4..9961a6a 100644 --- a/samples/kernalio/filewrite.c +++ b/samples/kernalio/filewrite.c @@ -16,11 +16,14 @@ Score score[] = { int main(void) { - krnio_setnam("@0:HIGHSCORE,P,W"); + // Set name for file and open it with replace on drive 9 + krnio_setnam("@0:HIGHSCORE,P,W"); if (krnio_open(2, 9, 2)) { + // Fill the file with the score array krnio_write(2, (char*)score, sizeof(score)); + // Close the file krnio_close(2); } diff --git a/samples/kernalio/hiresread.c b/samples/kernalio/hiresread.c index fdc1c0e..c4e73d7 100644 --- a/samples/kernalio/hiresread.c +++ b/samples/kernalio/hiresread.c @@ -12,27 +12,40 @@ Bitmap Screen; int main(void) { + // Install the IRQ trampoline mmap_trampoline(); + // Initialize the display bitmap bm_init(&Screen, ScreenMem, 40, 25); + // Clear the color memory with ROM and IO disabled mmap_set(MMAP_RAM); memset(ScreenMem, 0, 8000); memset(ColorMem, 0x70, 1000); mmap_set(MMAP_NO_ROM); + // Switch VIC to hires mode vic_setmode(VICM_HIRES, ColorMem, ScreenMem); + // Reenable the kernal rom mmap_set(MMAP_ROM); + + + // Set name for file and open it with replace on drive 9 krnio_setnam("TESTIMAGE,P,R"); if (krnio_open(2, 9, 2)) { + // Read the bitmap image in one go krnio_read(2, ScreenMem, 8000); + + // Close the file krnio_close(2); } + // Wait for a character getchar(); + // Restore VIC vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); return 0; diff --git a/samples/kernalio/hireswrite.c b/samples/kernalio/hireswrite.c index feed6ec..274bcdc 100644 --- a/samples/kernalio/hireswrite.c +++ b/samples/kernalio/hireswrite.c @@ -13,27 +13,34 @@ char Buffer[200]; int main(void) { + // Install the IRQ trampoline mmap_trampoline(); + // Initialize the display bitmap and a brush bm_init(&Screen, ScreenMem, 40, 25); bm_alloc(&Brush, 2, 2); + // Clear the color memory with ROM and IO disabled mmap_set(MMAP_RAM); memset(ScreenMem, 0, 8000); memset(ColorMem, 0x70, 1000); mmap_set(MMAP_NO_ROM); + // Switch VIC to hires mode vic_setmode(VICM_HIRES, ColorMem, ScreenMem); + // Draw the brush ClipRect crb = {0, 0, 16, 16}; bm_fill(&Brush, 0); bm_circle_fill(&Brush, &crb, 7, 7, 6, NineShadesOfGrey[8]); + // Draw the main image ClipRect crr = {0, 0, 320, 200}; 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, 200, 80, 20, NineShadesOfGrey[0]); + // And a smile for(int x=-40; x<=40; x+=4) { int y = bm_usqrt(50 * 50 - x * x); @@ -41,22 +48,32 @@ int main(void) } + // Reenable the kernal rom mmap_set(MMAP_ROM); + + // Set name for file and open it with replace on drive 9 krnio_setnam("@0:TESTIMAGE,P,W"); if (krnio_open(2, 9, 2)) { + // Loop in chunks of 200 bytes for(int i=0; i<8000; i+=200) { + // Disable ROM mmap_set(MMAP_NO_ROM); + // Copy chunk into buffer memcpy(Buffer, ScreenMem + i, 200); + // Reeable the ROM mmap_set(MMAP_ROM); + // Write the chunk to disk krnio_write(2, Buffer, 200); } + // Close the file krnio_close(2); } + // Restore the VIC vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000); return 0; diff --git a/samples/rasterirq/colorbars.c b/samples/rasterirq/colorbars.c index bbc1d46..5cafd62 100644 --- a/samples/rasterirq/colorbars.c +++ b/samples/rasterirq/colorbars.c @@ -2,25 +2,31 @@ #include #include - +// Prepare small 14 color bars and one IRQ for back to normal RIRQCode bars[15]; int main(void) { + // initialize raster IRQ rirq_init(true); for(int i=0; i<15; i++) { + // Build color change raster IRQ rirq_build(bars + i, 2); + // Change border color rirq_write(bars + i, 0, &vic.color_border, i); + // Change background color rirq_write(bars + i, 1, &vic.color_back, i); + // Place it on screen rirq_set(i, 80 + 8 * i, bars + i); } + // Sort all raster IRQs rirq_sort(); + // Start raster IRQs rirq_start(); - return 0; } diff --git a/samples/rasterirq/movingbars.c b/samples/rasterirq/movingbars.c index 85756e0..9483978 100644 --- a/samples/rasterirq/movingbars.c +++ b/samples/rasterirq/movingbars.c @@ -4,6 +4,8 @@ #include #include +// Five raster IRQs for top and bottom of the two chasing bars, and the bottom +// of the screen RIRQCode ftop, fbottom, btop, bbottom, final ; char sintab[256]; diff --git a/samples/rasterirq/openborder.c b/samples/rasterirq/openborder.c index f4c9b8b..dea6652 100644 --- a/samples/rasterirq/openborder.c +++ b/samples/rasterirq/openborder.c @@ -8,26 +8,36 @@ char spdata[] = { #embed "../resources/friendlybear.bin" }; +// Raster IRQs for last line of screen and below RIRQCode open, bottom; int main(void) { + // initialize raster IRQ rirq_init(true); + // Build open border raster IRQ rirq_build(&open, 1); + // Reduce vertical screen size to fool VIC counter 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); + // Build switch to normal raster IRQ rirq_build(&bottom, 1); rirq_write(&bottom, 0, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3 ); rirq_set(1, 50, &bottom); + // sort the raster IRQs rirq_sort(); + // start raster IRQ processing rirq_start(); + // Copy the sprite data memcpy((char *)0x0380, spdata, 128); + // Initialize sprites *(char *)(0x7f8) = 0x03c0 / 64; *(char *)(0x7f9) = 0x0380 / 64; *(char *)(0x7fa) = 0x03c0 / 64; @@ -52,6 +62,7 @@ int main(void) for(;;) { + // Move sprites through all vertical positions for(int i=0; i<255; i++) { vic_sprxy(0, 100, 1 * i); vic_sprxy(1, 100, 1 * i); diff --git a/samples/rasterirq/textcrawler.c b/samples/rasterirq/textcrawler.c index bdc9234..d3aa40b 100644 --- a/samples/rasterirq/textcrawler.c +++ b/samples/rasterirq/textcrawler.c @@ -10,29 +10,44 @@ const char * Text = S"CORPORIS, EOS? UNDE VERO ISTE QUIA? EAQUE EAQUE. IN. AUT ID " S"EXPEDITA ILLUM MOLESTIAS, "; +// Raster interrupt command structure for change to scrolled and back + RIRQCode scroll, bottom; int main(void) { + // initialize raster IRQ rirq_init(true); + // Build switch to scroll line IRQ rirq_build(&scroll, 1); + // Change control register two with this IRQ rirq_write(&scroll, 0, &vic.ctrl2, 0); + // Put it onto the scroll line rirq_set(0, 50 + 24 * 8, &scroll); + // Build the switch to normal IRQ rirq_build(&bottom, 1); + // re-enable left and right column and reset horizontal scroll rirq_write(&bottom, 0, &vic.ctrl2, VIC_CTRL2_CSEL); + // place this at the bottom rirq_set(1, 250, &bottom); + // sort the raster IRQs rirq_sort(); + // start raster IRQ processing rirq_start(); + // Loop through text int x = 0; for(;;) { + // wait for raster reaching bottom of screen rirq_wait(); + // Update raster IRQ for scroll line with new horizontal scroll offset rirq_data(&scroll, 0, 7 - (x & 7)); + // Copy scrolled version of text when switching over char border if ((x & 7) == 0) memcpy((char *)0x0400 + 40 * 24, Text + ((x >> 3) & 255), 40); x++; diff --git a/samples/scrolling/bigfont.c b/samples/scrolling/bigfont.c index 4107091..db5e0d6 100644 --- a/samples/scrolling/bigfont.c +++ b/samples/scrolling/bigfont.c @@ -4,6 +4,7 @@ byte font[2048]; +// Copy the system font into local RAM for easy access void copyFont(void) { mmap_set(MMAP_CHAR_ROM); @@ -13,15 +14,23 @@ void copyFont(void) mmap_set(MMAP_ROM); } +// 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)) + +// Start row for text #define srow 5 +// Move the screen one character to the left void scrollLeft(void) { + // Loop horizontaly for(char x=0; x<39; x++) { + // Unroll vetical loop 16 times #assign y 0 #repeat 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) { + // Address of glyph data byte * fp = font + 8 * c; + // Unroll eight times for each byte in glyph data #assign y 0 #repeat sline(39, srow + 2 * y + 0)[0] = @@ -54,28 +66,36 @@ const char * text = 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 + 40 * (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(); @@ -91,12 +111,16 @@ int main(void) 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++; } diff --git a/samples/scrolling/cgrid8way.c b/samples/scrolling/cgrid8way.c index a84bacd..d51a5c5 100644 --- a/samples/scrolling/cgrid8way.c +++ b/samples/scrolling/cgrid8way.c @@ -4,11 +4,15 @@ #include #include +// 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] = { { @@ -40,6 +44,7 @@ static const char quad[4][4 * 4] = #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; @@ -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) { 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 +// 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 @@ -100,6 +120,7 @@ void scroll_left(void) #until ty == VSPLIT } + // Update column #assign ty 0 #repeat sline(0, ty)[39] = news[ty]; @@ -107,9 +128,13 @@ void scroll_left(void) #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 @@ -120,6 +145,7 @@ void scroll_left(void) #until ty == 25 } + // Update new column #assign ty VSPLIT #repeat sline(0, ty)[39] = news[ty]; @@ -127,11 +153,16 @@ void scroll_left(void) #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(); @@ -185,6 +216,8 @@ void scroll_right(void) vic.ctrl2 = 0x04; } +// Scroll one character up in two pixel increments + void scroll_up(void) { vic_waitTop(); @@ -229,20 +262,36 @@ void scroll_up(void) 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 @@ -257,12 +306,12 @@ void scroll_down(void) } // 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++) { - tmp2[x] = sline(0, VSPLIT2)[x]; - tmp3[x] = cline(0, VSPLIT2)[x]; #assign ty VSPLIT2 #repeat @@ -275,6 +324,7 @@ void scroll_down(void) 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 @@ -288,9 +338,11 @@ void scroll_down(void) 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; @@ -302,11 +354,13 @@ char grid[16][16]; 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++) @@ -317,6 +371,7 @@ int main(void) char gridX = 0, gridY = 0; + // Inital drwaing of the screen char * dp = Screen, * cp = Color; for(char y=0; y<25; y++) { @@ -325,11 +380,18 @@ int main(void) cp += 40; } + // setup initial scroll offset + + vic.ctrl1 = 0x04 | VIC_CTRL1_DEN; + vic.ctrl2 = 0x04 + for(;;) { + // Check the joystick joy_poll(1); if (joyx[1] == 1) { + // Move to the right if (gridX < 24) { gridX++; @@ -339,6 +401,7 @@ int main(void) } else if (joyx[1] == -1) { + // Move to the left if (gridX > 0) { gridX--; @@ -348,6 +411,7 @@ int main(void) } else if (joyy[1] == 1) { + // Move down if (gridY < 39) { gridY++; @@ -357,6 +421,7 @@ int main(void) } else if (joyy[1] == -1) { + // Move up if (gridY > 0) { gridY--; diff --git a/samples/scrolling/colorram.c b/samples/scrolling/colorram.c index 60952e0..3f630c1 100644 --- a/samples/scrolling/colorram.c +++ b/samples/scrolling/colorram.c @@ -3,16 +3,22 @@ #include #include +// 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++) @@ -32,6 +38,7 @@ void scrollLeft0(void) #until y == SPLIT1 } +// Scroll bottom two sections void scrollLeft1(void) { for(char x=0; x<39; x++) @@ -67,7 +74,7 @@ void scrollLeft1(void) } - +// Prepare a new column with random data void prepcol(void) { for(char i=0; i<25; i++) @@ -80,6 +87,7 @@ void prepcol(void) int main(void) { + // Clear the screen memset(screen, 0x20, 1000); memset(color, 7, 1000); @@ -90,24 +98,33 @@ int main(void) 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(); diff --git a/samples/scrolling/grid2d.c b/samples/scrolling/grid2d.c index 42a6814..e3c8eb5 100644 --- a/samples/scrolling/grid2d.c +++ b/samples/scrolling/grid2d.c @@ -4,10 +4,14 @@ #include #include +// 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] = { { @@ -38,9 +42,11 @@ static const char quad[4][4 * 4] = #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; @@ -52,6 +58,8 @@ void expandrow0(char * dp, const char * grid, char ly) #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; @@ -72,6 +80,8 @@ void expandrow1(char * dp, const char * grid, char 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; @@ -92,6 +102,8 @@ void expandrow2(char * dp, const char * grid, char ly) 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; @@ -112,16 +124,24 @@ void expandrow3(char * dp, const char * grid, char ly) 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) { + // remainder of position, offset into the tile char ry = 4 * (py & 3); char rx = px & 3; + // target screen position 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++) { + // Update based on row (could be unrolled for inner groups of full tiles) switch (rx) { case 0: @@ -137,28 +157,35 @@ void expand(char * dp, const char * grid, char px, char py) expandrow3(cdp, cgrid, ry); break; } + + // Next row cdp += 40; ry += 4; + + // Next tile if (ry == 16) { ry = 0; - cgrid += 16; + cgrid += 32; } } } -char grid[16][16]; +char grid[32][32]; #pragma align(grid, 256) +// Raster IRQs for split screen + RIRQCode blank, scroll, bottom; 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; } @@ -166,18 +193,22 @@ int main(void) 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); @@ -187,46 +218,59 @@ int main(void) 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() & 127) == 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 > 10 * 8 * 4 * 32) + if (py < 0 || py > 26 * 8 * 4 * 32) { dy = -dy; py += dy; } px += dx; - if (px < 0 || px > 6 * 8 * 4 * 32) + if (px < 0 || px > 22 * 8 * 4 * 32) { dx = -dx; px += dx; diff --git a/samples/scrolling/tunnel.c b/samples/scrolling/tunnel.c index 2b5525f..0046c18 100644 --- a/samples/scrolling/tunnel.c +++ b/samples/scrolling/tunnel.c @@ -3,14 +3,20 @@ #include #include +// 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]; @@ -18,8 +24,13 @@ void expand(char x) #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 @@ -34,6 +45,7 @@ void scrollLeft(void) #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 @@ -49,6 +61,10 @@ void scrollLeft(void) #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--) @@ -80,19 +96,26 @@ void scrollRight(void) #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 0) @@ -112,6 +136,7 @@ void prepcol(char xi) } +// Initialize tunnel with "random" data void buildTunnel(void) { signed char yt = 1, yb = 24, dyt = 1, dyb = -1; @@ -152,49 +177,64 @@ void buildTunnel(void) 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) diff --git a/samples/sprites/joycontrol.c b/samples/sprites/joycontrol.c index 6d816ac..05bda69 100644 --- a/samples/sprites/joycontrol.c +++ b/samples/sprites/joycontrol.c @@ -12,29 +12,38 @@ int spx, spy; int main(void) { + // Copy the sprite data memcpy(SpriteData, spdata, 128); + // Initalize 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(1); + // Change position according to joystick spx += joyx[1]; spy += joyy[1]; + // Move sprites on screen spr_move(0, spx, spy); spr_move(1, spx, spy); + // Wait for one frame iteration vic_waitFrame(); }