1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-12-22 21:29:50 +00:00

Removed some tests.

This commit is contained in:
jespergravgaard 2021-01-04 00:26:11 +01:00
parent 0eed4e7857
commit a473e963d6
6 changed files with 364 additions and 642 deletions

View File

@ -19615,3 +19615,367 @@ ror {z1}
dex
bne !-
!e:
//FRAGMENT vwuz1=vwuc1_plus_vbuz2
lda {z2}
clc
adc #<{c1}
sta {z1}
lda #>{c1}
adc #0
sta {z1}+1
//FRAGMENT qbuz1_derefidx_vbuc1=pbuz2
ldy #{c1}
lda {z2}
sta ({z1}),y
iny
lda {z2}+1
sta ({z1}),y
//FRAGMENT qwuz1_derefidx_vbuc1=pwuz2
ldy #{c1}
lda {z2}
sta ({z1}),y
iny
lda {z2}+1
sta ({z1}),y
//FRAGMENT vwuz1=pwuz2_derefidx_vbuc1
ldy #{c1}
lda ({z2}),y
sta {z1}
iny
lda ({z2}),y
sta {z1}+1
//FRAGMENT vwuz1=vwuc1_plus_vbuaa
clc
adc #<{c1}
sta {z1}
lda #>{c1}
adc #0
sta {z1}+1
//FRAGMENT vwuz1=vwuc1_plus_vbuxx
txa
clc
adc #<{c1}
sta {z1}
lda #>{c1}
adc #0
sta {z1}+1
//FRAGMENT vwuz1=vwuc1_plus_vbuyy
tya
clc
adc #<{c1}
sta {z1}
lda #>{c1}
adc #0
sta {z1}+1
//FRAGMENT vbuz1_eq__deref_pbuc1_then_la1
lda {c1}
cmp {z1}
beq {la1}
//FRAGMENT _deref_pbuc1_eq_0_then_la1
lda {c1}
cmp #0
beq {la1}
//FRAGMENT vbuz1=_deref_pbuc1_rol_4
lda {c1}
asl
asl
asl
asl
sta {z1}
//FRAGMENT vbuz1=vbuz2_bor__deref_pbuc1
lda {c1}
ora {z2}
sta {z1}
//FRAGMENT vduz1=vduz2_plus_vbuz3
lda {z3}
clc
adc {z2}
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
lda {z2}+2
adc #0
sta {z1}+2
lda {z2}+3
adc #0
sta {z1}+3
//FRAGMENT pbuc1_derefidx_vbuz1=_dec_pbuc1_derefidx_vbuz1
ldx {z1}
dec {c1},x
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_(pbuc2_derefidx_vbuz2)
ldx {z2}
ldy {c2},x
lda {c1},y
ldy #0
sta ({z1}),y
//FRAGMENT pbuc1_derefidx_vbuz1_le_pbuc2_derefidx_vbuz1_then_la1
ldy {z1}
lda {c2},y
cmp {c1},y
bcs {la1}
//FRAGMENT vbuz1=_deref_pbuz2_bor_vbuc1
lda #{c1}
ldy #0
ora ({z2}),y
sta {z1}
//FRAGMENT pbuc1_derefidx_vbuz1=pbuz2_derefidx_vbuz1
ldy {z1}
lda ({z2}),y
sta {c1},y
//FRAGMENT vwuz1=vwuc1_plus_vwuz2
clc
lda {z2}
adc #<{c1}
sta {z1}
lda {z2}+1
adc #>{c1}
sta {z1}+1
//FRAGMENT vbuxx_eq__deref_pbuc1_then_la1
cpx {c1}
beq {la1}
//FRAGMENT vbuaa=_deref_pbuc1_rol_4
lda {c1}
asl
asl
asl
asl
//FRAGMENT vbuxx=_deref_pbuc1_rol_4
lda {c1}
asl
asl
asl
asl
tax
//FRAGMENT vbuyy=_deref_pbuc1_rol_4
lda {c1}
asl
asl
asl
asl
tay
//FRAGMENT vbuaa=vbuz1_bor__deref_pbuc1
lda {c1}
ora {z1}
//FRAGMENT vbuxx=vbuz1_bor__deref_pbuc1
lda {c1}
ora {z1}
tax
//FRAGMENT vbuyy=vbuz1_bor__deref_pbuc1
lda {c1}
ora {z1}
tay
//FRAGMENT vbuz1=vbuaa_bor__deref_pbuc1
ora {c1}
sta {z1}
//FRAGMENT vbuaa=vbuaa_bor__deref_pbuc1
ora {c1}
//FRAGMENT vbuxx=vbuaa_bor__deref_pbuc1
ora {c1}
tax
//FRAGMENT vbuyy=vbuaa_bor__deref_pbuc1
ora {c1}
tay
//FRAGMENT vbuz1=vbuxx_bor__deref_pbuc1
txa
ora {c1}
sta {z1}
//FRAGMENT vbuaa=vbuxx_bor__deref_pbuc1
txa
ora {c1}
//FRAGMENT vbuxx=vbuxx_bor__deref_pbuc1
txa
ora {c1}
tax
//FRAGMENT vbuyy=vbuxx_bor__deref_pbuc1
txa
ora {c1}
tay
//FRAGMENT vbuz1=vbuyy_bor__deref_pbuc1
tya
ora {c1}
sta {z1}
//FRAGMENT vbuaa=vbuyy_bor__deref_pbuc1
tya
ora {c1}
//FRAGMENT vbuxx=vbuyy_bor__deref_pbuc1
tya
ora {c1}
tax
//FRAGMENT vbuyy=vbuyy_bor__deref_pbuc1
tya
ora {c1}
tay
//FRAGMENT vduz1=vduz2_plus_vbuxx
txa
clc
adc {z2}
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
lda {z2}+2
adc #0
sta {z1}+2
lda {z2}+3
adc #0
sta {z1}+3
//FRAGMENT vduz1=vduz2_plus_vbuyy
tya
clc
adc {z2}
sta {z1}
lda {z2}+1
adc #0
sta {z1}+1
lda {z2}+2
adc #0
sta {z1}+2
lda {z2}+3
adc #0
sta {z1}+3
//FRAGMENT pbuz1_derefidx_vbuz2=pbuc1_derefidx_(pbuc2_derefidx_vbuaa)
tax
ldy {c2},x
lda {c1},y
ldy {z2}
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuz2=pbuc1_derefidx_(pbuc2_derefidx_vbuxx)
ldy {c2},x
lda {c1},y
ldy {z2}
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuz2=pbuc1_derefidx_(pbuc2_derefidx_vbuyy)
ldx {c2},y
lda {c1},x
ldy {z2}
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuaa=pbuc1_derefidx_(pbuc2_derefidx_vbuz2)
ldy {z2}
ldx {c2},y
tay
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuaa=pbuc1_derefidx_(pbuc2_derefidx_vbuaa)
tay
ldx {c2},y
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuaa=pbuc1_derefidx_(pbuc2_derefidx_vbuxx)
ldy {c2},x
ldx {c1},y
tay
txa
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuaa=pbuc1_derefidx_(pbuc2_derefidx_vbuyy)
ldx {c2},y
tay
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuxx=pbuc1_derefidx_(pbuc2_derefidx_vbuz2)
ldy {z2}
txa
ldx {c2},y
tay
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuxx=pbuc1_derefidx_(pbuc2_derefidx_vbuaa)
tay
txa
ldx {c2},y
tay
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuxx=pbuc1_derefidx_(pbuc2_derefidx_vbuxx)
txa
tay
ldx {c2},y
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuxx=pbuc1_derefidx_(pbuc2_derefidx_vbuyy)
txa
ldx {c2},y
tay
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuyy=pbuc1_derefidx_(pbuc2_derefidx_vbuz2)
ldx {z2}
lda {c2},x
tax
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuyy=pbuc1_derefidx_(pbuc2_derefidx_vbuaa)
tax
lda {c2},x
tax
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuyy=pbuc1_derefidx_(pbuc2_derefidx_vbuxx)
lda {c2},x
tax
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuz1_derefidx_vbuyy=pbuc1_derefidx_(pbuc2_derefidx_vbuyy)
ldx {c2},y
lda {c1},x
sta ({z1}),y
//FRAGMENT pbuc1_derefidx_vbuxx=_dec_pbuc1_derefidx_vbuxx
dec {c1},x
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_(pbuc2_derefidx_vbuxx)
ldy {c2},x
lda {c1},y
ldy #0
sta ({z1}),y
//FRAGMENT pbuc1_derefidx_vbuxx_le_pbuc2_derefidx_vbuxx_then_la1
txa
tay
lda {c2},x
cmp {c1},y
bcs {la1}
//FRAGMENT vbuaa=_deref_pbuz1_bor_vbuc1
lda #{c1}
ldy #0
ora ({z1}),y
//FRAGMENT vbuxx=_deref_pbuz1_bor_vbuc1
lda #{c1}
ldy #0
ora ({z1}),y
tax
//FRAGMENT vbuyy=_deref_pbuz1_bor_vbuc1
lda #{c1}
ldy #0
ora ({z1}),y
tay
//FRAGMENT pbuc1_derefidx_vbuaa=pbuz1_derefidx_vbuaa
tay
lda ({z1}),y
sta {c1},y
//FRAGMENT vduz1=vduz1_plus_vbuxx
txa
clc
adc {z1}
sta {z1}
lda {z1}+1
adc #0
sta {z1}+1
lda {z1}+2
adc #0
sta {z1}+2
lda {z1}+3
adc #0
sta {z1}+3
//FRAGMENT vwuz1=vwuz1_band_vwuc1
lda {z1}
and #<{c1}
sta {z1}
lda {z1}+1
and #>{c1}
sta {z1}+1
//FRAGMENT vwuz1=vwuc1_plus_vwuz1
clc
lda {z1}
adc #<{c1}
sta {z1}
lda {z1}+1
adc #>{c1}
sta {z1}+1

