1
0
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:
jespergravgaard 2021-01-04 00:33:51 +01:00
parent f7617fe06b
commit d67749719e
2 changed files with 0 additions and 308 deletions

View File

@ -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.

View File

@ -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;
}
}