mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
269 lines
7.7 KiB
Lua
269 lines
7.7 KiB
Lua
; optimized graphics routines for just the single screen mode: lores 320*240, 256c (8bpp)
|
|
; bitmap image needs to start at VRAM addres $00000.
|
|
; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
|
|
|
|
%import verafx
|
|
|
|
|
|
gfx_lores {
|
|
|
|
%option ignore_unused
|
|
|
|
sub set_screen_mode() {
|
|
cx16.VERA_CTRL=0
|
|
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
|
|
cx16.VERA_DC_HSCALE = 64
|
|
cx16.VERA_DC_VSCALE = 64
|
|
cx16.VERA_L1_CONFIG = %00000111
|
|
cx16.VERA_L1_MAPBASE = 0
|
|
cx16.VERA_L1_TILEBASE = 0
|
|
clear_screen(0)
|
|
}
|
|
|
|
sub clear_screen(ubyte color) {
|
|
if verafx.available() {
|
|
; use verafx cache writes to quicly clear the screen
|
|
const ubyte vbank = 0
|
|
const uword vaddr = 0
|
|
cx16.VERA_CTRL = 0
|
|
cx16.VERA_ADDR_H = vbank | %00110000 ; 4-byte increment
|
|
cx16.VERA_ADDR_M = msb(vaddr)
|
|
cx16.VERA_ADDR_L = lsb(vaddr)
|
|
cx16.VERA_CTRL = 6<<1 ; dcsel = 6, fill the 32 bits cache
|
|
cx16.VERA_FX_CACHE_L = color
|
|
cx16.VERA_FX_CACHE_M = color
|
|
cx16.VERA_FX_CACHE_H = color
|
|
cx16.VERA_FX_CACHE_U = color
|
|
cx16.VERA_CTRL = 2<<1 ; dcsel = 2
|
|
cx16.VERA_FX_MULT = 0
|
|
cx16.VERA_FX_CTRL = %01000000 ; cache write enable
|
|
repeat 320/4/4 {
|
|
%asm {{
|
|
ldy #240
|
|
- stz cx16.VERA_DATA0
|
|
stz cx16.VERA_DATA0
|
|
stz cx16.VERA_DATA0
|
|
stz cx16.VERA_DATA0
|
|
dey
|
|
bne -
|
|
}}
|
|
}
|
|
cx16.VERA_FX_CTRL = 0 ; cache write disable
|
|
cx16.VERA_CTRL = 0
|
|
return
|
|
}
|
|
; fallback to cpu clear
|
|
cx16.VERA_CTRL=0
|
|
cx16.VERA_ADDR=0
|
|
cx16.VERA_ADDR_H = 1<<4 ; 1 pixel auto increment
|
|
repeat 240 {
|
|
%asm {{
|
|
lda p8v_color
|
|
ldy #320/8
|
|
- .rept 8
|
|
sta cx16.VERA_DATA0
|
|
.endrept
|
|
dey
|
|
bne -
|
|
}}
|
|
}
|
|
cx16.VERA_ADDR=0
|
|
cx16.VERA_ADDR_H = 0
|
|
}
|
|
|
|
asmsub plot(uword x @AX, ubyte y @Y, ubyte color @R0) {
|
|
; x in r0, y in r1, color.
|
|
%asm {{
|
|
clc
|
|
adc times320_lo,y
|
|
sta cx16.VERA_ADDR_L
|
|
txa
|
|
adc times320_mid,y
|
|
sta cx16.VERA_ADDR_M
|
|
lda #0
|
|
adc times320_hi,y
|
|
sta cx16.VERA_ADDR_H
|
|
lda cx16.r0L
|
|
sta cx16.VERA_DATA0
|
|
rts
|
|
}}
|
|
}
|
|
|
|
sub line(uword x1, ubyte y1, uword x2, ubyte y2, ubyte color) {
|
|
; Bresenham algorithm.
|
|
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
|
|
; NOTE: this is about twice as fast as the kernal routine GRAPH_draw_line, and ~3-4 times as fast as gfx2.line()
|
|
; it trades memory for speed (uses inline plot routine and multiplication lookup tables)
|
|
;
|
|
; NOTE: is currently still a regular 6502 routine, could likely be made much faster with the VeraFX line helper.
|
|
|
|
cx16.r3L = y2 ; ensure zeropage
|
|
cx16.r1L = y1 ; ensure zeropage
|
|
|
|
if cx16.r1L > cx16.r3L {
|
|
; make sure dy is always positive to have only 4 instead of 8 special cases
|
|
cx16.r0 = x1
|
|
x1 = x2
|
|
x2 = cx16.r0
|
|
cx16.r0L = cx16.r1L
|
|
cx16.r1L = cx16.r3L
|
|
cx16.r3L = cx16.r0L
|
|
}
|
|
word @zp dx = x2 as word
|
|
word @zp dy = cx16.r3L
|
|
dx -= x1
|
|
dy -= cx16.r1L
|
|
|
|
if dx==0 {
|
|
vertical_line(x1, cx16.r1L, lsb(dy)+1, color)
|
|
return
|
|
}
|
|
if dy==0 {
|
|
if x1>x2
|
|
x1=x2
|
|
horizontal_line(x1, cx16.r1L, abs(dx) as uword +1, color)
|
|
return
|
|
}
|
|
|
|
word @zp d = 0
|
|
bool positive_ix = true
|
|
if dx < 0 {
|
|
dx = -dx
|
|
positive_ix = false
|
|
}
|
|
word @zp dx2 = dx*2
|
|
word @zp dy2 = dy*2
|
|
|
|
cx16.r0 = x1 ; ensure zeropage
|
|
cx16.r2 = x2 ; ensure zeropage
|
|
|
|
cx16.VERA_CTRL = 0
|
|
if dx >= dy {
|
|
if positive_ix {
|
|
repeat {
|
|
plot()
|
|
if cx16.r0==cx16.r2
|
|
return
|
|
cx16.r0++
|
|
d += dy2
|
|
if d > dx {
|
|
cx16.r1L++
|
|
d -= dx2
|
|
}
|
|
}
|
|
} else {
|
|
repeat {
|
|
plot()
|
|
if cx16.r0==cx16.r2
|
|
return
|
|
cx16.r0--
|
|
d += dy2
|
|
if d > dx {
|
|
cx16.r1L++
|
|
d -= dx2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if positive_ix {
|
|
repeat {
|
|
plot()
|
|
if cx16.r1L == cx16.r3L
|
|
return
|
|
cx16.r1L++
|
|
d += dx2
|
|
if d > dy {
|
|
cx16.r0++
|
|
d -= dy2
|
|
}
|
|
}
|
|
} else {
|
|
repeat {
|
|
plot()
|
|
if cx16.r1L == cx16.r3L
|
|
return
|
|
cx16.r1L++
|
|
d += dx2
|
|
if d > dy {
|
|
cx16.r0--
|
|
d -= dy2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
asmsub plot() {
|
|
; internal plot routine for the line algorithm: x in r0, y in r1, color in variable.
|
|
%asm {{
|
|
ldy cx16.r1L
|
|
clc
|
|
lda times320_lo,y
|
|
adc cx16.r0L
|
|
sta cx16.VERA_ADDR_L
|
|
lda times320_mid,y
|
|
adc cx16.r0H
|
|
sta cx16.VERA_ADDR_M
|
|
lda #0
|
|
adc times320_hi,y
|
|
sta cx16.VERA_ADDR_H
|
|
lda p8v_color
|
|
sta cx16.VERA_DATA0
|
|
rts
|
|
}}
|
|
}
|
|
}
|
|
|
|
sub horizontal_line(uword xx, ubyte yy, uword length, ubyte color) {
|
|
if length==0
|
|
return
|
|
plot(xx, yy, color) ; set starting position by reusing plot routine
|
|
; set vera auto-increment to 1 pixel
|
|
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | (1<<4)
|
|
|
|
%asm {{
|
|
lda p8v_color
|
|
ldx p8v_length+1
|
|
beq +
|
|
ldy #0
|
|
- sta cx16.VERA_DATA0
|
|
iny
|
|
bne -
|
|
dex
|
|
bne -
|
|
+ ldy p8v_length ; remaining
|
|
beq +
|
|
- sta cx16.VERA_DATA0
|
|
dey
|
|
bne -
|
|
+
|
|
}}
|
|
}
|
|
|
|
sub vertical_line(uword xx, ubyte yy, ubyte lheight, ubyte color) {
|
|
if lheight==0
|
|
return
|
|
plot(xx, yy, color) ; set starting position by reusing plot routine
|
|
; set vera auto-increment to 320 pixel increment (=next line)
|
|
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | (14<<4)
|
|
%asm {{
|
|
ldy p8v_lheight
|
|
lda p8v_color
|
|
- sta cx16.VERA_DATA0
|
|
dey
|
|
bne -
|
|
}}
|
|
}
|
|
|
|
|
|
%asm {{
|
|
; multiplication by 320 lookup table
|
|
times320 := 320*range(240)
|
|
|
|
times320_lo .byte <times320
|
|
times320_mid .byte >times320
|
|
times320_hi .byte `times320
|
|
}}
|
|
}
|
|
|