View File

@ -1,345 +0,0 @@
// Clears start screen throwing around the letters (by turning them into sprites)
#include <stdlib.h>
#include <sqr.h>
#include <atan2.h>
#include <multiply.h>
#include <c64.h>
// Generate debug code (raster time usage etc.)
const bool DEBUG = false;
// Address of the screen
byte* const SCREEN = 0x0400;
// Sprite data for the animating sprites
byte* const SPRITE_DATA = 0x2000;
// Values added to VX
const unsigned int VXSIN[40] = kickasm {{
.for(var i=0; i<40; i++) {
.word -sin(toRadians([i*360]/40))*4
}
}};
// Values added to VY
const unsigned int VYSIN[25] = kickasm {{
.for(var i=0; i<25; i++) {
.word -sin(toRadians([i*360]/25))*4
}
}};
// Copy of the screen used for finding chars to process
byte* SCREEN_COPY = malloc(1000);
// Screen containing bytes representing the distance to the center
byte* SCREEN_DIST = malloc(1000);
// Max number of chars processed at once
const byte NUM_PROCESSING = 8;
// Struct holding char being processed
struct ProcessingChar {
// x-position (0-39)
char x;
// y-position (0-24)
char y;
// squared distance to center (0-569)
char dist;
};
// Distance value meaning not found
const byte NOT_FOUND = 0xff;
// Struct holding sprite being processed
struct ProcessingSprite {
// sprite x-position. Fixed point [12.4]. Values (24-336)
unsigned int x;
// sprite y-position. Fixed point [12.4]. Values (30-228)
unsigned int y;
// sprite x velocity. Fixed point [12.4]
unsigned int vx;
// sprite y velocity. Fixed point [12.4]
unsigned int vy;
// sprite ID (0-7)
char id;
// sprite pointer (0-255)
char ptr;
// sprite color
char col;
// status of the processing
enum { STATUS_FREE, STATUS_NEW, STATUS_PROCESSING } status;
// Pointer to screen char being processed (used for deletion)
char* screenPtr;
};
// Sprites currently being processed in the interrupt
struct ProcessingSprite PROCESSING[NUM_PROCESSING];
void main() {
// Initialize the screen containing distance to the center
init_angle_screen(SCREEN_DIST);
// Copy screen to screen copy
for( char *src=SCREEN, *dst=SCREEN_COPY; src!=SCREEN+1000; src++, dst++) *dst = *src;
// Init processing array
for( char i: 0..NUM_PROCESSING-1 ) PROCESSING[i] = { 0, 0, 0, 0, 0, 0, 0, STATUS_FREE, 0};
// Init sprites
initSprites();
// Set-up raster interrupts
setupRasterIrq(RASTER_IRQ_TOP, &irqTop);
// Main loop
do {
// Look for the non-space closest to the screen center
struct ProcessingChar center = getCharToProcess();
if(center.dist==NOT_FOUND)
break;
startProcessing(center);
} while(true);
(*(SCREEN+999)) = '.';
do {
(*(COLS+999))++;
} while (true);
}
// Find the non-space char closest to the center of the screen
// If no non-space char is found the distance will be 0xffff
struct ProcessingChar getCharToProcess() {
struct ProcessingChar closest = { 0, 0, NOT_FOUND };
char* screen_line = SCREEN_COPY;
char* dist_line = SCREEN_DIST;
for( char y: 0..24) {
for( char x: 0..39) {
if(screen_line[x]!=' ') {
char dist = dist_line[x];
if(dist<closest.dist) {
// Update closest char
closest = { x, y, dist };
}
}
}
screen_line += 40;
dist_line += 40;
}
if(closest.dist != NOT_FOUND) {
// clear the found char on the screen copy
*(SCREEN_COPY+(unsigned int)closest.y*40+closest.x) = ' ';
}
return closest;
}
// Start processing a char - by inserting it into the PROCESSING array
void startProcessing(struct ProcessingChar center) {
// Busy-wait while finding an empty slot in the PROCESSING array
char freeIdx = 0xff;
do {
for( char i: 0..NUM_PROCESSING-1 ) {
if(PROCESSING[i].status==STATUS_FREE) {
freeIdx = i;
break;
}
}
} while (freeIdx==0xff);
// Found a free sprite
char spriteIdx = freeIdx;
// Copy char into sprite
unsigned int offset = (unsigned int)center.y*40+center.x;
char* colPtr = COLS+offset;
char spriteCol = *colPtr;
char* screenPtr = SCREEN+offset;
char* spriteData = SPRITE_DATA+(unsigned int)spriteIdx*64;
char ch = (*screenPtr);
char* chargenData = CHARGEN+(unsigned int)ch*8;
asm { sei }
*PROCPORT = PROCPORT_RAM_CHARROM;
for( char i: 0..7) {
*spriteData = *chargenData;
spriteData += 3;
chargenData++;
}
*PROCPORT = PROCPORT_RAM_IO;
asm { cli }
unsigned int spriteX = (BORDER_XPOS_LEFT + (unsigned int)center.x*8) << 4;
unsigned int spriteY = (BORDER_YPOS_TOP + (unsigned int)center.y*8) << 4;
char spritePtr = (char)(SPRITE_DATA/64)+spriteIdx;
// Put the sprite into the PROCESSING array
PROCESSING[spriteIdx] = { spriteX, spriteY, (unsigned int)(spriteIdx*8), 60, spriteIdx, spritePtr, spriteCol, STATUS_NEW, screenPtr };
}
const unsigned int XPOS_LEFTMOST = (unsigned int)(BORDER_XPOS_LEFT-8)<<4;
const unsigned int XPOS_RIGHTMOST = (unsigned int)(BORDER_XPOS_RIGHT)<<4;
const unsigned int YPOS_TOPMOST = (unsigned int)(BORDER_YPOS_TOP-8)<<4;
const unsigned int YPOS_BOTTOMMOST = (unsigned int)(BORDER_YPOS_BOTTOM)<<4;
// Process any chars in the PROCESSING array
void processChars() {
char numActive = 0;
for( char i: 0..NUM_PROCESSING-1 ) {
struct ProcessingSprite* processing = PROCESSING+i;
char bitmask = 1<<processing->id;
if(processing->status!=STATUS_FREE) {
if(processing->status==STATUS_NEW) {
// Clear the char on the screen
*(processing->screenPtr) = ' ';
// Enable the sprite
*SPRITES_ENABLE |= bitmask;
// Set the sprite color
SPRITES_COLOR[processing->id] = processing->col;
// Set sprite pointer
*(SCREEN+OFFSET_SPRITE_PTRS+processing->id) = processing->ptr;
// Set status
processing->status = STATUS_PROCESSING;
}
unsigned int xpos = processing->x >> 4;
// Set sprite position
if(>xpos) {
*SPRITES_XMSB |= bitmask;
} else {
*SPRITES_XMSB &= 0xff ^ bitmask;
}
SPRITES_XPOS[i*2] = (char)xpos;
char ypos = (char)(processing->y>>4);
SPRITES_YPOS[i*2] = ypos;
// Move sprite
if(processing->x < XPOS_LEFTMOST || processing->x > XPOS_RIGHTMOST || processing->y < YPOS_TOPMOST|| processing->y > YPOS_BOTTOMMOST ) {
// Set status to FREE
processing->status = STATUS_FREE;
// Disable the sprite
*SPRITES_ENABLE &= 0xff ^ bitmask;
} else {
char xchar = (char)(xpos/8) - BORDER_XPOS_LEFT/8;
processing->vx += VXSIN[xchar];
processing->x += processing->vx;
char ychar = (char)(ypos/8) - BORDER_YPOS_TOP/8;
processing->vy += VYSIN[ychar];
processing->y += processing->vy;
}
numActive++;
}
}
if(DEBUG) {
*(SCREEN+999) = '0'+numActive;
}
}
// Populates 1000 chars (a screen) with values representing the distance to the center.
// The actual value stored is distance*2 to increase precision
void init_dist_screen(char* screen) {
NUM_SQUARES = 0x30;
init_squares();
char* screen_topline = screen;
char *screen_bottomline = screen+40*24;
for(char y: 0..12) {
char y2 = y*2;
char yd = (y2>=24)?(y2-24):(24-y2);
unsigned int yds = sqr(yd);
for( char x=0,xb=39; x<=19; x++, xb--) {
char x2 = x*2;
char xd = (x2>=39)?(x2-39):(39-x2);
unsigned int xds = sqr(xd);
unsigned int ds = xds+yds;
char d = sqrt(ds);
screen_topline[x] = d;
screen_bottomline[x] = d;
screen_topline[xb] = d;
screen_bottomline[xb] = d;
}
screen_topline += 40;
screen_bottomline -= 40;
}
}
// Populates 1000 chars (a screen) with values representing the angle to the center.
// Utilizes symmetry around the center
void init_angle_screen(char* screen) {
char* screen_topline = screen+40*12;
char *screen_bottomline = screen+40*12;
for(char y: 0..12) {
for( char x=0,xb=39; x<=19; x++, xb--) {
signed int xw = (signed int)(unsigned int){ 39-x*2, 0 };
signed int yw = (signed int)(unsigned int){ y*2, 0 };
unsigned int angle_w = atan2_16(xw, yw);
char ang_w = >(angle_w+0x0080);
screen_bottomline[xb] = ang_w;
screen_topline[xb] = -ang_w;
screen_topline[x] = 0x80+ang_w;
screen_bottomline[x] = 0x80-ang_w;
}
screen_topline -= 40;
screen_bottomline += 40;
}
}
// Initialize sprites
void initSprites() {
// Clear sprite data
for( char* sp = SPRITE_DATA; sp<SPRITE_DATA+NUM_PROCESSING*64; sp++) *sp = 0;
// Initialize sprite registers
for( char i: 0..7) {
SPRITES_COLOR[i] = LIGHT_BLUE;
}
*SPRITES_MC = 0;
*SPRITES_EXPAND_X = 0;
*SPRITES_EXPAND_Y = 0;
}
// Setup Raster IRQ
void setupRasterIrq(unsigned int raster, void()* irqRoutine) {
asm { sei }
// Disable kernal & basic
*PROCPORT_DDR = PROCPORT_DDR_MEMORY_MASK;
*PROCPORT = PROCPORT_RAM_IO;
// Disable CIA 1 Timer IRQ
CIA1->INTERRUPT = CIA_INTERRUPT_CLEAR;
if(raster<0x100) {
*VICII_CONTROL &=0x7f;
} else {
*VICII_CONTROL |=0x80;
}
*RASTER = <raster;
// Enable Raster Interrupt
*IRQ_ENABLE = IRQ_RASTER;
// Set the IRQ routine
*HARDWARE_IRQ = irqRoutine;
asm { cli }
}
const char RASTER_IRQ_TOP = 0x30;
// Raster Interrupt at the top of the screen
__interrupt(hardware_clobber) void irqTop() {
if(DEBUG) {
for( char i: 0..4) {}
*BORDER_COLOR = WHITE;
*BG_COLOR = WHITE;
for( char i: 0..7) {}
*BORDER_COLOR = LIGHT_BLUE;
*BG_COLOR = BLUE;
}
// Trigger IRQ at the middle of the screen
*RASTER = RASTER_IRQ_MIDDLE;
*HARDWARE_IRQ = &irqBottom;
// Acknowledge the IRQ
*IRQ_STATUS = IRQ_RASTER;
}
const char RASTER_IRQ_MIDDLE = 0xff;
// Raster Interrupt at the bottom of the screen
__interrupt(hardware_clobber) void irqBottom() {
if(DEBUG) {
for( char i: 0..4) {}
*BORDER_COLOR = WHITE;
*BG_COLOR = WHITE;
}
processChars();
if(DEBUG) {
*BORDER_COLOR = LIGHT_BLUE;
*BG_COLOR = BLUE;
}
// Trigger IRQ at the top of the screen
*RASTER = RASTER_IRQ_TOP;
*HARDWARE_IRQ = &irqTop;
// Acknowledge the IRQ
*IRQ_STATUS = IRQ_RASTER;
}

