initial commit
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
( cd fractals ; ./build.sh )
|
||||
|
||||
( cd games ; ./build.sh )
|
||||
|
||||
( cd hires ; ./build.sh )
|
||||
|
||||
( cd hiresmc ; ./build.sh )
|
||||
|
||||
( cd particles ; ./build.sh )
|
||||
|
||||
( cd kernalio ; ./build.sh )
|
||||
|
||||
( cd memmap ; ./build.sh )
|
||||
|
||||
( cd rasterirq ; ./build.sh )
|
||||
|
||||
( cd scrolling ; ./build.sh )
|
||||
|
||||
( cd sprites ; ./build.sh )
|
||||
|
||||
( cd stdio ; ./build.sh )
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 mbtext.c -n
|
||||
../../bin/oscar64 mbhires.c -n
|
||||
../../bin/oscar64 mbmulti.c -n
|
||||
../../bin/oscar64 mbmulti3d.c -n
|
||||
../../bin/oscar64 mbfixed.c -n -O3
|
||||
../../bin/oscar64 mbzoom.c -n -O3
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
call ..\..\bin\oscar64 mbtext.c -n
|
||||
call ..\..\bin\oscar64 mbhires.c -n
|
||||
call ..\..\bin\oscar64 mbmulti.c -n
|
||||
call ..\..\bin\oscar64 mbmulti3d.c -n
|
||||
call ..\..\bin\oscar64 mbfixed.c -n -O3
|
||||
call ..\..\bin\oscar64 mbzoom.c -n -O3
|
||||
@@ -0,0 +1,14 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: mbtext.prg mbtext.prg mbhires.prg mbmulti.prg mbmulti3d.prg mbfixed.prg mbzoom.prg
|
||||
|
||||
mbfixed.prg: mbfixed.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) -O3 $<
|
||||
|
||||
mbzoom.prg: mbzoom.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) -O3 $<
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <string.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <conio.h>
|
||||
#include <fixmath.h>
|
||||
|
||||
// Address of hires buffer and color buffers
|
||||
#define Screen ((char *)0xe000)
|
||||
#define Color ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
|
||||
// Bit patterns for eight different color pairs
|
||||
char colors[] = {
|
||||
0xff, 0xff,
|
||||
0xee, 0xbb,
|
||||
0xaa, 0xaa,
|
||||
0x88, 0x22,
|
||||
|
||||
0x44, 0x11,
|
||||
0x55, 0x55,
|
||||
0xdd, 0x77,
|
||||
0x33, 0xcc
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
// int xz = (int)(((float)px * (3.5 / 160.0) - 2.5) * 4096 + 0.5);
|
||||
// int yz = (int)(((float)py * (2.4 / 100.0) - 1.2) * 4096 + 0.5);
|
||||
|
||||
int xz = lmul8f8s(px, (int)((3.5 / 160.0) * 4096 * 256)) - (int)(2.5 * 4096);
|
||||
int yz = lmul8f8s(py, (int)((2.4 / 100.0) * 4096 * 256)) - (int)(1.2 * 4096);
|
||||
|
||||
// Iterate up to 32 times
|
||||
int x = 0, y = 0;
|
||||
int i;
|
||||
for(i=0; i<32; i++)
|
||||
{
|
||||
unsigned long xq = lsqr4f12s(x), yq = lsqr4f12s(y);
|
||||
|
||||
if (xq + yq >= 0x04000000UL) break;
|
||||
|
||||
int xt = (int)(xq >> 12) - (int)(yq >> 12) + xz;
|
||||
y = 2 * lmul4f12s(x, y) + yz;
|
||||
x = xt;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <string.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <conio.h>
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if (x * x + y * y > 4.0) break;
|
||||
|
||||
float xt = x * x - y * y + xz;
|
||||
y = 2 * x * y + yz;
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include <string.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <conio.h>
|
||||
|
||||
// Address of hires buffer and color buffers
|
||||
#define Screen ((char *)0xe000)
|
||||
#define Color ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
|
||||
// Bit patterns for eight different color pairs
|
||||
char colors[] = {
|
||||
0xff, 0xff,
|
||||
0xee, 0xbb,
|
||||
0xaa, 0xaa,
|
||||
0x88, 0x22,
|
||||
|
||||
0x44, 0x11,
|
||||
0x55, 0x55,
|
||||
0xdd, 0x77,
|
||||
0x33, 0xcc
|
||||
};
|
||||
|
||||
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++)
|
||||
{
|
||||
if (x * x + y * y > 4.0) break;
|
||||
|
||||
float xt = x * x - y * y + xz;
|
||||
y = 2 * x * y + yz;
|
||||
x = xt;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
#include <string.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
|
||||
// Address of hires buffer and color buffers
|
||||
#define Screen ((char *)0xe000)
|
||||
#define Color1 ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
|
||||
// Bit patterns for two different color pairs and eight shades
|
||||
byte colors[2][17] =
|
||||
{
|
||||
{0x00,
|
||||
0x44, 0x44, 0x55, 0x55, 0xdd, 0xdd, 0xff, 0xff,
|
||||
0x88, 0x88, 0xaa, 0xaa, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
{0x00,
|
||||
0x00, 0x11, 0x11, 0x55, 0x55, 0x77, 0x77, 0xff,
|
||||
0x00, 0x22, 0x22, 0xaa, 0xaa, 0xbb, 0xbb, 0xff,
|
||||
}
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
h--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate up to 32 iterations and return a smoothed height
|
||||
float iter(float xz, float yz)
|
||||
{
|
||||
float x = 0.0, y = 0.0, r;
|
||||
int i;
|
||||
for(i=0; i<32; i++)
|
||||
{
|
||||
r = x * x + y * y;
|
||||
if (r > 64.0) break;
|
||||
|
||||
float xt = x * x - y * y + xz;
|
||||
y = 2 * x * y + yz;
|
||||
x = xt;
|
||||
}
|
||||
|
||||
|
||||
if (i == 32)
|
||||
return 32;
|
||||
else
|
||||
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;
|
||||
|
||||
float dd = sqrt(dx * dx + dy * dy + dz * dz);
|
||||
int ni = (int)floor((-2 * dx + dy + dz) / dd * 0.408 * 8);
|
||||
if (ni < 0) ni = 0; else if (ni > 7) ni = 7;
|
||||
|
||||
return ni;
|
||||
}
|
||||
|
||||
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;
|
||||
if (v < 1.0) v = 1.0;
|
||||
|
||||
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));
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
py = ty;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,36 @@
|
||||
#include <string.h>
|
||||
|
||||
#define Screen ((char *)0x0400)
|
||||
#define Color ((char *)0xd800)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
memset(Screen, 160, 1024);
|
||||
|
||||
int py, px;
|
||||
|
||||
for(py=0; py<25; py++)
|
||||
{
|
||||
for(px=0; px<40; px++)
|
||||
{
|
||||
float xz = (float)px * (3.5 / 40.0)- 2.5;
|
||||
float yz = (float)py * (2.0 / 25.0) - 1.0;
|
||||
|
||||
float x = 0.0, y = 0.0;
|
||||
int i;
|
||||
for(i=0; i<=14; i++)
|
||||
{
|
||||
if (x * x + y * y > 4.0) break;
|
||||
|
||||
float xt = x * x - y * y + xz;
|
||||
y = 2 * x * y + yz;
|
||||
x = xt;
|
||||
}
|
||||
i--;
|
||||
|
||||
Color[py * 40 + px] = i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <c64/vic.h>
|
||||
|
||||
#define Screen ((char *)0x0400)
|
||||
#define Color ((char *)0xd800)
|
||||
|
||||
// Lookup table for squares from 0..255
|
||||
__striped unsigned sqb[256];
|
||||
|
||||
// Shift byte right and left by 4
|
||||
char shlb4[256], shrb4[256];
|
||||
|
||||
#pragma align(sqb, 256);
|
||||
|
||||
// Square an unsigned int into an unsigned long
|
||||
inline unsigned long ssquare(unsigned x)
|
||||
{
|
||||
// Split into low byte and highbyte, so we have x = a + 0x100 * b
|
||||
|
||||
unsigned a = x & 0xff;
|
||||
unsigned b = x >> 8;
|
||||
|
||||
// So now we calculate (a + 0x100 * b)²
|
||||
// Result will be a² + 0x100 * 2 * a * b + 0x10000 * b²
|
||||
// with 2 * a * b == (a + b)² - a² - b²
|
||||
|
||||
// We can cover all cases with the square table except if a + b >= 0x100
|
||||
// in this case we have abp := a + b - 0x100
|
||||
// (abp + 0x100)² == abp² + 2 * 0x100 * abp + 0x10000
|
||||
|
||||
// Get squares of the bytes and the sum of the bytes
|
||||
unsigned a2 = sqb[a], b2 = sqb[b];
|
||||
unsigned apb = a + b;
|
||||
|
||||
// First approximation approximation
|
||||
// a² + 0x10000 * b²
|
||||
unsigned long sum = a2 + ((unsigned long)b2 << 16);
|
||||
|
||||
// Check if a + b >= 0x100
|
||||
if (apb & 0xff00)
|
||||
{
|
||||
apb &= 0xff;
|
||||
sum += 0x1000000UL;
|
||||
sum += (unsigned long)apb << 17;
|
||||
sum += (unsigned long)sqb[apb] << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
apb &= 0xff;
|
||||
sum += (unsigned long)sqb[apb] << 8;
|
||||
}
|
||||
|
||||
// Now w have a² + 0x1000 * b² + (a + b)²
|
||||
|
||||
sum -= (unsigned long)a2 << 8;
|
||||
sum -= (unsigned long)b2 << 8;
|
||||
|
||||
// And finally the complete result
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Signed square of x
|
||||
inline long sq(int x)
|
||||
{
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
return ssquare(x);
|
||||
}
|
||||
|
||||
// Colors to fill in the different levels
|
||||
static const char colors[32] = {
|
||||
VCOL_BLUE,
|
||||
VCOL_LT_BLUE,
|
||||
VCOL_WHITE,
|
||||
VCOL_LT_GREEN,
|
||||
VCOL_GREEN,
|
||||
VCOL_YELLOW,
|
||||
VCOL_ORANGE,
|
||||
VCOL_RED,
|
||||
VCOL_PURPLE,
|
||||
|
||||
VCOL_BLUE,
|
||||
VCOL_BLUE,
|
||||
VCOL_LT_BLUE,
|
||||
VCOL_LT_BLUE,
|
||||
VCOL_WHITE,
|
||||
VCOL_WHITE,
|
||||
VCOL_LT_GREEN,
|
||||
VCOL_LT_GREEN,
|
||||
VCOL_GREEN,
|
||||
VCOL_GREEN,
|
||||
VCOL_YELLOW,
|
||||
VCOL_YELLOW,
|
||||
VCOL_ORANGE,
|
||||
VCOL_ORANGE,
|
||||
VCOL_RED,
|
||||
VCOL_RED,
|
||||
VCOL_PURPLE,
|
||||
VCOL_PURPLE,
|
||||
|
||||
VCOL_LT_GREY,
|
||||
VCOL_LT_GREY,
|
||||
VCOL_MED_GREY,
|
||||
VCOL_MED_GREY,
|
||||
VCOL_DARK_GREY,
|
||||
};
|
||||
|
||||
inline int shr12(long l)
|
||||
{
|
||||
char b3 = (l >> 24) & 0xff;
|
||||
char b2 = (l >> 16) & 0xff;
|
||||
char b1 = (l >> 8) & 0xff;
|
||||
char a0 = shrb4[b1] | shlb4[b2];
|
||||
char a1 = shrb4[b2] | shlb4[b3];
|
||||
return a0 | (a1 << 8);
|
||||
}
|
||||
|
||||
// Return color for a given coordinate in the complex plane using
|
||||
// 12.4bit fixed numbers using m'=m²+b
|
||||
|
||||
inline char fcolor(int xz, int yz)
|
||||
{
|
||||
// Start value for iteration is the offset value itself
|
||||
|
||||
int x = xz, y = yz;
|
||||
|
||||
// Iterate up to 32 steps
|
||||
|
||||
for(int i=0; i<32; i++)
|
||||
{
|
||||
// Build squares of real and imaginary component
|
||||
long xx = sq(x), yy = sq(y), xxyy = sq(x + y);
|
||||
|
||||
long xxpyy = xx + yy;
|
||||
|
||||
// Use squares to check for exit condition of sure
|
||||
// to progress towards infinity
|
||||
if (xxpyy >= 4L * 4096 * 4096) return colors[i];
|
||||
|
||||
// Next iteration values using complex arithmetic
|
||||
// Mx' = Mx² - My² + Bx
|
||||
// My' = 2 * Mx * My + By = (Mx + My)² - Mx² - My² + By
|
||||
x = shr12(xx - yy + 2048) + xz;
|
||||
y = shr12(xxyy - xxpyy + 2048) + yz;
|
||||
}
|
||||
|
||||
// More than maximum number of iterations, so assume progress
|
||||
// towards zero
|
||||
|
||||
return VCOL_BLACK;
|
||||
}
|
||||
|
||||
// Fill a row with color
|
||||
void fill_row(char py, int cix, int yz, int cis)
|
||||
{
|
||||
int xz = cix;
|
||||
for(int px=0; px<40; px++)
|
||||
{
|
||||
Color[py * 40 + px] = fcolor(xz, yz);
|
||||
xz += cis;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill a column with color
|
||||
void fill_column(char px, int xz, int ciy, int cis)
|
||||
{
|
||||
int yz = ciy;
|
||||
for(int py=0; py<25; py++)
|
||||
{
|
||||
Color[py * 40 + px] = fcolor(xz, yz);
|
||||
yz += cis;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the complete image
|
||||
void fill_image(int cix, int ciy, int cis)
|
||||
{
|
||||
int yz = ciy;
|
||||
for(int py=0; py<25; py++)
|
||||
{
|
||||
fill_row(py, cix, yz, cis);
|
||||
yz += cis;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll screen to the left
|
||||
void scroll_left(void)
|
||||
{
|
||||
for(char x=0; x<39; x++)
|
||||
{
|
||||
#pragma unroll(full)
|
||||
for(char y=0; y<25; y++)
|
||||
{
|
||||
Color[y * 40 + x] = Color[y * 40 + x + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll screen to the right
|
||||
void scroll_right(void)
|
||||
{
|
||||
for(signed char x=38; x>=0; x--)
|
||||
{
|
||||
#pragma unroll(full)
|
||||
for(char y=0; y<25; y++)
|
||||
{
|
||||
Color[y * 40 + x + 1] = Color[y * 40 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll screen up
|
||||
void scroll_up(void)
|
||||
{
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#pragma unroll(full)
|
||||
for(char y=0; y<24; y++)
|
||||
{
|
||||
Color[y * 40 + x] = Color[(y + 1) * 40 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll screen down
|
||||
void scroll_down(void)
|
||||
{
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#pragma unroll(full)
|
||||
for(char y=0; y<24; y++)
|
||||
{
|
||||
Color[(24 - y) * 40 + x] = Color[(23 - y) * 40 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialize square table
|
||||
for(unsigned i=0; i<256; i++)
|
||||
{
|
||||
sqb[i] = i * i;
|
||||
shlb4[i] = i << 4;
|
||||
shrb4[i] = i >> 4;
|
||||
}
|
||||
|
||||
// Clear screen
|
||||
memset(Screen, 160, 1024);
|
||||
|
||||
// Start coordinates in float
|
||||
float cx = -0.4;
|
||||
float cy = 0.0;
|
||||
float cw = 3.2;
|
||||
|
||||
// Convert to top, left and step in 12.4 fixed point
|
||||
int cix = (int)((cx - 0.5 * cw) * 4096);
|
||||
int ciy = (int)((cy - 12.0 * cw / 40.0) * 4096);
|
||||
int cis = (int)(cw / 40.0 * 4096);
|
||||
|
||||
// Initial image
|
||||
fill_image(cix, ciy, cis);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Wait for keypress
|
||||
char ch = getch();
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case 'S':
|
||||
ciy += cis;
|
||||
scroll_up();
|
||||
fill_row(24, cix, ciy + 24 * cis, cis);
|
||||
break;
|
||||
case 'W':
|
||||
ciy -= cis;
|
||||
scroll_down();
|
||||
fill_row(0, cix, ciy, cis);
|
||||
break;
|
||||
case 'A':
|
||||
cix -= cis;
|
||||
scroll_right();
|
||||
fill_column(0, cix, ciy, cis);
|
||||
break;
|
||||
case 'D':
|
||||
cix += cis;
|
||||
scroll_left();
|
||||
fill_column(39, cix + 39 * cis, ciy, cis);
|
||||
break;
|
||||
case '+':
|
||||
cix += 20 * cis;
|
||||
ciy += 12 * cis;
|
||||
cis = cis * 2 / 3;
|
||||
cix -= 20 * cis;
|
||||
ciy -= 12 * cis;
|
||||
fill_image(cix, ciy, cis);
|
||||
break;
|
||||
case '-':
|
||||
cix += 20 * cis;
|
||||
ciy += 12 * cis;
|
||||
cis = cis * 3 / 2;
|
||||
cix -= 20 * cis;
|
||||
ciy -= 12 * cis;
|
||||
fill_image(cix, ciy, cis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <c64/sid.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Character set
|
||||
char charset[2048] = {
|
||||
#embed "../resources/breakoutchars.bin"
|
||||
};
|
||||
|
||||
char spriteset[2048] = {
|
||||
#embed "../resources/breakoutsprites.bin"
|
||||
};
|
||||
|
||||
byte * const Screen = (byte *)0xc800;
|
||||
byte * const Font = (byte *)0xd000;
|
||||
byte * const Color = (byte *)0xd800;
|
||||
byte * const Sprites = (byte *)0xd800;
|
||||
|
||||
unsigned flashingBricks[32];
|
||||
char numFlashingBricks[4];
|
||||
|
||||
// 0123456789012345678901234567890123456789
|
||||
const char StatusText[] = s" Score: 000000 High: 000000 Lives: 0 ";
|
||||
|
||||
void status_init(void)
|
||||
{
|
||||
for(char i=0; i<40; i++)
|
||||
{
|
||||
if (StatusText[i] != ' ')
|
||||
{
|
||||
Screen[i] = StatusText[i];
|
||||
Color[i] = 7;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Increment the score from a given digit on
|
||||
void score_inc(char digit, unsigned val)
|
||||
{
|
||||
// Lowest digit to increment
|
||||
char at = 13 - digit;
|
||||
|
||||
// Loop while there is still score to account for
|
||||
while (val)
|
||||
{
|
||||
// Increment one character
|
||||
char ch = Screen[at] + val % 10;
|
||||
|
||||
// Remove low digit from number
|
||||
val /= 10;
|
||||
|
||||
// Check overflow
|
||||
if (ch > '9')
|
||||
{
|
||||
ch -= 10;
|
||||
val++;
|
||||
}
|
||||
|
||||
Screen[at] = ch;
|
||||
|
||||
// Next higher character
|
||||
at --;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset score and update high score
|
||||
void score_reset(void)
|
||||
{
|
||||
// Find first digit, where score and highscore differ
|
||||
char i = 0;
|
||||
while (i < 6 && Screen[i + 8] == Screen[i + 22])
|
||||
i++;
|
||||
|
||||
// Check if new score is higher
|
||||
if (i < 6 && Screen[i + 8] > Screen[i + 22])
|
||||
{
|
||||
// If so, copy to highscore
|
||||
while (i < 6)
|
||||
{
|
||||
Screen[i + 22] = Screen[i + 8];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear score
|
||||
for(char i=0; i<6; i++)
|
||||
Screen[i + 8] = '0';
|
||||
}
|
||||
|
||||
void brick_put(char x, char y, char b, char c)
|
||||
{
|
||||
char * cp = Color + 40 * y + x;
|
||||
|
||||
cp[ 0] = c;
|
||||
cp[ 1] = c;
|
||||
cp[ 2] = c;
|
||||
cp[40] = c;
|
||||
cp[41] = c;
|
||||
cp[42] = c;
|
||||
cp[81] = 15;
|
||||
cp[82] = 15;
|
||||
cp[83] = 15;
|
||||
|
||||
char * sp = Screen + 40 * y + x;
|
||||
|
||||
sp[ 0] = b | 0;
|
||||
sp[ 1] = b | 1;
|
||||
sp[ 2] = b | 2;
|
||||
|
||||
sp[40] = b | 3;
|
||||
sp[41] = b | 4;
|
||||
sp[42] = b | 5;
|
||||
sp[43] = 103 - (x & 1) - 2 * (y & 1);
|
||||
|
||||
sp[81] = 101 - (x & 1) + 2 * (y & 1);
|
||||
sp[82] = 100 + (x & 1) + 2 * (y & 1);
|
||||
sp[83] = 101 - (x & 1) + 2 * (y & 1);
|
||||
}
|
||||
|
||||
void brick_init(void)
|
||||
{
|
||||
for(char y=0; y<25; y++)
|
||||
{
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
Screen[40 * y + x] = 96 + (x & 1) + 2 * (y & 1);// + 4 * (x == 0 || y == 0);
|
||||
}
|
||||
}
|
||||
|
||||
status_init();
|
||||
|
||||
for(char y=0; y<8; y++)
|
||||
{
|
||||
for(char x=0; x<12; x++)
|
||||
{
|
||||
brick_put(3 * x + 2, 2 * y + 1, 128 + (x / 4) * 8, 8 + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void brick_hit(char x, char y)
|
||||
{
|
||||
__assume(x < 40 && y < 25);
|
||||
|
||||
char c = Screen[40 * y + x + 0];
|
||||
|
||||
if (c >= 128)
|
||||
{
|
||||
c &= 7;
|
||||
|
||||
if (c >= 3)
|
||||
{
|
||||
y --;
|
||||
c -= 3;
|
||||
}
|
||||
|
||||
x -= c;
|
||||
|
||||
unsigned bi = 256 * y + x;
|
||||
char i = 0, n = numFlashingBricks[3];
|
||||
while (i < n && flashingBricks[i] != bi)
|
||||
i++;
|
||||
|
||||
if (i == n)
|
||||
{
|
||||
flashingBricks[i] = bi;
|
||||
numFlashingBricks[3]++;
|
||||
|
||||
char * cp = Color + 40 * y + x;
|
||||
|
||||
cp[ 0] = 9;
|
||||
cp[ 1] = 9;
|
||||
cp[ 2] = 9;
|
||||
cp[40] = 9;
|
||||
cp[41] = 9;
|
||||
cp[42] = 9;
|
||||
|
||||
score_inc(0, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void brick_animate(void)
|
||||
{
|
||||
char n = numFlashingBricks[0];
|
||||
|
||||
for(char i=0; i<n; i++)
|
||||
{
|
||||
char x = flashingBricks[i] & 0xff;
|
||||
char y = flashingBricks[i] >> 8;
|
||||
|
||||
char * cp = Color + 40 * y + x;
|
||||
|
||||
cp[ 0] = 15;
|
||||
cp[ 1] = 15;
|
||||
cp[ 2] = 15;
|
||||
cp[40] = 15;
|
||||
cp[41] = 15;
|
||||
cp[42] = 15;
|
||||
|
||||
char * sp = Screen + 40 * (y - 1) + (x - 1);
|
||||
|
||||
char ch = 96 + (x & 1) + 2 * (y & 1);
|
||||
if (sp[ 0] >= 128)
|
||||
sp[41] = ch | 4;
|
||||
else
|
||||
sp[41] = ch;
|
||||
|
||||
if (sp[ 1] >= 128)
|
||||
sp[42] = (ch ^ 1) | 4;
|
||||
else
|
||||
sp[42] = (ch ^ 1);
|
||||
|
||||
if (sp[ 2] >= 128)
|
||||
sp[43] = ch | 4;
|
||||
else
|
||||
sp[43] = ch;
|
||||
|
||||
if (sp[40] >= 128)
|
||||
sp[81] = (ch ^ 2) | 4;
|
||||
else
|
||||
sp[81] = (ch ^ 2);
|
||||
|
||||
sp[82] = (ch ^ 3);
|
||||
sp[83] = (ch ^ 2);
|
||||
|
||||
if (sp[84] < 128)
|
||||
sp[84] = (ch ^ 3);
|
||||
|
||||
if (sp[122] < 128)
|
||||
sp[122] = (ch ^ 1);
|
||||
if (sp[123] < 128)
|
||||
sp[123] = ch;
|
||||
if (sp[124] < 128)
|
||||
sp[124] = (ch ^ 1);
|
||||
}
|
||||
|
||||
for(char i=0; i<3; i++)
|
||||
numFlashingBricks[i] = numFlashingBricks[i + 1] - n;
|
||||
numFlashingBricks[3] = numFlashingBricks[2];
|
||||
|
||||
for(char i=0; i<numFlashingBricks[3]; i++)
|
||||
flashingBricks[i] = flashingBricks[i + n];
|
||||
}
|
||||
|
||||
struct Ball
|
||||
{
|
||||
char index;
|
||||
bool active;
|
||||
int sx, sy, vx, vy;
|
||||
};
|
||||
|
||||
// using 10.6 bit fixed point math
|
||||
|
||||
#define BALL_INT(x) ((x) >> 6)
|
||||
#define BALL_COORD(x, f) (((x) << 6) + f)
|
||||
|
||||
void ball_init(Ball * ball, char index, int sx, int sy, int vx, int vy)
|
||||
{
|
||||
ball->index = index;
|
||||
ball->active = true;
|
||||
ball->sx = sx;
|
||||
ball->sy = sy;
|
||||
ball->vx = vx;
|
||||
ball->vy = vy;
|
||||
|
||||
int ix = BALL_INT(ball->sx) + 24, iy = BALL_INT(ball->sy) + 50;
|
||||
|
||||
spr_set(2 * index + 2, true, ix, iy, 97, 0, false, false, false);
|
||||
spr_set(2 * index + 3, true, ix, iy, 96, 15, true, false, false);
|
||||
}
|
||||
|
||||
void ball_lost(Ball * ball)
|
||||
{
|
||||
ball->active = false;
|
||||
|
||||
spr_show(2 * ball->index + 2, false);
|
||||
spr_show(2 * ball->index + 3, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#define COL_00 1
|
||||
#define COL_01 2
|
||||
#define COL_10 4
|
||||
#define COL_11 8
|
||||
|
||||
int paddlex, paddlevx;
|
||||
|
||||
char sound_index;
|
||||
unsigned sound_freq;
|
||||
|
||||
void sound_trigger(unsigned freq)
|
||||
{
|
||||
sound_freq = freq;
|
||||
if (sound_index == 0)
|
||||
sound_index = 3;
|
||||
else if (sound_index > 6)
|
||||
sound_index = 1;
|
||||
}
|
||||
|
||||
void sound_loop(void)
|
||||
{
|
||||
switch (sound_index)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
case 18:
|
||||
sid.voices[0].ctrl = 0;
|
||||
sid.voices[0].attdec = 0;
|
||||
sid.voices[0].susrel = 0;
|
||||
sound_index++;
|
||||
break;
|
||||
case 2:
|
||||
case 19:
|
||||
sid.voices[0].ctrl = SID_CTRL_TEST;
|
||||
sound_index++;
|
||||
break;
|
||||
case 3:
|
||||
sid.voices[0].freq = sound_freq;
|
||||
sid.voices[0].attdec = SID_ATK_2 | SID_DKY_6;
|
||||
sid.voices[0].susrel = SID_DKY_300 | 0xf0;
|
||||
sid.voices[0].pwm = 0x800;
|
||||
sid.voices[0].ctrl = SID_CTRL_RECT | SID_CTRL_GATE | SID_CTRL_NOISE;
|
||||
sound_index++;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
sound_index++;
|
||||
break;
|
||||
case 6:
|
||||
sound_index++;
|
||||
sid.voices[0].ctrl = SID_CTRL_RECT;
|
||||
break;
|
||||
case 20:
|
||||
sound_index = 0;
|
||||
break;
|
||||
default:
|
||||
sound_index++;
|
||||
}
|
||||
}
|
||||
|
||||
void ball_loop(Ball * ball)
|
||||
{
|
||||
if (!ball->active)
|
||||
return;
|
||||
|
||||
ball->sx += ball->vx;
|
||||
ball->sy += ball->vy;
|
||||
|
||||
bool mirrorX = false, mirrorY = false;
|
||||
|
||||
int ix = BALL_INT(ball->sx), iy = BALL_INT(ball->sy);
|
||||
int px = BALL_INT(paddlex);
|
||||
|
||||
if (ix + 6 > 320 || ix < 0)
|
||||
{
|
||||
mirrorX = true;
|
||||
sound_trigger(NOTE_D(6));
|
||||
}
|
||||
|
||||
if (iy < 0)
|
||||
{
|
||||
mirrorY = true;
|
||||
sound_trigger(NOTE_D(6));
|
||||
}
|
||||
else if (iy >= 200)
|
||||
{
|
||||
ball_lost(ball);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iy + 6 > 190 && iy < 190)
|
||||
{
|
||||
if (ix + 5 >= px && ix < px + 48)
|
||||
{
|
||||
mirrorY = true;
|
||||
if (ix < px && ball->vx > 0)
|
||||
{
|
||||
mirrorX = true;
|
||||
}
|
||||
else if (ix + 6 >= px + 48 && ball->vx < 0)
|
||||
{
|
||||
mirrorX = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ball->vx = (ball->vx * 6 + paddlevx + 4) >> 3;
|
||||
}
|
||||
|
||||
sound_trigger(NOTE_D(7));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int x0 = ix >> 3;
|
||||
int y0 = iy >> 3;
|
||||
int x1 = (ix + 5) >> 3;
|
||||
int y1 = (iy + 5) >> 3;
|
||||
|
||||
|
||||
if (x0 >= 0 && x1 < 40 && y0 >= 0 && y1 < 24)
|
||||
{
|
||||
char col = 0;
|
||||
bool hit = false;
|
||||
|
||||
if (Screen[40 * y0 + x0] >= 128) col |= COL_00;
|
||||
if (Screen[40 * y0 + x1] >= 128) col |= COL_01;
|
||||
if (Screen[40 * y1 + x0] >= 128) col |= COL_10;
|
||||
if (Screen[40 * y1 + x1] >= 128) col |= COL_11;
|
||||
|
||||
if (ball->vx < 0 && ((col & (COL_00 | COL_01)) == COL_00) || ((col & (COL_10 | COL_11)) == COL_10))
|
||||
{
|
||||
mirrorX = true;
|
||||
hit = true;
|
||||
}
|
||||
else if (ball->vx > 0 && ((col & (COL_00 | COL_01)) == COL_01) || ((col & (COL_10 | COL_11)) == COL_11))
|
||||
{
|
||||
mirrorX = true;
|
||||
hit = true;
|
||||
}
|
||||
|
||||
if (ball->vy < 0 && ((col & (COL_00 | COL_10)) == COL_00) || ((col & (COL_01 | COL_11)) == COL_01))
|
||||
{
|
||||
mirrorY = true;
|
||||
hit = true;
|
||||
}
|
||||
else if (ball->vy > 0 && ((col & (COL_00 | COL_10)) == COL_10) || ((col & (COL_01 | COL_11)) == COL_11))
|
||||
{
|
||||
mirrorY = true;
|
||||
hit = true;
|
||||
}
|
||||
|
||||
if (col)
|
||||
{
|
||||
brick_hit(x0, y0);
|
||||
brick_hit(x1, y0);
|
||||
brick_hit(x0, y1);
|
||||
brick_hit(x1, y1);
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
sound_trigger(NOTE_D(8));
|
||||
}
|
||||
}
|
||||
|
||||
if (mirrorY)
|
||||
{
|
||||
ball->vy = - ball->vy;
|
||||
ball->sy += ball->vy;
|
||||
}
|
||||
if (mirrorX)
|
||||
{
|
||||
ball->vx = - ball->vx;
|
||||
ball->sx += ball->vx;
|
||||
}
|
||||
}
|
||||
|
||||
void ball_move(Ball * ball)
|
||||
{
|
||||
int ix = BALL_INT(ball->sx) + 24, iy = BALL_INT(ball->sy) + 50;
|
||||
|
||||
spr_move(2 * ball->index + 2, ix, iy);
|
||||
spr_move(2 * ball->index + 3, ix, iy);
|
||||
}
|
||||
|
||||
enum GameState
|
||||
{
|
||||
GS_READY, // Getting ready
|
||||
|
||||
GS_BALL_LOCKED, // The ball is locked on the paddle
|
||||
GS_PLAYING, // Playing the game
|
||||
GS_BALL_DROPPED, // The last ball has been dropped
|
||||
|
||||
GS_GAME_OVER
|
||||
};
|
||||
|
||||
struct Game
|
||||
{
|
||||
GameState state;
|
||||
Ball balls[3];
|
||||
char count;
|
||||
|
||||
} TheGame;
|
||||
|
||||
void paddle_init(void)
|
||||
{
|
||||
paddlevx = 0;
|
||||
paddlex = BALL_COORD(160, 0);
|
||||
|
||||
spr_set(0, true, 24 + BALL_INT(paddlex), 240, 99, 0, false, true, false);
|
||||
spr_set(1, true, 24 + BALL_INT(paddlex), 240, 98, 15, true, true, false);
|
||||
}
|
||||
|
||||
void paddle_control(void)
|
||||
{
|
||||
joy_poll(0);
|
||||
|
||||
if (joyx[0] == 0)
|
||||
{
|
||||
if (paddlevx < 0)
|
||||
paddlevx = (paddlevx + 1) >> 1;
|
||||
else
|
||||
paddlevx >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
paddlevx += joyx[0] * 8;
|
||||
|
||||
if (paddlevx >= 256)
|
||||
paddlevx = 256;
|
||||
else if (paddlevx < -256)
|
||||
paddlevx = -256;
|
||||
}
|
||||
|
||||
paddlex += paddlevx;
|
||||
if (paddlex < BALL_COORD(-4, 0) || paddlex > BALL_COORD(320 - 48 + 4, 0))
|
||||
{
|
||||
paddlevx = -paddlevx;
|
||||
paddlex += paddlevx;
|
||||
}
|
||||
}
|
||||
|
||||
void paddle_move(void)
|
||||
{
|
||||
spr_move(0, 24 + BALL_INT(paddlex), 240);
|
||||
spr_move(1, 24 + BALL_INT(paddlex), 240);
|
||||
}
|
||||
|
||||
void game_state(GameState state)
|
||||
{
|
||||
// Set new state
|
||||
TheGame.state = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case GS_READY:
|
||||
brick_init();
|
||||
paddle_init();
|
||||
TheGame.count = 120;
|
||||
break;
|
||||
|
||||
case GS_BALL_LOCKED:
|
||||
ball_init(TheGame.balls + 0, 0, paddlex + BALL_COORD(22, 0), BALL_COORD(184, 0), BALL_COORD(0, 0), BALL_COORD(0, 0));
|
||||
ball_init(TheGame.balls + 1, 1, paddlex + BALL_COORD(22, 0), BALL_COORD(184, 0), BALL_COORD(0, 0), BALL_COORD(0, 0));
|
||||
ball_init(TheGame.balls + 2, 2, paddlex + BALL_COORD(22, 0), BALL_COORD(184, 0), BALL_COORD(0, 0), BALL_COORD(0, 0));
|
||||
break;
|
||||
|
||||
case GS_PLAYING:
|
||||
TheGame.balls[0].vy = BALL_COORD(-2, 32);
|
||||
TheGame.balls[0].vx = paddlevx >> 2;
|
||||
TheGame.balls[1].vy = BALL_COORD(-2, 16);
|
||||
TheGame.balls[1].vx = (paddlevx >> 2) - 16;
|
||||
TheGame.balls[2].vy = BALL_COORD(-2, 16);
|
||||
TheGame.balls[2].vx = (paddlevx >> 2) + 16;
|
||||
break;
|
||||
|
||||
case GS_BALL_DROPPED:
|
||||
TheGame.count = 60;
|
||||
break;
|
||||
|
||||
case GS_GAME_OVER:
|
||||
TheGame.count = 120;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void game_loop()
|
||||
{
|
||||
switch (TheGame.state)
|
||||
{
|
||||
case GS_READY:
|
||||
paddle_control();
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_BALL_LOCKED);
|
||||
break;
|
||||
case GS_BALL_LOCKED:
|
||||
paddle_control();
|
||||
TheGame.balls[0].sx = paddlex + BALL_COORD(22, 0);
|
||||
TheGame.balls[1].sx = paddlex + BALL_COORD(22, 0);
|
||||
TheGame.balls[2].sx = paddlex + BALL_COORD(22, 0);
|
||||
if (joyb[0])
|
||||
game_state(GS_PLAYING);
|
||||
break;
|
||||
case GS_PLAYING:
|
||||
paddle_control();
|
||||
// vic.color_border++;
|
||||
for(char i=0; i<3; i++)
|
||||
ball_loop(TheGame.balls + i);
|
||||
for(char i=0; i<3; i++)
|
||||
ball_loop(TheGame.balls + i);
|
||||
// vic.color_border--;
|
||||
if (!(TheGame.balls[0].active || TheGame.balls[1].active || TheGame.balls[2].active))
|
||||
game_state(GS_BALL_DROPPED);
|
||||
break;
|
||||
case GS_BALL_DROPPED:
|
||||
paddle_control();
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_BALL_LOCKED);
|
||||
break;
|
||||
case GS_GAME_OVER:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
|
||||
// Install character set
|
||||
mmap_set(MMAP_RAM);
|
||||
memcpy(Font, charset, 2048);
|
||||
memcpy(Sprites, spriteset, 256);
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Switch screen
|
||||
vic_setmode(VICM_TEXT_MC, Screen, Font);
|
||||
|
||||
spr_init(Screen);
|
||||
|
||||
// Change colors
|
||||
vic.color_border = VCOL_BLACK;
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_back1 = VCOL_WHITE;
|
||||
vic.color_back2 = VCOL_DARK_GREY;
|
||||
|
||||
vic.spr_mcolor0 = VCOL_DARK_GREY;
|
||||
vic.spr_mcolor1 = VCOL_WHITE;
|
||||
|
||||
memset(Screen, 96, 1000);
|
||||
memset(Color, 15, 1000);
|
||||
|
||||
game_state(GS_READY);
|
||||
|
||||
sid.fmodevol = 15;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
brick_animate();
|
||||
game_loop();
|
||||
sound_loop();
|
||||
vic_waitFrame();
|
||||
|
||||
for(char j=0; j<3; j++)
|
||||
ball_move(TheGame.balls + j);
|
||||
paddle_move();
|
||||
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 snake.c
|
||||
../../bin/oscar64 lander.c -n
|
||||
../../bin/oscar64 maze3d.c -n
|
||||
../../bin/oscar64 missile.c -O3 -n
|
||||
../../bin/oscar64 breakout.c -n
|
||||
../../bin/oscar64 connectfour.c -n
|
||||
../../bin/oscar64 hscrollshmup.c -O2 -n
|
||||
|
||||
@@ -0,0 +1,819 @@
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <c64/sid.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/types.h>
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Include charset and sprite resources
|
||||
|
||||
char charset[2048] = {
|
||||
#embed "../resources/connect4chars.bin"
|
||||
};
|
||||
|
||||
char spriteset[2048] = {
|
||||
#embed "../resources/connect4sprites.bin"
|
||||
};
|
||||
|
||||
// Address ov video data
|
||||
|
||||
byte * const Screen = (byte *)0xc800;
|
||||
byte * const Font = (byte *)0xd000;
|
||||
byte * const Color = (byte *)0xd800;
|
||||
byte * const Sprites = (byte *)0xd800;
|
||||
|
||||
// Values for player 1 pieces and player 2 pieces.
|
||||
// The values 1 and 5 are selected so that the sum of the
|
||||
// values in a row of four will add up to a unique value
|
||||
// in the range of 0..24 for ranking
|
||||
|
||||
#define PLAYER1_INC 1
|
||||
#define PLAYER2_INC 5
|
||||
|
||||
// Current state of the board
|
||||
|
||||
struct Board
|
||||
{
|
||||
char fcols[48]; // Pieces in the 6x7 grid using 48 to have a multiplier of 8
|
||||
char ffree[7]; // Number of free places in each column
|
||||
} board;
|
||||
|
||||
enum GameState
|
||||
{
|
||||
GS_READY, // Getting ready
|
||||
|
||||
GS_PLAYER_MOVE, // The players move
|
||||
GS_COMPUTER_MOVE, // The computers move
|
||||
|
||||
GS_PLAYER_WIN, // The player wins
|
||||
GS_COMPUTER_WIN, // The computer wins
|
||||
GS_GAME_OVER // No more moves
|
||||
};
|
||||
|
||||
// Draw the board into the CharWin using the small
|
||||
// character set
|
||||
|
||||
void board_draw(CharWin * cwin)
|
||||
{
|
||||
for(char y=0; y<6; y++)
|
||||
{
|
||||
for(char x=0; x<7; x++)
|
||||
{
|
||||
if (board.fcols[8 * y + x] == PLAYER1_INC)
|
||||
cwin_putat_char_raw(cwin, x, y, 82, 10);
|
||||
else if (board.fcols[8 * y + x] == PLAYER2_INC)
|
||||
cwin_putat_char_raw(cwin, x, y, 82, 15);
|
||||
else
|
||||
cwin_putat_char_raw(cwin, x, y, 82, 8);
|
||||
}
|
||||
|
||||
// Right most column
|
||||
|
||||
cwin_putat_char_raw(cwin, 7, y, 83, 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a big piece or place with the given color, the
|
||||
// color 0 denotes an empty place. Empty places use different
|
||||
// tiles to allow sprite priority to obscure the falling pieces
|
||||
|
||||
void board_draw_item(CharWin * cwin, char x, char y, char c)
|
||||
{
|
||||
char cx = x * 3 + 1, cy = y * 3 + 2;
|
||||
|
||||
if (c)
|
||||
{
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 0, 73, c);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 0, 74, c);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 0, 75, c);
|
||||
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 1, 76, c);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 1, 77, c);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 1, 78, c);
|
||||
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 2, 79, c);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 2, 80, c);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 2, 81, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 0, 64, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 0, 65, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 0, 66, 14);
|
||||
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 1, 67, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 1, 68, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 1, 69, 14);
|
||||
|
||||
cwin_putat_char_raw(cwin, cx + 0, cy + 2, 70, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 1, cy + 2, 71, 14);
|
||||
cwin_putat_char_raw(cwin, cx + 2, cy + 2, 72, 14);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the big board
|
||||
|
||||
void board_draw_main(CharWin * cwin)
|
||||
{
|
||||
for(char y=0; y<6; y++)
|
||||
{
|
||||
for(char x=0; x<7; x++)
|
||||
{
|
||||
if (board.fcols[8 * y + x] == PLAYER1_INC)
|
||||
board_draw_item(cwin, x, y, 10);
|
||||
else if (board.fcols[8 * y + x] == PLAYER2_INC)
|
||||
board_draw_item(cwin, x, y, 15);
|
||||
else
|
||||
board_draw_item(cwin, x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the decoration of the big board
|
||||
|
||||
void board_init_main(CharWin * cwin)
|
||||
{
|
||||
// Frame around the board
|
||||
|
||||
cwin_putat_char_raw(cwin, 0, 1, 84, 14);
|
||||
cwin_fill_rect_raw(cwin, 1, 1, 21, 1, 85, 14);
|
||||
cwin_putat_char_raw(cwin, 22, 1, 86, 14);
|
||||
cwin_fill_rect_raw(cwin, 0, 2, 1, 18, 87, 14);
|
||||
cwin_fill_rect_raw(cwin, 22, 2, 1, 18, 88, 14);
|
||||
cwin_putat_char_raw(cwin, 0, 20, 89, 14);
|
||||
cwin_fill_rect_raw(cwin, 1, 20, 21, 1, 90, 14);
|
||||
cwin_putat_char_raw(cwin, 22, 20, 91, 14);
|
||||
|
||||
// Fields in the board
|
||||
|
||||
for(char x=0; x<7; x++)
|
||||
cwin_putat_char_raw(cwin, 3 * x + 2, 0, '1' + x, 1);
|
||||
|
||||
board_draw_main(cwin);
|
||||
}
|
||||
|
||||
// Play animation of a dropped piece
|
||||
|
||||
void item_drop_anim(CharWin * cwin, char x, char y, char c)
|
||||
{
|
||||
// Initial position
|
||||
|
||||
int ix = (cwin->sx + 3 * x + 1) * 8 + 24, iy = (cwin->sy + 2) * 8 + 20;
|
||||
|
||||
// Show sprite at start position
|
||||
spr_set(0, true, ix, iy, 97, c, true, false, false);
|
||||
|
||||
// Set sprite priority to be behind background
|
||||
vic.spr_priority = 0x01;
|
||||
|
||||
// Speed and target position, using four fractional bits
|
||||
int vy = 0, aiy = iy * 16, ty = ((cwin->sy + y * 3 + 2) * 8 + 50) * 16;
|
||||
|
||||
// Bounce three times back when reaching bottom
|
||||
char bounce = 3;
|
||||
|
||||
// Loop through the bounces
|
||||
while (bounce > 0)
|
||||
{
|
||||
// Let gravity do its thing of accelerating
|
||||
vy += 3;
|
||||
|
||||
// Add vertical velocity to position
|
||||
aiy += vy;
|
||||
|
||||
// Reached the bottom yet?
|
||||
if (aiy > ty)
|
||||
{
|
||||
// Reflect position
|
||||
aiy = 2 * ty - aiy;
|
||||
|
||||
// Reflect speed
|
||||
vy = - vy * 5 >> 4;
|
||||
|
||||
// One bounce down
|
||||
bounce--;
|
||||
}
|
||||
|
||||
// Move sprite and wait for display
|
||||
spr_move(0, ix, aiy >> 4);
|
||||
vic_waitFrame();
|
||||
}
|
||||
}
|
||||
|
||||
// Play column selection animation
|
||||
|
||||
void column_select_anim(CharWin * cwin, char x0, char x1, char c)
|
||||
{
|
||||
// Start position
|
||||
int ix = (cwin->sx + 3 * x0 + 1) * 8 + 24, iy = (cwin->sy + 2) * 8 + 20;
|
||||
|
||||
// Target position
|
||||
int tx = (cwin->sx + 3 * x1 + 1) * 8 + 24;
|
||||
|
||||
// Show sprite at start position
|
||||
spr_set(0, true, ix, iy, 97, c, true, false, false);
|
||||
|
||||
// Set sprite priority to be behind background
|
||||
vic.spr_priority = 0x01;
|
||||
|
||||
// Not at target position already?
|
||||
if (ix != tx)
|
||||
{
|
||||
// Eight frames for movement
|
||||
for(int i=1; i<=8; i++)
|
||||
{
|
||||
vic_waitFrame();
|
||||
// Move sprite along path
|
||||
spr_move(0, (ix * (8 - i) + tx * i) >> 3, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the board to empty
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
// Column has six free slots
|
||||
for(char x=0; x<7; x++)
|
||||
board.ffree[x] = 6;
|
||||
|
||||
// Clear all slots
|
||||
for(char i=0; i<48; i++)
|
||||
board.fcols[i] = 0;
|
||||
}
|
||||
|
||||
// Drop one piece of player p down column x
|
||||
|
||||
inline bool board_drop(char x, bool p)
|
||||
{
|
||||
// Check for free space
|
||||
if (board.ffree[x])
|
||||
{
|
||||
// Fill one slot
|
||||
char y = --(board.ffree[x]);
|
||||
board.fcols[8 * y + x] = p ? PLAYER2_INC : PLAYER1_INC;
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the top piece from column x
|
||||
|
||||
inline void board_undrop(char x)
|
||||
{
|
||||
// Free one slot
|
||||
char y = (board.ffree[x])++;
|
||||
board.fcols[8 * y + x] = 0x00;
|
||||
}
|
||||
|
||||
// Score for rows with 0, 1, 2, and 3 elements of same color
|
||||
|
||||
static const int score[5] = {0, 1, 8, 128, 10000};
|
||||
|
||||
// Score index is calculated (25 * rv + 5 * p1 + p2) with rv the
|
||||
// value range of the row, p1 and p2 number of pieces from player 1 or 2
|
||||
|
||||
int fscore[125];
|
||||
|
||||
// Indices of the board positions of four slots of each of the 69
|
||||
// 4 slot rows in the board. The fifth value is the value range
|
||||
// of the row
|
||||
|
||||
char frows[5][69];
|
||||
|
||||
#pragma align(fscore, 256)
|
||||
|
||||
// Tables for opening library for computer move 1, 2, 3 and 4
|
||||
|
||||
const char open1 = 3;
|
||||
const char open2[4 * 7] =
|
||||
{
|
||||
4, 3, 3, 3, 4, 3, 3, 3, 5, 3, 3, 4, 3, 3, 3, 3, 2, 3, 2, 2, 2, 4, 2, 4, 3, 2, 4, 2
|
||||
};
|
||||
|
||||
const char open3[4 * 7 * 7] = {
|
||||
0, 5, 2, 2, 5, 3, 2, 5, 4, 2, 4, 3, 3, 5, 2, 2, 3, 2, 3, 2, 2, 4, 5, 2, 4, 4, 3, 2,
|
||||
3, 3, 3, 3, 3, 3, 4, 1, 3, 2, 5, 3, 2, 1, 2, 5, 2, 2, 4, 1, 4, 5, 4, 2, 4, 3, 3, 5,
|
||||
4, 1, 3, 4, 4, 4, 3, 2, 1, 3, 2, 3, 2, 3, 5, 5, 1, 5, 4, 3, 3, 3, 4, 3, 3, 5, 3, 3,
|
||||
3, 5, 2, 3, 4, 1, 3, 5, 4, 3, 1, 4, 3, 5, 2, 2, 3, 2, 3, 2, 2, 2, 1, 3, 2, 3, 2, 3,
|
||||
3, 1, 3, 2, 2, 3, 3, 2, 1, 3, 2, 2, 2, 2, 3, 3, 3, 2, 1, 3, 3, 3, 3, 1, 3, 3, 2, 3,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 2, 3, 4, 3, 2, 4, 3, 2, 2, 2, 2, 1, 0, 2, 4, 3, 4, 4,
|
||||
4, 4, 1, 2, 5, 2, 2, 2, 2, 3, 2, 4, 6, 5, 4, 4, 4, 4, 3, 2, 4, 3, 2, 3, 4, 5, 4, 3,
|
||||
};
|
||||
|
||||
const char open4[4 * 7 * 7 * 7] = {
|
||||
2, 5, 2, 2, 5, 3, 2, 2, 2, 6, 2, 2, 2, 2, 0, 4, 4, 3, 2, 3, 3, 5, 5, 5, 5, 5, 1, 1,
|
||||
2, 2, 6, 2, 2, 2, 2, 0, 4, 4, 4, 3, 5, 4, 1, 5, 1, 1, 1, 1, 1, 0, 4, 2, 4, 3, 4, 5,
|
||||
5, 1, 4, 5, 5, 3, 2, 3, 3, 1, 1, 1, 1, 3, 5, 5, 4, 5, 5, 4, 4, 3, 3, 3, 1, 3, 3, 3,
|
||||
3, 3, 3, 1, 3, 3, 3, 5, 4, 2, 5, 3, 1, 4, 0, 3, 6, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 3,
|
||||
3, 3, 3, 2, 3, 3, 3, 2, 1, 6, 2, 4, 5, 2, 3, 3, 3, 2, 3, 3, 3, 3, 1, 5, 5, 3, 3, 3,
|
||||
3, 3, 0, 2, 3, 3, 3, 0, 5, 2, 2, 5, 1, 2, 4, 4, 2, 4, 5, 4, 2, 2, 2, 3, 2, 2, 2, 2,
|
||||
2, 5, 5, 2, 2, 1, 2, 4, 3, 4, 4, 3, 3, 4, 1, 3, 2, 1, 4, 4, 1, 4, 5, 4, 4, 4, 2, 4,
|
||||
0, 3, 3, 4, 3, 3, 3, 3, 3, 3, 1, 3, 5, 3, 3, 3, 3, 2, 2, 4, 3, 4, 3, 4, 4, 3, 3, 4,
|
||||
3, 3, 2, 3, 3, 5, 6, 3, 5, 4, 5, 5, 3, 3, 3, 3, 2, 3, 3, 3, 5, 0, 5, 3, 4, 4, 3, 2,
|
||||
3, 3, 3, 1, 3, 3, 3, 3, 1, 5, 5, 3, 3, 3, 3, 3, 2, 1, 4, 3, 1, 3, 3, 3, 4, 3, 3, 3,
|
||||
2, 2, 3, 2, 5, 5, 4, 2, 5, 3, 1, 4, 2, 1, 0, 2, 4, 4, 3, 2, 4, 5, 4, 2, 5, 3, 1, 4,
|
||||
3, 3, 0, 2, 3, 3, 3, 4, 2, 4, 4, 2, 2, 4, 3, 3, 3, 4, 6, 3, 3, 2, 5, 3, 1, 4, 2, 1,
|
||||
2, 2, 3, 2, 2, 4, 6, 0, 4, 2, 4, 3, 4, 5, 5, 1, 4, 5, 5, 3, 2, 3, 3, 1, 1, 1, 1, 3,
|
||||
5, 5, 4, 5, 5, 4, 4, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 5, 4, 2, 5, 3, 1, 4,
|
||||
2, 2, 6, 2, 2, 2, 2, 4, 4, 3, 4, 4, 4, 3, 4, 1, 3, 5, 3, 3, 3, 2, 2, 6, 2, 2, 2, 2,
|
||||
5, 1, 3, 3, 5, 4, 3, 2, 2, 6, 2, 2, 2, 2, 4, 1, 3, 5, 3, 1, 3, 3, 3, 1, 1, 1, 1, 3,
|
||||
6, 2, 3, 1, 4, 5, 4, 3, 3, 3, 2, 3, 3, 3, 1, 2, 3, 1, 4, 1, 1, 3, 3, 3, 4, 3, 2, 3,
|
||||
1, 3, 1, 1, 4, 2, 1, 3, 3, 3, 2, 3, 3, 3, 4, 4, 2, 4, 5, 4, 2, 4, 1, 6, 4, 4, 4, 2,
|
||||
1, 3, 2, 4, 3, 1, 1, 4, 4, 4, 4, 4, 4, 2, 3, 3, 4, 4, 3, 3, 4, 3, 5, 3, 1, 3, 1, 3,
|
||||
5, 2, 2, 5, 4, 3, 5, 3, 3, 3, 1, 3, 5, 3, 3, 1, 4, 4, 5, 3, 3, 3, 1, 3, 2, 2, 2, 3,
|
||||
3, 3, 4, 4, 3, 3, 4, 3, 5, 3, 3, 5, 5, 3, 5, 4, 2, 5, 5, 3, 5, 3, 3, 3, 1, 1, 5, 3,
|
||||
3, 3, 3, 1, 3, 3, 3, 5, 1, 1, 3, 4, 3, 3, 1, 3, 1, 1, 4, 2, 1, 5, 5, 2, 1, 4, 1, 1,
|
||||
5, 4, 2, 5, 5, 3, 5, 3, 3, 2, 3, 5, 5, 1, 3, 3, 3, 5, 3, 3, 3, 5, 4, 2, 5, 3, 1, 4,
|
||||
2, 1, 1, 4, 3, 4, 4, 3, 3, 3, 2, 3, 3, 3, 5, 3, 2, 5, 4, 3, 3, 3, 3, 3, 1, 1, 5, 3,
|
||||
3, 3, 3, 5, 3, 3, 3, 4, 3, 2, 2, 3, 1, 6, 0, 3, 6, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 3,
|
||||
3, 3, 3, 2, 3, 3, 3, 2, 1, 6, 2, 4, 5, 2, 3, 3, 3, 2, 3, 3, 3, 3, 1, 5, 5, 3, 3, 3,
|
||||
3, 3, 0, 2, 3, 3, 3, 3, 3, 1, 1, 1, 1, 3, 6, 2, 3, 1, 4, 5, 4, 3, 3, 3, 2, 3, 3, 3,
|
||||
1, 2, 3, 1, 4, 1, 1, 3, 3, 3, 4, 3, 2, 3, 1, 3, 1, 1, 4, 2, 1, 3, 3, 3, 2, 3, 3, 3,
|
||||
3, 3, 3, 4, 3, 3, 3, 2, 3, 1, 3, 0, 1, 1, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 2, 2, 3,
|
||||
4, 4, 4, 2, 2, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 2, 2, 2, 2,
|
||||
1, 3, 2, 4, 3, 1, 1, 0, 1, 2, 2, 4, 5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 2, 2, 3, 3, 2, 3, 3, 2, 2, 3, 2, 3, 1, 3, 4, 3, 3, 3, 1, 1, 4, 4, 2, 4, 2,
|
||||
3, 4, 3, 4, 3, 4, 4, 3, 2, 3, 2, 3, 3, 3, 1, 2, 2, 2, 4, 4, 2, 3, 4, 4, 4, 3, 5, 3,
|
||||
3, 2, 4, 4, 3, 3, 3, 3, 1, 5, 5, 3, 3, 3, 1, 3, 1, 1, 4, 2, 1, 3, 1, 1, 3, 3, 1, 3,
|
||||
2, 3, 3, 2, 2, 3, 3, 3, 4, 4, 4, 3, 5, 3, 3, 3, 1, 2, 2, 5, 3, 3, 1, 3, 5, 3, 3, 3,
|
||||
1, 3, 3, 3, 4, 3, 3, 3, 3, 1, 1, 2, 1, 3, 0, 1, 3, 3, 4, 3, 3, 2, 3, 3, 2, 2, 3, 2,
|
||||
3, 2, 4, 4, 3, 3, 3, 3, 1, 3, 5, 3, 3, 3, 3, 3, 3, 2, 3, 3, 6, 0, 2, 1, 2, 3, 4, 4,
|
||||
4, 1, 3, 3, 4, 4, 2, 4, 3, 2, 4, 3, 3, 4, 3, 3, 2, 4, 4, 4, 3, 3, 2, 1, 4, 3, 3, 3,
|
||||
4, 2, 1, 4, 5, 4, 2, 4, 2, 1, 2, 3, 4, 4, 2, 2, 1, 2, 1, 2, 2, 1, 1, 3, 3, 3, 5, 1,
|
||||
2, 5, 3, 2, 5, 3, 3, 2, 3, 1, 1, 1, 6, 2, 1, 4, 4, 1, 4, 6, 5, 2, 2, 1, 6, 6, 2, 4,
|
||||
2, 2, 1, 2, 5, 4, 2, 4, 3, 2, 4, 3, 3, 4, 4, 3, 3, 3, 3, 1, 1, 1, 0, 3, 3, 3, 3, 3,
|
||||
1, 0, 2, 2, 4, 5, 2, 1, 0, 3, 1, 3, 1, 3, 1, 0, 2, 5, 2, 2, 5, 1, 0, 3, 2, 2, 5, 2,
|
||||
2, 2, 1, 4, 4, 4, 2, 2, 4, 0, 2, 4, 2, 4, 5, 4, 2, 1, 5, 4, 1, 2, 1, 2, 2, 2, 4, 2,
|
||||
5, 2, 1, 5, 4, 2, 1, 2, 4, 2, 4, 6, 2, 4, 4, 2, 2, 2, 5, 4, 4, 4, 1, 4, 2, 3, 6, 5,
|
||||
1, 4, 4, 1, 4, 6, 5, 3, 5, 3, 5, 3, 6, 5, 2, 1, 2, 4, 4, 6, 5, 3, 3, 3, 3, 3, 6, 5,
|
||||
5, 5, 3, 3, 3, 3, 2, 2, 3, 3, 2, 4, 3, 2, 4, 2, 1, 4, 5, 4, 2, 2, 4, 0, 0, 5, 4, 2,
|
||||
1, 0, 2, 5, 2, 2, 5, 4, 0, 5, 5, 5, 3, 4, 3, 3, 1, 4, 3, 1, 2, 5, 1, 3, 3, 3, 5, 5,
|
||||
2, 2, 5, 4, 5, 4, 4, 2, 2, 3, 4, 5, 4, 2, 2, 2, 1, 2, 5, 4, 2, 3, 3, 3, 2, 5, 4, 3,
|
||||
3, 2, 2, 2, 4, 3, 3, 2, 3, 3, 2, 4, 3, 2, 4, 2, 2, 3, 3, 5, 2, 2, 2, 3, 4, 5, 4, 6,
|
||||
};
|
||||
|
||||
// Init the ai tables
|
||||
void ai_init(void)
|
||||
{
|
||||
// Loop over 5 value ranges, and 0 to 4 pieces of each player
|
||||
// in a row
|
||||
|
||||
for(char k=0; k<5; k++)
|
||||
{
|
||||
for(char i=0; i<5; i++)
|
||||
{
|
||||
for(char j=0; j<5; j++)
|
||||
{
|
||||
if (i && j)
|
||||
fscore[25 * k + PLAYER2_INC * i + j] = 0;
|
||||
else if (i == 4 || j == 4)
|
||||
fscore[25 * k + PLAYER2_INC * i + j] = score[i] - score[j];
|
||||
else
|
||||
fscore[25 * k + PLAYER2_INC * i + j] = (score[i] - score[j]) * (1 + k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the indices of all 69 rows
|
||||
|
||||
char p = 0;
|
||||
|
||||
// Vertical rows
|
||||
for(char x=0; x<7; x++)
|
||||
{
|
||||
for(char y=0; y<3; y++)
|
||||
{
|
||||
frows[0][p] = x + 8 * y;
|
||||
frows[1][p] = x + 8 * y + 8;
|
||||
frows[2][p] = x + 8 * y + 16;
|
||||
frows[3][p] = x + 8 * y + 24;
|
||||
frows[4][p] = 25 * (y + 1);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
for(char x=0; x<4; x++)
|
||||
{
|
||||
// Horizontal rows
|
||||
for(char y=0; y<6; y++)
|
||||
{
|
||||
frows[0][p] = x + 8 * y;
|
||||
frows[1][p] = x + 8 * y + 1;
|
||||
frows[2][p] = x + 8 * y + 2;
|
||||
frows[3][p] = x + 8 * y + 3;
|
||||
frows[4][p] = y > 0 ? 25 * (y - 1) : 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Diagonal down rows
|
||||
for(char y=0; y<3; y++)
|
||||
{
|
||||
frows[0][p] = x + 8 * y;
|
||||
frows[1][p] = x + 8 * y + 9;
|
||||
frows[2][p] = x + 8 * y + 18;
|
||||
frows[3][p] = x + 8 * y + 27;
|
||||
frows[4][p] = 25 * (y + 1);
|
||||
p++;
|
||||
}
|
||||
|
||||
// Diagonal up rows
|
||||
for(char y=3; y<6; y++)
|
||||
{
|
||||
frows[0][p] = x + 8 * y;
|
||||
frows[1][p] = x + 8 * y - 7;
|
||||
frows[2][p] = x + 8 * y - 14;
|
||||
frows[3][p] = x + 8 * y - 21;
|
||||
frows[4][p] = 25 * (y - 2);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate the current board state for the player
|
||||
|
||||
int board_eval(bool player)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
// Loop through all rows
|
||||
for(char r=0; r<69; r++)
|
||||
{
|
||||
// Build score index for row
|
||||
char sum =
|
||||
board.fcols[frows[0][r]] +
|
||||
board.fcols[frows[1][r]] +
|
||||
board.fcols[frows[2][r]] +
|
||||
board.fcols[frows[3][r]] +
|
||||
frows[4][r];
|
||||
|
||||
// Help compiler to avoid two byte pointer arithmetic
|
||||
__assume(sum < 128);
|
||||
|
||||
// Add score to board score
|
||||
score += fscore[sum];
|
||||
}
|
||||
|
||||
// Check if there was a row with four winning pieces and
|
||||
// normalize to +/- 32000 then
|
||||
|
||||
if (score < -8192)
|
||||
score = -32000;
|
||||
else if (score >= 8192)
|
||||
score = 32000;
|
||||
|
||||
// Invert score for other player
|
||||
|
||||
return player ? score : -score;
|
||||
}
|
||||
|
||||
CharWin cwt, cws;
|
||||
CharWin cw, cwm;
|
||||
|
||||
char buff[20];
|
||||
|
||||
static const char optx[7] = {3, 2, 4, 1, 5, 0, 6};
|
||||
|
||||
// Find a good move for the player using alpha/beta pruning
|
||||
// see: https://en.wikipedia.org/wiki/Alpha-beta_pruning
|
||||
|
||||
int board_check(char level, int alpha, int beta, bool player)
|
||||
{
|
||||
int best = alpha;
|
||||
bool checked = false;
|
||||
|
||||
// Current score to cutof early if clear win condition
|
||||
int val = board_eval(player) + level;
|
||||
|
||||
// Best move
|
||||
char zx = 0;
|
||||
|
||||
// Check for end of search
|
||||
if (level < 5 && val < 5000 && val > -5000)
|
||||
{
|
||||
// Update current check display at level 3
|
||||
if (level == 3)
|
||||
{
|
||||
board_draw(&cwt);
|
||||
itoa(val, buff, 10);
|
||||
cwin_fill_rect(&cwt, 0, 6, 7, 1, ' ', 1);
|
||||
cwin_putat_string(&cwt, 0, 6, buff, 1);
|
||||
}
|
||||
|
||||
// Check all seven columns
|
||||
for(char i=0; i<7; i++)
|
||||
{
|
||||
// Start check in the center, due to higher value of
|
||||
// pieces there
|
||||
|
||||
char ix = optx[i];
|
||||
|
||||
// Try to drop a piece
|
||||
|
||||
if (board_drop(ix, player))
|
||||
{
|
||||
// We still have a move
|
||||
checked = true;
|
||||
|
||||
// Check score of position
|
||||
int score = - board_check(level + 1, -beta, -best, !player);
|
||||
|
||||
// Better than what we have so far
|
||||
if (score > best)
|
||||
{
|
||||
// Remember
|
||||
best = score;
|
||||
zx = ix;
|
||||
|
||||
// Update best move if on level zero
|
||||
if (level == 0)
|
||||
{
|
||||
board_draw(&cw);
|
||||
itoa(best, buff, 10);
|
||||
cwin_fill_rect(&cw, 0, 6, 7, 1, ' ', 1);
|
||||
cwin_putat_string(&cw, 0, 6, buff, 1);
|
||||
}
|
||||
|
||||
// Check for beta pruning
|
||||
if (best > beta)
|
||||
{
|
||||
board_undrop(ix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Undo move
|
||||
board_undrop(ix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return new position if first move level
|
||||
if (level == 0)
|
||||
return zx;
|
||||
else if (checked)
|
||||
return best;
|
||||
else
|
||||
return val;
|
||||
}
|
||||
|
||||
// Return a move from the opening library if available
|
||||
|
||||
char board_opening(char step, char * moves)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case 1:
|
||||
return open1;
|
||||
case 2:
|
||||
if (moves[0] < 4)
|
||||
return open2[moves[0] * 7 + moves[1]];
|
||||
else
|
||||
return 6 - open2[(6 - moves[0]) * 7 + (6 - moves[1])];
|
||||
|
||||
case 3:
|
||||
if (moves[0] < 4)
|
||||
return open3[moves[0] * 49 + moves[1] * 7 + moves[2]];
|
||||
else
|
||||
return 6 - open3[(6 - moves[0]) * 49 + (6 - moves[1]) * 7 + (6 - moves[2])];
|
||||
|
||||
case 4:
|
||||
if (moves[0] < 4)
|
||||
return open4[moves[0] * 343 + moves[1] * 49 + moves[2] * 7 + moves[3]];
|
||||
else
|
||||
return 6 - open4[(6 - moves[0]) * 343 + (6 - moves[1]) * 49 + (6 - moves[2]) * 7 + (6 - moves[3])];
|
||||
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// Current state of the game
|
||||
struct Game
|
||||
{
|
||||
GameState state; // State
|
||||
char count; // Auto continue counter
|
||||
char posx; // Column osition of new piece
|
||||
char step; // Number of player moves
|
||||
char moves[21]; // Pieces placed by player
|
||||
|
||||
} TheGame;
|
||||
|
||||
// Set new game state
|
||||
|
||||
void game_state(GameState state)
|
||||
{
|
||||
// Set new state
|
||||
TheGame.state = state;
|
||||
|
||||
// Clear status line
|
||||
|
||||
cwin_fill_rect(&cws, 0, 0, 40, 1, ' ', 1);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Start play in one second
|
||||
TheGame.count = 60;
|
||||
TheGame.step = 0;
|
||||
|
||||
// Clear the board
|
||||
board_init();
|
||||
board_init_main(&cwm);
|
||||
break;
|
||||
|
||||
case GS_PLAYER_MOVE:
|
||||
// Place selection sprite in center
|
||||
TheGame.posx = 3;
|
||||
column_select_anim(&cwm, 3, 3, 7);
|
||||
cwin_putat_string(&cws, 0, 0, P"PLAYER MOVE", 7);
|
||||
break;
|
||||
|
||||
case GS_COMPUTER_MOVE:
|
||||
cwin_putat_string(&cws, 0, 0, P"COMPUTER MOVE", 2);
|
||||
break;
|
||||
|
||||
case GS_PLAYER_WIN:
|
||||
cwin_putat_string(&cws, 0, 0, P"PLAYER WINS", 7);
|
||||
|
||||
// Continue in 4 seconds
|
||||
TheGame.count = 240;
|
||||
break;
|
||||
|
||||
case GS_COMPUTER_WIN:
|
||||
cwin_putat_string(&cws, 0, 0, P"COMPUTER WINS", 2);
|
||||
|
||||
// Continue in 4 seconds
|
||||
TheGame.count = 240;
|
||||
break;
|
||||
|
||||
case GS_GAME_OVER:
|
||||
cwin_putat_string(&cws, 0, 0, P"NO MORE MOVES", 1);
|
||||
|
||||
// Continue in 4 seconds
|
||||
TheGame.count = 240;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Main game loop
|
||||
|
||||
void game_loop()
|
||||
{
|
||||
char bx = 0xff, cx;
|
||||
|
||||
switch (TheGame.state)
|
||||
{
|
||||
case GS_READY:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_PLAYER_MOVE);
|
||||
break;
|
||||
|
||||
case GS_PLAYER_MOVE:
|
||||
// Current selection
|
||||
cx = TheGame.posx;
|
||||
|
||||
// Check for key pressed
|
||||
if (kbhit())
|
||||
{
|
||||
// Get key
|
||||
char ch = getch();
|
||||
|
||||
// Numbers 1 to 7 drop immediate
|
||||
if (ch >= '1' && ch <= '7')
|
||||
bx = cx = ch - '1';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check Joystick
|
||||
joy_poll(0);
|
||||
|
||||
// Move cursor
|
||||
if (joyx[0] < 0 && cx > 0)
|
||||
cx--;
|
||||
else if (joyx[0] > 0 && cx < 6)
|
||||
cx++;
|
||||
else if(joyb[0])
|
||||
bx = cx;
|
||||
}
|
||||
|
||||
// Move selection piece
|
||||
column_select_anim(&cwm, TheGame.posx, cx, 7);
|
||||
TheGame.posx = cx;
|
||||
|
||||
if (bx != 0xff)
|
||||
{
|
||||
// Drop piece into board
|
||||
if (board_drop(bx, true))
|
||||
{
|
||||
// Remember move
|
||||
TheGame.moves[TheGame.step++] = bx;
|
||||
|
||||
// Play drop animation
|
||||
item_drop_anim(&cwm, bx, board.ffree[bx], 7);
|
||||
|
||||
// Show new state of the board
|
||||
board_draw_main(&cwm);
|
||||
spr_show(0, false);
|
||||
|
||||
// Check for win condition
|
||||
if (board_eval(true) == 32000)
|
||||
game_state(GS_PLAYER_WIN);
|
||||
else
|
||||
game_state(GS_COMPUTER_MOVE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_COMPUTER_MOVE:
|
||||
// Check for opening move or calculate next move
|
||||
bx = board_opening(TheGame.step, TheGame.moves);
|
||||
if (bx == 0xff)
|
||||
bx = board_check(0, -32767, 32767, false);
|
||||
|
||||
// Drop piece into board
|
||||
if (board_drop(bx, false))
|
||||
{
|
||||
// Play drop animation
|
||||
item_drop_anim(&cwm, bx, board.ffree[bx], 2);
|
||||
|
||||
// Show new state of the board
|
||||
board_draw_main(&cwm);
|
||||
spr_show(0, false);
|
||||
|
||||
// Check for loss or draw condition
|
||||
if (board_eval(false) == 32000)
|
||||
game_state(GS_COMPUTER_WIN);
|
||||
else if (TheGame.step == 21)
|
||||
game_state(GS_GAME_OVER);
|
||||
else
|
||||
game_state(GS_PLAYER_MOVE);
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_PLAYER_WIN:
|
||||
case GS_COMPUTER_WIN:
|
||||
case GS_GAME_OVER:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
|
||||
// Install character set
|
||||
mmap_set(MMAP_RAM);
|
||||
memcpy(Font, charset, 2048);
|
||||
memcpy(Sprites, spriteset, 256);
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Switch screen
|
||||
vic_setmode(VICM_TEXT_MC, Screen, Font);
|
||||
|
||||
spr_init(Screen);
|
||||
|
||||
// Change colors
|
||||
vic.color_border = VCOL_BLUE;
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_back1 = VCOL_BLUE;
|
||||
vic.color_back2 = VCOL_WHITE;
|
||||
|
||||
vic.spr_mcolor0 = VCOL_DARK_GREY;
|
||||
vic.spr_mcolor1 = VCOL_WHITE;
|
||||
|
||||
// Clear screen
|
||||
memset(Screen, 96, 1000);
|
||||
memset(Color, 15, 1000);
|
||||
|
||||
// Prepare char wins
|
||||
cwin_init(&cws, Screen, 5, 0, 30, 1);
|
||||
cwin_init(&cwm, Screen, 2, 3, 28, 19);
|
||||
cwin_init(&cw, Screen, 30, 6, 8, 7);
|
||||
cwin_init(&cwt, Screen, 30, 15, 8, 7);
|
||||
|
||||
// Init AI
|
||||
ai_init();
|
||||
|
||||
game_state(GS_READY);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
game_loop();
|
||||
vic_waitFrame();
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,279 @@
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
byte landersprites[] = {
|
||||
#embed "../resources/landersprites.bin"
|
||||
};
|
||||
|
||||
// Screen and color ram address
|
||||
|
||||
#define Screen ((byte *)0x0400)
|
||||
#define Color ((byte *)0xd800)
|
||||
|
||||
struct Lander
|
||||
{
|
||||
float px, py, vx, vy;
|
||||
};
|
||||
|
||||
enum GameState
|
||||
{
|
||||
GS_READY, // Getting ready
|
||||
GS_PLAYING, // Playing the game
|
||||
GS_LANDED, // Landed on pad
|
||||
GS_COLLIDE // Collided with something
|
||||
};
|
||||
|
||||
// State of the game
|
||||
struct Game
|
||||
{
|
||||
GameState state;
|
||||
byte count;
|
||||
Lander lander; // use an array for multiplayer
|
||||
|
||||
} TheGame; // Only one game, so global variable
|
||||
|
||||
// Put one char on screen
|
||||
inline void screen_put(byte x, byte y, char ch, char color)
|
||||
{
|
||||
__assume(y < 25);
|
||||
|
||||
Screen[40 * y + x] = ch;
|
||||
Color[40 * y + x] = color;
|
||||
}
|
||||
|
||||
// Get one char from screen
|
||||
inline char screen_get(byte x, byte y)
|
||||
{
|
||||
__assume(y < 25);
|
||||
|
||||
return Screen[40 * y + x];
|
||||
}
|
||||
|
||||
void screen_init(void)
|
||||
{
|
||||
// Fill screen with spaces
|
||||
memset(Screen, ' ', 1000);
|
||||
|
||||
for(char i=0; i<100; i++)
|
||||
screen_put(rand() % 40, rand() % 25, '.', VCOL_WHITE);
|
||||
|
||||
sbyte height[41];
|
||||
for(char i=0; i<41; i+=8)
|
||||
height[i] = 4 + rand() % 16;
|
||||
|
||||
for(char step = 8; step > 1; step /= 2)
|
||||
{
|
||||
for(char i=0; i<40; i+=step)
|
||||
{
|
||||
char p = (height[i] + height[i + step]) >> 1;
|
||||
p += rand() % step - (step / 2);
|
||||
height[i + step / 2] = p;
|
||||
}
|
||||
}
|
||||
|
||||
char xp = 2 + rand() % 33;
|
||||
char yp = height[xp];
|
||||
for(char i=1; i<4; i++)
|
||||
if (height[xp + i] < yp)
|
||||
yp = height[xp + i];
|
||||
|
||||
for(char i=0; i<4; i++)
|
||||
height[xp + i] = yp;
|
||||
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
char h = height[x];
|
||||
for(char y=0; y<h; y++)
|
||||
screen_put(x, 24 - y, 160, VCOL_YELLOW);
|
||||
}
|
||||
|
||||
|
||||
for(char i=0; i<4; i++)
|
||||
{
|
||||
screen_put(xp + i, 24 - yp, 128 + 86, VCOL_MED_GREY);
|
||||
screen_put(xp + i, 23 - yp, 100, VCOL_WHITE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void lander_init(Lander * lander)
|
||||
{
|
||||
lander->px = 160;
|
||||
lander->py = 50;
|
||||
lander->vx = 0;
|
||||
lander->vy = 0;
|
||||
|
||||
spr_set(0, true, (int)lander->px, (int)lander->py, 0x0380 / 64, VCOL_DARK_GREY, false, false, false);
|
||||
spr_set(1, true, (int)lander->px, (int)lander->py, 0x0340 / 64, VCOL_LT_GREY, true, false, false);
|
||||
spr_set(2, false, (int)lander->px, (int)lander->py + 20, 0x03c0 / 64, VCOL_WHITE, false, false, false);
|
||||
}
|
||||
|
||||
char ExhaustColor[] = {VCOL_YELLOW, VCOL_WHITE, VCOL_ORANGE, VCOL_LT_BLUE};
|
||||
|
||||
void lander_move(Lander * lander, sbyte jx, sbyte jy)
|
||||
{
|
||||
lander->px += lander->vx;
|
||||
lander->py += lander->vy;
|
||||
lander->vx += jx * 0.02;
|
||||
lander->vy += jy * 0.1 + 0.01;
|
||||
}
|
||||
|
||||
void lander_show(Lander * lander, sbyte jx, sbyte jy)
|
||||
{
|
||||
vic.color_border++;
|
||||
|
||||
int ix = (int)lander->px, iy = (int)lander->py;
|
||||
|
||||
spr_move(0, ix, iy);
|
||||
spr_move(1, ix, iy);
|
||||
if (jy < 0)
|
||||
{
|
||||
spr_move(2, ix, iy + 20);
|
||||
spr_color(2, ExhaustColor[rand() & 3]);
|
||||
spr_show(2, true);
|
||||
}
|
||||
else
|
||||
spr_show(2, false);
|
||||
|
||||
vic.color_border--;
|
||||
}
|
||||
|
||||
void lander_flash(Lander * lander, char c)
|
||||
{
|
||||
spr_color(0, rand() & 1);
|
||||
}
|
||||
|
||||
enum LanderCollision
|
||||
{
|
||||
LCOL_FREE,
|
||||
LCOL_GROUND,
|
||||
LCOL_PAD
|
||||
};
|
||||
|
||||
LanderCollision lander_check(Lander * lander)
|
||||
{
|
||||
sbyte ix = (sbyte)((lander->px - 24) * 0.125);
|
||||
sbyte iy = (sbyte)((lander->py - 29) * 0.125);
|
||||
|
||||
if (iy > 24)
|
||||
return LCOL_GROUND;
|
||||
if (iy < 0)
|
||||
return LCOL_FREE;
|
||||
|
||||
LanderCollision col = LCOL_FREE;
|
||||
for(char i=0; i<4; i++)
|
||||
{
|
||||
if (ix >= 0 && ix < 40)
|
||||
{
|
||||
char ch = screen_get(ix, iy);
|
||||
if (ch == 160)
|
||||
return LCOL_GROUND;
|
||||
else if (ch == 128 + 86)
|
||||
col = LCOL_PAD;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void game_state(GameState state)
|
||||
{
|
||||
// Set new state
|
||||
TheGame.state = state;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Clear the screen
|
||||
lander_init(&TheGame.lander);
|
||||
screen_init();
|
||||
TheGame.count = 32;
|
||||
break;
|
||||
|
||||
case GS_PLAYING:
|
||||
break;
|
||||
|
||||
case GS_LANDED:
|
||||
TheGame.lander.py = (sbyte)((TheGame.lander.py - 29) * 0.125) * 8 + 28;
|
||||
lander_show(&TheGame.lander, 0, 0);
|
||||
TheGame.count = 16;
|
||||
break;
|
||||
|
||||
case GS_COLLIDE:
|
||||
TheGame.count = 32;
|
||||
lander_show(&TheGame.lander, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Main game loop, invoked every vsync
|
||||
void game_loop(void)
|
||||
{
|
||||
switch (TheGame.state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Countdown ready to start
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_PLAYING);
|
||||
break;
|
||||
case GS_PLAYING:
|
||||
{
|
||||
// Check player input on every frame
|
||||
joy_poll(0);
|
||||
lander_move(&TheGame.lander, joyx[0], joyy[0]);
|
||||
LanderCollision col = lander_check(&TheGame.lander);
|
||||
if (col == LCOL_GROUND)
|
||||
game_state(GS_COLLIDE);
|
||||
else if (col == LCOL_PAD)
|
||||
game_state(GS_LANDED);
|
||||
else
|
||||
lander_show(&TheGame.lander, joyx[0], joyy[0]);
|
||||
} break;
|
||||
case GS_LANDED:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
case GS_COLLIDE:
|
||||
lander_flash(&TheGame.lander, TheGame.count);
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Screen color to black
|
||||
vic.color_border = VCOL_BLACK;
|
||||
vic.color_back = VCOL_BLACK;
|
||||
|
||||
vic.spr_mcolor0 = VCOL_MED_GREY;
|
||||
vic.spr_mcolor1 = VCOL_YELLOW;
|
||||
|
||||
memcpy((char *)0x0340, landersprites, 192);
|
||||
|
||||
spr_init(Screen);
|
||||
|
||||
// Start the game in ready state
|
||||
game_state(GS_READY);
|
||||
|
||||
// Forever
|
||||
for(;;)
|
||||
{
|
||||
// One game loop iteration
|
||||
game_loop();
|
||||
|
||||
// Wait one vsync
|
||||
vic_waitFrame();
|
||||
}
|
||||
|
||||
// Never reached
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,7 @@
|
||||
call ..\..\bin\oscar64 snake.c
|
||||
call ..\..\bin\oscar64 -n lander.c
|
||||
call ..\..\bin\oscar64 -n maze3d.c
|
||||
call ..\..\bin\oscar64 -n -O3 missile.c
|
||||
call ..\..\bin\oscar64 -n breakout.c
|
||||
call ..\..\bin\oscar64 -n connectfour.c
|
||||
call ..\..\bin\oscar64 -n -O2 hscrollshmup.c
|
||||
@@ -0,0 +1,17 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: snake.prg lander.prg maze3d.prg missile.prg breakout.prg connectfour.prg hscrollshmup.prg
|
||||
|
||||
snake.prg: snake.c
|
||||
@$(OSCAR64_CC) $<
|
||||
|
||||
missile.prg: missile.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) -O3 $<
|
||||
|
||||
hscrollshmup.prg: hscrollshmup.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) -O2 $<
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs
|
||||
@@ -0,0 +1,485 @@
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Moving the VIC into the third bank and making
|
||||
// room for double buffering+
|
||||
|
||||
byte * const Screen0 = (byte *)0xc800;
|
||||
byte * const Screen1 = (byte *)0xcc00;
|
||||
byte * const Font = (byte *)0xd000;
|
||||
byte * const Color = (byte *)0xd800;
|
||||
byte * const Color1 = (byte *)0xc400;
|
||||
|
||||
// Just to get started a mini maze
|
||||
static const char * maze[16] =
|
||||
{
|
||||
"################",
|
||||
"#..........#...#",
|
||||
"#.###.####.###.#",
|
||||
"#........#.#.#.#",
|
||||
"##.#####.###.#.#",
|
||||
"#..#......##.#.#",
|
||||
"#.##.####......#",
|
||||
"#.#.....#.####.#",
|
||||
"#.#####.#....#.#",
|
||||
"#.......######.#",
|
||||
"#.##.####......#",
|
||||
"#.#..##...####.#",
|
||||
"#.##....#....#.#",
|
||||
"#.#####.######.#",
|
||||
"#..............#",
|
||||
"################",
|
||||
};
|
||||
|
||||
// Character set including some ramps for the upper edge
|
||||
char charset[2048] = {
|
||||
#embed "../resources/maze3dchars.bin"
|
||||
};
|
||||
|
||||
// Current target screen
|
||||
char * DrawScreen;
|
||||
|
||||
// Current target index
|
||||
bool FlipIndex;
|
||||
|
||||
// Position and direction inside the maze
|
||||
sbyte px = 1, py = 3, dx = 1, dy = 0;
|
||||
|
||||
// Distance of blocks to the side, relative to the center of the screen
|
||||
// for full and half step
|
||||
static const char zxdist0[] = {18, 6, 4, 3, 2, 1, 0};
|
||||
static const char zxdist1[] = { 9, 5, 3, 2, 1, 0, 0};
|
||||
|
||||
|
||||
// Flip double buffer, copying the color ram
|
||||
|
||||
void screen_flip(void)
|
||||
{
|
||||
// Change idnex of screen
|
||||
FlipIndex = !FlipIndex;
|
||||
|
||||
// Wait until raster beam reaches bottom
|
||||
vic_waitBottom();
|
||||
|
||||
// Change vic start address
|
||||
vic_setmode(VICM_TEXT, FlipIndex ? Screen0 : Screen1, Font);
|
||||
|
||||
// Copy the color ram in four chunks, to avoid
|
||||
// colliding with the beam
|
||||
|
||||
char i = 0;
|
||||
do {
|
||||
Color[0x000 + i] = Color1[0x000 + i];
|
||||
i++;
|
||||
} while (i != 0);
|
||||
do {
|
||||
Color[0x100 + i] = Color1[0x100 + i];
|
||||
i++;
|
||||
} while (i != 0);
|
||||
do {
|
||||
Color[0x200 + i] = Color1[0x200 + i];
|
||||
i++;
|
||||
} while (i != 0);
|
||||
do {
|
||||
Color[0x300 + i] = Color1[0x300 + i];
|
||||
i++;
|
||||
} while (i != 0);
|
||||
|
||||
// Change target buffer for next frame
|
||||
DrawScreen = FlipIndex ? Screen1 : Screen0;
|
||||
}
|
||||
|
||||
// Rotating left or right is simulated by scrolling. For
|
||||
// performance reasons, we have four different scroll routines
|
||||
// due to two buffers and two directions
|
||||
|
||||
// Loop over the two buffers
|
||||
|
||||
#assign si 0
|
||||
#repeat
|
||||
|
||||
// other buffer
|
||||
#assign ri 1 - si
|
||||
|
||||
// pointers of the two screen buffers, from and to
|
||||
#define dst Screen##si
|
||||
#define src Screen##ri
|
||||
|
||||
// scroll left Screen0 or Screen1
|
||||
void screen_left_##si(void)
|
||||
{
|
||||
for(char sx=0; sx<40; sx+=4)
|
||||
{
|
||||
// Wait for the beam to be just below the first line
|
||||
vic_waitLine(58);
|
||||
|
||||
// Unroll for each row of screen and color ram
|
||||
#assign ry 0
|
||||
#repeat
|
||||
// Copy one row by four chars
|
||||
for(char x=0; x<36; x++)
|
||||
{
|
||||
dst[40 * ry + x] = dst[40 * ry + x + 4];
|
||||
Color[40 * ry + x] = Color[40 * ry + x + 4];
|
||||
}
|
||||
|
||||
// Fill in new screen and color data
|
||||
dst[40 * ry + 36] = src[40 * ry + sx + 0];
|
||||
dst[40 * ry + 37] = src[40 * ry + sx + 1];
|
||||
dst[40 * ry + 38] = src[40 * ry + sx + 2];
|
||||
dst[40 * ry + 39] = src[40 * ry + sx + 3];
|
||||
|
||||
Color[40 * ry + 36] = Color1[40 * ry + sx + 0];
|
||||
Color[40 * ry + 37] = Color1[40 * ry + sx + 1];
|
||||
Color[40 * ry + 38] = Color1[40 * ry + sx + 2];
|
||||
Color[40 * ry + 39] = Color1[40 * ry + sx + 3];
|
||||
|
||||
// repeat for each row
|
||||
#assign ry ry + 1
|
||||
#until ry == 25
|
||||
#undef ry
|
||||
}
|
||||
}
|
||||
|
||||
// scroll right Screen0 or Screen1
|
||||
void screen_right_##si(void)
|
||||
{
|
||||
for(char sx=40; sx>0; sx-=4)
|
||||
{
|
||||
vic_waitLine(58);
|
||||
#assign ry 0
|
||||
#repeat
|
||||
for(char x=39; x>=4; x--)
|
||||
{
|
||||
dst[40 * ry + x] = dst[40 * ry - 4 + x];
|
||||
Color[40 * ry + x] = Color[40 * ry - 4 + x];
|
||||
}
|
||||
|
||||
dst[40 * ry + 0] = src[40 * ry + sx - 4];
|
||||
dst[40 * ry + 1] = src[40 * ry + sx - 3];
|
||||
dst[40 * ry + 2] = src[40 * ry + sx - 2];
|
||||
dst[40 * ry + 3] = src[40 * ry + sx - 1];
|
||||
|
||||
Color[40 * ry + 0] = Color1[40 * ry + sx - 4];
|
||||
Color[40 * ry + 1] = Color1[40 * ry + sx - 3];
|
||||
Color[40 * ry + 2] = Color1[40 * ry + sx - 2];
|
||||
Color[40 * ry + 3] = Color1[40 * ry + sx - 1];
|
||||
#assign ry ry + 1
|
||||
#until ry == 25
|
||||
#undef ry
|
||||
}
|
||||
}
|
||||
|
||||
#assign si si + 1
|
||||
#until si == 2
|
||||
#undef si
|
||||
#undef ri
|
||||
|
||||
// Scroll current screen left
|
||||
void screen_left(void)
|
||||
{
|
||||
if (FlipIndex)
|
||||
screen_left_0();
|
||||
else
|
||||
screen_left_1();
|
||||
}
|
||||
|
||||
// Scroll current screen right
|
||||
void screen_right(void)
|
||||
{
|
||||
if (FlipIndex)
|
||||
screen_right_0();
|
||||
else
|
||||
screen_right_1();
|
||||
}
|
||||
|
||||
// Fill one color column
|
||||
void color_column(char cx, char color)
|
||||
{
|
||||
#assign ry 0
|
||||
#repeat
|
||||
Color1[40 * ry + cx] = color;
|
||||
#assign ry ry + 1
|
||||
#until ry == 25
|
||||
#undef ry
|
||||
}
|
||||
|
||||
// Fill one screen column
|
||||
void screen_column(char cx, char sx, char tc, char mc, char bc)
|
||||
{
|
||||
// Calculate top and bottom row
|
||||
char ty = sx / 4;
|
||||
char by = 25 - sx;
|
||||
|
||||
// Target pointer
|
||||
char * dp = DrawScreen + cx;
|
||||
|
||||
// Check for non empty column
|
||||
if (by > ty)
|
||||
{
|
||||
// Space above
|
||||
for(char cy=0; cy<ty; cy++)
|
||||
{
|
||||
*dp = 126; dp += 40;
|
||||
}
|
||||
|
||||
// Top element
|
||||
*dp = tc; dp += 40;
|
||||
|
||||
// Wall body
|
||||
char n = by - ty - 2;
|
||||
for(char cy=0; cy<n; cy++)
|
||||
{
|
||||
*dp = mc; dp += 40;
|
||||
}
|
||||
|
||||
// Bottom element
|
||||
*dp = bc; dp += 40;
|
||||
|
||||
// Space below
|
||||
for(char cy=by; cy<25; cy++)
|
||||
{
|
||||
*dp = 126; dp += 40;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Special case, clear column
|
||||
for(char cy=0; cy<25; cy++)
|
||||
{
|
||||
*dp = 126; dp += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the current maze using the given z/x distance array
|
||||
void maze_draw(const char * zxdist)
|
||||
{
|
||||
// pick colors based on orientation
|
||||
char cleft, cright, cfront;
|
||||
if (dx)
|
||||
{
|
||||
cfront = VCOL_MED_GREY;
|
||||
if (dx < 0)
|
||||
{
|
||||
cleft = VCOL_LT_GREY;
|
||||
cright = VCOL_DARK_GREY;
|
||||
}
|
||||
else
|
||||
{
|
||||
cleft = VCOL_DARK_GREY;
|
||||
cright = VCOL_LT_GREY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cleft = cright = VCOL_MED_GREY;
|
||||
cfront = dy > 0 ? VCOL_LT_GREY : VCOL_DARK_GREY;
|
||||
}
|
||||
|
||||
// Start position of player
|
||||
sbyte ix = px, iy = py;
|
||||
|
||||
// Starting at first screen column
|
||||
sbyte sx = 0;
|
||||
|
||||
for(char i=0; i<7; i++)
|
||||
{
|
||||
// Next screen column
|
||||
sbyte tx = 20 - zxdist[i];
|
||||
|
||||
// View blocked by wall
|
||||
if (maze[iy][ix] == '#')
|
||||
{
|
||||
// Fill with wall color
|
||||
for(char cx=sx; cx<40-sx; cx++)
|
||||
{
|
||||
color_column(cx, cfront);
|
||||
screen_column(cx, sx, 96 + (sx & 3), 96, 96);
|
||||
}
|
||||
|
||||
// And be done
|
||||
return ;
|
||||
}
|
||||
|
||||
// Check for left wall
|
||||
if (maze[iy - dx][ix + dy] == '#')
|
||||
{
|
||||
// Draw left wall
|
||||
for(char cx=sx; cx<tx; cx++)
|
||||
{
|
||||
// Perspective
|
||||
sbyte ty = cx / 4;
|
||||
sbyte by = 25 - cx;
|
||||
|
||||
color_column(cx, cleft);
|
||||
screen_column(cx, cx, 100 + (cx & 3), 96, 124);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw adjacent wall visible due to free space left
|
||||
sbyte ty = tx / 4;
|
||||
sbyte by = 25 - tx;
|
||||
|
||||
// All at same height, wall is facing us
|
||||
for(char cx=sx; cx<tx; cx++)
|
||||
{
|
||||
color_column(cx, cfront);
|
||||
screen_column(cx, tx, 96 + (tx & 3), 96, 96);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for right wall
|
||||
if (maze[iy + dx][ix - dy] == '#')
|
||||
{
|
||||
for(char cx=sx; cx<tx; cx++)
|
||||
{
|
||||
sbyte ty = cx / 4;
|
||||
sbyte by = 25 - cx;
|
||||
color_column(39 - cx, cright);
|
||||
screen_column(39 - cx, cx, 107 - (cx & 3), 96, 125);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sbyte ty = tx / 4;
|
||||
sbyte by = 25 - tx;
|
||||
for(char cx=sx; cx<tx; cx++)
|
||||
{
|
||||
color_column(39 - cx, cfront);
|
||||
screen_column(39 - cx, tx, 96 + (tx & 3), 96, 96);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance in maze
|
||||
sx = tx;
|
||||
ix += dx;
|
||||
iy += dy;
|
||||
}
|
||||
}
|
||||
|
||||
// Raster interrupts for ceiling and floor colors
|
||||
RIRQCode center, bottom;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
|
||||
// Install character set
|
||||
mmap_set(MMAP_RAM);
|
||||
memcpy(Font, charset, 2048);
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Switch screen
|
||||
vic_setmode(VICM_TEXT, Screen0, Font);
|
||||
|
||||
// Change colors
|
||||
vic.color_border = VCOL_BLACK;
|
||||
|
||||
// initialize raster IRQ
|
||||
rirq_init(true);
|
||||
|
||||
// Build switch to scroll line IRQ
|
||||
rirq_build(¢er, 1);
|
||||
// Change color for floor
|
||||
rirq_write(¢er, 0, &vic.color_back, VCOL_BLACK);
|
||||
// Put it into the perspective focus point
|
||||
rirq_set(0, 50 + 2 * 20, ¢er);
|
||||
|
||||
// Build the switch to normal IRQ
|
||||
rirq_build(&bottom, 1);
|
||||
// Change color for ceiling
|
||||
rirq_write(&bottom, 0, &vic.color_back, VCOL_WHITE);
|
||||
// place this at the bottom
|
||||
rirq_set(1, 250, &bottom);
|
||||
|
||||
// sort the raster IRQs
|
||||
rirq_sort();
|
||||
|
||||
// start raster IRQ processing
|
||||
rirq_start();
|
||||
|
||||
// Block multiple rotations
|
||||
bool rotate = false;
|
||||
|
||||
// Draw initial frame
|
||||
|
||||
screen_flip();
|
||||
maze_draw(zxdist0);
|
||||
screen_flip();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Read joystick input
|
||||
joy_poll(0);
|
||||
|
||||
// Forward or backward motion
|
||||
if (joyy[0])
|
||||
{
|
||||
// Target square
|
||||
sbyte tx = px - dx * joyy[0];
|
||||
sbyte ty = py - dy * joyy[0];
|
||||
|
||||
// Check i empty
|
||||
if (maze[ty][tx] != '#')
|
||||
{
|
||||
if (joyy[0] < 0)
|
||||
{
|
||||
// Forward animation
|
||||
px = tx;
|
||||
py = ty;
|
||||
maze_draw(zxdist1);
|
||||
screen_flip();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward animation
|
||||
maze_draw(zxdist1);
|
||||
screen_flip();
|
||||
px = tx;
|
||||
py = ty;
|
||||
}
|
||||
}
|
||||
|
||||
// New frame at new position
|
||||
maze_draw(zxdist0);
|
||||
screen_flip();
|
||||
}
|
||||
|
||||
// Check if new rotation
|
||||
if (!rotate)
|
||||
{
|
||||
if (joyx[0] == 1)
|
||||
{
|
||||
// Rotate right
|
||||
sbyte t = dx; dx = -dy; dy = t;
|
||||
rotate = true;
|
||||
maze_draw(zxdist0);
|
||||
screen_left();
|
||||
}
|
||||
else if (joyx[0] == -1)
|
||||
{
|
||||
// Rotate left
|
||||
sbyte t = dx; dx = dy; dy = -t;
|
||||
rotate = true;
|
||||
maze_draw(zxdist0);
|
||||
screen_right();
|
||||
}
|
||||
}
|
||||
else if (!joyx[0])
|
||||
{
|
||||
// No rotation, may rotate again in next frame
|
||||
rotate = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,869 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <c64/cia.h>
|
||||
#include <gfx/mcbitmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Make some room
|
||||
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
||||
|
||||
// Sprite assets
|
||||
const char MissileSprites[] = {
|
||||
#embed "../resources/missilesprites.bin"
|
||||
};
|
||||
|
||||
// Charset assets
|
||||
const char MissileChars[] = {
|
||||
#embed "../resources/missilechars.bin"
|
||||
};
|
||||
|
||||
// Graphics areas in bank 3
|
||||
#define Color1 ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
#define Hires ((char *)0xe000)
|
||||
#define Sprites ((char *)0xd000)
|
||||
#define Charset ((char *)0xd800)
|
||||
|
||||
// Joystick and crosshair control
|
||||
volatile int CrossX = 160, CrossY = 100;
|
||||
bool CrossP = false;
|
||||
char CrossDelay = 0;
|
||||
|
||||
// Display bitmap
|
||||
Bitmap sbm;
|
||||
const ClipRect scr = { 0, 0, 320, 200 };
|
||||
|
||||
// Structure for a explosion
|
||||
struct Explosion
|
||||
{
|
||||
int x, y; // Center of circle
|
||||
char r; // Radius of circle
|
||||
Explosion * next; // Next explosion in list
|
||||
};
|
||||
|
||||
// Structure for a missile (defensive and ICBM)
|
||||
struct Missile
|
||||
{
|
||||
int sx, sy; // start position
|
||||
int tx, ty; // target position
|
||||
int x, y; // current position
|
||||
int dx, dy; // distance in x and y
|
||||
int d; // error term for Bresenham
|
||||
sbyte stepx; // direction in x (+1 or -1)
|
||||
sbyte cnt; // speed counter
|
||||
Missile * next; // next missile in list
|
||||
};
|
||||
|
||||
// Storage space for explosion
|
||||
Explosion explosions[16];
|
||||
// First free and first used explosion
|
||||
Explosion * efree, * eused;
|
||||
|
||||
// Storage space for defending missiles
|
||||
Missile missiles[8];
|
||||
// First free and first used missile
|
||||
Missile * mfree, * mused;
|
||||
// Number of missiles available
|
||||
char nmissiles;
|
||||
|
||||
// Storage space for ICMBs
|
||||
Missile icbms[16];
|
||||
// First free and first used ICBM
|
||||
Missile * ifree, * iused;
|
||||
// Speed and number of ICBMs still incoming
|
||||
char icbmspeed, icbmcount;
|
||||
|
||||
// Cities not yet destroyed
|
||||
bool cities[6];
|
||||
char ncities;
|
||||
|
||||
// Init status bar at top
|
||||
void status_init(void)
|
||||
{
|
||||
memset(Color1, ' ', 40);
|
||||
memset(Color2, 1, 40);
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
Color1[i + 2] = '0';
|
||||
Color1[i + 12] = '0';
|
||||
Color2[i + 12] = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand an 8x8 character to 16x16 on screen
|
||||
void char_put(char cx, char cy, char c, char color)
|
||||
{
|
||||
// Get pointer to glyph data
|
||||
const char * sp = MissileChars + 8 * c;
|
||||
|
||||
// Loop over all pixel
|
||||
for(char y=0; y<8; y++)
|
||||
{
|
||||
char cl = sp[y];
|
||||
for(char x=0; x<8; x++)
|
||||
{
|
||||
// Draw two pixel if bit is set
|
||||
if (cl & 128)
|
||||
{
|
||||
bmmc_put(&sbm, cx + 2 * x, cy + 2 * y + 0, color);
|
||||
bmmc_put(&sbm, cx + 2 * x, cy + 2 * y + 1, color);
|
||||
}
|
||||
|
||||
// Next bit
|
||||
cl <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write a zero terminated string on screen
|
||||
void char_write(char cx, char cy, const char * s, char color)
|
||||
{
|
||||
// Loop over all characters
|
||||
while (*s)
|
||||
{
|
||||
char_put(cx, cy, *s, color);
|
||||
s++;
|
||||
cx += 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the score from a given digit on
|
||||
void score_inc(char digit, unsigned val)
|
||||
{
|
||||
// Lowest digit to increment
|
||||
char at = 9 - digit;
|
||||
|
||||
// Loop while there is still score to account for
|
||||
while (val)
|
||||
{
|
||||
// Increment one character
|
||||
char ch = Color1[at] + val % 10;
|
||||
|
||||
// Remove low digit from number
|
||||
val /= 10;
|
||||
|
||||
// Check overflow
|
||||
if (ch > '9')
|
||||
{
|
||||
ch -= 10;
|
||||
val++;
|
||||
}
|
||||
|
||||
Color1[at] = ch;
|
||||
|
||||
// Next higher character
|
||||
at --;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset score and update high score
|
||||
void score_reset(void)
|
||||
{
|
||||
// Find first digit, where score and highscore differ
|
||||
char i = 0;
|
||||
while (i < 8 && Color1[i + 2] == Color1[i + 12])
|
||||
i++;
|
||||
|
||||
// Check if new score is higher
|
||||
if (i < 8 && Color1[i + 2] > Color1[i + 12])
|
||||
{
|
||||
// If so, copy to highscore
|
||||
while (i < 8)
|
||||
{
|
||||
Color1[i + 12] = Color1[i + 2];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear score
|
||||
for(char i=0; i<8; i++)
|
||||
Color1[i + 2] = '0';
|
||||
}
|
||||
|
||||
// Update number of missiles
|
||||
void status_missiles(char num)
|
||||
{
|
||||
char n = 0;
|
||||
|
||||
// Draw full pairs
|
||||
while (2 * n + 1 < num)
|
||||
{
|
||||
Color1[25 + n] = 92;
|
||||
n++;
|
||||
}
|
||||
// Draw remaining single one
|
||||
if (num & 1)
|
||||
{
|
||||
Color1[25 + n] = 93;
|
||||
n++;
|
||||
}
|
||||
// Empty remainder
|
||||
while (n < 15)
|
||||
{
|
||||
Color1[25 + n] = 94;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize explosion list
|
||||
void explosion_init(void)
|
||||
{
|
||||
// No explosion active
|
||||
eused = nullptr;
|
||||
|
||||
// First free explosion element
|
||||
efree = explosions;
|
||||
// Build list
|
||||
for(char i=0; i<15; i++)
|
||||
explosions[i].next = explosions + i + 1;
|
||||
// Terminate last element
|
||||
explosions[15].next = nullptr;
|
||||
}
|
||||
|
||||
// Start a new explosion
|
||||
void explosion_start(int x, int y)
|
||||
{
|
||||
// Free slot in list of explosions?
|
||||
if (efree)
|
||||
{
|
||||
// Move entry from free to used list
|
||||
Explosion * e = efree;
|
||||
efree = e->next;
|
||||
e->next = eused;
|
||||
eused = e;
|
||||
|
||||
// Initialize position and size
|
||||
e->r = 0;
|
||||
e->x = x;
|
||||
e->y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// Animate all explosions
|
||||
void explosion_animate(void)
|
||||
{
|
||||
// Loop over active explosions with "e", use "ep" to point
|
||||
// to previous explosion, so we can remove the current explosion
|
||||
// from the list
|
||||
Explosion * e = eused, * ep = nullptr;
|
||||
while (e)
|
||||
{
|
||||
// Remember next entry in list
|
||||
Explosion * en = e->next;
|
||||
|
||||
// Increment phase (radius)
|
||||
e->r++;
|
||||
|
||||
// Advance every fourth frame
|
||||
if (!(e->r & 3))
|
||||
{
|
||||
// Draw or erase outer perimeter depending on growing or
|
||||
// shrinking explosion phase
|
||||
if (e->r <= 64)
|
||||
bmmc_circle(&sbm, &scr, e->x, e->y, e->r >> 2, 1);
|
||||
else
|
||||
bmmc_circle(&sbm, &scr, e->x, e->y, 33 - (e->r >> 2), 0);
|
||||
}
|
||||
|
||||
// End of explosion live
|
||||
if (e->r == 128)
|
||||
{
|
||||
// Remove explosion from used list
|
||||
if (ep)
|
||||
ep->next = e->next;
|
||||
else
|
||||
eused = e->next;
|
||||
|
||||
// Prepend it to free list
|
||||
e->next = efree;
|
||||
efree = e;
|
||||
}
|
||||
else
|
||||
ep = e;
|
||||
|
||||
// Next explosion in list
|
||||
e = en;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize defending missile list
|
||||
void missile_init(void)
|
||||
{
|
||||
mused = nullptr;
|
||||
mfree = missiles;
|
||||
for(char i=0; i<7; i++)
|
||||
missiles[i].next = missiles + i + 1;
|
||||
missiles[7].next = nullptr;
|
||||
}
|
||||
|
||||
// Add a new defending missile
|
||||
void missile_start(int sx, int sy, int tx, int ty)
|
||||
{
|
||||
// Check if entry in free list and missile in silo remaining
|
||||
if (mfree && nmissiles > 0)
|
||||
{
|
||||
// Detach from free list
|
||||
Missile * m = mfree;
|
||||
mfree = m->next;
|
||||
|
||||
// Attach to active list
|
||||
m->next = mused;
|
||||
mused = m;
|
||||
|
||||
// Initialize start and target coordinates
|
||||
m->sx = sx >> 1; m->x = sx >> 1;
|
||||
m->sy = sy; m->y = sy;
|
||||
m->tx = tx >> 1;
|
||||
m->ty = ty;
|
||||
|
||||
// Initialize line drawing parameters
|
||||
m->dy = m->sy - m->ty;
|
||||
m->dx = m->tx - m->sx;
|
||||
m->stepx = 1;
|
||||
if (m->dx < 0)
|
||||
{
|
||||
m->dx = -m->dx;
|
||||
m->stepx = -1;
|
||||
}
|
||||
|
||||
m->d = m->dy - m->dx;
|
||||
m->dx *= 2;
|
||||
m->dy *= 2;
|
||||
|
||||
// Remove missile from silo
|
||||
nmissiles--;
|
||||
status_missiles(nmissiles);
|
||||
}
|
||||
}
|
||||
|
||||
// Animate all active missiles
|
||||
void missile_animate(void)
|
||||
{
|
||||
Missile * m = mused, * mp = nullptr;
|
||||
while (m)
|
||||
{
|
||||
Missile * mn = m->next;
|
||||
|
||||
// Advance missile position using one step of Bresenham
|
||||
if (m->d >= 0)
|
||||
{
|
||||
m->y--;
|
||||
m->d -= m->dx;
|
||||
}
|
||||
if (m->d < 0)
|
||||
{
|
||||
m->x += m->stepx;
|
||||
m->d += m->dy;
|
||||
}
|
||||
|
||||
// Check if target reached
|
||||
if (m->y == m->ty)
|
||||
{
|
||||
// If so, clear line and start explosion
|
||||
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
||||
explosion_start(m->x * 2, m->y);
|
||||
|
||||
// Remove from active list
|
||||
if (mp)
|
||||
mp->next = m->next;
|
||||
else
|
||||
mused = m->next;
|
||||
m->next = mfree;
|
||||
mfree = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw new pixel in missile trace
|
||||
bmmc_put(&sbm, m->x * 2, m->y, 3);
|
||||
mp = m;
|
||||
}
|
||||
|
||||
m = mn;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize incoming ICBM list
|
||||
void icbm_init(void)
|
||||
{
|
||||
iused = nullptr;
|
||||
ifree = icbms;
|
||||
for(char i=0; i<15; i++)
|
||||
icbms[i].next = icbms + i + 1;
|
||||
icbms[15].next = nullptr;
|
||||
}
|
||||
|
||||
// Add a new ICBM to the attacking set
|
||||
void icbm_start(int sx, int sy, int tx, int ty)
|
||||
{
|
||||
if (icbmcount && ifree)
|
||||
{
|
||||
Missile * m = ifree;
|
||||
ifree = m->next;
|
||||
m->next = iused;
|
||||
iused = m;
|
||||
|
||||
m->sx = sx >> 1; m->x = sx >> 1;
|
||||
m->sy = sy; m->y = sy;
|
||||
m->tx = tx >> 1;
|
||||
m->ty = ty;
|
||||
m->cnt = 0;
|
||||
|
||||
m->dy = m->ty - m->sy;
|
||||
m->dx = m->tx - m->sx;
|
||||
m->stepx = 1;
|
||||
if (m->dx < 0)
|
||||
{
|
||||
m->dx = -m->dx;
|
||||
m->stepx = -1;
|
||||
}
|
||||
|
||||
m->d = m->dy - m->dx;
|
||||
m->dx *= 2;
|
||||
m->dy *= 2;
|
||||
|
||||
icbmcount--;
|
||||
}
|
||||
}
|
||||
|
||||
void icbm_animate(void)
|
||||
{
|
||||
Missile * m = iused, * mp = nullptr;
|
||||
while (m)
|
||||
{
|
||||
Missile * mn = m->next;
|
||||
|
||||
// Check speed of ICBMs
|
||||
m->cnt += icbmspeed;
|
||||
while (m->cnt > 0)
|
||||
{
|
||||
m->cnt -= 32;
|
||||
|
||||
// Draw pixel in trace
|
||||
bmmc_put(&sbm, m->x * 2, m->y, 2);
|
||||
|
||||
// Advance using Bresenham
|
||||
if (m->d >= 0)
|
||||
{
|
||||
m->y++;
|
||||
m->d -= m->dx;
|
||||
}
|
||||
if (m->d < 0)
|
||||
{
|
||||
m->x += m->stepx;
|
||||
m->d += m->dy;
|
||||
}
|
||||
|
||||
// Check if colliding with cloud or target reached
|
||||
if (bmmc_get(&sbm, m->x * 2, m->y) == 1 || m->y == m->ty)
|
||||
{
|
||||
// If so, clear trace and start explosion
|
||||
bmmcu_line(&sbm, m->sx * 2, m->sy, m->tx * 2, m->ty, 0);
|
||||
explosion_start(m->x * 2, m->y);
|
||||
|
||||
// Check if we hit the ground
|
||||
if (m->y == m->ty)
|
||||
{
|
||||
// If so, find matching city
|
||||
int x = m->x * 2;
|
||||
char ix;
|
||||
if (x > 160)
|
||||
ix = ((x - 202) >> 5) + 3;
|
||||
else
|
||||
ix = (x - 58) >> 5;
|
||||
|
||||
// Destroy, destroy, annihilate, kill, kill
|
||||
if (cities[ix])
|
||||
{
|
||||
ncities--;
|
||||
cities[ix] = false;
|
||||
spr_show(ix + 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Add score for destroyed ICBM
|
||||
score_inc(0, 25);
|
||||
|
||||
// Remove from list
|
||||
if (mp)
|
||||
mp->next = m->next;
|
||||
else
|
||||
iused = m->next;
|
||||
m->next = ifree;
|
||||
ifree = m;
|
||||
m = nullptr;
|
||||
|
||||
// End loop early
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If ICBM still in flight
|
||||
if (m)
|
||||
{
|
||||
// Remember for list management
|
||||
mp = m;
|
||||
// Draw white head
|
||||
bmmc_put(&sbm, m->x * 2, m->y, 1);
|
||||
}
|
||||
|
||||
m = mn;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize game screen
|
||||
void screen_init(void)
|
||||
{
|
||||
// Clean up
|
||||
bmmcu_rect_fill(&sbm, 0, 8, 320, 184, 0);
|
||||
|
||||
// Draw bottom
|
||||
bmmcu_rect_fill(&sbm, 0, 192, 320, 8, 3);
|
||||
bmmc_quad_fill(&sbm, &scr, 0, 192, 16, 184, 32, 184, 48, 192, MixedColors[3][3]);
|
||||
bmmc_quad_fill(&sbm, &scr, 136, 192, 152, 184, 176, 184, 192, 192, MixedColors[3][3]);
|
||||
bmmc_quad_fill(&sbm, &scr, 272, 192, 288, 184, 304, 184, 320, 192, MixedColors[3][3]);
|
||||
|
||||
// Show cities
|
||||
for(char i=0; i<3; i++)
|
||||
{
|
||||
if (cities[i + 0])
|
||||
spr_set(i + 1, true, 70 + 32 * i, 222, 65, 15, false, false, false);
|
||||
if (cities[i + 3])
|
||||
spr_set(i + 4, true, 214 + 32 * i, 222, 65, 15, false, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear inner area of screen
|
||||
void screen_clear(void)
|
||||
{
|
||||
bmmcu_rect_fill(&sbm, 0, 8, 320, 176, 0);
|
||||
}
|
||||
|
||||
// Interrupt routine for joystick control, called by raster IRQ at bottom
|
||||
// of screen
|
||||
|
||||
__interrupt void joy_interrupt()
|
||||
{
|
||||
// vic.color_border++;
|
||||
// Poll joystick
|
||||
joy_poll(0);
|
||||
|
||||
// Move crosshair coordinates
|
||||
int cx = CrossX + 2 * joyx[0], cy = CrossY + 2 * joyy[0];
|
||||
|
||||
// Stop at edges of screen
|
||||
if (cx < 8)
|
||||
cx = 8;
|
||||
else if (cx > 312)
|
||||
cx = 312;
|
||||
if (cy < 20)
|
||||
cy = 20;
|
||||
else if (cy > 172)
|
||||
cy = 172;
|
||||
|
||||
// Move crosshair sprite
|
||||
spr_move(0, cx + 14, cy + 40);
|
||||
CrossX = cx;
|
||||
CrossY = cy;
|
||||
|
||||
// Check button
|
||||
if (joyb[0])
|
||||
{
|
||||
// Avoid quickfire and bouncing
|
||||
if (CrossDelay == 0)
|
||||
{
|
||||
// Request fire from non interrupt code
|
||||
CrossP = true;
|
||||
CrossDelay = 4;
|
||||
}
|
||||
}
|
||||
else if (CrossDelay > 0)
|
||||
CrossDelay--;
|
||||
// vic.color_border--;
|
||||
}
|
||||
|
||||
enum GameState
|
||||
{
|
||||
GS_READY, // Getting ready
|
||||
GS_LEVEL, // Show level message
|
||||
GS_PLAYING, // Playing the game
|
||||
GS_BONUS, // Landed on pad
|
||||
GS_ARMAGEDDON, // Show end game animation
|
||||
GS_END // Wait for restart
|
||||
};
|
||||
|
||||
// State of the game
|
||||
struct Game
|
||||
{
|
||||
GameState state;
|
||||
byte count, level;
|
||||
|
||||
} TheGame; // Only one game, so global variable
|
||||
|
||||
// Character buffer for some texts
|
||||
char cbuffer[10];
|
||||
|
||||
void game_state(GameState state)
|
||||
{
|
||||
|
||||
TheGame.state = state;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Start of new game
|
||||
score_reset();
|
||||
screen_init();
|
||||
char_write(40, 100, s"READY PLAYER 1", 3);
|
||||
|
||||
// New cities
|
||||
for(char i=0; i<6; i++)
|
||||
cities[i] = true;
|
||||
ncities = 6;
|
||||
TheGame.count = 60;
|
||||
|
||||
// Starting at level 1
|
||||
TheGame.level = 0;
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
// Advance to next level
|
||||
TheGame.level++;
|
||||
utoa(TheGame.level ,cbuffer, 10);
|
||||
screen_clear();
|
||||
char_write(96, 100, s"LEVEL", 3);
|
||||
char_write(96 + 16 * 6, 100, cbuffer, 3);
|
||||
TheGame.count = 30;
|
||||
break;
|
||||
|
||||
case GS_PLAYING:
|
||||
// Avoid old fire request
|
||||
CrossP = false;
|
||||
|
||||
// Setup display
|
||||
screen_init();
|
||||
missile_init();
|
||||
explosion_init();
|
||||
icbm_init();
|
||||
|
||||
// A new set of 30 missiles
|
||||
nmissiles = 30;
|
||||
status_missiles(nmissiles);
|
||||
|
||||
// Game parameters based on level
|
||||
if (TheGame.level < 112)
|
||||
icbmspeed = 8 + TheGame.level;
|
||||
else
|
||||
icbmspeed = 120;
|
||||
|
||||
if (TheGame.level < 50)
|
||||
icbmcount = 5 + TheGame.level / 2;
|
||||
else
|
||||
icbmcount = 30;
|
||||
|
||||
TheGame.count = 15;
|
||||
break;
|
||||
|
||||
case GS_BONUS:
|
||||
{
|
||||
// Show bonus
|
||||
|
||||
unsigned bonus = ncities * 50 + nmissiles * 5;
|
||||
utoa(bonus, cbuffer, 10);
|
||||
|
||||
char_write(96, 100, s"BONUS", 3);
|
||||
char_write(96 + 16 * 6, 100, cbuffer, 3);
|
||||
|
||||
score_inc(0, bonus);
|
||||
TheGame.count = 30;
|
||||
} break;
|
||||
|
||||
case GS_ARMAGEDDON:
|
||||
TheGame.count = 0;
|
||||
break;
|
||||
|
||||
case GS_END:
|
||||
char_write(104, 92, s"THE END", 0);
|
||||
TheGame.count = 120;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Main game play code
|
||||
void game_play(void)
|
||||
{
|
||||
// Check if fire request
|
||||
if (CrossP)
|
||||
{
|
||||
int cx = CrossX, cy = CrossY;
|
||||
|
||||
// Find launch site
|
||||
int sx = 160;
|
||||
if (cx < 120)
|
||||
sx = 24;
|
||||
else if (cx > 200)
|
||||
sx = 296;
|
||||
|
||||
// Fire missile
|
||||
missile_start(sx, 184, cx, cy);
|
||||
|
||||
// Reset request
|
||||
CrossP = false;
|
||||
}
|
||||
|
||||
// Wait for next ICMB to enter the game
|
||||
if (!--TheGame.count)
|
||||
{
|
||||
// Pick target city
|
||||
char ci;
|
||||
do {
|
||||
ci = rand() & 7;
|
||||
} while (ci >= 6 || !cities[ci]);
|
||||
|
||||
int cx;
|
||||
if (ci < 3)
|
||||
cx = 58 + 32 * ci;
|
||||
else
|
||||
cx = 202 + 32 * (ci - 3);
|
||||
|
||||
// Launch ICBM
|
||||
icbm_start((rand() & 0xff) + 32, 0, cx, 184);
|
||||
|
||||
// Next launch time
|
||||
TheGame.count = 8 + (rand() & 63);
|
||||
}
|
||||
|
||||
// Advance defending missiles by four pixels
|
||||
for(char i=0; i<4; i++)
|
||||
missile_animate();
|
||||
|
||||
// Advance ICBMs
|
||||
icbm_animate();
|
||||
|
||||
// Show explosions
|
||||
explosion_animate();
|
||||
}
|
||||
|
||||
// Main game loop, entered every VSYNC, slower if too busy with explosions
|
||||
void game_loop(void)
|
||||
{
|
||||
switch(TheGame.state)
|
||||
{
|
||||
case GS_READY:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_LEVEL);
|
||||
break;
|
||||
case GS_LEVEL:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_PLAYING);
|
||||
break;
|
||||
|
||||
case GS_PLAYING:
|
||||
game_play();
|
||||
|
||||
// Check for level and game end conditions
|
||||
if (!icbmcount && !iused && !eused)
|
||||
game_state(GS_BONUS);
|
||||
else if (ncities == 0)
|
||||
game_state(GS_ARMAGEDDON);
|
||||
break;
|
||||
|
||||
case GS_BONUS:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_LEVEL);
|
||||
break;
|
||||
|
||||
case GS_ARMAGEDDON:
|
||||
// Draw end game animation
|
||||
TheGame.count++;
|
||||
bmmc_circle(&sbm, &scr, 160, 100, TheGame.count, 1);
|
||||
explosion_animate();
|
||||
if (TheGame.count == 90)
|
||||
game_state(GS_END);
|
||||
break;
|
||||
|
||||
case GS_END:
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupts for status line and joystick routine
|
||||
RIRQCode bottom, top;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Activate trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// Disable CIA interrupts, we do not want interference
|
||||
// with our joystick interrupt
|
||||
cia_init();
|
||||
|
||||
// Copy assets
|
||||
mmap_set(MMAP_RAM);
|
||||
memcpy(Sprites, MissileSprites, 1024);
|
||||
memcpy(Charset, MissileChars, 2048);
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
// Clean out screen space
|
||||
memset(Color1, 0x18, 1000);
|
||||
memset(Color2, 0x06, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
memset(Color2 + 40 * 23, 0x07, 80);
|
||||
|
||||
// initialize raster IRQ
|
||||
rirq_init(true);
|
||||
|
||||
// Switch to hires mode
|
||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||
spr_init(Color1);
|
||||
|
||||
// Black background and border
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_border = VCOL_BLACK;
|
||||
|
||||
// Init bitmap
|
||||
bm_init(&sbm, Hires, 40, 25);
|
||||
|
||||
// Init status line
|
||||
status_init();
|
||||
|
||||
// Init cross hair sprite
|
||||
spr_set(0, true, CrossX + 14, CrossY + 40, 64, 1, false, false, false);
|
||||
|
||||
// Build to multicolor highres at top of screen
|
||||
rirq_build(&top, 3);
|
||||
rirq_delay(&top, 10);
|
||||
rirq_write(&top, 1, &vic.ctrl1, VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||
rirq_write(&top, 2, &vic.memptr, 0x28);
|
||||
rirq_set(0, 57, &top);
|
||||
|
||||
// Switch to text mode for status line and poll joystick at bottom
|
||||
rirq_build(&bottom, 3);
|
||||
rirq_write(&bottom, 0, &vic.memptr, 0x27);
|
||||
rirq_write(&bottom, 1, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||
rirq_call(&bottom, 2, joy_interrupt);
|
||||
rirq_set(1, 252, &bottom);
|
||||
|
||||
// sort the raster IRQs
|
||||
rirq_sort();
|
||||
|
||||
// start raster IRQ processing
|
||||
rirq_start();
|
||||
|
||||
// start game state machine
|
||||
game_state(GS_READY);
|
||||
for(;;)
|
||||
{
|
||||
game_loop();
|
||||
rirq_wait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,282 @@
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/vic.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// Position/Direction on screen
|
||||
struct Point
|
||||
{
|
||||
sbyte x, y;
|
||||
};
|
||||
|
||||
struct Snake
|
||||
{
|
||||
Point head; // Position of head
|
||||
Point dir; // Direction of head
|
||||
Point tail[256]; // Position of tail
|
||||
byte length; // Length of tail
|
||||
byte pos; // Tail start
|
||||
};
|
||||
|
||||
enum GameState
|
||||
{
|
||||
GS_READY, // Getting ready
|
||||
GS_PLAYING, // Playing the game
|
||||
GS_COLLIDE // Collided with something
|
||||
};
|
||||
|
||||
// State of the game
|
||||
struct Game
|
||||
{
|
||||
GameState state;
|
||||
byte count;
|
||||
Snake snake; // use an array for multiplayer
|
||||
|
||||
} TheGame; // Only one game, so global variable
|
||||
|
||||
|
||||
// Screen and color ram address
|
||||
|
||||
#define Screen ((byte *)0x0400)
|
||||
#define Color ((byte *)0xd800)
|
||||
|
||||
// Put one char on screen
|
||||
inline void screen_put(byte x, byte y, char ch, char color)
|
||||
{
|
||||
Screen[40 * y + x] = ch;
|
||||
Color[40 * y + x] = color;
|
||||
}
|
||||
|
||||
// Get one char from screen
|
||||
inline char screen_get(byte x, byte y)
|
||||
{
|
||||
return Screen[40 * y + x];
|
||||
}
|
||||
|
||||
// Put a fruit/heart at random position
|
||||
void screen_fruit(void)
|
||||
{
|
||||
byte x, y;
|
||||
do
|
||||
{
|
||||
// Draw a random position
|
||||
x = 1 + rand() % 38;
|
||||
y = 1 + rand() % 23;
|
||||
|
||||
// Ensure it is an empty place
|
||||
} while (screen_get(x, y) != ' ');
|
||||
|
||||
// Put the heart on screen
|
||||
screen_put(x, y, 83, VCOL_YELLOW);
|
||||
|
||||
}
|
||||
|
||||
// Clear screen and draw borders
|
||||
void screen_init(void)
|
||||
{
|
||||
// Fill screen with spaces
|
||||
memset(Screen, ' ', 1000);
|
||||
|
||||
// Bottom and top row
|
||||
for(byte x=0; x<40; x++)
|
||||
{
|
||||
screen_put(x, 0, 0xa0, VCOL_LT_GREY);
|
||||
screen_put(x, 24, 0xa0, VCOL_LT_GREY);
|
||||
}
|
||||
|
||||
// Left and right column
|
||||
for(byte y=0; y<25; y++)
|
||||
{
|
||||
screen_put( 0, y, 0xa0, VCOL_LT_GREY);
|
||||
screen_put( 39, y, 0xa0, VCOL_LT_GREY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialize a snake
|
||||
void snake_init(Snake * s)
|
||||
{
|
||||
// Length of tail is one
|
||||
s->length = 1;
|
||||
s->pos = 0;
|
||||
|
||||
// Snake in the center of screen
|
||||
s->head.x = 20;
|
||||
s->head.y = 12;
|
||||
|
||||
// Starting to the right
|
||||
s->dir.x = 1;
|
||||
s->dir.y = 0;
|
||||
|
||||
// Show head
|
||||
screen_put(s->head.x, s->head.y, 81, VCOL_WHITE);
|
||||
}
|
||||
|
||||
bool snake_advance(Snake * s)
|
||||
{
|
||||
// Promote head to start of tail
|
||||
s->tail[s->pos] = s->head;
|
||||
s->pos++;
|
||||
|
||||
screen_put(s->head.x, s->head.y, 81, VCOL_LT_BLUE);
|
||||
|
||||
// Advance head
|
||||
s->head.x += s->dir.x;
|
||||
s->head.y += s->dir.y;
|
||||
|
||||
// Get character at new head position
|
||||
char ch = screen_get(s->head.x, s->head.y);
|
||||
|
||||
// Draw head
|
||||
screen_put(s->head.x, s->head.y, 81, VCOL_WHITE);
|
||||
|
||||
// Clear tail
|
||||
char tpos = s->pos - s->length;
|
||||
screen_put(s->tail[tpos].x, s->tail[tpos].y, ' ', VCOL_BLACK);
|
||||
|
||||
// Did snake collect the fruit
|
||||
if (ch == 83)
|
||||
{
|
||||
// Extend tail
|
||||
s->length++;
|
||||
screen_fruit();
|
||||
}
|
||||
else if (ch != ' ')
|
||||
{
|
||||
// Snake collided with something
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// flash the snake after collision
|
||||
void snake_flash(Snake * s, char c)
|
||||
{
|
||||
// Loop over all tail elements
|
||||
for(char i=0; i<s->length; i++)
|
||||
{
|
||||
// Set color
|
||||
char tpos = s->pos - i - 1;
|
||||
screen_put(s->tail[tpos].x, s->tail[tpos].y, 81, c);
|
||||
}
|
||||
}
|
||||
|
||||
// Change snake direction based on user input
|
||||
void snake_control(Snake * s, sbyte jx, sbyte jy)
|
||||
{
|
||||
// First change from horizontal to vertical, otherwise
|
||||
// check vertical to horizontal
|
||||
if (s->dir.x && jy)
|
||||
{
|
||||
s->dir.x = 0;
|
||||
s->dir.y = jy;
|
||||
}
|
||||
else if (s->dir.y && jx)
|
||||
{
|
||||
s->dir.y = 0;
|
||||
s->dir.x = jx;
|
||||
}
|
||||
}
|
||||
|
||||
void game_state(GameState state)
|
||||
{
|
||||
// Set new state
|
||||
TheGame.state = state;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Clear the screen
|
||||
screen_init();
|
||||
TheGame.count = 32;
|
||||
break;
|
||||
|
||||
case GS_PLAYING:
|
||||
// Init the snake
|
||||
snake_init(&TheGame.snake);
|
||||
|
||||
// Initial fruit
|
||||
screen_fruit();
|
||||
|
||||
TheGame.count = 16;
|
||||
break;
|
||||
|
||||
case GS_COLLIDE:
|
||||
TheGame.count = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Colors for collision "animation"
|
||||
char FlashColors[] = {
|
||||
VCOL_YELLOW,
|
||||
VCOL_WHITE,
|
||||
VCOL_LT_GREY,
|
||||
VCOL_YELLOW,
|
||||
VCOL_ORANGE,
|
||||
VCOL_RED,
|
||||
VCOL_MED_GREY,
|
||||
VCOL_DARK_GREY
|
||||
};
|
||||
|
||||
// Main game loop, invoked every vsync
|
||||
void game_loop(void)
|
||||
{
|
||||
switch (TheGame.state)
|
||||
{
|
||||
case GS_READY:
|
||||
// Countdown ready to start
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_PLAYING);
|
||||
break;
|
||||
case GS_PLAYING:
|
||||
// Check player input on every frame
|
||||
joy_poll(0);
|
||||
snake_control(&TheGame.snake, joyx[0], joyy[0]);
|
||||
|
||||
if (!--TheGame.count)
|
||||
{
|
||||
// Move snake every four frames, advance to collision
|
||||
// state if collided
|
||||
if (snake_advance(&TheGame.snake))
|
||||
game_state(GS_COLLIDE);
|
||||
else
|
||||
TheGame.count = 4;
|
||||
}
|
||||
break;
|
||||
case GS_COLLIDE:
|
||||
// Flash the collided snake
|
||||
snake_flash(&TheGame.snake, FlashColors[(16 - TheGame.count) / 2]);
|
||||
if (!--TheGame.count)
|
||||
game_state(GS_READY);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Screen color to black
|
||||
vic.color_border = VCOL_BLACK;
|
||||
vic.color_back = VCOL_BLACK;
|
||||
|
||||
// Start the game in ready state
|
||||
game_state(GS_READY);
|
||||
|
||||
// Forever
|
||||
for(;;)
|
||||
{
|
||||
// One game loop iteration
|
||||
game_loop();
|
||||
|
||||
// Wait one vsync
|
||||
vic_waitFrame();
|
||||
}
|
||||
|
||||
// Never reached
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define Color ((char *)0xd000)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen, Brush;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x10, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
int poly_x[] = {0, 32, 32, 24, 40, 32, 32, 64, 52, 42, 22, 12};
|
||||
int poly_y[] = {64, 0, 20, 36, 36, 20, 0, 64, 64, 44, 44, 64};
|
||||
|
||||
struct BlitDemo
|
||||
{
|
||||
const char * name;
|
||||
BlitOp op;
|
||||
};
|
||||
|
||||
BlitDemo blitDemos[11] = {
|
||||
|
||||
{"SET", BLTOP_SET},
|
||||
{"RESET", BLTOP_RESET},
|
||||
{"NOT", BLTOP_NOT},
|
||||
|
||||
{"XOR", BLTOP_XOR},
|
||||
{"OR", BLTOP_OR},
|
||||
{"AND", BLTOP_AND},
|
||||
{"NAND", BLTOP_AND_NOT},
|
||||
|
||||
{"COPY", BLTOP_COPY},
|
||||
{"NCOPY", BLTOP_NCOPY},
|
||||
|
||||
{"PATTERN", BLTOP_PATTERN},
|
||||
{"MASKPAT", BLTOP_PATTERN_AND_SRC},
|
||||
};
|
||||
|
||||
char pat[] = {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
bm_alloc(&Brush, 8, 8);
|
||||
bm_fill(&Brush, 0);
|
||||
|
||||
ClipRect bcr = {0, 0, 64, 64};
|
||||
|
||||
bm_polygon_nc_fill(&Brush, &bcr, poly_x, poly_y, 12, NineShadesOfGrey[8]);
|
||||
|
||||
bmu_rect_pattern(&Screen, 0, 0, 320, 200, NineShadesOfGrey[2]);
|
||||
|
||||
ClipRect scr = {0, 0, 320, 200};
|
||||
|
||||
for(int i=0; i<11; i++)
|
||||
{
|
||||
int dx = 80 * ((i + 1) % 4);
|
||||
int dy = 66 * ((i + 1) / 4);
|
||||
|
||||
bmu_bitblit(&Screen, dx + 8, dy + 1, &Brush, 0, 0, 64, 64, pat, blitDemos[i].op);
|
||||
bm_put_string(&Screen, &scr, dx + 8, dy + 20, blitDemos[i].name, BLTOP_COPY);
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 splitscreen.c
|
||||
../../bin/oscar64 func3d.c -n
|
||||
../../bin/oscar64 lines.c -n
|
||||
../../bin/oscar64 polygon.c -n
|
||||
../../bin/oscar64 bitblit.c -n
|
||||
../../bin/oscar64 cube3d.c -n
|
||||
../../bin/oscar64 fractaltree.c -n
|
||||
../../bin/oscar64 qsort.c -n
|
||||
@@ -0,0 +1,222 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <stdio.h>
|
||||
#include <gfx/vector3d.h>
|
||||
#include <math.h>
|
||||
#include <fixmath.h>
|
||||
|
||||
char * const Color = (char *)0xd000;
|
||||
char * const Hires = (char *)0xe000;
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x01, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
ClipRect cr = {0, 0, 320, 200};
|
||||
|
||||
|
||||
struct Point
|
||||
{
|
||||
int x, y;
|
||||
};
|
||||
|
||||
|
||||
__striped Point tcorners[8], pcorners[8];
|
||||
|
||||
void drawCube(void)
|
||||
{
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
if (!(i & 1))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 1].x, tcorners[i | 1].y, 0xff, LINOP_OR);
|
||||
if (!(i & 2))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 2].x, tcorners[i | 2].y, 0xff, LINOP_OR);
|
||||
if (!(i & 4))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 4].x, tcorners[i | 4].y, 0xff, LINOP_OR);
|
||||
pcorners[i] = tcorners[i];
|
||||
}
|
||||
}
|
||||
|
||||
void hideCube(void)
|
||||
{
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
if (!(i & 1))
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 1].x, pcorners[i | 1].y, 0xff, LINOP_AND);
|
||||
if (!(i & 2))
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 2].x, pcorners[i | 2].y, 0xff, LINOP_AND);
|
||||
if (!(i & 4))
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 4].x, pcorners[i | 4].y, 0xff, LINOP_AND);
|
||||
}
|
||||
}
|
||||
|
||||
void xorCube(void)
|
||||
{
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
if (!(i & 1))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 1].x, tcorners[i | 1].y, 0xff, LINOP_XOR);
|
||||
if (!(i & 2))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 2].x, tcorners[i | 2].y, 0xff, LINOP_XOR);
|
||||
if (!(i & 4))
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 4].x, tcorners[i | 4].y, 0xff, LINOP_XOR);
|
||||
pcorners[i] = tcorners[i];
|
||||
}
|
||||
}
|
||||
|
||||
void xor2Cube(void)
|
||||
{
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
if (!(i & 1))
|
||||
{
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 1].x, pcorners[i | 1].y, 0xff, LINOP_XOR);
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 1].x, tcorners[i | 1].y, 0xff, LINOP_XOR);
|
||||
}
|
||||
if (!(i & 2))
|
||||
{
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 2].x, pcorners[i | 2].y, 0xff, LINOP_XOR);
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 2].x, tcorners[i | 2].y, 0xff, LINOP_XOR);
|
||||
}
|
||||
if (!(i & 4))
|
||||
{
|
||||
bm_line(&Screen, &cr, pcorners[i].x, pcorners[i].y, pcorners[i | 4].x, pcorners[i | 4].y, 0xff, LINOP_XOR);
|
||||
bm_line(&Screen, &cr, tcorners[i].x, tcorners[i].y, tcorners[i | 4].x, tcorners[i | 4].y, 0xff, LINOP_XOR);
|
||||
}
|
||||
}
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
pcorners[i] = tcorners[i];
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
F12Vector3 corners[8];
|
||||
|
||||
|
||||
|
||||
F12Matrix3 rmat, tmat;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
corners[i].v[0] = (i & 1) ? -FIX12_ONE : FIX12_ONE;
|
||||
corners[i].v[1] = (i & 2) ? -FIX12_ONE : FIX12_ONE;
|
||||
corners[i].v[2] = (i & 4) ? -FIX12_ONE : FIX12_ONE;
|
||||
}
|
||||
|
||||
for(int k=0; k<100; k++)
|
||||
{
|
||||
f12mat3_set_rotate_x(&rmat, 0.1 * k);
|
||||
f12mat3_set_rotate_y(&tmat, 0.06 * k);
|
||||
f12mat3_mmul(&rmat, &tmat);
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
F12Vector3 vd;
|
||||
|
||||
f12vec3_mmul(&vd, &rmat, corners + i);
|
||||
|
||||
tcorners[i].x = lmuldiv16s(vd.v[0], 140, vd.v[2] + 4 * FIX12_ONE) + 160;
|
||||
tcorners[i].y = lmuldiv16s(vd.v[1], 140, vd.v[2] + 4 * FIX12_ONE) + 100;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (k)
|
||||
xor2Cube();
|
||||
else
|
||||
xorCube();
|
||||
#else
|
||||
hideCube();
|
||||
drawCube();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Matrix4 wmat, pmat, tmat, rmat;
|
||||
Vector3 corners[8];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
mat4_ident(&wmat);
|
||||
mat4_make_perspective(&pmat, 0.5 * PI, 1.0, 0.0, 200.0);
|
||||
|
||||
mat4_scale(&wmat, 1);
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
vec3_set(corners + i,
|
||||
(i & 1) ? -1.0 : 1.0,
|
||||
(i & 2) ? -1.0 : 1.0,
|
||||
(i & 4) ? -1.0 : 1.0);
|
||||
}
|
||||
|
||||
for(int k=0; k<100; k++)
|
||||
{
|
||||
mat4_set_rotate_x(&rmat, 0.1 * k);
|
||||
mat4_set_rotate_y(&tmat, 0.06 * k);
|
||||
mat4_rmmul(&rmat, &tmat);
|
||||
|
||||
mat4_rmmul(&rmat, &wmat);
|
||||
rmat.m[14] += 4.0;
|
||||
|
||||
tmat = pmat;
|
||||
mat4_mmul(&tmat, &rmat);
|
||||
|
||||
for(char i=0; i<8; i++)
|
||||
{
|
||||
Vector3 vd;
|
||||
vec3_project(&vd, &rmat, corners + i);
|
||||
tcorners[i].x = (int)(vd.v[0] * 100) + 160;
|
||||
tcorners[i].y = (int)(vd.v[1] * 100) + 100;
|
||||
}
|
||||
|
||||
hideCube();
|
||||
drawCube();
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
|
||||
|
||||
char * const Color = (char *)0xd000;
|
||||
char * const Hires = (char *)0xe000;
|
||||
|
||||
Bitmap Screen;
|
||||
ClipRect Clip = {0, 0, 320, 200};
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x01, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
void draw(float x, float y, float a, float s)
|
||||
{
|
||||
if (s < 6.0)
|
||||
return;
|
||||
|
||||
float tx = x + cos(a) * s;
|
||||
float ty = y + sin(a) * s;
|
||||
|
||||
bm_line(&Screen, &Clip, x, y, tx, ty, 0xff, LINOP_SET);
|
||||
|
||||
draw(tx, ty, a + 0.3, s * 0.9);
|
||||
draw(tx, ty, a - 0.4, s * 0.8);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
draw(140, 199, PI * 1.5, 32);
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,231 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
#include <gfx/vector3d.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma stacksize(1024)
|
||||
|
||||
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
||||
|
||||
|
||||
#define Color ((char *)0xc800)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen = {
|
||||
Hires, nullptr, 40, 25, 320
|
||||
};
|
||||
|
||||
ClipRect SRect = {
|
||||
0, 0, 320, 200
|
||||
};
|
||||
|
||||
char chk[] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
|
||||
char white[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
char black[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
||||
Matrix4 wmat, pmat, tmat, rmat;
|
||||
Vector3 vlight;
|
||||
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_back = VCOL_WHITE;
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
memset(Color, 0x01, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
}
|
||||
|
||||
void restore(void)
|
||||
{
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
mmap_set(MMAP_ROM);
|
||||
}
|
||||
|
||||
struct Point
|
||||
{
|
||||
int x, y;
|
||||
};
|
||||
|
||||
#define HALF 15
|
||||
#define FULL (HALF + HALF)
|
||||
#define SIZE (FULL + 1)
|
||||
#define QFULL (FULL * FULL)
|
||||
|
||||
Vector3 v[SIZE][SIZE];
|
||||
Point p[SIZE][SIZE];
|
||||
float z[SIZE][SIZE];
|
||||
|
||||
struct Surf
|
||||
{
|
||||
float z;
|
||||
char x, y;
|
||||
} surfs[QFULL];
|
||||
|
||||
|
||||
|
||||
void qsort(Surf * n, int s)
|
||||
{
|
||||
if (s > 1)
|
||||
{
|
||||
Surf pn = n[0];
|
||||
int pi = 0;
|
||||
for(int i=1; i<s; i++)
|
||||
{
|
||||
if (n[i].z > pn.z)
|
||||
{
|
||||
n[pi] = n[i];
|
||||
pi++;
|
||||
n[i] = n[pi];
|
||||
}
|
||||
}
|
||||
n[pi] = pn;
|
||||
|
||||
qsort(n, pi);
|
||||
qsort(n + pi + 1, s - pi - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 0, "Preparing function", BLTOP_COPY);
|
||||
|
||||
mat4_ident(&wmat);
|
||||
mat4_make_perspective(&pmat, 0.5 * PI, 1.0, 0.0, 200.0);
|
||||
|
||||
for(int ix=0; ix<SIZE; ix++)
|
||||
{
|
||||
for(int iy=0; iy<SIZE; iy++)
|
||||
{
|
||||
float x = (ix - HALF) * (1.0 / HALF), y = (HALF - iy) * (1.0 / HALF);
|
||||
|
||||
float r = sqrt(x * x + y * y);
|
||||
float f = - cos(r * 16) * exp(- 2 * r);
|
||||
|
||||
vec3_set(&(v[iy][ix]), x, f * 0.5, y);
|
||||
}
|
||||
}
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 8, "Projecting vertices", BLTOP_COPY);
|
||||
|
||||
vec3_set(&vlight, 2.0, -2.0, -1.0);
|
||||
vec3_norm(&vlight);
|
||||
|
||||
mat4_scale(&wmat, 18);
|
||||
|
||||
mat4_set_rotate_x(&rmat, -0.98);
|
||||
mat4_set_rotate_y(&tmat, 0.3);
|
||||
mat4_rmmul(&rmat, &tmat);
|
||||
|
||||
mat4_rmmul(&rmat, &wmat);
|
||||
rmat.m[14] += 20.0;
|
||||
|
||||
tmat = pmat;
|
||||
mat4_mmul(&tmat, &rmat);
|
||||
|
||||
for(int ix=0; ix<SIZE; ix++)
|
||||
{
|
||||
for(int iy=0; iy<SIZE; iy++)
|
||||
{
|
||||
Vector3 vp;
|
||||
|
||||
vec3_project(&vp, &tmat, &(v[iy][ix]));
|
||||
|
||||
p[iy][ix].x = vp.v[0] * 140 + 160;
|
||||
p[iy][ix].y = vp.v[1] * 140 + 80;
|
||||
z[iy][ix] = vp.v[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 16, "Sorting surfaces", BLTOP_COPY);
|
||||
|
||||
for(int iy=0; iy<FULL; iy++)
|
||||
{
|
||||
for(int ix=0; ix<FULL; ix++)
|
||||
{
|
||||
surfs[FULL * iy + ix].z =
|
||||
z[iy + 0][ix + 0] +
|
||||
z[iy + 0][ix + 1] +
|
||||
z[iy + 1][ix + 0] +
|
||||
z[iy + 1][ix + 1];
|
||||
surfs[FULL * iy + ix].x = ix;
|
||||
surfs[FULL * iy + ix].y = iy;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(surfs, QFULL);
|
||||
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 24, "Drawing surfaces", BLTOP_COPY);
|
||||
|
||||
for(int i=0; i< QFULL; i++)
|
||||
{
|
||||
char ix = surfs[i].x, iy = surfs[i].y;
|
||||
|
||||
Vector3 d0, d1, n;
|
||||
|
||||
vec3_diff(&d0, &(v[iy + 0][ix + 0]), &(v[iy + 1][ix + 1]));
|
||||
vec3_diff(&d1, &(v[iy + 1][ix + 0]), &(v[iy + 0][ix + 1]));
|
||||
|
||||
vec3_xmul(&n, &d0, &d1);
|
||||
vec3_norm(&n);
|
||||
|
||||
float f = vec3_vmul(&vlight, &n);
|
||||
int c = 8;
|
||||
char patt = 0xaa;
|
||||
if (f > 0)
|
||||
{
|
||||
c = 8 - (int)(f * 9);
|
||||
if (c < 5)
|
||||
patt = 0xff;
|
||||
}
|
||||
|
||||
bm_quad_fill(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y,
|
||||
NineShadesOfGrey[c]);
|
||||
|
||||
|
||||
bm_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y, patt, LINOP_SET);
|
||||
|
||||
bm_line(&Screen, &SRect,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y, patt, LINOP_SET);
|
||||
|
||||
bm_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y, patt, LINOP_SET);
|
||||
|
||||
bm_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y, patt, LINOP_SET);
|
||||
}
|
||||
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
getch();
|
||||
|
||||
restore();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,68 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
|
||||
|
||||
#define Color ((char *)0xd000)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x01, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
void draw(ClipRect * cr, byte pattern)
|
||||
{
|
||||
for(int i=0; i<40; i ++)
|
||||
{
|
||||
bm_line(&Screen, cr, 8 * i, 0, 319, 5 * i, pattern, LINOP_SET);
|
||||
bm_line(&Screen, cr, 319, 5 * i, 319 - 8 * i, 199, pattern, LINOP_SET);
|
||||
bm_line(&Screen, cr, 319 - 8 * i, 199, 0, 199 - 5 * i, pattern, LINOP_SET);
|
||||
bm_line(&Screen, cr, 0, 199 - 5 * i, 8 * i, 0, pattern, LINOP_SET);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
ClipRect cr = {0, 0, 320, 200};
|
||||
|
||||
draw(&cr, 0xff);
|
||||
draw(&cr, 0x00);
|
||||
|
||||
draw(&cr, 0xff);
|
||||
draw(&cr, 0xaa);
|
||||
draw(&cr, 0x88);
|
||||
draw(&cr, 0x80);
|
||||
draw(&cr, 0x00);
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
call ..\..\bin\oscar64 splitscreen.c
|
||||
call ..\..\bin\oscar64 func3d.c -n
|
||||
call ..\..\bin\oscar64 lines.c -n
|
||||
call ..\..\bin\oscar64 polygon.c -n
|
||||
call ..\..\bin\oscar64 bitblit.c -n
|
||||
call ..\..\bin\oscar64 cube3d.c -n
|
||||
call ..\..\bin\oscar64 fractaltree.c -n
|
||||
call ..\..\bin\oscar64 qsort.c -n
|
||||
@@ -0,0 +1,11 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: splitscreen.prg func3d.prg lines.prg polygon.prg bitblit.prg cube3d.prg fractaltree.prg qsort.prg
|
||||
|
||||
splitscreen.prg: splitscreen.c
|
||||
@$(OSCAR64_CC) $<
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs
|
||||
@@ -0,0 +1,83 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define Color ((char *)0xd000)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x10, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
bmu_rect_pattern(&Screen, 0, 0, 320, 200, NineShadesOfGrey[4]);
|
||||
bmu_rect_clear(&Screen, 14, 14, 304, 184);
|
||||
bmu_rect_fill(&Screen, 8, 8, 304, 184);
|
||||
bmu_rect_clear(&Screen, 10, 10, 300, 180);
|
||||
|
||||
ClipRect cr = {11, 11, 309, 189};
|
||||
|
||||
float px[10], py[10];
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
{
|
||||
float w = i * PI / 5, c = cos(w), s = sin(w), r = (i & 1) ? 1.0 : 0.4;
|
||||
px[i] = r * c; py[i] = r * s;
|
||||
|
||||
}
|
||||
|
||||
for(int i=0; i<128; i++)
|
||||
{
|
||||
int rpx[10], rpy[10];
|
||||
float r = i + 4;
|
||||
float w = i * PI / 16, c = r * cos(w), s = r * sin(w), cw = r * cos(w * 2.0), sw = r * sin(w * 2.0);
|
||||
|
||||
for(int j=0; j<10; j++)
|
||||
{
|
||||
float fx = px[j], fy = py[j];
|
||||
rpx[j] = 160 + cw + fx * c + fy * s;
|
||||
rpy[j] = 100 + sw - fx * s + fy * c;
|
||||
}
|
||||
|
||||
bm_polygon_nc_fill(&Screen, &cr, rpx, rpy, 10, NineShadesOfGrey[i % 9]);
|
||||
for(int j=0; j<10; j++)
|
||||
{
|
||||
int k = (j + 1) % 10;
|
||||
bm_line(&Screen, &cr, rpx[j], rpy[j], rpx[k], rpy[k], 0xff, LINOP_SET);
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define Color ((char *)0xd000)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color, 0x01, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
vic.color_border = VCOL_WHITE;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
char field[160];
|
||||
|
||||
void fill(void)
|
||||
{
|
||||
for(int i=0; i<160; i++)
|
||||
field[i] = i;
|
||||
}
|
||||
|
||||
void shuffle(void)
|
||||
{
|
||||
for(int i=0; i<160; i++)
|
||||
{
|
||||
int j = rand() % 160;
|
||||
char t = field[i];
|
||||
field[i] = field[j];
|
||||
field[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
void draw(unsigned i)
|
||||
{
|
||||
bmu_line(&Screen, 2 * i, 0, 2 * i, field[i], 0x00, LINOP_SET);
|
||||
bmu_line(&Screen, 2 * i, field[i], 2 * i, 160, 0xff, LINOP_SET);
|
||||
}
|
||||
|
||||
void partition(int l, int r)
|
||||
{
|
||||
while (l < r)
|
||||
{
|
||||
int i = l;
|
||||
int j = r;
|
||||
char pi = field[(r + l) >> 1];
|
||||
while (i <= j)
|
||||
{
|
||||
while (field[i] > pi)
|
||||
i++;
|
||||
while (field[j] < pi)
|
||||
j--;
|
||||
if (i <= j)
|
||||
{
|
||||
char t = field[i];
|
||||
field[i] = field[j];
|
||||
field[j] = t;
|
||||
draw(i);
|
||||
draw(j);
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
partition(l, j);
|
||||
l = i;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
fill();
|
||||
shuffle();
|
||||
|
||||
for(int i=0; i<160; i++)
|
||||
draw(i);
|
||||
|
||||
clock_t t0 = clock();
|
||||
partition(0, 159);
|
||||
clock_t t1 = clock();
|
||||
|
||||
char t[20];
|
||||
sprintf(t, "TIME : %.1f SECS.", (float)(t1 - t0) / 60);
|
||||
bmu_put_chars(&Screen, 4, 170, t, strlen(t), BLTOP_COPY);
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <c64/charwin.h>
|
||||
|
||||
#define Color ((char *)0xc800)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
char white[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
char check[] = {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa};
|
||||
char black[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
RIRQCode rirqtop, rirqbottom;
|
||||
|
||||
#pragma align(rirqtop, 32)
|
||||
#pragma align(rirqbottom, 32)
|
||||
|
||||
CharWin twin;
|
||||
CharWin ewin;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
|
||||
mmap_set(MMAP_CHAR_ROM);
|
||||
memcpy((char *)0xd000, (char *)0xd000, 4096);
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
rirq_init(true);
|
||||
|
||||
vic.color_back = VCOL_BLACK;
|
||||
|
||||
memset(Color, 0x10, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
|
||||
vic_setmode(VICM_HIRES, Color, Hires);
|
||||
|
||||
rirq_build(&rirqtop, 2);
|
||||
rirq_write(&rirqtop, 0, &vic.memptr, 0x28);
|
||||
rirq_write(&rirqtop, 1, &vic.ctrl1, VIC_CTRL1_BMM | VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||
|
||||
rirq_build(&rirqbottom, 3);
|
||||
rirq_delay(&rirqbottom, 10);
|
||||
rirq_write(&rirqbottom, 1, &vic.ctrl1, VIC_CTRL1_DEN | VIC_CTRL1_RSEL | 3);
|
||||
rirq_write(&rirqbottom, 2, &vic.memptr, 0x26);
|
||||
|
||||
rirq_set(0, 10, &rirqtop);
|
||||
rirq_set(1, 49 + 8 * 20, &rirqbottom);
|
||||
rirq_sort();
|
||||
|
||||
rirq_start();
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
|
||||
bmu_rect_pattern(&Screen, 0, 0, 320, 160, check);
|
||||
bmu_rect_fill(&Screen, 0, 159, 320, 1);
|
||||
bmu_rect_clear(&Screen, 0, 158, 320, 1);
|
||||
|
||||
cwin_init(&twin, Color, 0, 20, 40, 4);
|
||||
cwin_init(&ewin, Color, 0, 24, 40, 1);
|
||||
|
||||
ClipRect rect = {0, 0, 320, 158};
|
||||
|
||||
cwin_clear(&twin);
|
||||
cwin_putat_string(&twin, 0, 0, p"Enter x, y and radius for circle", 0x07);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cwin_clear(&ewin);
|
||||
cwin_cursor_move(&ewin, 0, 0);
|
||||
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
cwin_edit(&ewin);
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
char str[40];
|
||||
cwin_read_string(&ewin, str);
|
||||
|
||||
int n, x, y, r;
|
||||
n = sscanf(str, "%d %d %d", &x, &y, &r);
|
||||
|
||||
cwin_putat_string(&twin, 0, 1, str, 0x0e);
|
||||
sprintf(str, p"N: %d X: %3d Y: %3d R: %2d", n, x, y, r);
|
||||
cwin_putat_string(&twin, 0, 2, str, 0x07);
|
||||
|
||||
if (n == 3)
|
||||
{
|
||||
bm_circle_fill(&Screen, &rect, x, y, r + 1, black);
|
||||
bm_circle_fill(&Screen, &rect, x, y, r - 1, white);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 func3d.c -n
|
||||
../../bin/oscar64 polygon.c -n
|
||||
../../bin/oscar64 floodfill.c -n
|
||||
../../bin/oscar64 paint.c -n
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <gfx/mcbitmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
|
||||
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
||||
|
||||
#define Color1 ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap sbm;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
|
||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_border = VCOL_BLACK;
|
||||
|
||||
memset(Color1, 0x67, 1000);
|
||||
memset(Color2, 0x02, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
|
||||
bm_init(&sbm, Hires, 40, 25);
|
||||
|
||||
ClipRect scr = { 0, 0, 320, 200 };
|
||||
|
||||
for(;;)
|
||||
{
|
||||
for(int i=0; i<20; i++)
|
||||
{
|
||||
bmmc_circle_fill(&sbm, &scr, rand() % 320, rand() % 200, 5 + rand() % 40, MixedColors[1][1]);
|
||||
}
|
||||
for(int i=0; i<20; i++)
|
||||
{
|
||||
bmmc_circle_fill(&sbm, &scr, rand() % 320, rand() % 200, 5 + rand() % 40, MixedColors[0][0]);
|
||||
}
|
||||
bmmc_flood_fill(&sbm, &scr, 210, 100, 2);
|
||||
bmmc_flood_fill(&sbm, &scr, 60, 140, 3);
|
||||
}
|
||||
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
#include <gfx/vector3d.h>
|
||||
#include <gfx/mcbitmap.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma region(main, 0x0a00, 0xc800, , , {code, data, bss, heap, stack} )
|
||||
|
||||
|
||||
#define Color1 ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen = {
|
||||
Hires, nullptr, 40, 25, 320
|
||||
};
|
||||
|
||||
ClipRect SRect = {
|
||||
0, 0, 320, 200
|
||||
};
|
||||
|
||||
|
||||
Matrix4 wmat, pmat, tmat, rmat;
|
||||
Vector3 vlight;
|
||||
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||
|
||||
vic.color_back = VCOL_DARK_GREY;
|
||||
vic.color_border = VCOL_DARK_GREY;
|
||||
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
memset(Color1, 0xcf, 1000);
|
||||
memset(Color2, 0x01, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
}
|
||||
|
||||
void restore(void)
|
||||
{
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
mmap_set(MMAP_ROM);
|
||||
}
|
||||
|
||||
struct Point
|
||||
{
|
||||
int x, y;
|
||||
};
|
||||
|
||||
#define HALF 15
|
||||
#define FULL (HALF + HALF)
|
||||
#define SIZE (FULL + 1)
|
||||
#define QFULL (FULL * FULL)
|
||||
|
||||
Vector3 v[SIZE][SIZE];
|
||||
Point p[SIZE][SIZE];
|
||||
float z[SIZE][SIZE];
|
||||
|
||||
struct Surf
|
||||
{
|
||||
float z;
|
||||
char x, y;
|
||||
} surfs[QFULL];
|
||||
|
||||
|
||||
|
||||
void qsort(Surf * n, int s)
|
||||
{
|
||||
if (s > 1)
|
||||
{
|
||||
Surf pn = n[0];
|
||||
int pi = 0;
|
||||
for(int i=1; i<s; i++)
|
||||
{
|
||||
if (n[i].z > pn.z)
|
||||
{
|
||||
n[pi] = n[i];
|
||||
pi++;
|
||||
n[i] = n[pi];
|
||||
}
|
||||
}
|
||||
n[pi] = pn;
|
||||
|
||||
qsort(n, pi);
|
||||
qsort(n + pi + 1, s - pi - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 0, "Preparing function", BLTOP_COPY);
|
||||
|
||||
mat4_ident(&wmat);
|
||||
mat4_make_perspective(&pmat, 0.5 * PI, 1.0, 0.0, 200.0);
|
||||
|
||||
for(int ix=0; ix<SIZE; ix++)
|
||||
{
|
||||
for(int iy=0; iy<SIZE; iy++)
|
||||
{
|
||||
float x = (ix - HALF) * (1.0 / HALF), y = (HALF - iy) * (1.0 / HALF);
|
||||
|
||||
float r = sqrt(x * x + y * y);
|
||||
float f = - cos(r * 16) * exp(- 2 * r);
|
||||
|
||||
vec3_set(&(v[iy][ix]), x, f * 0.5, y);
|
||||
}
|
||||
}
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 8, "Projecting vertices", BLTOP_COPY);
|
||||
|
||||
vec3_set(&vlight, 2.0, -2.0, -1.0);
|
||||
vec3_norm(&vlight);
|
||||
|
||||
mat4_scale(&wmat, 18);
|
||||
|
||||
mat4_set_rotate_x(&rmat, -0.98);
|
||||
mat4_set_rotate_y(&tmat, 0.3);
|
||||
mat4_rmmul(&rmat, &tmat);
|
||||
|
||||
mat4_rmmul(&rmat, &wmat);
|
||||
rmat.m[14] += 20.0;
|
||||
|
||||
tmat = pmat;
|
||||
mat4_mmul(&tmat, &rmat);
|
||||
|
||||
for(int ix=0; ix<SIZE; ix++)
|
||||
{
|
||||
for(int iy=0; iy<SIZE; iy++)
|
||||
{
|
||||
Vector3 vp;
|
||||
|
||||
vec3_project(&vp, &tmat, &(v[iy][ix]));
|
||||
|
||||
p[iy][ix].x = vp.v[0] * 140 + 160;
|
||||
p[iy][ix].y = vp.v[1] * 140 + 80;
|
||||
z[iy][ix] = vp.v[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 16, "Sorting surfaces", BLTOP_COPY);
|
||||
|
||||
for(int iy=0; iy<FULL; iy++)
|
||||
{
|
||||
for(int ix=0; ix<FULL; ix++)
|
||||
{
|
||||
surfs[FULL * iy + ix].z =
|
||||
z[iy + 0][ix + 0] +
|
||||
z[iy + 0][ix + 1] +
|
||||
z[iy + 1][ix + 0] +
|
||||
z[iy + 1][ix + 1];
|
||||
surfs[FULL * iy + ix].x = ix;
|
||||
surfs[FULL * iy + ix].y = iy;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(surfs, QFULL);
|
||||
|
||||
|
||||
bm_put_string(&Screen, &SRect, 0, 24, "Drawing surfaces", BLTOP_COPY);
|
||||
|
||||
for(int i=0; i< QFULL; i++)
|
||||
{
|
||||
char ix = surfs[i].x, iy = surfs[i].y;
|
||||
|
||||
Vector3 d0, d1, n;
|
||||
|
||||
vec3_diff(&d0, &(v[iy + 0][ix + 0]), &(v[iy + 1][ix + 1]));
|
||||
vec3_diff(&d1, &(v[iy + 1][ix + 0]), &(v[iy + 0][ix + 1]));
|
||||
|
||||
vec3_xmul(&n, &d0, &d1);
|
||||
vec3_norm(&n);
|
||||
|
||||
float f = vec3_vmul(&vlight, &n);
|
||||
int c = 0;
|
||||
char patt = 3;
|
||||
if (f > 0)
|
||||
{
|
||||
c = 1 + (int)(f * 6);
|
||||
if (c > 4)
|
||||
patt = 0;
|
||||
}
|
||||
|
||||
bmmc_quad_fill(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y,
|
||||
MixedColors[c >> 1][(c + 1) >> 1]);
|
||||
|
||||
#if 0
|
||||
bmmc_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y, patt);
|
||||
|
||||
bmmc_line(&Screen, &SRect,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y, patt);
|
||||
|
||||
bmmc_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 0].x, p[iy + 0][ix + 0].y,
|
||||
p[iy + 1][ix + 0].x, p[iy + 1][ix + 0].y, patt);
|
||||
|
||||
bmmc_line(&Screen, &SRect,
|
||||
p[iy + 0][ix + 1].x, p[iy + 0][ix + 1].y,
|
||||
p[iy + 1][ix + 1].x, p[iy + 1][ix + 1].y, patt);
|
||||
#endif
|
||||
}
|
||||
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
getch();
|
||||
|
||||
restore();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
call ..\..\bin\oscar64 floodfill.c -n
|
||||
call ..\..\bin\oscar64 polygon.c -n
|
||||
call ..\..\bin\oscar64 func3d.c -n
|
||||
call ..\..\bin\oscar64 paint.c -n
|
||||
@@ -0,0 +1,8 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: func3d.prg polygon.prg floodfill.prg paint.prg
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg
|
||||
@@ -0,0 +1,181 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <gfx/mcbitmap.h>
|
||||
#include <c64/mouse.h>
|
||||
#include <c64/joystick.h>
|
||||
#include <c64/keyboard.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/sprites.h>
|
||||
#include <string.h>
|
||||
#include <oscar.h>
|
||||
|
||||
#pragma region(main, 0x0880, 0xd000, , , {code, data, bss, heap, stack} )
|
||||
|
||||
static char * const Color1 = (char *)0xd000;
|
||||
static char * const Color2 = (char *)0xd800;
|
||||
static char * const Hires = (char *)0xe000;
|
||||
static char * const Sprites = (char *)0xd800;
|
||||
|
||||
const char MouseSpriteData[] = {
|
||||
#embed spd_sprites lzo "../resources/mouse.spd"
|
||||
};
|
||||
|
||||
Bitmap sbm;
|
||||
ClipRect scr = { 0, 0, 320, 200 };
|
||||
|
||||
void init(void)
|
||||
{
|
||||
// Install IRQ trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
cia_init();
|
||||
|
||||
// All RAM
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
// Init hires mem, and resources
|
||||
memset(Color1, 0x67, 1000);
|
||||
memset(Hires, 0, 8000);
|
||||
oscar_expand_lzo(Sprites, MouseSpriteData);
|
||||
|
||||
// Sprite image for cursor
|
||||
Color1[0x3f8] = 97;
|
||||
Color1[0x3f9] = 96;
|
||||
|
||||
// Enable IO space
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
// Clear color RAM
|
||||
memset(Color2, 0x02, 1000);
|
||||
|
||||
// Set screen
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_border = VCOL_BLACK;
|
||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||
|
||||
// Init mouse cursor
|
||||
spr_show(0, true);
|
||||
spr_show(1, true);
|
||||
spr_color(0, VCOL_BLACK);
|
||||
spr_color(1, VCOL_WHITE);
|
||||
spr_move(0, 24, 50);
|
||||
spr_move(1, 24, 50);
|
||||
|
||||
// Disable system interrupt and init mouse
|
||||
mouse_init();
|
||||
|
||||
bm_init(&sbm, Hires, 40, 25);
|
||||
}
|
||||
|
||||
int mouse_x, mouse_y;
|
||||
|
||||
bool mouse_move(void)
|
||||
{
|
||||
// Poll mouse and joystick for backup
|
||||
joy_poll(0);
|
||||
mouse_poll();
|
||||
|
||||
// New mouse cursor position
|
||||
int mx = mouse_x + (signed char)(joyx[0] + mouse_dx);
|
||||
int my = mouse_y + (signed char)(joyy[0] - mouse_dy);
|
||||
|
||||
// Clip to screen
|
||||
if (mx < 0)
|
||||
mx = 0;
|
||||
else if (mx > 319)
|
||||
mx = 319;
|
||||
if (my < 0)
|
||||
my = 0;
|
||||
else if (my > 199)
|
||||
my = 199;
|
||||
|
||||
// Check if moved
|
||||
if (mx != mouse_x || my != mouse_y)
|
||||
{
|
||||
mouse_x = mx;
|
||||
mouse_y = my;
|
||||
|
||||
// Update cursor sprite
|
||||
spr_move(0, mx + 24, my + 50);
|
||||
spr_move(1, mx + 24, my + 50);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
char c0 = 1, c1 = 1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Check if mouse moved
|
||||
if (mouse_move())
|
||||
{
|
||||
// Paint a circle at the mouse position, if mouse was moved
|
||||
|
||||
if (mouse_lb || joyb[0])
|
||||
bmmc_circle_fill(&sbm, &scr, mouse_x, mouse_y, 5, MixedColors[c0][c1]);
|
||||
else if (mouse_rb)
|
||||
bmmc_circle_fill(&sbm, &scr, mouse_x, mouse_y, 5, MixedColors[0][0]);
|
||||
}
|
||||
|
||||
// Poll the keyboard
|
||||
keyb_poll();
|
||||
|
||||
switch (keyb_key)
|
||||
{
|
||||
// Clear screen
|
||||
case KSCAN_HOME + KSCAN_QUAL_DOWN:
|
||||
bmmcu_rect_fill(&sbm, 0, 0, 320, 200, 0);
|
||||
break;
|
||||
|
||||
// Select color with 0..9
|
||||
case KSCAN_0 + KSCAN_QUAL_DOWN:
|
||||
c0 = 0; c1 = 0;
|
||||
break;
|
||||
case KSCAN_1 + KSCAN_QUAL_DOWN:
|
||||
c0 = 1; c1 = 1;
|
||||
break;
|
||||
case KSCAN_2 + KSCAN_QUAL_DOWN:
|
||||
c0 = 2; c1 = 2;
|
||||
break;
|
||||
case KSCAN_3 + KSCAN_QUAL_DOWN:
|
||||
c0 = 3; c1 = 3;
|
||||
break;
|
||||
|
||||
case KSCAN_4 + KSCAN_QUAL_DOWN:
|
||||
c0 = 1; c1 = 0;
|
||||
break;
|
||||
case KSCAN_5 + KSCAN_QUAL_DOWN:
|
||||
c0 = 1; c1 = 2;
|
||||
break;
|
||||
case KSCAN_6 + KSCAN_QUAL_DOWN:
|
||||
c0 = 1; c1 = 3;
|
||||
break;
|
||||
case KSCAN_7 + KSCAN_QUAL_DOWN:
|
||||
c0 = 2; c1 = 0;
|
||||
break;
|
||||
case KSCAN_8 + KSCAN_QUAL_DOWN:
|
||||
c0 = 2; c1 = 3;
|
||||
break;
|
||||
case KSCAN_9 + KSCAN_QUAL_DOWN:
|
||||
c0 = 3; c1 = 0;
|
||||
break;
|
||||
|
||||
// Flood fill
|
||||
case KSCAN_F + KSCAN_QUAL_DOWN:
|
||||
bmmc_flood_fill(&sbm, &scr, mouse_x, mouse_y, c0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait one frame
|
||||
vic_waitFrame();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/mcbitmap.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define Color1 ((char *)0xc800)
|
||||
#define Color2 ((char *)0xd800)
|
||||
#define Hires ((char *)0xe000)
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
void init(void)
|
||||
{
|
||||
mmap_trampoline();
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
memset(Color1, 0x67, 1000);
|
||||
memset(Color2, 0x02, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
vic_setmode(VICM_HIRES_MC, Color1, Hires);
|
||||
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_border = VCOL_BLACK;
|
||||
|
||||
bm_init(&Screen, Hires, 40, 25);
|
||||
}
|
||||
|
||||
void done(void)
|
||||
{
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
getch();
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
bmmcu_rect_fill(&Screen, 0, 0, 320, 200, 1);
|
||||
bmmcu_rect_fill(&Screen, 8, 8, 304, 184, 2);
|
||||
bmmcu_rect_fill(&Screen, 10, 10, 300, 180, 0);
|
||||
|
||||
ClipRect cr = {10, 10, 310, 190};
|
||||
|
||||
float px[10], py[10];
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
{
|
||||
float w = i * PI / 5, c = cos(w), s = sin(w), r = (i & 1) ? 1.0 : 0.4;
|
||||
px[i] = r * c; py[i] = r * s;
|
||||
|
||||
}
|
||||
|
||||
for(int i=0; i<128; i++)
|
||||
{
|
||||
int rpx[10], rpy[10];
|
||||
float r = i + 4;
|
||||
float w = i * PI / 16, c = r * cos(w), s = r * sin(w), cw = r * cos(w * 2.0), sw = r * sin(w * 2.0);
|
||||
|
||||
for(int j=0; j<10; j++)
|
||||
{
|
||||
float fx = px[j], fy = py[j];
|
||||
rpx[j] = 160 + cw + fx * c + fy * s;
|
||||
rpy[j] = 100 + sw - fx * s + fy * c;
|
||||
}
|
||||
|
||||
bmmc_polygon_nc_fill(&Screen, &cr, rpx, rpy, 10, MixedColors[i & 3][(i >> 2) & 3]);
|
||||
|
||||
for(int j=0; j<10; j++)
|
||||
{
|
||||
int k = (j + 1) % 10;
|
||||
bmmc_line(&Screen, &cr, rpx[j], rpy[j], rpx[k], rpy[k], 0);
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 diskdir.c
|
||||
../../bin/oscar64 filewrite.c
|
||||
../../bin/oscar64 fileread.c
|
||||
../../bin/oscar64 charwrite.c
|
||||
../../bin/oscar64 charread.c
|
||||
../../bin/oscar64 hireswrite.c
|
||||
../../bin/oscar64 hiresread.c
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <stdio.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Set name for directory
|
||||
|
||||
krnio_setnam("$");
|
||||
|
||||
// Open #2 on drive 9 (or 8)
|
||||
|
||||
if (krnio_open(2, 9, 0))
|
||||
{
|
||||
// Switch input to file #2
|
||||
|
||||
if (krnio_chkin(2))
|
||||
{
|
||||
// Skip BASIC load address
|
||||
|
||||
krnio_chrin();
|
||||
krnio_chrin();
|
||||
|
||||
// Loop while we have more lines
|
||||
|
||||
int ch;
|
||||
while((ch = krnio_chrin()) > 0)
|
||||
{
|
||||
unsigned line;
|
||||
char buff[40];
|
||||
|
||||
// Skip second basic link byte
|
||||
krnio_chrin();
|
||||
|
||||
// Read line number (size in blocks)
|
||||
ch = krnio_chrin();
|
||||
line = ch;
|
||||
ch = krnio_chrin();
|
||||
line += 256 * ch;
|
||||
|
||||
// Read file name, reading till end of basic line
|
||||
int n = 0;
|
||||
while ((ch = krnio_chrin()) > 0)
|
||||
buff[n++] = ch;
|
||||
buff[n] = 0;
|
||||
|
||||
// Print size and name
|
||||
|
||||
printf("%u %s\n", line, buff);
|
||||
}
|
||||
|
||||
// Reset channels
|
||||
|
||||
krnio_clrchn();
|
||||
}
|
||||
|
||||
// Close file #2
|
||||
|
||||
krnio_close(2);
|
||||
}
|
||||
else
|
||||
printf("FAIL OPEN %d\n", krnio_status());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <stdio.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
struct Score
|
||||
{
|
||||
char name[5];
|
||||
unsigned score;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
struct Score
|
||||
{
|
||||
char name[5];
|
||||
unsigned score;
|
||||
};
|
||||
|
||||
Score score[] = {
|
||||
{"AAA", 10000},
|
||||
{"BBB", 9000},
|
||||
{"CCC", 8000},
|
||||
{"DDD", 4000}
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <c64/kernalio.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/flossiec.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char * const Hires = (char *)0xe000;
|
||||
char * const Color = (char *)0xd800;
|
||||
char * const Screen = (char *)0xcc00;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Prepare fast loader in floppy memory
|
||||
flosskio_init(8);
|
||||
|
||||
// Map filenames to track/sector addresses
|
||||
floss_blk blks[1];
|
||||
flosskio_mapdir(p"blumba2", blks);
|
||||
|
||||
// Clear screen
|
||||
memset(Hires, 0x00, 8000);
|
||||
memset(Screen, 0xff, 1000);
|
||||
memset(Color, 0x01, 1000);
|
||||
|
||||
// Switch to multicolor hires
|
||||
vic_setmode(VICM_HIRES_MC, Screen, Hires);
|
||||
vic.color_back = VCOL_BLACK;
|
||||
vic.color_border = VCOL_BLACK;
|
||||
|
||||
// Open file
|
||||
flosskio_open(blks[0].track, blks[0].sector);
|
||||
|
||||
// Read compressed image
|
||||
flossiec_read_lzo(Hires, 8000);
|
||||
flossiec_read_lzo(Screen, 1000);
|
||||
flossiec_read_lzo(Color, 1000);
|
||||
|
||||
// Close file
|
||||
flosskio_close();
|
||||
|
||||
// Remove drive code
|
||||
flosskio_shutdown();
|
||||
|
||||
// Wait for a character
|
||||
getchar();
|
||||
|
||||
// Restore VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <c64/kernalio.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Bitmap Screen;
|
||||
|
||||
#define ScreenMem ((char *)0xe000)
|
||||
#define ColorMem ((char *)0xd000)
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <c64/kernalio.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/vic.h>
|
||||
#include <gfx/bitmap.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
Bitmap Screen, Brush;
|
||||
char Buffer[200];
|
||||
|
||||
#define ScreenMem ((char *)0xe000)
|
||||
#define ColorMem ((char *)0xd000)
|
||||
|
||||
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);
|
||||
bm_bitblit(&Screen, &crr, 160 - 7 + x, 100 + y, &Brush, 0, 0, 15, 15, nullptr, BLTOP_AND_NOT);
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
call ..\..\bin\oscar64 diskdir.c
|
||||
call ..\..\bin\oscar64 filewrite.c
|
||||
call ..\..\bin\oscar64 fileread.c
|
||||
call ..\..\bin\oscar64 charwrite.c
|
||||
call ..\..\bin\oscar64 charread.c
|
||||
call ..\..\bin\oscar64 hireswrite.c
|
||||
call ..\..\bin\oscar64 hiresread.c
|
||||
call ..\..\bin\oscar64 hiresfload.c -d64=hiresfload.d64 -fz=../resources/blumba2.bin
|
||||
@@ -0,0 +1,8 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: diskdir.prg filewrite.prg fileread.prg charwrite.prg charread.prg hireswrite.prg hiresread.prg
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs
|
||||
@@ -0,0 +1,44 @@
|
||||
cd fractals
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd games
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd hires
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd hiresmc
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd particles
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd kernalio
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd memmap
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd rasterirq
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd scrolling
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd sprites
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
cd stdio
|
||||
call make.bat
|
||||
cd ..
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
all:
|
||||
@$(MAKE) -C fractals
|
||||
@$(MAKE) -C games
|
||||
@$(MAKE) -C hires
|
||||
@$(MAKE) -C hiresmc
|
||||
@$(MAKE) -C particles
|
||||
@$(MAKE) -C kernalio
|
||||
@$(MAKE) -C memmap
|
||||
@$(MAKE) -C rasterirq
|
||||
@$(MAKE) -C scrolling
|
||||
@$(MAKE) -C sprites
|
||||
@$(MAKE) -C stdio
|
||||
|
||||
clean:
|
||||
@$(MAKE) -C fractals $@
|
||||
@$(MAKE) -C games $@
|
||||
@$(MAKE) -C hires $@
|
||||
@$(MAKE) -C hiresmc $@
|
||||
@$(MAKE) -C particles $@
|
||||
@$(MAKE) -C kernalio $@
|
||||
@$(MAKE) -C memmap $@
|
||||
@$(MAKE) -C rasterirq $@
|
||||
@$(MAKE) -C scrolling $@
|
||||
@$(MAKE) -C sprites $@
|
||||
@$(MAKE) -C stdio $@
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// make space until 0x1000 by for the stack
|
||||
|
||||
#pragma stacksize(0x0600)
|
||||
|
||||
#pragma region( stack, 0x0a00, 0x1000, , , {stack} )
|
||||
|
||||
// everything beyond will be code, data, bss and heap to the end
|
||||
|
||||
#pragma region( main, 0x1000, 0xfff0, , , {code, data, bss, heap} )
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Install the IRQ trampoline
|
||||
|
||||
mmap_trampoline();
|
||||
|
||||
// Hide the basic ROM, must be first instruction
|
||||
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
// Allocate all memory
|
||||
|
||||
unsigned total = 0;
|
||||
while (char * data = malloc(1024))
|
||||
{
|
||||
total += 1024;
|
||||
|
||||
// Swap in kernal for print
|
||||
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
printf("ALLOCATED %5u AT %04x\n", total, (unsigned)data);
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
// Fill it with trash
|
||||
|
||||
for(unsigned i=0; i<1024; i++)
|
||||
data[i] = 0xaa;
|
||||
}
|
||||
|
||||
// Return basic ROM to normal state
|
||||
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 largemem.c
|
||||
../../bin/oscar64 allmem.c
|
||||
../../bin/oscar64 charsetlo.c
|
||||
../../bin/oscar64 charsethi.c
|
||||
../../bin/oscar64 charsetcopy.c
|
||||
../../bin/oscar64 charsetexpand.c
|
||||
../../bin/oscar64 charsetload.c -d64=charsetload.d64 -fz=../resources/charset.bin
|
||||
../../bin/oscar64 easyflash.c -n -tf=crt
|
||||
../../bin/oscar64 easyflashreloc.c -n -tf=crt
|
||||
../../bin/oscar64 easyflashshared.c -n -tf=crt
|
||||
../../bin/oscar64 easyflashcall.cpp -n -tf=crt
|
||||
../../bin/oscar64 tsr.c -n -dNOFLOAT -dNOLONG
|
||||
../../bin/oscar64 overlay.c -n -d64=overlay.d64
|
||||
@@ -0,0 +1,69 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// make space until 0xcc00 by extending the default region
|
||||
|
||||
#pragma region( main, 0x0a00, 0xcc00, , , {code, data, bss, heap, stack} )
|
||||
|
||||
// space for our custom charset from c000 to c800, will be copied to
|
||||
// 0xd000 during startup to free space for stack and heap
|
||||
|
||||
#pragma section( charset, 0)
|
||||
|
||||
#pragma region( charset, 0xc000, 0xc800, , , {charset} )
|
||||
|
||||
// set initialized data segment to charset section
|
||||
|
||||
#pragma data(charset)
|
||||
|
||||
char charset[2048] = {
|
||||
#embed "../resources/charset.bin"
|
||||
};
|
||||
|
||||
// back to normal
|
||||
|
||||
#pragma data(data)
|
||||
|
||||
// pointers to charset and screen in memory
|
||||
|
||||
#define Screen ((char *)0xcc00)
|
||||
#define Charset ((char *)0xd000)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Install the trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// make all of RAM visible to the CPU
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
// copy the font
|
||||
memcpy(Charset, charset, 2048);
|
||||
|
||||
// make lower part of RAM visible to CPU
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// map the vic to the new charset
|
||||
|
||||
vic_setmode(VICM_TEXT, Screen, Charset);
|
||||
|
||||
for(int i=0; i<1000; i++)
|
||||
Screen[i] = (char)i;
|
||||
|
||||
// wait for keypress
|
||||
|
||||
getchar();
|
||||
|
||||
// restore VIC
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
|
||||
// restore basic ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <oscar.h>
|
||||
|
||||
// make space until 0xcc00 by extending the default region
|
||||
|
||||
#pragma region( main, 0x0a00, 0xcc00, , , {code, data, bss, heap, stack} )
|
||||
|
||||
// space for our custom charset from c000 to c800, will be copied to
|
||||
// 0xd000 during startup to free space for stack and heap
|
||||
|
||||
#pragma section( charset, 0)
|
||||
|
||||
#pragma region( charset, 0xc000, 0xc800, , , {charset} )
|
||||
|
||||
// set initialized data segment to charset section
|
||||
|
||||
#pragma data(charset)
|
||||
|
||||
// lz compressed data
|
||||
char charset[] = {
|
||||
#embed 2048 0 lzo "../resources/charset.bin"
|
||||
};
|
||||
|
||||
// back to normal
|
||||
|
||||
#pragma data(data)
|
||||
|
||||
// pointers to charset and screen in memory
|
||||
|
||||
#define Screen ((char *)0xcc00)
|
||||
#define Charset ((char *)0xd000)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Install the trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// make all of RAM visible to the CPU
|
||||
mmap_set(MMAP_RAM);
|
||||
|
||||
// expand the font
|
||||
oscar_expand_lzo(Charset, charset);
|
||||
|
||||
// make lower part of RAM visible to CPU
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// map the vic to the new charset
|
||||
|
||||
vic_setmode(VICM_TEXT, Screen, Charset);
|
||||
|
||||
for(int i=0; i<1000; i++)
|
||||
Screen[i] = (char)i;
|
||||
|
||||
// wait for keypress
|
||||
|
||||
getchar();
|
||||
|
||||
// restore VIC
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
|
||||
// restore basic ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <c64/vic.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// space for our custom charset from c800
|
||||
|
||||
#pragma section( charset, 0)
|
||||
|
||||
#pragma region( charset, 0xc800, 0xd000, , , {charset} )
|
||||
|
||||
#pragma data(charset)
|
||||
|
||||
char charset[2048] = {
|
||||
#embed "../resources/charset.bin"
|
||||
};
|
||||
|
||||
#pragma data(data)
|
||||
|
||||
#define Screen ((char *)0xc000)
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// map the vic to the new charset
|
||||
|
||||
vic_setmode(VICM_TEXT, Screen, charset);
|
||||
|
||||
for(int i=0; i<1000; i++)
|
||||
Screen[i] = (char)i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <c64/vic.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// make space until 0x2000 for code and data
|
||||
|
||||
#pragma region( lower, 0x0a00, 0x2000, , , {code, data} )
|
||||
|
||||
// then space for our custom charset
|
||||
|
||||
#pragma section( charset, 0)
|
||||
|
||||
#pragma region( charset, 0x2000, 0x2800, , , {charset} )
|
||||
|
||||
// everything beyond will be code, data, bss and heap to the end
|
||||
|
||||
#pragma region( main, 0x2800, 0xa000, , , {code, data, bss, heap, stack} )
|
||||
|
||||
|
||||
#pragma data(charset)
|
||||
|
||||
char charset[2048] = {
|
||||
#embed "../resources/charset.bin"
|
||||
};
|
||||
|
||||
#pragma data(data)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// map the vic to the new charset
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, charset);
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
printf(p"%D Hello World\n", i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/kernalio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define Screen ((char *)0xcc00)
|
||||
#define Charset ((char *)0xc000)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Set name for file and open it on drive 9
|
||||
krnio_setnam("CHARSET,P,R");
|
||||
if (krnio_open(2, 8, 2))
|
||||
{
|
||||
// Read the content of the file into the charset buffer,
|
||||
// decompressing on the fly
|
||||
krnio_read_lzo(2, Charset);
|
||||
|
||||
// Close the file
|
||||
krnio_close(2);
|
||||
}
|
||||
|
||||
// Change display address to new screen and charset
|
||||
|
||||
vic_setmode(VICM_TEXT, Screen, Charset);
|
||||
|
||||
for(int i=0; i<1000; i++)
|
||||
Screen[i] = (char)i;
|
||||
|
||||
// wait for keypress
|
||||
|
||||
getchar();
|
||||
|
||||
// restore VIC
|
||||
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1000);
|
||||
|
||||
// restore basic ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/easyflash.h>
|
||||
|
||||
// Shared code/data region, copied from easyflash bank 0 to ram during startup
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
// Section and region for first easyflash bank
|
||||
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xc000, , 1, { bcode1, bdata1 } )
|
||||
|
||||
// Section and region for second easyflash bank
|
||||
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0xc000, , 2, { bcode2, bdata2 } )
|
||||
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0xc000, , 3, { bcode3, bdata3 } )
|
||||
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0xc000, , 4, { bcode4, bdata4 } )
|
||||
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0xc000, , 5, { bcode5, bdata5 } )
|
||||
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0xc000, , 6, { bcode6, bdata6 } )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fourth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
|
||||
// Function for indirect cross bank call
|
||||
void fcall(char bank, void (* func)())
|
||||
{
|
||||
eflash.bank = bank;
|
||||
func();
|
||||
}
|
||||
|
||||
// Macro for indirect cross bank call
|
||||
#define FCALL(f) fcall(__bankof(f), f)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
// Switch easyflash ROM region to bank 1
|
||||
eflash.bank = 1;
|
||||
|
||||
// Call function in bank 1
|
||||
print1();
|
||||
|
||||
// Switch easyflash ROM region to bank 2
|
||||
eflash.bank = 2;
|
||||
|
||||
// Call function in bank 2
|
||||
print2();
|
||||
|
||||
eflash.bank = 3;
|
||||
print3();
|
||||
|
||||
// Get bank of function using __bankof operator
|
||||
eflash.bank = __bankof print4;
|
||||
print4();
|
||||
|
||||
// Indirect call
|
||||
fcall(__bankof print5, print5);
|
||||
|
||||
// Macro call
|
||||
FCALL(print6);
|
||||
|
||||
// Loop forever
|
||||
while (true)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/easyflash.h>
|
||||
|
||||
// Shared code/data region, copied from easyflash bank 0 to ram during startup
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
// Section and region for first easyflash bank
|
||||
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xc000, , 1, { bcode1, bdata1 } )
|
||||
|
||||
// Section and region for second easyflash bank
|
||||
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0xc000, , 2, { bcode2, bdata2 } )
|
||||
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0xc000, , 3, { bcode3, bdata3 } )
|
||||
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0xc000, , 4, { bcode4, bdata4 } )
|
||||
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0xc000, , 5, { bcode5, bdata5 } )
|
||||
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0xc000, , 6, { bcode6, bdata6 } )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1_p(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2_p(const char * p)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second bank:", 7);
|
||||
cwin_put_string(&cw, p, 1);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3_p(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4_p(int x, int y)
|
||||
{
|
||||
cwin_cursor_move(&cw, x, y);
|
||||
cwin_put_string(&cw, p"This is fourth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5_p(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
void print5a_p(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth bank second", 14);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
|
||||
EF_CALL(print1);
|
||||
EF_CALL(print2);
|
||||
EF_CALL(print3);
|
||||
EF_CALL(print4);
|
||||
EF_CALL(print5);
|
||||
EF_CALL(print5a);
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6_p(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
print5a();
|
||||
cwin_put_string(&cw, p"This is sixth bank again", 7);
|
||||
}
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
EF_CALL(print6);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
print1();
|
||||
print2("hello");
|
||||
print3();
|
||||
print4(5, 8);
|
||||
print5();
|
||||
print6();
|
||||
|
||||
// Loop forever
|
||||
while (true)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma section( startup, 0 )
|
||||
|
||||
#pragma region( startup, 0x0100, 0x0200, , , { startup } )
|
||||
|
||||
#pragma region( main, 0x0400, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
CharWin cw;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Copy Char ROM
|
||||
mmap_set(MMAP_ALL_ROM);
|
||||
|
||||
memcpy((char *)0xd000, (char *)0xd000, 0x1000);
|
||||
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0xc000, (char *)0xd800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0xc000, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
cwin_put_string(&cw, p"Hello World", 7);
|
||||
|
||||
while (true) ;
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/easyflash.h>
|
||||
#include <string.h>
|
||||
|
||||
// Shared code/data region, copied from easyflash bank 0 to ram during startup
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
// Section and region for first easyflash bank, code is compiled for a
|
||||
// target address of 0x7000 but placed into the bank at 0x8000
|
||||
// The data section is first to ensure the jump table is at the start
|
||||
// address
|
||||
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0x9000, , 1, { bdata1, bcode1 }, 0x7000 )
|
||||
|
||||
// Section and region for second easyflash bank
|
||||
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0x9000, , 2, { bdata2, bcode2 }, 0x7000 )
|
||||
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0x9000, , 3, { bdata3, bcode3 }, 0x7000 )
|
||||
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0x9000, , 4, { bdata4, bcode4 }, 0x7000 )
|
||||
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0x9000, , 5, { bdata5, bcode5 }, 0x7000 )
|
||||
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0x9000, , 6, { bdata6, bcode6 } , 0x7000 )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
struct EntryTable
|
||||
{
|
||||
void (*fhello)(void);
|
||||
void (*fdone)(void);
|
||||
};
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first bank", 7);
|
||||
}
|
||||
|
||||
void done1(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry1 = {
|
||||
.fhello = &print1,
|
||||
.fdone = &done1
|
||||
};
|
||||
|
||||
// make sure the function is referenced
|
||||
#pragma reference(entry1)
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second bank", 7);
|
||||
}
|
||||
|
||||
void done2(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry2 = {
|
||||
.fhello = &print2,
|
||||
.fdone = &done2
|
||||
};
|
||||
|
||||
// make sure the function is referenced
|
||||
#pragma reference(entry2)
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third bank", 7);
|
||||
}
|
||||
|
||||
void done3(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry3 = {
|
||||
.fhello = &print3,
|
||||
.fdone = &done3
|
||||
};
|
||||
|
||||
#pragma reference(entry3)
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fourth bank", 7);
|
||||
}
|
||||
|
||||
void done4(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry4 = {
|
||||
.fhello = &print4,
|
||||
.fdone = &done4
|
||||
};
|
||||
|
||||
#pragma reference(entry4)
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth bank", 7);
|
||||
}
|
||||
|
||||
void done5(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry5 = {
|
||||
.fhello = &print5,
|
||||
.fdone = &done5
|
||||
};
|
||||
|
||||
#pragma reference(entry5)
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth bank", 7);
|
||||
}
|
||||
|
||||
void done6(void)
|
||||
{
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
const EntryTable entry6 = {
|
||||
.fhello = &print6,
|
||||
.fdone = &done6
|
||||
};
|
||||
|
||||
#pragma reference(entry6)
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
// Copy the data of the rom bank, and call the function
|
||||
// with the jump table
|
||||
|
||||
void callbank(char bank)
|
||||
{
|
||||
eflash.bank = bank;
|
||||
memcpy((char *)0x7000, (char *)0x8000, 0x1000);
|
||||
|
||||
// call function at start of copied section
|
||||
((EntryTable *)0x7000)->fhello();
|
||||
((EntryTable *)0x7000)->fdone();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
|
||||
// Call function in bank 1
|
||||
callbank(1);
|
||||
|
||||
// Switch easyflash ROM region to bank 2
|
||||
callbank(2);
|
||||
|
||||
callbank(3);
|
||||
callbank(4);
|
||||
callbank(5);
|
||||
callbank(6);
|
||||
|
||||
// Loop forever
|
||||
while (true)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/easyflash.h>
|
||||
|
||||
// Shared code/data region, copied from easyflash bank 0 to ram during startup
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xbf00, , 1, { bcode1, bdata1 } )
|
||||
|
||||
// Section and region for second easyflash bank
|
||||
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0xbf00, , 2, { bcode2, bdata2 } )
|
||||
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0xbf00, , 3, { bcode3, bdata3 } )
|
||||
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0xbf00, , 4, { bcode4, bdata4 } )
|
||||
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0xbf00, , 5, { bcode5, bdata5 } )
|
||||
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0xbf00, , 6, { bcode6, bdata6 } )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Setting up a common range
|
||||
|
||||
#pragma section( ccode, 0 )
|
||||
#pragma region( cbank, 0xbf00, 0xc000, , {1, 2, 3, 4, 5, 6}, { ccode } )
|
||||
|
||||
// Code shared by all banks
|
||||
|
||||
#pragma code( ccode )
|
||||
|
||||
__export void callbank(void (* fn)(void), char bank)
|
||||
{
|
||||
eflash.bank = bank;
|
||||
fn();
|
||||
}
|
||||
|
||||
#pragma code( code )
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fourth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth bank", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
eflash.bank = 1;
|
||||
|
||||
// Call function in bank 1
|
||||
callbank(print1, 1);
|
||||
|
||||
// Call function in bank 2
|
||||
callbank(print2, 2);
|
||||
|
||||
callbank(print3, 3);
|
||||
callbank(print4, 4);
|
||||
callbank(print5, 5);
|
||||
callbank(print6, 6);
|
||||
|
||||
// Loop forever
|
||||
while (true)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// make space until 0xd000 by extending the default region
|
||||
|
||||
#pragma region( main, 0x0a00, 0xd000, , , {code, data, bss, heap, stack} )
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Hide the basic ROM, must be first instruction
|
||||
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Allocate all memory
|
||||
|
||||
unsigned total = 0;
|
||||
while (char * data = malloc(1024))
|
||||
{
|
||||
total += 1024;
|
||||
|
||||
printf("ALLOCATED %5u AT %04x\n", total, (unsigned)data);
|
||||
|
||||
// Fill it with trash
|
||||
|
||||
for(unsigned i=0; i<1024; i++)
|
||||
data[i] = 0xaa;
|
||||
}
|
||||
|
||||
// Return basic ROM to normal state
|
||||
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
|
||||
// Set rom region end at 0x9f80 to leave some space for copy code
|
||||
#pragma region(rom, 0x8080, 0x9f80, , 0, { code, data } )
|
||||
|
||||
// We do not want to pollute main RAM region with our data
|
||||
#pragma region(main, 0xc000, 0xd000, , , { bss, stack, heap })
|
||||
#pragma stacksize( 256 )
|
||||
|
||||
// Region and code for a cross bank copy routine
|
||||
#pragma section( ccode, 0 )
|
||||
#pragma region( crom, 0x9f80, 0xa000, , 0, { ccode }, 0x0380 )
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Copy code from any bank to RAM, returns to bank 0, this code is
|
||||
// copied from bank 0 to RAM at 0x0380 at program start
|
||||
|
||||
#pragma code ( ccode )
|
||||
|
||||
__export void ccopy(char bank, char * dst, const char * src, unsigned n)
|
||||
{
|
||||
*((volatile char *)0xde00) = bank;
|
||||
while (n)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
n--;
|
||||
}
|
||||
*((volatile char *)0xde00) = 0;
|
||||
}
|
||||
|
||||
// Region of code to be executed from RAM after copied from 2nd ROM
|
||||
// bank
|
||||
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xa000, , 1, { bcode1, bdata1 }, 0x2000 )
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first bank", 1);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Back to main sections in bank 0
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enable ROM
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
// Init CIAs (no kernal rom was executed so far)
|
||||
cia_init();
|
||||
|
||||
// Copy ccopy code to RAM
|
||||
for(char i=0; i<128; i++)
|
||||
((char *)0x0380)[i] = ((char *)0x9f80)[i];
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
// Write first line
|
||||
cwin_put_string(&cw, p"Hello World", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
|
||||
// Copy bank 1 to RAM
|
||||
ccopy(1, (char *)0x2000, (char *)0x8000, 0x2000);
|
||||
|
||||
// Call function in copy
|
||||
print1();
|
||||
|
||||
// Third line
|
||||
cwin_put_string(&cw, p"Final words", 14);
|
||||
cwin_cursor_newline(&cw);
|
||||
|
||||
while (true) ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
call ..\..\bin\oscar64 largemem.c
|
||||
call ..\..\bin\oscar64 allmem.c
|
||||
call ..\..\bin\oscar64 charsetlo.c
|
||||
call ..\..\bin\oscar64 charsethi.c
|
||||
call ..\..\bin\oscar64 charsetcopy.c
|
||||
call ..\..\bin\oscar64 charsetexpand.c
|
||||
call ..\..\bin\oscar64 charsetload.c -d64=charsetload.d64 -fz=../resources/charset.bin
|
||||
call ..\..\bin\oscar64 easyflash.c -n -tf=crt
|
||||
call ..\..\bin\oscar64 easyflashreloc.c -n -tf=crt
|
||||
call ..\..\bin\oscar64 easyflashshared.c -n -tf=crt
|
||||
call ..\..\bin\oscar64 easyflashlow.c -n -tf=crt
|
||||
call ..\..\bin\oscar64 easyflashcall.cpp -n -tf=crt
|
||||
call ..\..\bin\oscar64 tsr.c -n -dNOFLOAT -dNOLONG
|
||||
call ..\..\bin\oscar64 overlay.c -n -d64=overlay.d64
|
||||
call ..\..\bin\oscar64 overlaylzo.c -n -d64=overlaylzo.d64
|
||||
call ..\..\bin\oscar64 magicdesk.c -n -tf=crt8 -cid=19
|
||||
@@ -0,0 +1,30 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: largemem.prg allmem.prg charsetlo.prg charsethi.prg charsetcopy.prg charsetexpand.prg \
|
||||
charsetload.prg easyflash.crt easyflashreloc.crt easyflashshared.crt tsr.prg overlay.prg
|
||||
|
||||
charsetload.prg: charsetload.c ../resources/charset.bin
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -d64=charsetload.d64 -fz=../resources/charset.bin
|
||||
|
||||
easyflash.crt: easyflash.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -tf=crt
|
||||
|
||||
easyflashreloc.crt: easyflashreloc.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -tf=crt
|
||||
|
||||
easyflashshared.crt: easyflashshared.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -tf=crt
|
||||
|
||||
tsr.prg: tsr.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -dNOFLOAT -dNOLONG
|
||||
|
||||
overlay.prg: overlay.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -d64=overlay.d64
|
||||
|
||||
overlay.prg: overlaylzo.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n -d64=overlaylzo.d64
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs *.d64 *.crt
|
||||
@@ -0,0 +1,157 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/kernalio.h>
|
||||
|
||||
// Common memory area for all overlays
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
// Section and region for first overlay bank
|
||||
|
||||
#pragma overlay( ovl1, 1 )
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xc000, , 1, { bcode1, bdata1 } )
|
||||
|
||||
// Section and region for second overlay bank
|
||||
|
||||
#pragma overlay( ovl2, 2 )
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0xc000, , 2, { bcode2, bdata2 } )
|
||||
|
||||
#pragma overlay( ovl3, 3 )
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0xc000, , 3, { bcode3, bdata3 } )
|
||||
|
||||
#pragma overlay( ovl4, 4 )
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0xc000, , 4, { bcode4, bdata4 } )
|
||||
|
||||
#pragma overlay( ovl5, 5 )
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0xc000, , 5, { bcode5, bdata5 } )
|
||||
|
||||
#pragma overlay( ovl6, 6 )
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0xc000, , 6, { bcode6, bdata6 } )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fourth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
// Load an overlay section into memory
|
||||
|
||||
void load(const char * fname)
|
||||
{
|
||||
krnio_setnam(fname);
|
||||
krnio_load(1, 8, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Kernal memory only
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
// Call function in overlay 1
|
||||
load(P"OVL1");
|
||||
print1();
|
||||
|
||||
// Call function in overlay 2
|
||||
load(P"OVL2");
|
||||
print2();
|
||||
|
||||
load(P"OVL3");
|
||||
print3();
|
||||
|
||||
load(P"OVL4");
|
||||
print4();
|
||||
|
||||
load(P"OVL5");
|
||||
print5();
|
||||
|
||||
load(P"OVL6");
|
||||
print6();
|
||||
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
#include <c64/memmap.h>
|
||||
#include <c64/charwin.h>
|
||||
#include <c64/cia.h>
|
||||
#include <c64/vic.h>
|
||||
#include <c64/kernalio.h>
|
||||
#include <oscar.h>
|
||||
|
||||
// Common memory area for all overlays
|
||||
|
||||
#pragma region( main, 0x0900, 0x8000, , , { code, data, bss, heap, stack } )
|
||||
|
||||
// Section and region for first overlay bank
|
||||
|
||||
#pragma overlay( ovl1, 1, lzo )
|
||||
#pragma section( bcode1, 0 )
|
||||
#pragma section( bdata1, 0 )
|
||||
#pragma region(bank1, 0x8000, 0xc000, , 1, { bcode1, bdata1 } )
|
||||
|
||||
// Section and region for second overlay bank
|
||||
|
||||
#pragma overlay( ovl2, 2, lzo )
|
||||
#pragma section( bcode2, 0 )
|
||||
#pragma section( bdata2, 0 )
|
||||
#pragma region(bank2, 0x8000, 0xc000, , 2, { bcode2, bdata2 } )
|
||||
|
||||
#pragma overlay( ovl3, 3, lzo )
|
||||
#pragma section( bcode3, 0 )
|
||||
#pragma section( bdata3, 0 )
|
||||
#pragma region(bank3, 0x8000, 0xc000, , 3, { bcode3, bdata3 } )
|
||||
|
||||
#pragma overlay( ovl4, 4, lzo )
|
||||
#pragma section( bcode4, 0 )
|
||||
#pragma section( bdata4, 0 )
|
||||
#pragma region(bank4, 0x8000, 0xc000, , 4, { bcode4, bdata4 } )
|
||||
|
||||
#pragma overlay( ovl5, 5, lzo )
|
||||
#pragma section( bcode5, 0 )
|
||||
#pragma section( bdata5, 0 )
|
||||
#pragma region(bank5, 0x8000, 0xc000, , 5, { bcode5, bdata5 } )
|
||||
|
||||
#pragma overlay( ovl6, 6, lzo )
|
||||
#pragma section( bcode6, 0 )
|
||||
#pragma section( bdata6, 0 )
|
||||
#pragma region(bank6, 0x8000, 0xc000, , 6, { bcode6, bdata6 } )
|
||||
|
||||
// Charwin in shared memory section
|
||||
|
||||
CharWin cw;
|
||||
|
||||
// Now switch code generation to bank 1
|
||||
|
||||
#pragma code ( bcode1 )
|
||||
#pragma data ( bdata1 )
|
||||
|
||||
// Print into shared charwin
|
||||
|
||||
void print1(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is first overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Now switch code generation to bank 2
|
||||
|
||||
#pragma code ( bcode2 )
|
||||
#pragma data ( bdata2 )
|
||||
|
||||
void print2(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is second overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode3 )
|
||||
#pragma data ( bdata3 )
|
||||
|
||||
void print3(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is third overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode4 )
|
||||
#pragma data ( bdata4 )
|
||||
|
||||
void print4(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fourth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode5 )
|
||||
#pragma data ( bdata5 )
|
||||
|
||||
void print5(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is fifth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
#pragma code ( bcode6 )
|
||||
#pragma data ( bdata6 )
|
||||
|
||||
void print6(void)
|
||||
{
|
||||
cwin_put_string(&cw, p"This is sixth overlay", 7);
|
||||
cwin_cursor_newline(&cw);
|
||||
}
|
||||
|
||||
// Switching code generation back to shared section
|
||||
|
||||
#pragma code ( code )
|
||||
#pragma data ( data )
|
||||
|
||||
// Load an overlay section into memory
|
||||
|
||||
void load(const char * fname)
|
||||
{
|
||||
krnio_setnam(fname);
|
||||
if (krnio_open(2, 8, 2))
|
||||
{
|
||||
if (krnio_chkin(2))
|
||||
{
|
||||
char lo = krnio_chrin();
|
||||
char hi = krnio_chrin();
|
||||
|
||||
char * dp = (char *)((hi << 8) | lo);
|
||||
krnio_clrchn();
|
||||
krnio_read_lzo(2, dp);
|
||||
}
|
||||
krnio_close(2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Kernal memory only
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Init VIC
|
||||
vic_setmode(VICM_TEXT, (char *)0x0400, (char *)0x1800);
|
||||
|
||||
// Prepare output window
|
||||
cwin_init(&cw, (char *)0x0400, 0, 0, 40, 25);
|
||||
cwin_clear(&cw);
|
||||
|
||||
// Call function in overlay 1
|
||||
load(P"OVL1");
|
||||
print1();
|
||||
|
||||
// Call function in overlay 2
|
||||
load(P"OVL2");
|
||||
print2();
|
||||
|
||||
load(P"OVL3");
|
||||
print3();
|
||||
|
||||
load(P"OVL4");
|
||||
print4();
|
||||
|
||||
load(P"OVL5");
|
||||
print5();
|
||||
|
||||
load(P"OVL6");
|
||||
print6();
|
||||
|
||||
mmap_set(MMAP_ROM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <c64/asm6502.h>
|
||||
|
||||
// Invoke resident section with "SYS 49152" from basic
|
||||
|
||||
// not much space, so we go with a smaller stack size
|
||||
|
||||
#pragma stacksize(256)
|
||||
|
||||
// shrink size of startup section
|
||||
|
||||
#pragma section(startup, 0);
|
||||
#pragma region(startup, 0x0801, 0x0870, , , { startup } )
|
||||
|
||||
// section for code copy
|
||||
|
||||
#pragma section(rcode, 0)
|
||||
#pragma region(rcode, 0x0870, 0x0900, , , { rcode } )
|
||||
|
||||
// main section to stay resident, save three bytes at the
|
||||
// beginning to have space for an entry jump
|
||||
|
||||
#pragma region(main, 0x0903, 0x1900, , , {code, data, bss, heap, stack}, 0xc003 )
|
||||
|
||||
// resident entry routine
|
||||
|
||||
void tsr(void)
|
||||
{
|
||||
// Initialize stack pointer
|
||||
|
||||
__asm {
|
||||
lda #$ff
|
||||
sta __sp
|
||||
lda #$cf
|
||||
sta __sp +1
|
||||
}
|
||||
|
||||
// do something useless
|
||||
|
||||
printf(p"Hello World\n");
|
||||
|
||||
// and done
|
||||
}
|
||||
|
||||
// Now the copy code section
|
||||
|
||||
#pragma code(rcode)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// source and target address to copy, no memcpy as it is itself
|
||||
// not yet copied
|
||||
|
||||
char * dp = (char *)0xc000;
|
||||
char * sp = (char *)0x0903;
|
||||
|
||||
// A jmp to the code at the absolute address 0xc000 / 49152
|
||||
|
||||
dp += asm_ab(dp, ASM_JMP, (unsigned)tsr);
|
||||
|
||||
// then the code
|
||||
|
||||
for(unsigned i=0; i<0xffd; i++)
|
||||
*dp++ = *sp++;
|
||||
|
||||
// now we are done
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 -n fireworks_ptr.c
|
||||
../../bin/oscar64 -n fireworks_hires.c
|
||||
../../bin/oscar64 -n fireworks_stripe.c
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char * const Screen = (char *)0xc800;
|
||||
static char * const Color = (char *)0xd800;
|
||||
static char * const Hires = (char *)0xe000;
|
||||
|
||||
// Single particle, with position and veloicty, using a next
|
||||
// pointer for single linked list
|
||||
struct Particle
|
||||
{
|
||||
int px, py, vx, vy;
|
||||
Particle * next;
|
||||
};
|
||||
|
||||
// Storage for up to 256 particles
|
||||
Particle particles[256];
|
||||
|
||||
// Heads of used and free list
|
||||
Particle * pfirst, * pfree;
|
||||
|
||||
// Lookup table for hires row buffer
|
||||
static char * Hirows[25];
|
||||
|
||||
// Pixel masks
|
||||
static const char setmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||
static const char clrmask[8] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};
|
||||
|
||||
// Set a pixel at the given coordinate
|
||||
void pix_set(unsigned px, unsigned py)
|
||||
{
|
||||
// Give the compiler a hand
|
||||
__assume(px < 320);
|
||||
__assume(py < 200);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 3] + (px & ~7);
|
||||
|
||||
// Set the pixel
|
||||
dp[py & 7] |= setmask[px & 7];
|
||||
}
|
||||
|
||||
// Clear a pixel at the given coordinate
|
||||
void pix_clr(unsigned px, unsigned py)
|
||||
{
|
||||
__assume(px < 320);
|
||||
__assume(py < 200);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 3] + (px & ~7);
|
||||
|
||||
// Clear the pixel
|
||||
dp[py & 7] &= clrmask[px & 7];
|
||||
}
|
||||
|
||||
// Init free list of particles
|
||||
void particle_init(void)
|
||||
{
|
||||
// Init address table for hires
|
||||
for(int i=0; i<25; i++)
|
||||
Hirows[i] = Hires + 320 * i;
|
||||
|
||||
// Init list heads
|
||||
pfirst = nullptr;
|
||||
pfree = particles;
|
||||
|
||||
// Link all particles in free list
|
||||
for(int i=0; i<255; i++)
|
||||
particles[i].next = particles + i + 1;
|
||||
}
|
||||
|
||||
// Add a particle to the list
|
||||
void particle_add(int px, int py, int vx, int vy)
|
||||
{
|
||||
// Check if we have a particle left
|
||||
if (pfree)
|
||||
{
|
||||
// Remove from free list
|
||||
Particle * p = pfree;
|
||||
pfree = pfree->next;
|
||||
|
||||
// Add to used list
|
||||
p->next = pfirst;
|
||||
pfirst = p;
|
||||
|
||||
// Init particle data
|
||||
p->px = px;
|
||||
p->py = py;
|
||||
p->vx = vx;
|
||||
p->vy = vy;
|
||||
}
|
||||
}
|
||||
|
||||
// Move particles in used list
|
||||
void particle_move(void)
|
||||
{
|
||||
// Start with first particle, remember previous
|
||||
// particle for list removal
|
||||
Particle * p = pfirst, * pp = nullptr;
|
||||
|
||||
// Loop over all particles in used list
|
||||
while (p)
|
||||
{
|
||||
// Clear previous particle image, using 10.6 fixed point
|
||||
pix_clr(p->px >> 6, p->py >> 6);
|
||||
|
||||
// Advance position by velocity
|
||||
p->px += p->vx;
|
||||
p->py += p->vy;
|
||||
|
||||
// Apply gravity
|
||||
p->vy += 8;
|
||||
|
||||
// Check if particle is still on screen
|
||||
if (p->px < 0 || p->px >= 320 * 64 || p->py < 0 || p->py >= 200 * 64)
|
||||
{
|
||||
// Particle is offscreen, so we remove it from the used list
|
||||
|
||||
// Remember next particle in used list
|
||||
Particle * pn = p->next;
|
||||
|
||||
// Remove from used list
|
||||
if (pp)
|
||||
pp->next = pn;
|
||||
else
|
||||
pfirst = pn;
|
||||
|
||||
// Attach to free list
|
||||
p->next = pfree;
|
||||
pfree = p;
|
||||
|
||||
// Advance to next particle
|
||||
p = pn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set image at new position
|
||||
pix_set(p->px >> 6, p->py >> 6);
|
||||
|
||||
// Advance to next particle
|
||||
pp = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalized random function
|
||||
int rnorm(void)
|
||||
{
|
||||
int l0 = (rand() & 0xfff) - 0x800;
|
||||
int l1 = (rand() & 0xfff) - 0x800;
|
||||
int l2 = (rand() & 0xfff) - 0x800;
|
||||
int l3 = (rand() & 0xfff) - 0x800;
|
||||
|
||||
return l0 + l1 + l2 + l3;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Turn off BASIC ROM
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Install IRQ trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// Turn off kernal ROM
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
// Switch to hires mode
|
||||
vic_setmode(VICM_HIRES, Screen, Hires);
|
||||
|
||||
// Clear screen
|
||||
memset(Screen, 0x10, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
// Black background
|
||||
vic.color_border = 0x00;
|
||||
vic.color_back = 0x00;
|
||||
|
||||
// Init particle system
|
||||
particle_init();
|
||||
|
||||
char k = 0;
|
||||
for(int i=0; i<10000; i++)
|
||||
{
|
||||
// Advance particles
|
||||
particle_move();
|
||||
|
||||
if (k < 25)
|
||||
{
|
||||
// Add a particle from the left for the first third
|
||||
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)));
|
||||
}
|
||||
else if (k < 50)
|
||||
{
|
||||
// Add a particle from the right for the second third
|
||||
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)));
|
||||
}
|
||||
else if (k < 75)
|
||||
{
|
||||
// Add a particle from the middle for the final third
|
||||
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)));
|
||||
}
|
||||
|
||||
// Advance thirds counter
|
||||
k++;
|
||||
if (k == 75)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char * const Screen = (char *)0xc800;
|
||||
static char * const Color = (char *)0xd800;
|
||||
static char * const Hires = (char *)0xe000;
|
||||
|
||||
// Single particle, with position, veloicty and color pattern, using a next
|
||||
// pointer for single linked list
|
||||
struct Particle
|
||||
{
|
||||
int px, py, vx, vy;
|
||||
char pat;
|
||||
Particle * next;
|
||||
};
|
||||
|
||||
// Storage for up to 256 particles
|
||||
Particle particles[256];
|
||||
|
||||
// Heads of used and free list
|
||||
Particle * pfirst, * pfree;
|
||||
|
||||
// Lookup table for hires row buffer
|
||||
static char * Hirows[25];
|
||||
|
||||
// Pixel masks
|
||||
static const char setmask[8] = {0xc0, 0xc0, 0x30, 0x30, 0x0c, 0x0c, 0x03, 0x03};
|
||||
static const char clrmask[8] = {0x3f, 0x3f, 0xcf, 0xcf, 0xf3, 0xf3, 0xfc, 0xfc};
|
||||
|
||||
// Set a pixel at the given coordinate
|
||||
void pix_set(unsigned px, unsigned py, char pat)
|
||||
{
|
||||
__assume(px < 320);
|
||||
__assume(py < 200);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 3] + (px & ~7);
|
||||
|
||||
// Set two pixels for a square pixel look
|
||||
char ly = py & 6;
|
||||
dp[ly + 1] = dp[ly + 0] |= setmask[px & 7] & pat;
|
||||
}
|
||||
|
||||
// Clear a pixel at the given coordinate
|
||||
void pix_clr(unsigned px, unsigned py)
|
||||
{
|
||||
__assume(px < 320);
|
||||
__assume(py < 200);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 3] + (px & ~7);
|
||||
|
||||
// Clear two pixels for a square pixel look
|
||||
char ly = py & 6;
|
||||
dp[ly + 1] = dp[ly + 0] &= clrmask[px & 7];
|
||||
}
|
||||
|
||||
// Init free list of particles
|
||||
void particle_init(void)
|
||||
{
|
||||
// Init address table for hires
|
||||
for(int i=0; i<25; i++)
|
||||
Hirows[i] = Hires + 320 * i;
|
||||
|
||||
// Init list heads
|
||||
pfirst = nullptr;
|
||||
pfree = particles;
|
||||
|
||||
// Link all particles in free list
|
||||
for(int i=0; i<255; i++)
|
||||
particles[i].next = particles + i + 1;
|
||||
}
|
||||
|
||||
// Add a particle to the list
|
||||
void particle_add(int px, int py, int vx, int vy, char pat)
|
||||
{
|
||||
// Check if we have a particle left
|
||||
if (pfree)
|
||||
{
|
||||
// Remove from free list
|
||||
Particle * p = pfree;
|
||||
pfree = pfree->next;
|
||||
|
||||
// Add to used list
|
||||
p->next = pfirst;
|
||||
pfirst = p;
|
||||
|
||||
// Init particle data
|
||||
p->px = px;
|
||||
p->py = py;
|
||||
p->vx = vx;
|
||||
p->vy = vy;
|
||||
p->pat = pat;
|
||||
}
|
||||
}
|
||||
|
||||
// Move particles in used list
|
||||
void particle_move(void)
|
||||
{
|
||||
// Start with first particle, remember previous
|
||||
// particle for list removal
|
||||
Particle * p = pfirst, * pp = nullptr;
|
||||
|
||||
// Loop over all particles in used list
|
||||
while (p)
|
||||
{
|
||||
// Clear previous particle image, using 10.6 fixed point
|
||||
pix_clr(p->px >> 6, p->py >> 6);
|
||||
|
||||
// Advance position by velocity
|
||||
p->px += p->vx;
|
||||
p->py += p->vy;
|
||||
|
||||
// Apply gravity
|
||||
p->vy += 8;
|
||||
|
||||
// Check if particle is still on screen
|
||||
if (p->px < 0 || p->px >= 320 * 64 || p->py < 0 || p->py >= 200 * 64)
|
||||
{
|
||||
// Particle is offscreen, so we remove it from the used list
|
||||
|
||||
// Remember next particle in used list
|
||||
Particle * pn = p->next;
|
||||
|
||||
// Remove from used list
|
||||
if (pp)
|
||||
pp->next = pn;
|
||||
else
|
||||
pfirst = pn;
|
||||
|
||||
// Attach to free list
|
||||
p->next = pfree;
|
||||
pfree = p;
|
||||
|
||||
// Advance to next particle
|
||||
p = pn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set image at new position
|
||||
pix_set(p->px >> 6, p->py >> 6, p->pat);
|
||||
|
||||
// Advance to next particle
|
||||
pp = p;
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalized random function
|
||||
int rnorm(void)
|
||||
{
|
||||
int l0 = (rand() & 0xfff) - 0x800;
|
||||
int l1 = (rand() & 0xfff) - 0x800;
|
||||
int l2 = (rand() & 0xfff) - 0x800;
|
||||
int l3 = (rand() & 0xfff) - 0x800;
|
||||
|
||||
return l0 + l1 + l2 + l3;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Turn off BASIC ROM
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Install IRQ trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// Turn off kernal ROM
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
// Switch to hires multicolor mode
|
||||
vic_setmode(VICM_HIRES_MC, Screen, Hires);
|
||||
|
||||
// Clear screen
|
||||
memset(Screen, 0x78, 1000);
|
||||
memset(Color, 0x0e, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
// Black background
|
||||
vic.color_border = 0x00;
|
||||
vic.color_back = 0x00;
|
||||
|
||||
// Init particle system
|
||||
particle_init();
|
||||
|
||||
char k = 0;
|
||||
for(int i=0; i<10000; i++)
|
||||
{
|
||||
// Advance particles
|
||||
particle_move();
|
||||
|
||||
if (k < 25)
|
||||
{
|
||||
// Add a particle from the left for the first third
|
||||
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)), 0x55);
|
||||
}
|
||||
else if (k < 50)
|
||||
{
|
||||
// Add a particle from the right for the second third
|
||||
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)), 0xaa);
|
||||
}
|
||||
else if (k < 75)
|
||||
{
|
||||
// Add a particle from the middle for the final third
|
||||
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)), 0xff);
|
||||
}
|
||||
|
||||
// Advance thirds counter
|
||||
k++;
|
||||
if (k == 75)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char * const Screen = (char *)0xc800;
|
||||
static char * const Color = (char *)0xd800;
|
||||
static char * const Hires = (char *)0xe000;
|
||||
|
||||
|
||||
// Single particle, with position, veloicty and color pattern, using a next
|
||||
// index for single linked list
|
||||
struct Particle
|
||||
{
|
||||
int px, py, vx, vy;
|
||||
char pat;
|
||||
char next;
|
||||
};
|
||||
|
||||
// Striped storage of particles, using an index for linkage
|
||||
__striped Particle particles[256];
|
||||
|
||||
#pragma align(particles, 256)
|
||||
|
||||
// Index for used and free list heads
|
||||
char pfirst, pfree;
|
||||
|
||||
static char * Hirows[25];
|
||||
|
||||
static const char setmask[4] = {0xc0, 0x30, 0x0c, 0x03};
|
||||
static const char clrmask[4] = {0x3f, 0xcf, 0xf3, 0xfc};
|
||||
|
||||
// Set a pixel at the given coordinate
|
||||
void pix_set(char px, char py, char pat)
|
||||
{
|
||||
__assume(px < 160);
|
||||
__assume(py < 100);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
|
||||
|
||||
// Set two pixels for a square pixel look
|
||||
char ly = 2 * (py & 3);
|
||||
dp[ly + 1] = dp[ly + 0] |= setmask[px & 3] & pat;
|
||||
}
|
||||
|
||||
// Clear a pixel at the given coordinate
|
||||
void pix_clr(char px, char py)
|
||||
{
|
||||
__assume(px < 160);
|
||||
__assume(py < 100);
|
||||
|
||||
// Calculate base position in hires
|
||||
char * dp = Hirows[py >> 2] + 2 * (px & ~3);
|
||||
|
||||
// Clear two pixels for a square pixel look
|
||||
char ly = 2 * (py & 3);
|
||||
dp[ly + 1] = dp[ly + 0] &= clrmask[px & 3];
|
||||
}
|
||||
|
||||
// Init free list of particles
|
||||
void particle_init(void)
|
||||
{
|
||||
// Init address table for hires
|
||||
for(int i=0; i<25; i++)
|
||||
Hirows[i] = Hires + 320 * i;
|
||||
|
||||
// Init list heads, using index 0 for list termination
|
||||
pfirst = 0;
|
||||
pfree = 1;
|
||||
|
||||
// Link all particles in free list
|
||||
for(int i=1; i<255; i++)
|
||||
particles[i].next = i + 1;
|
||||
}
|
||||
|
||||
// Add a particle to the list
|
||||
void particle_add(int px, int py, int vx, int vy, char pat)
|
||||
{
|
||||
// Check if we have a particle left
|
||||
if (pfree)
|
||||
{
|
||||
// Use "auto" to generate a striped pointer
|
||||
char i = pfree;
|
||||
auto p = particles + pfree;
|
||||
|
||||
// Remove from free list
|
||||
pfree = p->next;
|
||||
p->next = pfirst;
|
||||
|
||||
// Add to used list
|
||||
pfirst = i;
|
||||
|
||||
// Init particle data
|
||||
p->px = px;
|
||||
p->py = py;
|
||||
p->vx = vx;
|
||||
p->vy = vy;
|
||||
p->pat = pat;
|
||||
}
|
||||
}
|
||||
|
||||
// Move particles in used list
|
||||
void particle_move(void)
|
||||
{
|
||||
// Start with first particle, remember previous
|
||||
// particle for list removal, using indices instead of pointers
|
||||
char i = pfirst, pi = 0;
|
||||
|
||||
// Zero is still list termination
|
||||
while (i)
|
||||
{
|
||||
// Use "auto" to generate a striped pointer
|
||||
auto p = particles + i;
|
||||
|
||||
// Clear previous particle image, using 9.7 fixed point
|
||||
pix_clr(p->px >> 7, p->py >> 7);
|
||||
|
||||
// Advance position by velocity
|
||||
p->px += p->vx;
|
||||
p->py += p->vy;
|
||||
|
||||
// Apply gravity
|
||||
p->vy += 8;
|
||||
|
||||
// Check if particle is still on screen
|
||||
if (p->px < 0 || p->px >= 160 * 128 || p->py < 0 || p->py >= 100 * 128)
|
||||
{
|
||||
// Particle is offscreen, so we remove it from the used list
|
||||
|
||||
// Remember next particle in used list
|
||||
char pn = p->next;
|
||||
|
||||
// Remove from used list
|
||||
if (pi)
|
||||
particles[pi].next = pn;
|
||||
else
|
||||
pfirst = pn;
|
||||
|
||||
// Attach to free list
|
||||
p->next = pfree;
|
||||
pfree = i;
|
||||
|
||||
// Advance to next particle
|
||||
i = pn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set image at new position
|
||||
pix_set(p->px >> 7, p->py >> 7, p->pat);
|
||||
|
||||
// Advance to next particle
|
||||
pi = i;
|
||||
i = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalized random function
|
||||
int rnorm(void)
|
||||
{
|
||||
int l0 = (rand() & 0xfff) - 0x800;
|
||||
int l1 = (rand() & 0xfff) - 0x800;
|
||||
int l2 = (rand() & 0xfff) - 0x800;
|
||||
int l3 = (rand() & 0xfff) - 0x800;
|
||||
|
||||
return l0 + l1 + l2 + l3;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Turn off BASIC ROM
|
||||
mmap_set(MMAP_NO_BASIC);
|
||||
|
||||
// Install IRQ trampoline
|
||||
mmap_trampoline();
|
||||
|
||||
// Turn off kernal ROM
|
||||
mmap_set(MMAP_NO_ROM);
|
||||
|
||||
// Switch to hires multicolor mode
|
||||
vic_setmode(VICM_HIRES_MC, Screen, Hires);
|
||||
|
||||
// Clear screen
|
||||
memset(Screen, 0x78, 1000);
|
||||
memset(Color, 0x0e, 1000);
|
||||
memset(Hires, 0x00, 8000);
|
||||
|
||||
// Black background
|
||||
vic.color_border = 0x00;
|
||||
vic.color_back = 0x00;
|
||||
|
||||
// Init particle system
|
||||
particle_init();
|
||||
|
||||
char k = 0;
|
||||
for(int i=0; i<10000; i++)
|
||||
{
|
||||
// Advance particles
|
||||
particle_move();
|
||||
|
||||
if (k < 25)
|
||||
{
|
||||
// Add a particle from the left for the first third
|
||||
particle_add(4 * 64, 196 * 64, 256 + (rnorm() >> 6), -(384 + (rnorm() >> 6)), 0x55);
|
||||
}
|
||||
else if (k < 50)
|
||||
{
|
||||
// Add a particle from the right for the second third
|
||||
particle_add(316 * 64, 196 * 64, - (256 + (rnorm() >> 6)), -(384 + (rnorm() >> 6)), 0xaa);
|
||||
}
|
||||
else if (k < 75)
|
||||
{
|
||||
// Add a particle from the middle for the final third
|
||||
particle_add(160 * 64, 196 * 64, rnorm() >> 6, -(384 + (rnorm() >> 6)), 0xff);
|
||||
}
|
||||
|
||||
// Advance thirds counter
|
||||
k++;
|
||||
if (k == 75)
|
||||
k = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
call ..\..\bin\oscar64 -n fireworks_ptr.c
|
||||
call ..\..\bin\oscar64 -n fireworks_hires.c
|
||||
call ..\..\bin\oscar64 -n fireworks_stripe.c -O2
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: fireworks_ptr.prg fireworks_hires.prg fireworks_stripe.prg
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <string.h>
|
||||
|
||||
const char Text[] =
|
||||
S"LABORUM RERUM QUO. QUASI IN, SEQUI, TENETUR VOLUPTATEM RERUM "
|
||||
S"PORRO NON ET MAIORES ALIAS ODIO EST EOS. MAGNAM APERIAM CUM ET "
|
||||
S"ESSE TEMPORE ITAQUE TEMPORA VOLUPTAS ET IPSAM IPSAM EARUM. ID "
|
||||
S"SUSCIPIT QUIA RERUM REPREHENDERIT ERROR ET UT. DOLOR ID "
|
||||
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, restore;
|
||||
|
||||
int x;
|
||||
|
||||
// Loop through text
|
||||
__interrupt void doscroll(void)
|
||||
{
|
||||
vic.color_border++;
|
||||
|
||||
// Update raster IRQ for scroll line with new horizontal scroll offset
|
||||
rirq_data(&scroll, 1, 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++;
|
||||
|
||||
vic.color_border--;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// initialize raster IRQ
|
||||
rirq_init(true);
|
||||
|
||||
// Build switch to scroll line IRQ
|
||||
rirq_build(&scroll, 2);
|
||||
// Delay for one line to get to right border
|
||||
rirq_delay(&scroll, 11);
|
||||
// Change control register two with this IRQ
|
||||
rirq_write(&scroll, 1, &vic.ctrl2, 0);
|
||||
// Put it onto the scroll line
|
||||
rirq_set(0, 49 + 24 * 8, &scroll);
|
||||
|
||||
// Build the switch to normal IRQ
|
||||
rirq_build(&restore, 2);
|
||||
// re-enable left and right column and reset horizontal scroll
|
||||
rirq_write(&restore, 0, &vic.ctrl2, VIC_CTRL2_CSEL);
|
||||
// call scroll copy code
|
||||
rirq_call(&restore, 1, doscroll);
|
||||
// place this at the top of the screen before the display starts
|
||||
rirq_set(1, 250, &restore);
|
||||
|
||||
// sort the raster IRQs
|
||||
rirq_sort();
|
||||
|
||||
// start raster IRQ processing
|
||||
rirq_start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
../../bin/oscar64 colorbars.c
|
||||
../../bin/oscar64 openborder.c
|
||||
../../bin/oscar64 textcrawler.c
|
||||
../../bin/oscar64 movingbars.c -n
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <conio.h>
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,5 @@
|
||||
call ..\..\bin\oscar64 colorbars.c
|
||||
call ..\..\bin\oscar64 openborder.c
|
||||
call ..\..\bin\oscar64 textcrawler.c
|
||||
call ..\..\bin\oscar64 movingbars.c -n
|
||||
call ..\..\bin\oscar64 autocrawler.c -n
|
||||
@@ -0,0 +1,11 @@
|
||||
%.prg: %.c
|
||||
@echo "Compiling sample file" $<
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $<
|
||||
|
||||
all: colorbars.prg openborder.prg textcrawler.prg movingbars.prg
|
||||
|
||||
movingbars.prg: movingbars.c
|
||||
@$(OSCAR64_CC) $(OSCAR64_CFLAGS) $< -n
|
||||
|
||||
clean:
|
||||
@$(RM) *.asm *.int *.lbl *.map *.prg *.bcs
|
||||
@@ -0,0 +1,94 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <string.h>
|
||||
#include <math.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 ;
|
||||
|
||||
char sintab[256];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
rirq_init(true);
|
||||
|
||||
rirq_build(&ftop, 3);
|
||||
rirq_delay(&ftop, 10);
|
||||
rirq_write(&ftop, 1, &vic.color_back, 2);
|
||||
rirq_write(&ftop, 2, &vic.color_border, 2);
|
||||
|
||||
rirq_build(&fbottom, 3);
|
||||
rirq_delay(&fbottom, 10);
|
||||
rirq_write(&fbottom, 1, &vic.color_back, 6);
|
||||
rirq_write(&fbottom, 2, &vic.color_border, 14);
|
||||
|
||||
rirq_build(&btop, 3);
|
||||
rirq_delay(&btop, 10);
|
||||
rirq_write(&btop, 1, &vic.color_back, 7);
|
||||
rirq_write(&btop, 2, &vic.color_border, 7);
|
||||
|
||||
rirq_build(&bbottom, 3);
|
||||
rirq_delay(&bbottom, 10);
|
||||
rirq_write(&bbottom, 1, &vic.color_back, 6);
|
||||
rirq_write(&bbottom, 2, &vic.color_border, 14);
|
||||
|
||||
rirq_build(&final, 0);
|
||||
|
||||
char yfront = 100, yback = 200;
|
||||
|
||||
rirq_set(0, yfront, &ftop);
|
||||
rirq_set(1, yfront + 16, &fbottom);
|
||||
rirq_set(2, yback, &btop);
|
||||
rirq_set(3, yback + 16, &bbottom);
|
||||
rirq_set(4, 250, &final);
|
||||
rirq_sort();
|
||||
|
||||
|
||||
rirq_start();
|
||||
|
||||
for(int i=0; i<32; i++)
|
||||
sintab[i] = (int)(120 + 60 * sin(i * PI / 16)) | 1;
|
||||
|
||||
char fi = 3, bi = 0;
|
||||
for(;;)
|
||||
{
|
||||
yfront = sintab[fi & 31];
|
||||
yback = sintab[bi & 31];
|
||||
|
||||
rirq_move(0, yfront);
|
||||
if (yback == yfront)
|
||||
{
|
||||
rirq_move(1, yfront + 16);
|
||||
rirq_clear(2);
|
||||
rirq_clear(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yback < yfront || yback > yfront + 16)
|
||||
{
|
||||
rirq_move(1, yfront + 16);
|
||||
rirq_move(2, yback);
|
||||
}
|
||||
else
|
||||
{
|
||||
rirq_clear(1);
|
||||
rirq_move(2, yfront + 16);
|
||||
}
|
||||
if (yback < yfront - 16 || yback > yfront)
|
||||
rirq_move(3, yback + 16);
|
||||
else
|
||||
rirq_clear(3);
|
||||
}
|
||||
|
||||
rirq_sort();
|
||||
rirq_wait();
|
||||
|
||||
fi ++;
|
||||
bi ++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <conio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
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;
|
||||
*(char *)(0x7fb) = 0x0380 / 64;
|
||||
*(char *)(0x7fc) = 0x03c0 / 64;
|
||||
*(char *)(0x7fd) = 0x0380 / 64;
|
||||
*(char *)(0x7fe) = 0x03c0 / 64;
|
||||
*(char *)(0x7ff) = 0x0380 / 64;
|
||||
|
||||
vic.spr_enable = 0b11111111;
|
||||
vic.spr_multi = 0b10101010;
|
||||
vic.spr_color[0] = VCOL_BLACK;
|
||||
vic.spr_color[1] = VCOL_ORANGE;
|
||||
vic.spr_color[2] = VCOL_BLACK;
|
||||
vic.spr_color[3] = VCOL_ORANGE;
|
||||
vic.spr_color[4] = VCOL_BLACK;
|
||||
vic.spr_color[5] = VCOL_ORANGE;
|
||||
vic.spr_color[6] = VCOL_BLACK;
|
||||
vic.spr_color[7] = VCOL_ORANGE;
|
||||
vic.spr_mcolor0 = VCOL_BROWN;
|
||||
vic.spr_mcolor1 = VCOL_WHITE;
|
||||
|
||||
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);
|
||||
vic_sprxy(2, 140, 2 * i); vic_sprxy(3, 140, 2 * i);
|
||||
vic_sprxy(4, 180, 3 * i); vic_sprxy(5, 180, 3 * i);
|
||||
vic_sprxy(6, 220, 4 * i); vic_sprxy(7, 220, 4 * i);
|
||||
|
||||
rirq_wait();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/rasterirq.h>
|
||||
#include <string.h>
|
||||
|
||||
const char * Text =
|
||||
S"LABORUM RERUM QUO. QUASI IN, SEQUI, TENETUR VOLUPTATEM RERUM "
|
||||
S"PORRO NON ET MAIORES ALIAS ODIO EST EOS. MAGNAM APERIAM CUM ET "
|
||||
S"ESSE TEMPORE ITAQUE TEMPORA VOLUPTAS ET IPSAM IPSAM EARUM. ID "
|
||||
S"SUSCIPIT QUIA RERUM REPREHENDERIT ERROR ET UT. DOLOR ID "
|
||||
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, 2);
|
||||
// Delay for one line to get to right border
|
||||
rirq_delay(&scroll, 11);
|
||||
// Change control register two with this IRQ
|
||||
rirq_write(&scroll, 1, &vic.ctrl2, 0);
|
||||
// Put it onto the scroll line
|
||||
rirq_set(0, 49 + 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, 1, 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++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||