prog8/examples/c64graphics.p8
2020-03-28 13:42:24 +01:00

251 lines
8.2 KiB
Lua

%import c64lib
; bitmap pixel graphics module for the C64
; only black/white monchrome for now
; you could put this code at $4000 which is after the bitmap screen in memory ($2000-$3fff),
; this leaves more space for user program code.
graphics {
const uword bitmap_address = $2000
sub enable_bitmap_mode() {
; enable bitmap screen, erase it and set colors to black/white.
c64.SCROLY |= %00100000
c64.VMCSB = (c64.VMCSB & %11110000) | %00001000 ; $2000-$3fff
memset(bitmap_address, 320*200/8, 0)
c64scr.clear_screen($10, 0) ; pixel color $1 (white) backround $0 (black)
}
sub line(uword x1, ubyte y1, uword x2, ubyte y2) {
; Bresenham algorithm
word dx
word dy
byte ix = 1
byte iy = 1
if x2>x1 {
dx = x2-x1
} else {
ix = -1
dx = x1-x2
}
if y2>y1 {
dy = y2-y1
} else {
iy = -1
dy = y1-y2
}
word dx2 = 2 * dx
word dy2 = 2 * dy
word d = 0
plotx = x1
if dx >= dy {
if ix<0 {
forever {
graphics.plot(y1)
if plotx==x2
return
plotx--
d += dy2
if d > dx {
y1 += iy
d -= dx2
}
}
} else {
forever {
graphics.plot(y1)
if plotx==x2
return
plotx++
d += dy2
if d > dx {
y1 += iy
d -= dx2
}
}
}
} else {
if iy<0 {
forever {
plot(y1)
if y1 == y2
return
y1--
d += dx2
if d > dy {
plotx += ix as word
d -= dy2
}
}
} else {
forever {
plot(y1)
if y1 == y2
return
y1++
d += dx2
if d > dy {
plotx += ix as word
d -= dy2
}
}
}
}
}
sub circle(uword xcenter, ubyte ycenter, ubyte radius) {
; Midpoint algorithm
ubyte ploty
ubyte xx = radius
ubyte yy = 0
byte decisionOver2 = 1-xx
while xx>=yy {
plotx = xcenter + xx
ploty = ycenter + yy
plot(ploty)
plotx = xcenter - xx
plot(ploty)
plotx = xcenter + xx
ploty = ycenter - yy
plot(ploty)
plotx = xcenter - xx
plot(ploty)
plotx = xcenter + yy
ploty = ycenter + xx
plot(ploty)
plotx = xcenter - yy
plot(ploty)
plotx = xcenter + yy
ploty = ycenter - xx
plot(ploty)
plotx = xcenter - yy
plot(ploty)
yy++
if decisionOver2<=0
decisionOver2 += 2*yy+1
else {
xx--
decisionOver2 += 2*(yy-xx)+1
}
}
}
sub disc(uword cx, ubyte cy, ubyte radius) {
; Midpoint algorithm, filled
ubyte xx = radius
ubyte yy = 0
byte decisionOver2 = 1-xx
while xx>=yy {
for plotx in cx to cx+xx {
plot(cy + yy)
plot(cy - yy)
}
for plotx in cx-xx to cx-1 {
plot(cy + yy)
plot(cy - yy)
}
for plotx in cx to cx+yy {
plot(cy + xx)
plot(cy - xx)
}
for plotx in cx-yy to cx {
plot(cy + xx)
plot(cy - xx)
}
yy++
if decisionOver2<=0
decisionOver2 += 2*yy+1
else {
xx--
decisionOver2 += 2*(yy-xx)+1
}
}
}
; here is the non-asm code for the plot routine below:
; sub plot_nonasm(uword px, ubyte py) {
; ubyte[] ormask = [128, 64, 32, 16, 8, 4, 2, 1]
; uword addr = bitmap_address + 320*(py>>3) + (py & 7) + (px & %0000000111111000)
; @(addr) |= ormask[lsb(px) & 7]
; }
uword plotx ; 0..319
asmsub plot(ubyte ploty @A) { ; plotx is 16 bits 0 to 319... doesn't fit in a register
%asm {{
tay
stx c64.SCRATCH_ZPREGX
lda plotx+1
sta c64.SCRATCH_ZPWORD2+1
lsr a ; 0
sta c64.SCRATCH_ZPWORD2
lda plotx
pha
and #7
tax
lda _y_lookup_lo,y
clc
adc c64.SCRATCH_ZPWORD2
sta c64.SCRATCH_ZPWORD2
lda _y_lookup_hi,y
adc c64.SCRATCH_ZPWORD2+1
sta c64.SCRATCH_ZPWORD2+1
pla ; plotx
and #%11111000
tay
lda (c64.SCRATCH_ZPWORD2),y
ora _ormask,x
sta (c64.SCRATCH_ZPWORD2),y
ldx c64.SCRATCH_ZPREGX
rts
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
; note: this can be even faster if we also have a 256 byte x-lookup table, but hey.
; see http://codebase64.org/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
; the y lookup tables encode this formula: bitmap_address + 320*(py>>3) + (py & 7) (y from 0..199)
_y_lookup_hi
.byte $20, $20, $20, $20, $20, $20, $20, $20, $21, $21, $21, $21, $21, $21, $21, $21
.byte $22, $22, $22, $22, $22, $22, $22, $22, $23, $23, $23, $23, $23, $23, $23, $23
.byte $25, $25, $25, $25, $25, $25, $25, $25, $26, $26, $26, $26, $26, $26, $26, $26
.byte $27, $27, $27, $27, $27, $27, $27, $27, $28, $28, $28, $28, $28, $28, $28, $28
.byte $2a, $2a, $2a, $2a, $2a, $2a, $2a, $2a, $2b, $2b, $2b, $2b, $2b, $2b, $2b, $2b
.byte $2c, $2c, $2c, $2c, $2c, $2c, $2c, $2c, $2d, $2d, $2d, $2d, $2d, $2d, $2d, $2d
.byte $2f, $2f, $2f, $2f, $2f, $2f, $2f, $2f, $30, $30, $30, $30, $30, $30, $30, $30
.byte $31, $31, $31, $31, $31, $31, $31, $31, $32, $32, $32, $32, $32, $32, $32, $32
.byte $34, $34, $34, $34, $34, $34, $34, $34, $35, $35, $35, $35, $35, $35, $35, $35
.byte $36, $36, $36, $36, $36, $36, $36, $36, $37, $37, $37, $37, $37, $37, $37, $37
.byte $39, $39, $39, $39, $39, $39, $39, $39, $3a, $3a, $3a, $3a, $3a, $3a, $3a, $3a
.byte $3b, $3b, $3b, $3b, $3b, $3b, $3b, $3b, $3c, $3c, $3c, $3c, $3c, $3c, $3c, $3c
.byte $3e, $3e, $3e, $3e, $3e, $3e, $3e, $3e
_y_lookup_lo
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07, $40, $41, $42, $43, $44, $45, $46, $47
.byte $80, $81, $82, $83, $84, $85, $86, $87, $c0, $c1, $c2, $c3, $c4, $c5, $c6, $c7
.byte $00, $01, $02, $03, $04, $05, $06, $07
}}
}
}