View File

@ -1,33 +0,0 @@
// Chunky DYPP with arbitrary sine
// First implemented as dyppa.asm in 2011
#pragma emulator("C64Debugger")
#include <c64.h>
#include <string.h>
// The DYPPA charset containing the sloped offset characters
char __address(0x2000) DYPPA_CHARSET[0x0800] = kickasm(resource "dyppacharset.bin") {{
.var dyppaFile = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile.getCharsetSize(), dyppaFile.getCharset(i)
}};
// The DYPPA tables mapping the slopes, offsets and pixels to the right character in the charset
// for(offset:0..7) for(slope:0..f) for(pixels: 0..f) glyph_id(offset,slope,pixels)
char __align(0x100) DYPPA_TABLE[0x0800] = kickasm(resource "dyppacharset.bin") {{
.var dyppaFile2 = LoadBinary("dyppacharset.bin", "Charset=$000,Tables=$800")
.fill dyppaFile2.getTablesSize(), dyppaFile2.getTables(i)
}};
void main() {
VICII->MEMORY = toD018(DEFAULT_SCREEN, DYPPA_CHARSET);
memset(DEFAULT_SCREEN, DYPPA_TABLE[0], 1000);
for(;;) {
(*(DEFAULT_SCREEN+999))++;
}
}

