2020-03-24 23:32:54 +00:00
|
|
|
%import c64lib
|
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
; bitmap pixel graphics module for the C64
|
|
|
|
; only black/white monchrome for now
|
2020-03-24 23:32:54 +00:00
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
; 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.
|
2020-03-24 23:32:54 +00:00
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
graphics {
|
2020-03-24 23:32:54 +00:00
|
|
|
const uword bitmap_address = $2000
|
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
sub enable_bitmap_mode() {
|
2020-03-24 23:32:54 +00:00
|
|
|
; 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)
|
2020-03-28 11:33:16 +00:00
|
|
|
c64scr.clear_screen($10, 0) ; pixel color $1 (white) backround $0 (black)
|
2020-03-24 23:32:54 +00:00
|
|
|
}
|
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
sub line(uword x1, ubyte y1, uword x2, ubyte y2) {
|
|
|
|
; Bresenham algorithm
|
2020-06-02 19:27:38 +00:00
|
|
|
; This code is a bit long because each of the 8 different octants has a dedicated loop.
|
|
|
|
; This minimizes the number of actual math operations, and allows usins simple ++ and -- operations.
|
|
|
|
; TODO sort X/Y coordinates to eliminate some of the special cases
|
|
|
|
word d = 0
|
|
|
|
ubyte positive_ix = true
|
|
|
|
ubyte positive_iy = true
|
|
|
|
word dx = x2 - x1 as word
|
|
|
|
word dy = y2 as word - y1 as word
|
|
|
|
if dx < 0 {
|
|
|
|
dx = -dx
|
|
|
|
positive_ix = false
|
2020-03-24 23:32:54 +00:00
|
|
|
}
|
2020-06-02 19:27:38 +00:00
|
|
|
if dy < 0 {
|
|
|
|
dy = -dy
|
|
|
|
positive_iy = false
|
2020-03-24 23:32:54 +00:00
|
|
|
}
|
2020-06-02 19:27:38 +00:00
|
|
|
dx *= 2
|
|
|
|
dy *= 2
|
2020-03-27 22:45:01 +00:00
|
|
|
plotx = x1
|
2020-03-26 22:33:55 +00:00
|
|
|
|
|
|
|
if dx >= dy {
|
2020-06-02 19:27:38 +00:00
|
|
|
if positive_ix {
|
|
|
|
if positive_iy {
|
|
|
|
forever {
|
|
|
|
graphics.plot(y1)
|
|
|
|
if plotx==x2
|
|
|
|
return
|
|
|
|
plotx++
|
|
|
|
d += dy
|
|
|
|
if d > dx {
|
|
|
|
y1++
|
|
|
|
d -= dx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
forever {
|
|
|
|
graphics.plot(y1)
|
|
|
|
if plotx==x2
|
|
|
|
return
|
|
|
|
plotx++
|
|
|
|
d += dy
|
|
|
|
if d > dx {
|
|
|
|
y1--
|
|
|
|
d -= dx
|
|
|
|
}
|
2020-03-28 11:33:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-06-02 19:27:38 +00:00
|
|
|
if positive_iy {
|
|
|
|
forever {
|
|
|
|
graphics.plot(y1)
|
|
|
|
if plotx==x2
|
|
|
|
return
|
|
|
|
plotx--
|
|
|
|
d += dy
|
|
|
|
if d > dx {
|
|
|
|
y1++
|
|
|
|
d -= dx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
forever {
|
|
|
|
graphics.plot(y1)
|
|
|
|
if plotx==x2
|
|
|
|
return
|
|
|
|
plotx--
|
|
|
|
d += dy
|
|
|
|
if d > dx {
|
|
|
|
y1--
|
|
|
|
d -= dx
|
|
|
|
}
|
2020-03-28 11:33:16 +00:00
|
|
|
}
|
2020-03-26 22:33:55 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-02 19:27:38 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if positive_iy {
|
|
|
|
if positive_ix {
|
|
|
|
forever {
|
|
|
|
plot(y1)
|
|
|
|
if y1 == y2
|
|
|
|
return
|
|
|
|
y1++
|
|
|
|
d += dx
|
|
|
|
if d > dy {
|
|
|
|
plotx++
|
|
|
|
d -= dy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
forever {
|
|
|
|
plot(y1)
|
|
|
|
if y1 == y2
|
|
|
|
return
|
|
|
|
y1++
|
|
|
|
d += dx
|
|
|
|
if d > dy {
|
|
|
|
plotx--
|
|
|
|
d -= dy
|
|
|
|
}
|
2020-03-28 11:33:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-06-02 19:27:38 +00:00
|
|
|
if positive_ix {
|
|
|
|
forever {
|
|
|
|
plot(y1)
|
|
|
|
if y1 == y2
|
|
|
|
return
|
|
|
|
y1--
|
|
|
|
d += dx
|
|
|
|
if d > dy {
|
|
|
|
plotx++
|
|
|
|
d -= dy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
forever {
|
|
|
|
plot(y1)
|
|
|
|
if y1 == y2
|
|
|
|
return
|
|
|
|
y1--
|
|
|
|
d += dx
|
|
|
|
if d > dy {
|
|
|
|
plotx--
|
|
|
|
d -= dy
|
|
|
|
}
|
2020-03-28 11:33:16 +00:00
|
|
|
}
|
2020-03-26 22:33:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-24 23:32:54 +00:00
|
|
|
|
2020-03-26 22:33:55 +00:00
|
|
|
sub circle(uword xcenter, ubyte ycenter, ubyte radius) {
|
2020-03-24 23:32:54 +00:00
|
|
|
; Midpoint algorithm
|
2020-03-27 22:45:01 +00:00
|
|
|
ubyte ploty
|
|
|
|
ubyte xx = radius
|
|
|
|
ubyte yy = 0
|
2020-06-02 19:27:38 +00:00
|
|
|
byte decisionOver2 = 1-xx as byte
|
2020-03-27 22:45:01 +00:00
|
|
|
|
|
|
|
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++
|
2020-03-24 23:32:54 +00:00
|
|
|
if decisionOver2<=0
|
2020-03-27 22:45:01 +00:00
|
|
|
decisionOver2 += 2*yy+1
|
2020-03-24 23:32:54 +00:00
|
|
|
else {
|
2020-03-27 22:45:01 +00:00
|
|
|
xx--
|
|
|
|
decisionOver2 += 2*(yy-xx)+1
|
2020-03-24 23:32:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 22:33:55 +00:00
|
|
|
sub disc(uword cx, ubyte cy, ubyte radius) {
|
2020-03-26 22:18:51 +00:00
|
|
|
; Midpoint algorithm, filled
|
2020-03-27 22:45:01 +00:00
|
|
|
ubyte xx = radius
|
|
|
|
ubyte yy = 0
|
2020-06-02 19:27:38 +00:00
|
|
|
byte decisionOver2 = 1-xx as byte
|
2020-03-27 22:45:01 +00:00
|
|
|
|
|
|
|
while xx>=yy {
|
2020-04-08 01:38:22 +00:00
|
|
|
ubyte cy_plus_yy = cy + yy
|
|
|
|
ubyte cy_min_yy = cy - yy
|
|
|
|
ubyte cy_plus_xx = cy + xx
|
|
|
|
ubyte cy_min_xx = cy - xx
|
|
|
|
|
2020-03-27 22:45:01 +00:00
|
|
|
for plotx in cx to cx+xx {
|
2020-04-08 01:38:22 +00:00
|
|
|
plot(cy_plus_yy)
|
|
|
|
plot(cy_min_yy)
|
2020-03-26 22:18:51 +00:00
|
|
|
}
|
2020-03-27 22:45:01 +00:00
|
|
|
for plotx in cx-xx to cx-1 {
|
2020-04-08 01:38:22 +00:00
|
|
|
plot(cy_plus_yy)
|
|
|
|
plot(cy_min_yy)
|
2020-03-26 22:18:51 +00:00
|
|
|
}
|
2020-03-27 22:45:01 +00:00
|
|
|
for plotx in cx to cx+yy {
|
2020-04-08 01:38:22 +00:00
|
|
|
plot(cy_plus_xx)
|
|
|
|
plot(cy_min_xx)
|
2020-03-26 22:18:51 +00:00
|
|
|
}
|
2020-03-27 22:45:01 +00:00
|
|
|
for plotx in cx-yy to cx {
|
2020-04-08 01:38:22 +00:00
|
|
|
plot(cy_plus_xx)
|
|
|
|
plot(cy_min_xx)
|
2020-03-26 22:18:51 +00:00
|
|
|
}
|
2020-03-27 22:45:01 +00:00
|
|
|
yy++
|
2020-03-26 22:18:51 +00:00
|
|
|
if decisionOver2<=0
|
2020-03-27 22:45:01 +00:00
|
|
|
decisionOver2 += 2*yy+1
|
2020-03-26 22:18:51 +00:00
|
|
|
else {
|
2020-03-27 22:45:01 +00:00
|
|
|
xx--
|
|
|
|
decisionOver2 += 2*(yy-xx)+1
|
2020-03-26 22:18:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-24 23:32:54 +00:00
|
|
|
|
2020-03-27 22:45:01 +00:00
|
|
|
|
2020-03-28 11:33:16 +00:00
|
|
|
; 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]
|
|
|
|
; }
|
|
|
|
|
2020-06-02 19:27:38 +00:00
|
|
|
uword plotx ; 0..319 ; separate 'parameter' for plot()
|
2020-03-27 22:45:01 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}}
|
2020-03-24 23:32:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|