mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-25 20:32:25 +00:00
Removed some tests.
This commit is contained in:
parent
f7617fe06b
commit
d67749719e
@ -1,41 +0,0 @@
|
||||
### Line Buffer
|
||||
|
||||
Used for rendering lines into. Organized with linear addressed columns of 8 bits, allowing the line routine to addess the y-coordinate using X/Y-addressing.
|
||||
|
||||
### Screen Buffer
|
||||
|
||||
Used for filling & showing to the user. There are 2 screen buffers allowing for double buffering.
|
||||
Memory organization is be adapted to the specific display. This means the same line routines can be used for charsets, bitmaps, sprites etc.
|
||||
|
||||
### Algorithm
|
||||
|
||||
1. Move points
|
||||
2. Clear line buffer
|
||||
3. Render lines into line buffer
|
||||
4. Wait for screen buffer being available for rendering (mostly instant)
|
||||
5. EOR-fill from line buffer into screen buffer
|
||||
6. Mark screen buffer for showing, swap screen buffer
|
||||
|
||||
### Line Drawing
|
||||
|
||||
Optimized line drawing routines for the 8 different cases. (xd positive/negative, yd , xd-yd positive/negative)
|
||||
|
||||
- Lines are organized in a clockwise fashion ensuring that xd positive means the fill starts and xd negative means the fill ends.
|
||||
- xd positive (start fill): steep slope lines render the top-most pixel, flat slope lines render the actual pixel.
|
||||
- xd negative (stop fill): steep slope lines render the pixel below bottom-most pixel, flat slope lines render below the actual pixel.
|
||||
- unrolled line routines with code for each individual x-pixel position can plot lines quite fast
|
||||
- unrolled line routines can be called by writing an RTS at code of the stop x-position and JSR'ing into the code for the start X-position.
|
||||
- The RTS must be fixed again after return.
|
||||
|
||||
### EOR filling
|
||||
|
||||
Unrolled EOR-filler from the line buffer. The screen buffer does not need to be cleared because the filler always fills all bytes.
|
||||
|
||||
### Effective Canvas Shape
|
||||
|
||||
Both the line canvas and screen canvas can benefit from identifying the effective canvas shape where an object can be rendered.
|
||||
For instance a freely 3D-rotated object may only occupy a circular shaped canvas.
|
||||
By only clearing & filling this effective canvas these time consuming routines arebecome faster.
|
||||
|
||||
It might also be worth dynamically detecting the canvas shape for each rendered frame - to allow even faster clear/fill.
|
||||
This will require an efficient way of identifying min/max y-value in for each column that consumes less time than the time saved by not clearing/filling.
|
@ -1,267 +0,0 @@
|
||||
// Filling a simple 16x16 2D polygon using EOR-filling
|
||||
// - Clearing canvas
|
||||
// - Trivial 2D rotation using sine tables
|
||||
// - Line-drawing polygon edges (fill-ready lines)
|
||||
// - Up-to-down EOR filling
|
||||
// - Double buffering
|
||||
|
||||
#include <string.h>
|
||||
#include <c64.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
// The line buffer
|
||||
char* const LINE_BUFFER = 0x2000;
|
||||
// The two charsets used as screen buffers
|
||||
char* const CANVAS1 = 0x3000;
|
||||
char* const CANVAS2 = 0x3800;
|
||||
// The screen matrix
|
||||
char* const SCREEN = 0x2c00;
|
||||
|
||||
// The screen console
|
||||
char* const CONSOLE = 0x0400;
|
||||
// The default charset address
|
||||
char* const PETSCII = 0x1000;
|
||||
|
||||
// The current canvas being rendered to the screen - in D018 format.
|
||||
char volatile canvas_show_memory = toD018(SCREEN, CANVAS2);
|
||||
// Flag signalling that the canvas on screen needs to be updated.
|
||||
// Set to 1 by the renderer when a new canvas is ready for showing, and to 0 by the raster when the canvas is shown on screen.
|
||||
char volatile canvas_show_flag = 0;
|
||||
|
||||
// SIN/COS tables
|
||||
char __align(0x100) SINTAB[0x140] = kickasm {{
|
||||
.fill $200, round(63 + 63*sin(i*2*PI/$100))
|
||||
}};
|
||||
char* COSTAB = SINTAB+0x40;
|
||||
|
||||
void main() {
|
||||
// Clear the console
|
||||
memset(CONSOLE, ' ', 40*25);
|
||||
// Clear the screen
|
||||
memset(SCREEN, 0, 40*25);
|
||||
memset(COLS, BLACK, 40*25);
|
||||
// Setup 16x16 canvas for rendering
|
||||
char *screen= SCREEN+12, *cols=COLS+12;
|
||||
for(char y=0;y<16;y++) {
|
||||
char c=y;
|
||||
for(char x=0;x<16;x++) {
|
||||
cols[x] = WHITE;
|
||||
screen[x] = c;
|
||||
c+=0x10;
|
||||
}
|
||||
cols += 40;
|
||||
screen += 40;
|
||||
}
|
||||
VICII->BORDER_COLOR = BLACK;
|
||||
VICII->BG_COLOR = BLACK;
|
||||
|
||||
// Set-up the raster IRQ
|
||||
setup_irq();
|
||||
// Set text color
|
||||
textcolor(WHITE);
|
||||
|
||||
char p0_idx = 0xb5;
|
||||
char p1_idx = p0_idx+15;
|
||||
char p2_idx = p0_idx+170;
|
||||
|
||||
// The current canvas being rendered to
|
||||
char* canvas = CANVAS1;
|
||||
|
||||
while(1) {
|
||||
clock_start();
|
||||
// Clear line buffer
|
||||
memset(LINE_BUFFER, 0, 0x0800);
|
||||
// Plot in line buffer
|
||||
char x0 = COSTAB[p0_idx];
|
||||
char y0 = SINTAB[p0_idx];
|
||||
char x1 = COSTAB[p1_idx];
|
||||
char y1 = SINTAB[p1_idx];
|
||||
line(LINE_BUFFER, x0, y0, x1, y1);
|
||||
char x2 = COSTAB[p2_idx];
|
||||
char y2 = SINTAB[p2_idx];
|
||||
line(LINE_BUFFER, x1, y1, x2, y2);
|
||||
line(LINE_BUFFER, x2, y2, x0, y0);
|
||||
// Move idx
|
||||
p0_idx++;
|
||||
p1_idx++;
|
||||
p2_idx++;
|
||||
// Wait until the canvas on screen has been switched before starting work on the next frame
|
||||
VICII->BORDER_COLOR = RED;
|
||||
while(canvas_show_flag) {}
|
||||
VICII->BORDER_COLOR = BLACK;
|
||||
// Fill canvas
|
||||
eorfill(LINE_BUFFER, canvas);
|
||||
// swap canvas being rendered to (using XOR)
|
||||
canvas ^= (CANVAS1^CANVAS2);
|
||||
// Swap canvas to show on screen (using XOR)
|
||||
canvas_show_memory ^= toD018(SCREEN,CANVAS1)^toD018(SCREEN,CANVAS2);
|
||||
// Set flag used to signal when the canvas has been shown
|
||||
canvas_show_flag = 1;
|
||||
// Read and display cycles
|
||||
clock_t cyclecount = clock()-CLOCKS_PER_INIT;
|
||||
//gotoxy(0,24);
|
||||
//printf("frame: %02x cycles: %6lu", p0_idx, cyclecount);
|
||||
//printf("(%02x,%02x)-(%02x,%02x)", x0, y0, x1, y1);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup raster IRQ to change charset at different lines
|
||||
void setup_irq() {
|
||||
asm { sei }
|
||||
// Disable CIA 1 Timer IRQ
|
||||
CIA1->INTERRUPT = CIA_INTERRUPT_CLEAR;
|
||||
// Set raster line to 8 pixels before the border
|
||||
VICII->CONTROL1 &= 0x7f;
|
||||
VICII->RASTER = BORDER_YPOS_BOTTOM-8;
|
||||
// Enable Raster Interrupt
|
||||
VICII->IRQ_ENABLE = IRQ_RASTER;
|
||||
// Set the IRQ routine
|
||||
*KERNEL_IRQ = &irq_bottom_1;
|
||||
asm { cli }
|
||||
}
|
||||
|
||||
// Interrupt Routine 1: Just above last text line.
|
||||
__interrupt void irq_bottom_1() {
|
||||
// Change border color
|
||||
VICII->BORDER_COLOR = DARK_GREY;
|
||||
// Show the cycle counter
|
||||
VICII->MEMORY = toD018(CONSOLE, PETSCII);
|
||||
// Acknowledge the IRQ
|
||||
VICII->IRQ_STATUS = IRQ_RASTER;
|
||||
// Trigger IRQ 2 at bottom of text-line
|
||||
VICII->RASTER = BORDER_YPOS_BOTTOM;
|
||||
*KERNEL_IRQ = &irq_bottom_2;
|
||||
}
|
||||
|
||||
// Interrupt Routine 2
|
||||
__interrupt(rom_sys_c64) void irq_bottom_2() {
|
||||
// Change border color
|
||||
VICII->BORDER_COLOR = BLACK;
|
||||
// Show the current canvas (unless a key is being pressed)
|
||||
if(!kbhit()) {
|
||||
VICII->MEMORY = canvas_show_memory;
|
||||
} else {
|
||||
VICII->MEMORY = toD018(SCREEN, LINE_BUFFER);
|
||||
}
|
||||
canvas_show_flag = 0;
|
||||
// Acknowledge the IRQ
|
||||
VICII->IRQ_STATUS = IRQ_RASTER;
|
||||
// Trigger IRQ 1 at 8 pixels before the border
|
||||
VICII->RASTER = BORDER_YPOS_BOTTOM-8;
|
||||
*KERNEL_IRQ = &irq_bottom_1;
|
||||
}
|
||||
|
||||
// Draw a EOR friendly line between two points
|
||||
// Uses bresenham line drawing routine
|
||||
void line(char* canvas, char x1, char y1, char x2, char y2) {
|
||||
char x = x1;
|
||||
char y = y1;
|
||||
char dx = abs_u8(x2-x1);
|
||||
char dy = abs_u8(y2-y1);
|
||||
char sx = sgn_u8(x2-x1);
|
||||
char sy = sgn_u8(y2-y1);
|
||||
// The sign of the x-difference determines if this is a line at the top of the face
|
||||
// being filled or a line at the bottom of the face. Because the points are organized in a clockwise
|
||||
// fashion any line pointing right is filled below the line and any line pointing left is filled above
|
||||
if(sx==0xff) {
|
||||
// This is a line at the bottom of the face - move it 1 pixel down to stop the fill correctly
|
||||
y++; y2++;
|
||||
}
|
||||
if(dx > dy) {
|
||||
// Flat slope - X is the driver - plot every X using bresenham
|
||||
char e = dx/2;
|
||||
do {
|
||||
plot(x, y);
|
||||
x += sx;
|
||||
e += dy;
|
||||
if(e>dx) {
|
||||
y += sy;
|
||||
e -= dx;
|
||||
}
|
||||
} while (x != x2);
|
||||
plot(x, y);
|
||||
} else {
|
||||
// Steep slope - Y is the driver - only plot one plot per X
|
||||
if(sx==sy) {
|
||||
// If dx/dy signs are identical we must render the first pixel of each segment
|
||||
plot(x, y);
|
||||
if(dx==0)
|
||||
return;
|
||||
char e = dy/2;
|
||||
do {
|
||||
do {
|
||||
y += sy;
|
||||
e += dx;
|
||||
} while(e<=dy);
|
||||
x += sx;
|
||||
e -= dy;
|
||||
plot(x, y);
|
||||
} while (x != x2);
|
||||
} else {
|
||||
// If dx/dy signs differ we must render the last pixel of each segment
|
||||
char e = dy/2;
|
||||
do {
|
||||
y += sy;
|
||||
e += dx;
|
||||
if(e>dy) {
|
||||
plot(x, y-sy);
|
||||
x += sx;
|
||||
e -= dy;
|
||||
}
|
||||
} while (y != y2);
|
||||
plot(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Column offsets
|
||||
char* plot_column[16] = { LINE_BUFFER+0, LINE_BUFFER+1*128, LINE_BUFFER+2*128, LINE_BUFFER+3*128, LINE_BUFFER+4*128, LINE_BUFFER+5*128, LINE_BUFFER+6*128, LINE_BUFFER+7*128, LINE_BUFFER+8*128, LINE_BUFFER+9*128, LINE_BUFFER+10*128, LINE_BUFFER+11*128, LINE_BUFFER+12*128, LINE_BUFFER+13*128, LINE_BUFFER+14*128, LINE_BUFFER+15*128 };
|
||||
// The bits used for plotting a pixel
|
||||
char plot_bit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
||||
|
||||
// Plot a single point on the canvas
|
||||
inline void plot(char x, char y) {
|
||||
// Find the canvas column
|
||||
char* column = plot_column[x/8];
|
||||
// Plot the bit
|
||||
column[y] |= plot_bit[x&7];
|
||||
}
|
||||
|
||||
// EOR fill from the line buffer onto the canvas
|
||||
void eorfill(char* line_buffer, char* canvas) {
|
||||
char* line_column = line_buffer;
|
||||
char* fill_column = canvas;
|
||||
for(char x=0;x<16;x++) {
|
||||
char eor = line_column[0];
|
||||
fill_column[0] = eor;
|
||||
for(char y=1;y<16*8;y++) {
|
||||
eor ^= line_column[y];
|
||||
fill_column[y] = eor;
|
||||
}
|
||||
line_column += 16*8;
|
||||
fill_column += 16*8;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the absolute value of a 8-bit unsigned number treated as a signed number.
|
||||
unsigned char abs_u8(unsigned char u) {
|
||||
if(u & 0x80) {
|
||||
return -u;
|
||||
} else {
|
||||
return u;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the sign of a 8-bit unsigned number treated as a signed number.
|
||||
// Returns unsigned -1 if the number is negative
|
||||
unsigned char sgn_u8(unsigned char u) {
|
||||
if(u & 0x80) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user