View File

@ -1,136 +0,0 @@
// Quadratic Spline Library
// Implements an iterative algorithm using only addition for calculating quadratic splines
//
// A quadratic spline is a curve defined by 3 points: P0, P1 and P2.
// The curve connects P0 to P2 through a smooth curve that moves towards P1, but does usually not touch it.
//
// The general formula for the quadratic spline is as follows:
// A = P2 - 2*P1 + P0
// B = 2*P1 - 2*P0
// C = P0
// P(t) = A*t*t + B*t + C
// for 0 <= t <= 1
//
// This library implements a iterative algorithm using multiplications in the initialization and only additions for calculating each point on the spline.
// The iterative algorithm is based on the following:
// P(t+Dt) = P(t) + A*Dt*Dt + 2*A*t*Dt + B*Dt
//
// init:
// N = 16 (number of plots)
// Dt = 1/N
// P = C
// I = A*Dt*Dt + B*Dt
// J = 2*A*Dt*Dt
// loop(N times):
// plot(P)
// P = P + I
// I = I + J
// When N=16 then Dt[0.16] = $0.1000 Dt^2[0.16] = $0.0100
// When N=8 then Dt[0.16] = $0.2000 Dt^2[0.16] = $0.0400
// Vector with 16-coordinates that is part of a spline
struct SplineVector16 {
// x-position s[16.0]
signed int x;
// y-position s[16.0]
signed int y;
};
// Vector with 32-bit coordinates that is part of a spline
struct SplineVector32 {
// x-position s[16.16]
signed long x;
// y-position s[16.16]
signed long y;
};
// Array filled with spline segment points by splinePlot_16()
struct SplineVector16 SPLINE_16SEG[17];
// Generate a 16-segment quadratic spline using 32-bit fixed point 1/$10000-format math 16 decimal bits).
// This function can handle all signed int values in the points.
// The resulting spline segment points are returned in SPLINE_16SEG[]
// A quadratic spline is a curve defined by 3 points: P0, P1 and P2.
// The curve connects P0 to P2 through a smooth curve that moves towards P1, but does usually not touch it.
void spline_16seg(struct SplineVector16 p0, struct SplineVector16 p1, struct SplineVector16 p2) {
// A = P2 - 2*P1 + P0
struct SplineVector16 a = { p2.x - p1.x*2 + p0.x, p2.y - p1.y*2 + p0.y};
// B = 2*P1 - 2*P0
struct SplineVector16 b = { (p1.x - p0.x)*2, (p1.y - p0.y)*2 };
// I = A*Dt*Dt + B*Dt - Fixed point s[16.16]
// Dt = 1/16 and Dt*Dt=1/256 - we can multiply using only bitshifts
struct SplineVector32 i = { (signed long)a.x*0x100 + (signed long)b.x*0x100*0x10, (signed long)a.y*0x100 + (signed long)b.y*0x100*0x10 };
// J = 2*A*Dt*Dt - Fixed point s[16.16]
// Dt = 1/16 and Dt*Dt=1/256 - we can multiply using only bitshifts
struct SplineVector32 j = { (signed long)a.x*0x100*2, (signed long)a.y*0x100*2 };
// P = P0 - Fixed point s[16.16]
struct SplineVector32 p = { (signed long)p0.x*0x10000, (signed long)p0.y*0x10000 };
for( char n: 0..15) {
SPLINE_16SEG[n] = { (signed word)>(p.x+0x8000), (signed word)>(p.y+0x8000) };
// P = P + I;
p = { p.x+i.x, p.y+i.y };
// I = I + J;
i = { i.x+j.x, i.y+j.y };
}
SPLINE_16SEG[16] = { (signed word)>(p.x+0x8000), (signed word)>(p.y+0x8000) };
}
// Array filled with spline segment points by splinePlot_8()
struct SplineVector16 SPLINE_8SEG[9];
// Generate a 8-segment quadratic spline using 32-bit fixed point 1/$10000-format math 16 decimal bits).
// The resulting spline segment points are returned in SPLINE_8SEG[]
// This function can handle all signed int values in the points.
// A quadratic spline is a curve defined by 3 points: P0, P1 and P2.
// The curve connects P0 to P2 through a smooth curve that moves towards P1, but does usually not touch it.
void spline_8seg(struct SplineVector16 p0, struct SplineVector16 p1, struct SplineVector16 p2) {
// A = P2 - 2*P1 + P0
struct SplineVector16 a = { p2.x - p1.x*2 + p0.x, p2.y - p1.y*2 + p0.y};
// B = 2*P1 - 2*P0
struct SplineVector16 b = { (p1.x - p0.x)*2, (p1.y - p0.y)*2 };
// I = A*Dt*Dt + B*Dt - Fixed point s[16.16]
// Dt = 1/8 and Dt*Dt=1/64 - we can multiply using only bitshifts
struct SplineVector32 i = { (signed long)a.x*0x100*0x4 + (signed long)b.x*0x100*0x20, (signed long)a.y*0x100*0x4 + (signed long)b.y*0x100*0x20 };
// J = 2*A*Dt*Dt - Fixed point s[16.16]
// Dt = 1/8 and Dt*Dt=1/64 - we can multiply using only bitshifts
struct SplineVector32 j = { (signed long)a.x*0x100*0x8, (signed long)a.y*0x100*0x8 };
// P = P0 - Fixed point s[16.16]
struct SplineVector32 p = { (signed long)p0.x*0x10000, (signed long)p0.y*0x10000 };
for( char n: 0..7) {
SPLINE_8SEG[n] = { (signed word)>(p.x+0x8000), (signed word)>(p.y+0x8000) };
// P = P + I;
p = { p.x+i.x, p.y+i.y };
// I = I + J;
i = { i.x+j.x, i.y+j.y };
}
SPLINE_8SEG[8] = { (signed word)>(p.x+0x8000), (signed word)>(p.y+0x8000) };
}
// Generate a 8-segment quadratic spline using 16-bit fixed point 1/64-format math (6 decimal bits).
// The resulting spline segment points are returned in SPLINE_8SEG[]
// Point values must be within [-200 ; 1ff] for the calculation to not overflow.
// A quadratic spline is a curve defined by 3 points: P0, P1 and P2.
// The curve connects P0 to P2 through a smooth curve that moves towards P1, but does usually not touch it.
void spline_8segB(struct SplineVector16 p0, struct SplineVector16 p1, struct SplineVector16 p2) {
// A = P2 - 2*P1 + P0
struct SplineVector16 a = { p2.x - p1.x*2 + p0.x, p2.y - p1.y*2 + p0.y};
// B = 2*P1 - 2*P0
struct SplineVector16 b = { (p1.x - p0.x)*2, (p1.y - p0.y)*2 };
// I = A*Dt*Dt + B*Dt - I is in fixed point 1/64-format (6 decimal bits) [-200 ; 1ff]
// Dt = 1/8 and Dt*Dt=1/64 - we can multiply using only bitshifts. Dt*Dt is exactly==1 in the fixed point format.
struct SplineVector16 i = { a.x + b.x*8, a.y + b.y*8};
// J = 2*A*Dt*Dt - J is in fixed point 1/64-format (6 decimal bits) [-200 ; 1ff]
// Dt = 1/8 and Dt*Dt=1/64 - we can multiply using only bitshifts. Dt*Dt is exactly==1 in the fixed point format.
struct SplineVector16 j = { a.x*2, a.y*2 };
// P = P0 - P is in fixed point 1/64-format (6 decimal bits) [-200 ; 1ff]
struct SplineVector16 p = { p0.x*0x40, p0.y*0x40 };
for( char n: 0..7) {
// Get the rounded result
SPLINE_8SEG[n] = { (p.x+0x20)/0x40, (p.y+0x20)/0x40 };
// P = P + I;
p = { p.x+i.x, p.y+i.y };
// I = I + J;
i = { i.x+j.x, i.y+j.y };
}
SPLINE_8SEG[8] = { (p.x+0x20)/0x40, (p.y+0x20)/0x40 };
}

