mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 00:29:31 +00:00
291 lines
6.0 KiB
C
291 lines
6.0 KiB
C
// --------------------------------------------------------------------------
|
|
// Simple Graphics Test for KIM-1 with MTU Visible Memory Board
|
|
//
|
|
// Assumes the MTU Visible Memory Board mapped at 0xA000 for 8K of video RAM
|
|
//
|
|
// davepl@davepl.com
|
|
// --------------------------------------------------------------------------
|
|
|
|
#include <stdio.h> // For printf
|
|
#include <stdlib.h> // For rand, srand
|
|
#include <string.h> // For memcpy
|
|
#include <ctype.h>
|
|
|
|
typedef unsigned char byte;
|
|
|
|
extern void ClearScreen(void); // In subs.asm
|
|
extern void ScrollScreen(void);
|
|
extern void DrawCircle(void);
|
|
extern void SetPixel(void);
|
|
extern void ClearPixel(void);
|
|
extern void DrawChar(void);
|
|
extern void Demo(void);
|
|
extern void __fastcall__ Delay(byte loops);
|
|
extern void __fastcall__ DrawLine(byte bSet);
|
|
extern byte __fastcall__ AscToPet(byte in);
|
|
extern byte __fastcall__ PetToAsc(byte in);
|
|
extern byte __fastcall__ ReverseBits(byte in);
|
|
extern void __fastcall__ CharOut(byte asci_char);
|
|
extern byte __fastcall__ getch();
|
|
extern unsigned char font8x8_basic[256][8];
|
|
|
|
extern int x1cord;
|
|
extern int y1cord;
|
|
extern int x2cord;
|
|
extern int y2cord;
|
|
extern int cursorX;
|
|
extern int cursorY;
|
|
|
|
// If in zeropage:
|
|
//
|
|
// #pragma zpsym("x1cord")
|
|
// #pragma zpsym("x2cord")
|
|
// #pragma zpsym("y1cord")
|
|
// #pragma zpsym("y2cord")
|
|
|
|
// Screen memory is placed at A000-BFFF, 320x200 pixels, mapped right to left within each horizontal byte
|
|
|
|
byte * screen = (byte *) 0xA000;
|
|
|
|
// Cursor position
|
|
|
|
#define SCREEN_WIDTH 320
|
|
#define SCREEN_HEIGHT 200
|
|
#define CHARWIDTH 8
|
|
#define CHARHEIGHT 8
|
|
#define BYTESPERROW (SCREEN_WIDTH / 8)
|
|
#define BYTESPERCHARROW (BYTESPERROW * 8)
|
|
#define CHARSPERROW (SCREEN_WIDTH / CHARWIDTH)
|
|
#define ROWSPERCOLUMN (SCREEN_HEIGHT / CHARHEIGHT)
|
|
|
|
// SETPIXEL
|
|
//
|
|
// 0 <= x < 320
|
|
// 0 <= y < 200
|
|
//
|
|
// Draws a pixel on the screen in white or black at pixel pos x, y
|
|
|
|
void SETPIXEL(int x, int y, byte b)
|
|
{
|
|
x1cord = x;
|
|
y1cord = y;
|
|
|
|
if (b)
|
|
SetPixel();
|
|
else
|
|
ClearPixel();
|
|
}
|
|
|
|
// DRAWPIXEL
|
|
//
|
|
// 0 <= x < 320
|
|
// 0 <= y < 200
|
|
//
|
|
// Turns on a screen pixel at pixel pos x,y
|
|
|
|
void DRAWPIXEL(int x, int y)
|
|
{
|
|
x1cord = x;
|
|
y1cord = y;
|
|
SetPixel();
|
|
}
|
|
|
|
int c;
|
|
|
|
void DrawText(char * psz)
|
|
{
|
|
while (*psz)
|
|
{
|
|
while (cursorX >= CHARSPERROW)
|
|
{
|
|
cursorX -= CHARSPERROW;
|
|
cursorY += 1;
|
|
}
|
|
|
|
// If we've gone off the bottom of the screen, we scroll the screen and back up to the last line again
|
|
|
|
if (cursorY >= ROWSPERCOLUMN)
|
|
{
|
|
cursorY = ROWSPERCOLUMN - 1;
|
|
ScrollScreen();
|
|
}
|
|
|
|
// If we output a newline we advanced the cursor down one line and reset it to the left
|
|
|
|
if (*psz == 0x0A)
|
|
{
|
|
cursorX = 0;
|
|
cursorY++;
|
|
psz++;
|
|
}
|
|
else
|
|
{
|
|
c = *psz;
|
|
|
|
__asm__ ("ldx %v", cursorX);
|
|
__asm__ ("ldy %v", cursorY);
|
|
__asm__ ("lda %v", c);
|
|
DrawChar();
|
|
cursorX++;
|
|
psz++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawTextAt(int x, int y, char * psz)
|
|
{
|
|
cursorX = x;
|
|
cursorY = y;
|
|
DrawText(psz);
|
|
}
|
|
|
|
// Something like Bresenham's algorithm for drawing a line
|
|
/*
|
|
void DrawLine(int x0, int y0, int x1, int y1, byte val)
|
|
{
|
|
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
|
int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
|
int err = (dx > dy ? dx : -dy) / 2, e2;
|
|
|
|
while (1)
|
|
{
|
|
SETPIXEL(x0, y0, val);
|
|
|
|
if (x0 == x1 && y0 == y1)
|
|
break;
|
|
|
|
e2 = err;
|
|
|
|
if (e2 > -dx)
|
|
{
|
|
err -= dy;
|
|
x0 += sx;
|
|
}
|
|
if (e2 < dy)
|
|
{
|
|
err += dx;
|
|
y0 += sy;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// DrawCircle
|
|
//
|
|
// Draw a circle without sin, cos, or floating point!
|
|
|
|
void DrawCircleC(int x0, int y0, int radius, byte)
|
|
{
|
|
x1cord = x0;
|
|
y1cord = y0;
|
|
y2cord = radius;
|
|
DrawCircle();
|
|
}
|
|
|
|
void DrawLineC(int x1, int y1, int x2, int y2, byte bSet)
|
|
{
|
|
x1cord = x1;
|
|
y1cord = y1;
|
|
x2cord = x2;
|
|
y2cord = y2;
|
|
DrawLine(bSet);
|
|
}
|
|
|
|
// MirrorFont
|
|
//
|
|
// RAM font is backwards left-right relative to the way memory is laid out on the KIM-1, so we swap all the
|
|
// bytes in place by reversing the order of the bits in every byte
|
|
|
|
void MirrorFont()
|
|
{
|
|
int c;
|
|
byte * pb = (byte *) font8x8_basic;
|
|
|
|
for (c = 0; c < 128 * 8; c++)
|
|
pb[c] = ReverseBits(pb[c]);
|
|
}
|
|
|
|
// DrawScreenMoire
|
|
//
|
|
// Draws a moire pattern on the screen without clearing it first
|
|
|
|
void DrawMoire(int left, int top, int right, int bottom, byte pixel)
|
|
{
|
|
int x, y;
|
|
|
|
for (x = left; x < right; x += 6)
|
|
DrawLineC(x, top, right - x + left, bottom, pixel);
|
|
|
|
for (y = top; y < bottom; y += 6)
|
|
DrawLineC(left, y, right, bottom - y + top, pixel);
|
|
}
|
|
|
|
void DrawScreenMoire(int left, int top, int right, int bottom)
|
|
{
|
|
int x, y;
|
|
|
|
DrawLineC(left, top, right, top, 1);
|
|
DrawLineC(left, bottom, right, bottom, 1);
|
|
DrawLineC(left, top, left, bottom, 1);
|
|
DrawLineC(right, top, right, bottom, 1);
|
|
|
|
left++; top++; right--; bottom--;
|
|
|
|
for (x = left; x < right; x += 6)
|
|
DrawLineC(x, top, right - x + left, bottom, 1);
|
|
for (y = top; y < bottom; y += 6)
|
|
DrawLineC(left, y, right, bottom - y + top, 1);
|
|
for (x = left; x < right; x += 6)
|
|
DrawLineC(x, top, right - x + left, bottom, 0);
|
|
for (y = top; y < bottom; y += 6)
|
|
DrawLineC(left, y, right, bottom - y + top, 0);
|
|
|
|
}
|
|
|
|
int main (void)
|
|
{
|
|
|
|
int i;
|
|
int c = 0;
|
|
|
|
Demo();
|
|
|
|
CharOut('R');
|
|
CharOut('E');
|
|
CharOut('A');
|
|
CharOut('D');
|
|
CharOut('Y');
|
|
CharOut('.');
|
|
CharOut('\n');
|
|
|
|
|
|
while(1)
|
|
{
|
|
c = toupper(getch());
|
|
if (c != EOF)
|
|
CharOut(c);
|
|
}
|
|
|
|
// Clear the screen memory
|
|
while(1)
|
|
{
|
|
Demo();
|
|
DrawScreenMoire(0,30, 319, 199);
|
|
Delay(10);
|
|
|
|
Demo();
|
|
for (i = 5; i < 80; i+=5)
|
|
{
|
|
DrawCircleC(SCREEN_WIDTH/2, SCREEN_HEIGHT/2 + 20, i, 1);
|
|
DrawCircleC(SCREEN_WIDTH/4, SCREEN_HEIGHT/2 + 20, i, 1);
|
|
DrawCircleC(SCREEN_WIDTH*3/4, SCREEN_HEIGHT/2 + 20, i, 1);
|
|
}
|
|
|
|
Delay(10);
|
|
|
|
}
|
|
|
|
printf("Done, exiting...\r\n");
|
|
return 0;
|
|
}
|