initial commit
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
#include <c64/vic.h>
|
||||
#include <c64/memmap.h>
|
||||
#include <string.h>
|
||||
#include <c64/joystick.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Screen and color space
|
||||
#define Screen ((byte *)0x0400)
|
||||
#define Color ((byte *)0xd800)
|
||||
|
||||
// Macro for easy access to screen and color space
|
||||
#define sline(x, y) (Screen + 40 * (y) + (x))
|
||||
#define cline(x, y) (Color + 40 * (y) + (x))
|
||||
|
||||
// Tile data, each column has four rows of four tiles
|
||||
static const char quad[4][4 * 4] =
|
||||
{
|
||||
{
|
||||
0x20, 0x55, 0x6c, 0x4e,
|
||||
0x20, 0x5d, 0xe1, 0x65,
|
||||
0x20, 0x5d, 0xe1, 0x65,
|
||||
0x20, 0x4a, 0x7c, 0x4d,
|
||||
},
|
||||
{
|
||||
0x20, 0x40, 0x62, 0x77,
|
||||
0x20, 0x20, 0xa0, 0x20,
|
||||
0x20, 0x20, 0xa0, 0x20,
|
||||
0x20, 0x40, 0xe2, 0x6f,
|
||||
},
|
||||
{
|
||||
0x20, 0x40, 0x62, 0x77,
|
||||
0x20, 0x20, 0xa0, 0x20,
|
||||
0x20, 0x20, 0xa0, 0x20,
|
||||
0x20, 0x40, 0xe2, 0x6f,
|
||||
},
|
||||
{
|
||||
0x20, 0x49, 0x7b, 0x4d,
|
||||
0x20, 0x5d, 0x61, 0x6a,
|
||||
0x20, 0x5d, 0x61, 0x6a,
|
||||
0x20, 0x4b, 0x7e, 0x4e,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma align(quad, 256)
|
||||
|
||||
// Expand a single row into an offscreen buffer
|
||||
void expandrow(char * dp, char * cp, const char * grid, char ly, char lx)
|
||||
{
|
||||
char hx = 0;
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
dp[x] = quad[lx][ly + grid[hx]];
|
||||
cp[x] = grid[hx];
|
||||
lx++;
|
||||
if (lx == 4)
|
||||
{
|
||||
lx = 0;
|
||||
hx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expand a single column into an offscreen buffer
|
||||
void expandcol(char * dp, char * cp, const char * grid, char ly, char lx)
|
||||
{
|
||||
for(char y=0; y<25; y++)
|
||||
{
|
||||
dp[y] = quad[lx][ly + grid[0]];
|
||||
cp[y] = grid[0];
|
||||
ly += 4;
|
||||
if (ly == 16)
|
||||
{
|
||||
grid += 16;
|
||||
ly = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two split scroll for left, right and up
|
||||
#define VSPLIT 12
|
||||
|
||||
// Three split scroll for down. Downscrolling is more tricky because
|
||||
// we have to copy towards the raster
|
||||
#define VSPLIT 12
|
||||
#define VSPLIT2 20
|
||||
|
||||
// New line/column of screen and color data
|
||||
char news[40], newc[40];
|
||||
|
||||
// All scroll routines start with a pixel offset of 4, 4
|
||||
|
||||
// Scroll one character left in two pixel increments
|
||||
void scroll_left(void)
|
||||
{
|
||||
// Wait for one frame
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
// Switch to offset 2, 4
|
||||
vic.ctrl2 = 0x02;
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
// Switch to offset 0, 4
|
||||
vic.ctrl2 = 0x00;
|
||||
|
||||
// Wait until bottom of section
|
||||
vic_waitLine(50 + 8 * VSPLIT);
|
||||
|
||||
// Scroll upper section
|
||||
|
||||
for(char x=0; x<39; x++)
|
||||
{
|
||||
#assign ty 0
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(1, ty)[x];
|
||||
cline(0, ty)[x] = cline(1, ty)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == VSPLIT
|
||||
}
|
||||
|
||||
// Update column
|
||||
#assign ty 0
|
||||
#repeat
|
||||
sline(0, ty)[39] = news[ty];
|
||||
cline(0, ty)[39] = newc[ty];
|
||||
#assign ty ty + 1
|
||||
#until ty == VSPLIT
|
||||
|
||||
// Wait for bottom of visible screen
|
||||
vic_waitBottom();
|
||||
|
||||
// Switch to offset 6, 4
|
||||
vic.ctrl2 = 0x06;
|
||||
|
||||
// Scroll lower part of the screen, while top is redrawn
|
||||
for(char x=0; x<39; x++)
|
||||
{
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(1, ty)[x];
|
||||
cline(0, ty)[x] = cline(1, ty)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == 25
|
||||
}
|
||||
|
||||
// Update new column
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[39] = news[ty];
|
||||
cline(0, ty)[39] = newc[ty];
|
||||
#assign ty ty + 1
|
||||
#until ty == 25
|
||||
|
||||
// Wait for bottom
|
||||
vic_waitBottom();
|
||||
|
||||
// Now back to 4, 4
|
||||
vic.ctrl2 = 0x04;
|
||||
|
||||
}
|
||||
|
||||
// Scroll one character right in two pixel increments
|
||||
|
||||
void scroll_right(void)
|
||||
{
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
vic.ctrl2 = 0x06;
|
||||
vic_waitLine(50 + 8 * VSPLIT);
|
||||
|
||||
for(char x=39; x>0; x--)
|
||||
{
|
||||
#assign ty 0
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(-1, ty)[x];
|
||||
cline(0, ty)[x] = cline(-1, ty)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == VSPLIT
|
||||
}
|
||||
|
||||
#assign ty 0
|
||||
#repeat
|
||||
sline(0, ty)[0] = news[ty];
|
||||
cline(0, ty)[0] = newc[ty];
|
||||
#assign ty ty + 1
|
||||
#until ty == VSPLIT
|
||||
|
||||
vic_waitBottom();
|
||||
vic.ctrl2 = 0x00;
|
||||
|
||||
for(char x=39; x>0; x--)
|
||||
{
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(-1, ty)[x];
|
||||
cline(0, ty)[x] = cline(-1, ty)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == 25
|
||||
}
|
||||
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[0] = news[ty];
|
||||
cline(0, ty)[0] = newc[ty];
|
||||
#assign ty ty + 1
|
||||
#until ty == 25
|
||||
|
||||
vic_waitBottom();
|
||||
vic.ctrl2 = 0x02;
|
||||
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
vic.ctrl2 = 0x04;
|
||||
}
|
||||
|
||||
// Scroll one character up in two pixel increments
|
||||
|
||||
void scroll_up(void)
|
||||
{
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
vic.ctrl1 = 0x02 | VIC_CTRL1_DEN;
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
vic.ctrl1 = 0x00 | VIC_CTRL1_DEN;
|
||||
vic_waitLine(50 + 8 * VSPLIT);
|
||||
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#assign ty 0
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(0, ty + 1)[x];
|
||||
cline(0, ty)[x] = cline(0, ty + 1)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == VSPLIT
|
||||
}
|
||||
|
||||
vic_waitBottom();
|
||||
vic.ctrl1 = 0x06 | VIC_CTRL1_DEN;
|
||||
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(0, ty + 1)[x];
|
||||
cline(0, ty)[x] = cline(0, ty + 1)[x];
|
||||
#assign ty ty + 1
|
||||
#until ty == 24
|
||||
|
||||
sline(0, ty)[x] = news[x];
|
||||
cline(0, ty)[x] = newc[x];
|
||||
}
|
||||
|
||||
vic_waitBottom();
|
||||
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
|
||||
}
|
||||
|
||||
char tmp0[40], tmp1[40], tmp2[40], tmp3[40];
|
||||
|
||||
// Scroll one character down in two pixel increments. This is more tricky than
|
||||
// the other three cases, because we have to work towards the beam because
|
||||
// we have to copy backwards in memory.
|
||||
//
|
||||
// The scroll is split into three sections, the seam rows are saved into
|
||||
// intermediate arrays, so we can copy the top section first and the bottom
|
||||
// section last, and stay ahead of the beam.
|
||||
|
||||
void scroll_down(void)
|
||||
{
|
||||
// Wait one frame
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
|
||||
// Save seam lines
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
tmp0[x] = sline(0, VSPLIT)[x];
|
||||
tmp1[x] = cline(0, VSPLIT)[x];
|
||||
tmp2[x] = sline(0, VSPLIT2)[x];
|
||||
tmp3[x] = cline(0, VSPLIT2)[x];
|
||||
}
|
||||
|
||||
// Now switch to 4, 6
|
||||
vic.ctrl1 = 0x06 | VIC_CTRL1_DEN;
|
||||
|
||||
// Wait for bottom of top section
|
||||
vic_waitLine(58 + 8 * VSPLIT);
|
||||
|
||||
// Scroll top section down and copy new column
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#assign ty VSPLIT
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(0, ty - 1)[x];
|
||||
cline(0, ty)[x] = cline(0, ty - 1)[x];
|
||||
#assign ty ty - 1
|
||||
#until ty == 0
|
||||
|
||||
sline(0, ty)[x] = news[x];
|
||||
cline(0, ty)[x] = newc[x];
|
||||
}
|
||||
|
||||
// vic_waitBottom();
|
||||
// We have already reached the bottom, switch to 4, 0
|
||||
vic.ctrl1 = 0x00 | VIC_CTRL1_DEN;
|
||||
|
||||
// Copy the second section, update the seam line from the buffer
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
|
||||
#assign ty VSPLIT2
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(0, ty - 1)[x];
|
||||
cline(0, ty)[x] = cline(0, ty - 1)[x];
|
||||
#assign ty ty - 1
|
||||
#until ty == VSPLIT + 1
|
||||
|
||||
sline(0, ty)[x] = tmp0[x];
|
||||
cline(0, ty)[x] = tmp1[x];
|
||||
}
|
||||
|
||||
// Copy the third section, update the seam line from the buffer
|
||||
for(char x=0; x<40; x++)
|
||||
{
|
||||
#assign ty 24
|
||||
#repeat
|
||||
sline(0, ty)[x] = sline(0, ty - 1)[x];
|
||||
cline(0, ty)[x] = cline(0, ty - 1)[x];
|
||||
#assign ty ty - 1
|
||||
#until ty == VSPLIT2 + 1
|
||||
|
||||
sline(0, ty)[x] = tmp2[x];
|
||||
cline(0, ty)[x] = tmp3[x];
|
||||
}
|
||||
|
||||
// Switch to 4, 2
|
||||
vic_waitBottom();
|
||||
vic.ctrl1 = 0x02 | VIC_CTRL1_DEN;
|
||||
|
||||
// Switch to 4, 4
|
||||
vic_waitTop();
|
||||
vic_waitBottom();
|
||||
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
|
||||
}
|
||||
|
||||
char grid[16][16];
|
||||
|
||||
#pragma align(grid, 256)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// We need some more accurate timing for this, so kill the kernal IRQ
|
||||
__asm
|
||||
{
|
||||
sei
|
||||
}
|
||||
|
||||
// Init the grid
|
||||
for(char y=0; y<16; y++)
|
||||
{
|
||||
for(char x=0; x<16; x++)
|
||||
{
|
||||
grid[y][x] = rand() & 3;
|
||||
}
|
||||
}
|
||||
|
||||
char gridX = 0, gridY = 0;
|
||||
|
||||
// Initial drawing of the screen
|
||||
char * dp = Screen, * cp = Color;
|
||||
for(char y=0; y<25; y++)
|
||||
{
|
||||
expandrow(dp, cp, &(grid[y >> 2][0]), 4 * (y & 3), 0);
|
||||
dp += 40;
|
||||
cp += 40;
|
||||
}
|
||||
|
||||
// setup initial scroll offset
|
||||
|
||||
vic.ctrl1 = 0x04 | VIC_CTRL1_DEN;
|
||||
vic.ctrl2 = 0x04;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Check the joystick
|
||||
joy_poll(0);
|
||||
if (joyx[0] == 1)
|
||||
{
|
||||
// Move to the right
|
||||
if (gridX < 24)
|
||||
{
|
||||
gridX++;
|
||||
expandcol(news, newc, &(grid[gridY >> 2][(gridX + 39) >> 2]), 4 * (gridY & 3), (gridX + 39) & 3);
|
||||
scroll_left();
|
||||
}
|
||||
}
|
||||
else if (joyx[0] == -1)
|
||||
{
|
||||
// Move to the left
|
||||
if (gridX > 0)
|
||||
{
|
||||
gridX--;
|
||||
expandcol(news, newc, &(grid[gridY >> 2][gridX >> 2]), 4 * (gridY & 3), gridX & 3);
|
||||
scroll_right();
|
||||
}
|
||||
}
|
||||
else if (joyy[0] == 1)
|
||||
{
|
||||
// Move down
|
||||
if (gridY < 39)
|
||||
{
|
||||
gridY++;
|
||||
expandrow(news, newc, &(grid[(gridY + 24) >> 2][gridX >> 2]), 4 * ((gridY + 24) & 3), gridX & 3);
|
||||
scroll_up();
|
||||
}
|
||||
}
|
||||
else if (joyy[0] == -1)
|
||||
{
|
||||
// Move up
|
||||
if (gridY > 0)
|
||||
{
|
||||
gridY--;
|
||||
expandrow(news, newc, &(grid[gridY >> 2][gridX >> 2]), 4 * (gridY & 3), gridX & 3);
|
||||
scroll_down();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user