View File

@ -1,128 +0,0 @@
// Show a few simple splines using the splines library
#include "splines.c"
#include <bitmap2.h>
#include <time.h>
#include <print.h>
#include <fastmultiply.h>
#include <c64.h>
char* const PRINT_SCREEN = 0x0400;
char* const BITMAP_SCREEN = 0x5c00;
char* const BITMAP_GRAPHICS = 0x6000;
// A segment of a spline
struct Segment {
enum SegmentType { MOVE_TO, SPLINE_TO, LINE_TO} type;
struct SplineVector16 to;
struct SplineVector16 via;
};
// True type letter c
struct Segment letter_c[22] = {
{ MOVE_TO, {108,146}, {0,0} },
{ SPLINE_TO, {89,182}, {103,169} },
{ SPLINE_TO, {59,195}, {75,195} },
{ SPLINE_TO, {23,178}, {38,195} },
{ SPLINE_TO, {9,132}, {9,161} },
{ SPLINE_TO, {25,87}, {9,104} },
{ SPLINE_TO, {65,69}, {42,69} },
{ SPLINE_TO, {93,79}, {82,69} },
{ SPLINE_TO, {105,98}, {105,88} },
{ SPLINE_TO, {102,106}, {105,103} },
{ SPLINE_TO, {93,109}, {98,109} },
{ SPLINE_TO, {81,104}, {85,109} },
{ SPLINE_TO, {78,93}, {79,101} },
{ SPLINE_TO, {73,82}, {78,86} },
{ SPLINE_TO, {61,78}, {69,78} },
{ SPLINE_TO, {40,88}, {48,78} },
{ SPLINE_TO, {29,121}, {29,100} },
{ SPLINE_TO, {40,158}, {29,142} },
{ SPLINE_TO, {68,174}, {50,174} },
{ SPLINE_TO, {91,166}, {80,174} },
{ SPLINE_TO, {104,144}, {98,160} },
{ LINE_TO, {108,146}, {0,0} }
};
void main() {
mulf_init();
bitmap_init(BITMAP_GRAPHICS, BITMAP_SCREEN);
bitmap_clear(BLACK, WHITE);
vicSelectGfxBank(BITMAP_SCREEN);
*D018 = toD018(BITMAP_SCREEN, BITMAP_GRAPHICS);
*D011 = VICII_BMM|VICII_DEN|VICII_RSEL|3;
char angle = 0;
while(true) {
bitmap_clear(BLACK, WHITE);
show_letter(angle);
for ( byte w: 0..60) {
do {} while(*RASTER!=0xfe);
do {} while(*RASTER!=0xff);
}
angle += 9;
}
while(true) { (*(PRINT_SCREEN+999))++; }
}
void show_letter(char angle) {
struct SplineVector16 current = {0,0};
for( byte i: 0..21) {
struct SplineVector16 to = letter_c[i].to;
to = { to.x - 50, to.y - 150};
to = rotate(to, angle);
to = { to.x + 100, to.y + 100};
struct SplineVector16 via = letter_c[i].via;
via = { via.x - 50, via.y - 150};
via = rotate(via, angle);
via = { via.x + 100, via.y + 100};
struct Segment segment = { letter_c[i].type, to, via};
if(segment.type==MOVE_TO) {
//bitmap_plot((unsigned int)segment.to.x, (unsigned char)segment.to.y);
current = segment.to;
} else if(segment.type==SPLINE_TO) {
spline_8segB(current, segment.via, segment.to);
bitmap_plot_spline_8seg();
//bitmap_plot((unsigned int)segment.to.x, (unsigned char)segment.to.y);
//bitmap_plot((unsigned int)segment.via.x, (unsigned char)segment.via.y);
current = segment.to;
} else {
bitmap_line((unsigned int)current.x, (unsigned int)current.y, (unsigned int)segment.to.x, (unsigned int)segment.to.y);
current = segment.to;
}
}
}
// Plot the spline in the SPLINE_8SEG array
void bitmap_plot_spline_8seg() {
struct SplineVector16 current = SPLINE_8SEG[0];
for(char n:1..8) {
bitmap_line((unsigned int)current.x, (unsigned int)current.y, (unsigned int)SPLINE_8SEG[n].x, (unsigned int)SPLINE_8SEG[n].y);
//bitmap_plot((unsigned int)current.x, (unsigned char)current.y);
current = SPLINE_8SEG[n];
}
}
// Sine and Cosine tables
// Angles: $00=0, $80=PI,$100=2*PI
// Sine/Cosine: signed fixed [-$7f,$7f]
signed char __align(0x40) SIN[0x140] = kickasm {{
.for(var i=0;i<$140;i++)
.byte >round($7fff*sin(i*2*PI/256))
}};
signed char* COS = SIN+$40; // sin(x) = cos(x+PI/2)
// 2D-rotate a vector by an angle
struct SplineVector16 rotate(struct SplineVector16 vector, char angle) {
signed int cos_a = (signed int) COS[angle]; // signed fixed[0.7]
signed int xr = (signed int )mulf16s(cos_a, vector.x)*2; // signed fixed[8.8]
signed int yr = (signed int )mulf16s(cos_a, vector.y)*2; // signed fixed[8.8]
signed int sin_a = (signed int) SIN[angle]; // signed fixed[0.7]
xr -= (signed int)mulf16s(sin_a, vector.y)*2; // signed fixed[8.8]
yr += (signed int)mulf16s(sin_a, vector.x)*2; // signed fixed[8.8]
struct SplineVector16 rotated = { (signed int)(signed char)>xr, (signed int)(signed char)>yr };
return rotated;
}