added doublebuffering to monogfx (in both lores and hires mode)

This commit is contained in:
Irmen de Jong
2025-05-21 21:28:30 +02:00
parent 322fa7ea69
commit 548e421e27
5 changed files with 125 additions and 78 deletions

View File

@@ -22,18 +22,23 @@ monogfx {
const ubyte MODE_STIPPLE = %00000001
const ubyte MODE_INVERT = %00000010
uword buffer_visible, buffer_back
sub lores() {
; enable 320*240 bitmap mode
buffer_visible = buffer_back = $0000
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 = %00000100
cx16.VERA_L1_MAPBASE = 0
cx16.VERA_L1_TILEBASE = 0
cx16.VERA_L1_TILEBASE = 0 ; lores
width = 320
height = 240
lores_mode = true
buffer_visible = buffer_back = $0000
mode = MODE_NORMAL
clear_screen(false)
}
@@ -46,14 +51,40 @@ monogfx {
cx16.VERA_DC_VSCALE = 128
cx16.VERA_L1_CONFIG = %00000100
cx16.VERA_L1_MAPBASE = 0
cx16.VERA_L1_TILEBASE = %00000001
cx16.VERA_L1_TILEBASE = %00000001 ; hires
width = 640
height = 480
lores_mode = false
buffer_visible = buffer_back = $0000
mode = MODE_NORMAL
clear_screen(false)
}
sub enable_doublebuffer() {
; enable double buffering mode
if lores_mode {
buffer_visible = $0000
buffer_back = $2800
} else {
buffer_visible = $0000
buffer_back = $9800
}
}
sub swap_buffers(bool wait_for_vsync) {
; flip the buffers: make the back buffer visible and the other one now the backbuffer.
; to avoid any screen tearing it is advised to call this during the vertical blank (pass true)
if wait_for_vsync
sys.waitvsync()
cx16.r0 = buffer_back
buffer_back = buffer_visible
buffer_visible = cx16.r0
cx16.VERA_CTRL = 0
cx16.r0 &= %1111110000000000
cx16.VERA_L1_TILEBASE = cx16.VERA_L1_TILEBASE & 1 | (cx16.r0H >>1 )
}
sub textmode() {
; back to normal text mode
cx16.r15L = cx16.VERA_DC_VIDEO & %00000111 ; retain chroma + output mode
@@ -559,6 +590,7 @@ drawmode: ora cx16.r15L
sub disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, bool draw) {
; Warning: NO BOUNDS CHECKS. Make sure circle fits in the screen.
; Midpoint algorithm, filled
; Note: has problems with INVERT draw mode because of horizontal span overdrawing. Horizontal lines may occur.
if radius==0
return
ubyte @zp yy = 0
@@ -597,6 +629,7 @@ drawmode: ora cx16.r15L
sub safe_disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, bool draw) {
; Does bounds checking and clipping.
; Midpoint algorithm, filled
; Note: has problems with INVERT draw mode because of horizontal span overdrawing. Horizontal lines may occur.
if radius==0
return
ubyte @zp yy = 0
@@ -696,7 +729,7 @@ invert:
adc p8v_times40_lsb,y
sta cx16.VERA_ADDR_L
lda p8v_times40_msb,y
adc #0
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda p8v_xx
@@ -708,7 +741,6 @@ invert:
; width=640 (hires)
%asm {{
stz cx16.VERA_CTRL
stz cx16.VERA_ADDR_H
lda p8v_xx
and #7
pha ; xbits
@@ -723,10 +755,15 @@ invert:
;xx /= 8
xx += yy*(640/8)
%asm {{
lda p8v_xx+1
sta cx16.VERA_ADDR_M
lda p8v_xx
sta cx16.VERA_ADDR_L
lda p8v_xx+1
clc
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda #0
rol a ; hi bit carry also needed when double-buffering
sta cx16.VERA_ADDR_H
plx ; xbits
lda p8v_maskbits,x
}}
@@ -768,11 +805,15 @@ invert:
%asm {{
stz cx16.VERA_CTRL
stz cx16.VERA_ADDR_H
lda p8v_xx+1
sta cx16.VERA_ADDR_M
lda p8v_xx
sta cx16.VERA_ADDR_L
lda p8v_xx+1
clc
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda #0
rol a ; hi bit carry also needed when double-buffering
sta cx16.VERA_ADDR_H
ply ; xbits
lda p8s_plot.p8v_maskbits,y
and cx16.VERA_DATA0
@@ -855,8 +896,8 @@ skip:
}
sub fill_scanline_right() {
; TODO maybe this could use vera auto increment, but that requires some clever masking calculations
cx16.r9s = xx
; TODO maybe this could use vera auto increment, but that requires some clever masking calculations
cx16.r9s = xx
while xx <= width-1 {
if pgetset()
break
@@ -891,11 +932,15 @@ skip:
%asm {{
stz cx16.VERA_CTRL
stz cx16.VERA_ADDR_H
lda p8v_xpos+1
sta cx16.VERA_ADDR_M
lda p8v_xpos
sta cx16.VERA_ADDR_L
lda p8v_xpos+1
clc
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda #0
rol a ; hi bit carry also needed when double-buffering
sta cx16.VERA_ADDR_H
ply ; xbits
lda p8s_plot.p8v_maskbits,y
and cx16.VERA_DATA0
@@ -942,12 +987,12 @@ _doplot beq +
ror a
lsr a
lsr a
clc
ldy p8v_yy
clc
adc p8v_times40_lsb,y
sta cx16.VERA_ADDR_L
lda p8v_times40_msb,y
adc #0
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda #%00010000 ; autoincr
sta cx16.VERA_ADDR_H
@@ -975,8 +1020,11 @@ _doplot beq +
lda cx16.r0L
sta cx16.VERA_ADDR_L
lda cx16.r0H
clc
adc p8v_buffer_back+1
sta cx16.VERA_ADDR_M
lda #%00010000 ; autoincr
lda #%00001000 ; autoincr (1 bit shifted)
rol a ; hi bit carry also needed when double-buffering
sta cx16.VERA_ADDR_H
}}
}
@@ -1146,15 +1194,11 @@ cdraw_mod2 ora cx16.VERA_DATA1
cmp #0
beq +
lda #255
+ ldy #80
- sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
sta cx16.VERA_DATA0
+ ldy #40
-
.rept 16
sta cx16.VERA_DATA0
.endrept
dey
bne -
rts

View File

@@ -816,6 +816,7 @@ Full-screen lores or hires monochrome bitmap graphics routines, available on the
- two resolutions: lores 320*240 or hires 640*480 bitmap mode
- optimized routines for monochrome (2-color) graphics
- clearing screen, switching screen mode, also back to text mode
- doublebuffering option to avoid flicker
- drawing and reading individual pixels
- drawing lines, rectangles, filled rectangles, circles, discs
- flood fill
@@ -823,7 +824,7 @@ Full-screen lores or hires monochrome bitmap graphics routines, available on the
- can draw using a stipple pattern (alternate black/white pixels) and in invert mode (toggle pixels)
Read the `monogfx source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/monogfx.p8>`_
to see what's in there.
and the `testmonogfx` example program, to see what's in there.
palette (cx16 only)

View File

@@ -1,6 +1,9 @@
TODO
====
Bug: monogfx circle, plot and line drawing with INVERT mode is broken (garbage pixels)
STRUCTS: are being developed in their own separate branch for now, called "structs".
Idea is to make it feature complete in the IR/Virtual target, then merge it to master?, and then start building the 6502 code generation for it.

View File

@@ -1,6 +1,6 @@
%import monogfx
%import textio
%import math
%import conv
%option no_sysinit
%zeropage basicsafe
@@ -18,8 +18,7 @@ main {
sys.wait(2*60)
demo2()
monogfx.textmode()
txt.print("done!\n")
doublebuffer.demo()
}
sub demofill() {
@@ -214,3 +213,40 @@ main {
}
}
doublebuffer {
sub demo() {
monogfx.lores()
monogfx.text_charset(1)
monogfx.enable_doublebuffer()
uword cx = 100
repeat {
monogfx.clear_screen(false)
monogfx.text(50, 10, true, iso:"Double Buffered")
monogfx.circle(160, 120, 100, true)
monogfx.disc(160, 120, 40, true)
monogfx.rect(40, 40, 240, 180, true)
monogfx.drawmode(monogfx.MODE_STIPPLE)
monogfx.fill(50, 50, true, 1)
monogfx.drawmode(monogfx.MODE_NORMAL)
monogfx.fill(250, 50, true, 1)
monogfx.fillrect( 10, 50, 20, 100, true)
monogfx.line(10, 10, 300, 200, true)
repeat 200 {
monogfx.plot($00e0 + math.randrange(64), 20 + math.randrange(20), true)
}
monogfx.circle(cx, 219, 20, true)
monogfx.text(cx+20, 225, true, conv.str_uw(cx))
cx++
monogfx.swap_buffers()
}
}
}

View File

@@ -1,58 +1,21 @@
%import textio
%zeropage basicsafe
%import math
%import monogfx
main {
sub start() {
word w1, w2, w3, w4
uword uw1, uw2, uw3
monogfx.hires()
monogfx.fillrect(100, 100, 200, 100, true)
w1 = -111
w2 = 222
w3 = -333
w4 = -20
sys.wait(60)
uw1 = 111
uw2 = 222
uw3 = 333
monogfx.drawmode(monogfx.MODE_INVERT)
monogfx.circle(150, 120, 80, true) ; TODO INVERT is BROKEN
monogfx.line(10, 20, 250, 160, true) ; TODO INVERT is BROKEN
txt.print_w(w2*w3)
txt.spc()
w1 = w2 * w3
txt.print_w(w1)
txt.nl()
txt.print_w(w3*w4)
txt.nl()
repeat 500 {
monogfx.plot( math.rnd(), math.rnd(), true) ; TODO INVERT is BROKEN
}
txt.print_uw(uw2*uw3)
txt.spc()
uw1 = uw2 * uw3
txt.print_uw(uw1)
txt.nl()
txt.nl()
w1 = -111
w2 = 22222
w3 = -333
w4 = -17
uw1 = 111
uw2 = 22222
uw3 = 333
txt.print_w(w2/w3)
txt.spc()
w1 = w2 / w3
txt.print_w(w1)
txt.nl()
txt.print_w(w3/w4)
txt.nl()
txt.print_uw(uw2/uw3)
txt.spc()
uw1 = uw2 / uw3
txt.print_uw(uw1)
txt.nl()
repeat {}
}
}