mirror of
https://github.com/irmen/prog8.git
synced 2024-12-27 05:29:38 +00:00
cx16: added monogfx library module, replaces gfx2 for monochrome screenmodes.
This commit is contained in:
parent
989a5a2f8a
commit
6395d1908e
@ -29,7 +29,7 @@ gfx2 {
|
||||
uword width = 0
|
||||
uword height = 0
|
||||
ubyte bpp = 0
|
||||
bool monochrome_dont_stipple_flag = false ; set to false to enable stippling mode in monochrome displaymodes
|
||||
bool monochrome_dont_stipple_flag = true ; set to false to enable stippling mode in monochrome displaymodes
|
||||
|
||||
sub screen_mode(ubyte mode) {
|
||||
cx16.VERA_CTRL=0
|
||||
|
@ -5,7 +5,7 @@
|
||||
; Wraps the graphics functions that are in ROM.
|
||||
; Only lo-res 320x240 256 color mode for now.
|
||||
; Unlike graphics module on the C64, you can use colors() to set new drawing colors for every draw operation.
|
||||
; For other resolutions or other color modes, use the "gfx2" module instead. (which is Cx16-specific)
|
||||
; For other resolutions or other color modes, use the "gfx2" or "monogfx" module instead. (which is Cx16-specific)
|
||||
; Note: there is no color palette manipulation here, you have to do that yourself or use the "palette" module.
|
||||
|
||||
|
||||
|
727
compiler/res/prog8lib/cx16/monogfx.p8
Normal file
727
compiler/res/prog8lib/cx16/monogfx.p8
Normal file
@ -0,0 +1,727 @@
|
||||
; Monochrome Bitmap pixel graphics routines for the CommanderX16
|
||||
; Using the full-screen 640x480 and 320x240 screen modes, in 1 bpp mode (black/white).
|
||||
;
|
||||
; No text layer is currently shown, but text can be drawn as part of the bitmap itself.
|
||||
; For color bitmap graphics, see the gfx2 library.
|
||||
;
|
||||
; NOTE: a lot of the code here is similar or the same to that in gfx2
|
||||
|
||||
monogfx {
|
||||
|
||||
%option no_symbol_prefixing
|
||||
|
||||
; read-only control variables:
|
||||
uword width = 0
|
||||
uword height = 0
|
||||
bool dont_stipple_flag = true ; set to false to enable stippling mode
|
||||
|
||||
sub lores() {
|
||||
; enable 320*240 bitmap 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 = %00000100
|
||||
cx16.VERA_L1_MAPBASE = 0
|
||||
cx16.VERA_L1_TILEBASE = 0
|
||||
width = 320
|
||||
height = 240
|
||||
clear_screen()
|
||||
}
|
||||
|
||||
sub hires() {
|
||||
; enable 640*480 bitmap mode
|
||||
cx16.VERA_CTRL=0
|
||||
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
|
||||
cx16.VERA_DC_HSCALE = 128
|
||||
cx16.VERA_DC_VSCALE = 128
|
||||
cx16.VERA_L1_CONFIG = %00000100
|
||||
cx16.VERA_L1_MAPBASE = 0
|
||||
cx16.VERA_L1_TILEBASE = %00000001
|
||||
width = 640
|
||||
height = 480
|
||||
clear_screen()
|
||||
}
|
||||
|
||||
sub textmode() {
|
||||
; back to normal text mode
|
||||
cx16.r15L = cx16.VERA_DC_VIDEO & %00000111 ; retain chroma + output mode
|
||||
cbm.CINT()
|
||||
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11111000) | cx16.r15L
|
||||
}
|
||||
|
||||
sub clear_screen() {
|
||||
stipple(false)
|
||||
position(0, 0)
|
||||
when width {
|
||||
320 -> {
|
||||
repeat 240/2/8
|
||||
cs_innerloop640()
|
||||
}
|
||||
640 -> {
|
||||
repeat 480/8
|
||||
cs_innerloop640()
|
||||
}
|
||||
}
|
||||
position(0, 0)
|
||||
}
|
||||
|
||||
sub stipple(bool enable) {
|
||||
dont_stipple_flag = not enable
|
||||
}
|
||||
|
||||
sub rect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
||||
if rwidth==0 or rheight==0
|
||||
return
|
||||
horizontal_line(xx, yy, rwidth, draw)
|
||||
if rheight==1
|
||||
return
|
||||
horizontal_line(xx, yy+rheight-1, rwidth, draw)
|
||||
vertical_line(xx, yy+1, rheight-2, draw)
|
||||
if rwidth==1
|
||||
return
|
||||
vertical_line(xx+rwidth-1, yy+1, rheight-2, draw)
|
||||
}
|
||||
|
||||
sub fillrect(uword xx, uword yy, uword rwidth, uword rheight, bool draw) {
|
||||
if rwidth==0
|
||||
return
|
||||
repeat rheight {
|
||||
horizontal_line(xx, yy, rwidth, draw)
|
||||
yy++
|
||||
}
|
||||
}
|
||||
|
||||
sub horizontal_line(uword xx, uword yy, uword length, bool draw) {
|
||||
ubyte[9] masked_starts = [ 0, %00000001, %00000011, %00000111, %00001111, %00011111, %00111111, %01111111, %11111111]
|
||||
ubyte[9] masked_ends = [ 0, %10000000, %11000000, %11100000, %11110000, %11111000, %11111100, %11111110, %11111111]
|
||||
|
||||
if length==0
|
||||
return
|
||||
ubyte separate_pixels = (8-lsb(xx)) & 7
|
||||
if separate_pixels as uword > length
|
||||
separate_pixels = lsb(length)
|
||||
if separate_pixels {
|
||||
if dont_stipple_flag {
|
||||
position(xx,yy)
|
||||
cx16.VERA_ADDR_H &= %00000111 ; vera auto-increment off
|
||||
if draw
|
||||
cx16.VERA_DATA0 |= masked_starts[separate_pixels]
|
||||
else
|
||||
cx16.VERA_DATA0 &= ~masked_starts[separate_pixels]
|
||||
xx += separate_pixels
|
||||
} else {
|
||||
repeat separate_pixels {
|
||||
plot(xx, yy, draw)
|
||||
xx++
|
||||
}
|
||||
}
|
||||
length -= separate_pixels
|
||||
}
|
||||
if length {
|
||||
position(xx, yy)
|
||||
separate_pixels = lsb(length) & 7
|
||||
xx += length & $fff8
|
||||
%asm {{
|
||||
lsr length+1
|
||||
ror length
|
||||
lsr length+1
|
||||
ror length
|
||||
lsr length+1
|
||||
ror length
|
||||
lda draw
|
||||
bne +
|
||||
ldy #0 ; black
|
||||
bra _loop
|
||||
+ lda dont_stipple_flag
|
||||
beq _stipple
|
||||
ldy #255 ; don't stipple
|
||||
bra _loop
|
||||
_stipple lda yy
|
||||
and #1 ; determine stipple pattern to use
|
||||
bne +
|
||||
ldy #%01010101
|
||||
bra _loop
|
||||
+ ldy #%10101010
|
||||
_loop lda length
|
||||
ora length+1
|
||||
beq _done
|
||||
sty cx16.VERA_DATA0
|
||||
lda length
|
||||
bne +
|
||||
dec length+1
|
||||
+ dec length
|
||||
bra _loop
|
||||
_done
|
||||
}}
|
||||
|
||||
if dont_stipple_flag {
|
||||
cx16.VERA_ADDR_H &= %00000111 ; vera auto-increment off
|
||||
if draw
|
||||
cx16.VERA_DATA0 |= masked_ends[separate_pixels]
|
||||
else
|
||||
cx16.VERA_DATA0 &= ~masked_ends[separate_pixels]
|
||||
} else {
|
||||
repeat separate_pixels {
|
||||
plot(xx, yy, draw)
|
||||
xx++
|
||||
}
|
||||
}
|
||||
}
|
||||
cx16.VERA_ADDR_H &= %00000111 ; vera auto-increment off again
|
||||
}
|
||||
|
||||
sub vertical_line(uword xx, uword yy, uword lheight, bool draw) {
|
||||
cx16.r15L = monogfx.plot.maskbits[xx as ubyte & 7] ; bitmask
|
||||
if draw {
|
||||
if dont_stipple_flag {
|
||||
; draw continuous line.
|
||||
position2(xx,yy,true)
|
||||
if width==320
|
||||
set_both_strides(11) ; 40 increment = 1 line in 320 px monochrome
|
||||
else
|
||||
set_both_strides(12) ; 80 increment = 1 line in 640 px monochrome
|
||||
repeat lheight {
|
||||
%asm {{
|
||||
lda cx16.VERA_DATA0
|
||||
ora cx16.r15L
|
||||
sta cx16.VERA_DATA1
|
||||
}}
|
||||
}
|
||||
} else {
|
||||
; draw stippled line.
|
||||
if xx&1 {
|
||||
yy++
|
||||
lheight--
|
||||
}
|
||||
position2(xx,yy,true)
|
||||
if width==320
|
||||
set_both_strides(12) ; 80 increment = 2 line in 320 px monochrome
|
||||
else
|
||||
set_both_strides(13) ; 160 increment = 2 line in 640 px monochrome
|
||||
repeat lheight/2 {
|
||||
%asm {{
|
||||
lda cx16.VERA_DATA0
|
||||
ora cx16.r15L
|
||||
sta cx16.VERA_DATA1
|
||||
}}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
position2(xx,yy,true)
|
||||
cx16.r15 = ~cx16.r15 ; erase pixels
|
||||
if width==320
|
||||
set_both_strides(11) ; 40 increment = 1 line in 320 px monochrome
|
||||
else
|
||||
set_both_strides(12) ; 80 increment = 1 line in 640 px monochrome
|
||||
repeat lheight {
|
||||
%asm {{
|
||||
lda cx16.VERA_DATA0
|
||||
and cx16.r15L
|
||||
sta cx16.VERA_DATA1
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
sub set_both_strides(ubyte stride) {
|
||||
stride <<= 4
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | stride
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | stride
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub line(uword @zp x1, uword @zp y1, uword @zp x2, uword @zp y2, bool draw) {
|
||||
; Bresenham algorithm.
|
||||
; This code special-cases various quadrant loops to allow simple ++ and -- operations.
|
||||
if y1>y2 {
|
||||
; make sure dy is always positive to have only 4 instead of 8 special cases
|
||||
cx16.r0 = x1
|
||||
x1 = x2
|
||||
x2 = cx16.r0
|
||||
cx16.r0 = y1
|
||||
y1 = y2
|
||||
y2 = cx16.r0
|
||||
}
|
||||
word @zp dx = (x2 as word)-x1
|
||||
word @zp dy = (y2 as word)-y1
|
||||
|
||||
if dx==0 {
|
||||
vertical_line(x1, y1, abs(dy) as uword +1, draw)
|
||||
return
|
||||
}
|
||||
if dy==0 {
|
||||
if x1>x2
|
||||
x1=x2
|
||||
horizontal_line(x1, y1, abs(dx) as uword +1, draw)
|
||||
return
|
||||
}
|
||||
|
||||
word @zp d = 0
|
||||
cx16.r1L = true ; 'positive_ix'
|
||||
if dx < 0 {
|
||||
dx = -dx
|
||||
cx16.r1L = false
|
||||
}
|
||||
word @zp dx2 = dx*2
|
||||
word @zp dy2 = dy*2
|
||||
cx16.r14 = x1 ; internal plot X
|
||||
|
||||
if dx >= dy {
|
||||
if cx16.r1L {
|
||||
repeat {
|
||||
plot(cx16.r14, y1, draw)
|
||||
if cx16.r14==x2
|
||||
return
|
||||
cx16.r14++
|
||||
d += dy2
|
||||
if d > dx {
|
||||
y1++
|
||||
d -= dx2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
repeat {
|
||||
plot(cx16.r14, y1, draw)
|
||||
if cx16.r14==x2
|
||||
return
|
||||
cx16.r14--
|
||||
d += dy2
|
||||
if d > dx {
|
||||
y1++
|
||||
d -= dx2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if cx16.r1L {
|
||||
repeat {
|
||||
plot(cx16.r14, y1, draw)
|
||||
if y1 == y2
|
||||
return
|
||||
y1++
|
||||
d += dx2
|
||||
if d > dy {
|
||||
cx16.r14++
|
||||
d -= dy2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
repeat {
|
||||
plot(cx16.r14, y1, draw)
|
||||
if y1 == y2
|
||||
return
|
||||
y1++
|
||||
d += dx2
|
||||
if d > dy {
|
||||
cx16.r14--
|
||||
d -= dy2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub circle(uword @zp xcenter, uword @zp ycenter, ubyte radius, bool draw) {
|
||||
; Midpoint algorithm.
|
||||
if radius==0
|
||||
return
|
||||
|
||||
ubyte @zp xx = radius
|
||||
ubyte @zp yy = 0
|
||||
word @zp decisionOver2 = (1 as word)-xx
|
||||
; R14 = internal plot X
|
||||
; R15 = internal plot Y
|
||||
|
||||
while xx>=yy {
|
||||
cx16.r14 = xcenter + xx
|
||||
cx16.r15 = ycenter + yy
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter - xx
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter + xx
|
||||
cx16.r15 = ycenter - yy
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter - xx
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter + yy
|
||||
cx16.r15 = ycenter + xx
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter - yy
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter + yy
|
||||
cx16.r15 = ycenter - xx
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
cx16.r14 = xcenter - yy
|
||||
plot(cx16.r14, cx16.r15, draw)
|
||||
|
||||
yy++
|
||||
if decisionOver2<=0
|
||||
decisionOver2 += (yy as word)*2+1
|
||||
else {
|
||||
xx--
|
||||
decisionOver2 += (yy as word -xx)*2+1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub disc(uword @zp xcenter, uword @zp ycenter, ubyte @zp radius, bool draw) {
|
||||
; Midpoint algorithm, filled
|
||||
if radius==0
|
||||
return
|
||||
ubyte @zp yy = 0
|
||||
word @zp decisionOver2 = (1 as word)-radius
|
||||
|
||||
while radius>=yy {
|
||||
horizontal_line(xcenter-radius, ycenter+yy, radius*$0002+1, draw)
|
||||
horizontal_line(xcenter-radius, ycenter-yy, radius*$0002+1, draw)
|
||||
horizontal_line(xcenter-yy, ycenter+radius, yy*$0002+1, draw)
|
||||
horizontal_line(xcenter-yy, ycenter-radius, yy*$0002+1, draw)
|
||||
yy++
|
||||
if decisionOver2<=0
|
||||
decisionOver2 += (yy as word)*2+1
|
||||
else {
|
||||
radius--
|
||||
decisionOver2 += (yy as word -radius)*2+1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub plot(uword @zp xx, uword @zp yy, bool @zp draw) {
|
||||
ubyte[8] @shared maskbits = [128, 64, 32, 16, 8, 4, 2, 1]
|
||||
if draw {
|
||||
; solid color or perhaps stipple
|
||||
%asm {{
|
||||
lda xx
|
||||
eor yy
|
||||
ora dont_stipple_flag
|
||||
and #1
|
||||
}}
|
||||
if_nz {
|
||||
prepare()
|
||||
%asm {{
|
||||
tsb cx16.VERA_DATA0
|
||||
}}
|
||||
}
|
||||
} else {
|
||||
; only erase
|
||||
prepare()
|
||||
%asm {{
|
||||
trb cx16.VERA_DATA0
|
||||
}}
|
||||
}
|
||||
|
||||
sub prepare() {
|
||||
%asm {{
|
||||
lda xx
|
||||
and #7
|
||||
pha ; xbits
|
||||
}}
|
||||
xx /= 8
|
||||
if width==320
|
||||
xx += yy*(320/8)
|
||||
else
|
||||
xx += yy*(640/8)
|
||||
%asm {{
|
||||
stz cx16.VERA_CTRL
|
||||
stz cx16.VERA_ADDR_H
|
||||
lda xx+1
|
||||
sta cx16.VERA_ADDR_M
|
||||
lda xx
|
||||
sta cx16.VERA_ADDR_L
|
||||
ply ; xbits
|
||||
lda maskbits,y
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
sub pget(uword @zp xx, uword yy) -> ubyte {
|
||||
%asm {{
|
||||
lda xx
|
||||
and #7
|
||||
pha ; xbits
|
||||
}}
|
||||
xx /= 8
|
||||
if width==320
|
||||
xx += yy*(320/8)
|
||||
else
|
||||
xx += yy*(640/8)
|
||||
|
||||
%asm {{
|
||||
stz cx16.VERA_CTRL
|
||||
stz cx16.VERA_ADDR_H
|
||||
lda xx+1
|
||||
sta cx16.VERA_ADDR_M
|
||||
lda xx
|
||||
sta cx16.VERA_ADDR_L
|
||||
ply ; xbits
|
||||
lda plot.maskbits,y
|
||||
and cx16.VERA_DATA0
|
||||
beq +
|
||||
lda #1
|
||||
+ rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub fill(word @zp xx, word @zp yy, bool draw) {
|
||||
; Non-recursive scanline flood fill.
|
||||
; based loosely on code found here https://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
|
||||
; with the fixes applied to the seedfill_4 routine as mentioned in the comments.
|
||||
const ubyte MAXDEPTH = 48
|
||||
word[MAXDEPTH] @split @shared stack_xl
|
||||
word[MAXDEPTH] @split @shared stack_xr
|
||||
word[MAXDEPTH] @split @shared stack_y
|
||||
byte[MAXDEPTH] @shared stack_dy
|
||||
cx16.r12L = 0 ; stack pointer
|
||||
word x1
|
||||
word x2
|
||||
byte dy
|
||||
cx16.r10L = draw as ubyte
|
||||
sub push_stack(word sxl, word sxr, word sy, byte sdy) {
|
||||
if cx16.r12L==MAXDEPTH
|
||||
return
|
||||
cx16.r0s = sy+sdy
|
||||
if cx16.r0s>=0 and cx16.r0s<=height-1 {
|
||||
;; stack_xl[cx16.r12L] = sxl
|
||||
;; stack_xr[cx16.r12L] = sxr
|
||||
;; stack_y[cx16.r12L] = sy
|
||||
;; stack_dy[cx16.r12L] = sdy
|
||||
;; cx16.r12L++
|
||||
%asm {{
|
||||
ldy cx16.r12L
|
||||
lda sxl
|
||||
sta stack_xl_lsb,y
|
||||
lda sxl+1
|
||||
sta stack_xl_msb,y
|
||||
lda sxr
|
||||
sta stack_xr_lsb,y
|
||||
lda sxr+1
|
||||
sta stack_xr_msb,y
|
||||
lda sy
|
||||
sta stack_y_lsb,y
|
||||
lda sy+1
|
||||
sta stack_y_msb,y
|
||||
ldy cx16.r12L
|
||||
lda sdy
|
||||
sta stack_dy,y
|
||||
inc cx16.r12L
|
||||
}}
|
||||
}
|
||||
}
|
||||
sub pop_stack() {
|
||||
;; cx16.r12L--
|
||||
;; x1 = stack_xl[cx16.r12L]
|
||||
;; x2 = stack_xr[cx16.r12L]
|
||||
;; y = stack_y[cx16.r12L]
|
||||
;; dy = stack_dy[cx16.r12L]
|
||||
%asm {{
|
||||
dec cx16.r12L
|
||||
ldy cx16.r12L
|
||||
lda stack_xl_lsb,y
|
||||
sta x1
|
||||
lda stack_xl_msb,y
|
||||
sta x1+1
|
||||
lda stack_xr_lsb,y
|
||||
sta x2
|
||||
lda stack_xr_msb,y
|
||||
sta x2+1
|
||||
lda stack_y_lsb,y
|
||||
sta yy
|
||||
lda stack_y_msb,y
|
||||
sta yy+1
|
||||
ldy cx16.r12L
|
||||
lda stack_dy,y
|
||||
sta dy
|
||||
}}
|
||||
yy+=dy
|
||||
}
|
||||
cx16.r11L = pget(xx as uword, yy as uword) ; old_color
|
||||
if cx16.r11L == cx16.r10L
|
||||
return
|
||||
if xx<0 or xx>width-1 or yy<0 or yy>height-1
|
||||
return
|
||||
push_stack(xx, xx, yy, 1)
|
||||
push_stack(xx, xx, yy + 1, -1)
|
||||
word left = 0
|
||||
while cx16.r12L {
|
||||
pop_stack()
|
||||
xx = x1
|
||||
while xx >= 0 and pget(xx as uword, yy as uword) == cx16.r11L {
|
||||
plot(xx as uword, yy as uword, cx16.r10L)
|
||||
xx--
|
||||
}
|
||||
if xx >= x1
|
||||
goto skip
|
||||
|
||||
left = xx + 1
|
||||
if left < x1
|
||||
push_stack(left, x1 - 1, yy, -dy)
|
||||
xx = x1 + 1
|
||||
|
||||
do {
|
||||
while xx <= width-1 and pget(xx as uword, yy as uword) == cx16.r11L {
|
||||
plot(xx as uword, yy as uword, cx16.r10L)
|
||||
xx++
|
||||
}
|
||||
push_stack(left, xx - 1, yy, dy)
|
||||
if xx > x2 + 1
|
||||
push_stack(x2 + 1, xx - 1, yy, -dy)
|
||||
skip:
|
||||
xx++
|
||||
while xx <= x2 and pget(xx as uword, yy as uword) != cx16.r11L
|
||||
xx++
|
||||
left = xx
|
||||
} until xx>x2
|
||||
}
|
||||
}
|
||||
|
||||
sub position(uword @zp xx, uword yy) {
|
||||
if width==320
|
||||
cx16.r0 = yy*(320/8)
|
||||
else
|
||||
cx16.r0 = yy*(640/8)
|
||||
cx16.vaddr(0, cx16.r0+xx/8, 0, 1)
|
||||
}
|
||||
|
||||
sub position2(uword @zp xx, uword yy, bool also_port_1) {
|
||||
position(xx, yy)
|
||||
if also_port_1
|
||||
cx16.vaddr_clone(0)
|
||||
}
|
||||
|
||||
const ubyte charset_bank = $1
|
||||
const uword charset_addr = $f000 ; in bank 1, so $1f000
|
||||
|
||||
sub text_charset(ubyte charset) {
|
||||
; -- select the text charset to use with the text() routine
|
||||
; the charset number is the same as for the cx16.screen_set_charset() ROM function.
|
||||
; 1 = ISO charset, 2 = PETSCII uppercase+graphs, 3= PETSCII uppercase+lowercase.
|
||||
cx16.screen_set_charset(charset, 0)
|
||||
}
|
||||
|
||||
sub text(uword @zp xx, uword yy, bool draw, uword sctextptr) {
|
||||
; -- Write some text at the given pixel position. The text string must be in screencode encoding (not petscii!).
|
||||
; You must also have called text_charset() first to select and prepare the character set to use.
|
||||
uword chardataptr
|
||||
ubyte[8] @shared char_bitmap_bytes_left
|
||||
ubyte[8] @shared char_bitmap_bytes_right
|
||||
|
||||
cx16.r3 = sctextptr
|
||||
while @(cx16.r3) {
|
||||
chardataptr = charset_addr + @(cx16.r3) * $0008
|
||||
; copy the character bitmap into RAM
|
||||
cx16.vaddr_autoincr(charset_bank, chardataptr, 0, 1)
|
||||
%asm {{
|
||||
; pre-shift the bits
|
||||
lda text.xx
|
||||
and #7
|
||||
sta P8ZP_SCRATCH_B1
|
||||
ldy #0
|
||||
- lda cx16.VERA_DATA0
|
||||
stz P8ZP_SCRATCH_REG
|
||||
ldx P8ZP_SCRATCH_B1
|
||||
cpx #0
|
||||
beq +
|
||||
- lsr a
|
||||
ror P8ZP_SCRATCH_REG
|
||||
dex
|
||||
bne -
|
||||
+ sta char_bitmap_bytes_left,y
|
||||
lda P8ZP_SCRATCH_REG
|
||||
sta char_bitmap_bytes_right,y
|
||||
iny
|
||||
cpy #8
|
||||
bne --
|
||||
}}
|
||||
; left part of shifted char
|
||||
position2(xx, yy, true)
|
||||
set_autoincrs()
|
||||
if draw {
|
||||
%asm {{
|
||||
ldy #0
|
||||
- lda char_bitmap_bytes_left,y
|
||||
ora cx16.VERA_DATA1
|
||||
sta cx16.VERA_DATA0
|
||||
iny
|
||||
cpy #8
|
||||
bne -
|
||||
}}
|
||||
} else {
|
||||
%asm {{
|
||||
ldy #0
|
||||
- lda char_bitmap_bytes_left,y
|
||||
eor #255
|
||||
and cx16.VERA_DATA1
|
||||
sta cx16.VERA_DATA0
|
||||
iny
|
||||
cpy #8
|
||||
bne -
|
||||
}}
|
||||
}
|
||||
; right part of shifted char
|
||||
if lsb(xx) & 7 {
|
||||
position2(xx+8, yy, true)
|
||||
set_autoincrs()
|
||||
if draw {
|
||||
%asm {{
|
||||
ldy #0
|
||||
- lda char_bitmap_bytes_right,y
|
||||
ora cx16.VERA_DATA1
|
||||
sta cx16.VERA_DATA0
|
||||
iny
|
||||
cpy #8
|
||||
bne -
|
||||
}}
|
||||
} else {
|
||||
%asm {{
|
||||
ldy #0
|
||||
- lda char_bitmap_bytes_right,y
|
||||
eor #255
|
||||
and cx16.VERA_DATA1
|
||||
sta cx16.VERA_DATA0
|
||||
iny
|
||||
cpy #8
|
||||
bne -
|
||||
}}
|
||||
}
|
||||
}
|
||||
cx16.r3++
|
||||
xx += 8
|
||||
}
|
||||
|
||||
sub set_autoincrs() {
|
||||
; set autoincrements to go to next pixel row (40 or 80 increment)
|
||||
if width==320 {
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & $0f | (11<<4)
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & $0f | (11<<4)
|
||||
} else {
|
||||
cx16.VERA_CTRL = 0
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & $0f | (12<<4)
|
||||
cx16.VERA_CTRL = 1
|
||||
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & $0f | (12<<4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asmsub cs_innerloop640() clobbers(Y) {
|
||||
%asm {{
|
||||
ldy #80
|
||||
- stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
stz cx16.VERA_DATA0
|
||||
dey
|
||||
bne -
|
||||
rts
|
||||
}}
|
||||
}
|
||||
}
|
@ -122,6 +122,7 @@ class TestCompilerOnExamplesCx16: FunSpec({
|
||||
"spotlight",
|
||||
"tehtriz",
|
||||
"testgfx2",
|
||||
"testmonogfx",
|
||||
),
|
||||
listOf(false, true)
|
||||
)
|
||||
|
@ -447,18 +447,34 @@ to see what's in there.
|
||||
Information about the exposed debug registers is in the `emulator's documentation <https://github.com/X16Community/x16-emulator#debug-io-registers>`_.
|
||||
|
||||
|
||||
monogfx (cx16 only)
|
||||
--------------------
|
||||
Full-screen lores or hires monochrome bitmap graphics routines, available on the Cx16 machine only.
|
||||
Same interface as gfx2, but is optimized for monochrome (1 bpp) screens.
|
||||
|
||||
gfx2 (cx16 only)
|
||||
-----------------
|
||||
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
|
||||
|
||||
- multiple full-screen resolutions: 640 * 480 monochrome, and 320 * 240 monochrome and 256 colors
|
||||
- clearing screen, switching screen mode, also back to text mode is possible.
|
||||
- lores 320*240 or hires 640*480 bitmap mode, monochrome
|
||||
- clearing screen, switching screen mode, also back to text mode
|
||||
- drawing and reading individual pixels
|
||||
- drawing lines, rectangles, filled rectangles, circles, discs
|
||||
- flood fill
|
||||
- drawing text inside the bitmap
|
||||
- can draw using a stipple pattern (alternate black/white pixels)
|
||||
|
||||
Read the `source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/monogfx.p8>`_
|
||||
to see what's in there.
|
||||
|
||||
|
||||
gfx2 (cx16 only)
|
||||
-----------------
|
||||
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
|
||||
Same interface as monogfx, but for color screens. For 1 bpp monochrome screens, use monogfx.
|
||||
|
||||
- multiple full-screen bitmap color resolutions
|
||||
- clearing screen, switching screen mode, also back to text mode
|
||||
- drawing and reading individual pixels
|
||||
- drawing lines, rectangles, filled rectangles, circles, discs
|
||||
- flood fill
|
||||
- drawing text inside the bitmap
|
||||
- in monochrome mode, it's possible to use a stippled drawing pattern to simulate a shade of gray.
|
||||
|
||||
Read the `source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx2.p8>`_
|
||||
to see what's in there.
|
||||
|
@ -1,6 +1,8 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- gfx2 and monogfx rect draw problem in monochrome modes one of the small rectangles is drawn garbled
|
||||
- make monogfx the new graphics module? also change c64 and c128 graphics modules
|
||||
- add %option verafxmuls in block to enable transparent verafx muls use for that block only + add warning message to docs to not use it it in prg AND irq code
|
||||
|
||||
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
||||
|
@ -1,4 +1,4 @@
|
||||
%import gfx2
|
||||
%import monogfx
|
||||
%import floats
|
||||
%import textio
|
||||
%import math
|
||||
@ -7,77 +7,77 @@
|
||||
main {
|
||||
|
||||
sub start () {
|
||||
gfx2.text_charset(3)
|
||||
monogfx.text_charset(3)
|
||||
|
||||
test_monochrome()
|
||||
|
||||
gfx2.screen_mode(0)
|
||||
monogfx.textmode()
|
||||
txt.print("done!\n")
|
||||
}
|
||||
|
||||
sub test_monochrome() {
|
||||
gfx2.screen_mode(5)
|
||||
monogfx.hires()
|
||||
uword yy
|
||||
uword xx
|
||||
word ww
|
||||
|
||||
yy = 20
|
||||
xx = 20
|
||||
gfx2.monochrome_stipple(false)
|
||||
gfx2.rect(xx, yy, 250, 80, 1)
|
||||
gfx2.monochrome_stipple(true)
|
||||
gfx2.fillrect(xx+2, yy+2, 250-4, 80-4, 1)
|
||||
gfx2.monochrome_stipple(false)
|
||||
gfx2.fillrect(xx+20, yy+20, 200, 30, 1)
|
||||
gfx2.rect(xx+21, yy+21, 200-2, 30-2, 0)
|
||||
monogfx.stipple(false)
|
||||
monogfx.rect(xx, yy, 250, 80, 1)
|
||||
monogfx.stipple(true)
|
||||
monogfx.fillrect(xx+2, yy+2, 250-4, 80-4, 1)
|
||||
monogfx.stipple(false)
|
||||
monogfx.fillrect(xx+20, yy+20, 200, 30, 1)
|
||||
monogfx.rect(xx+21, yy+21, 200-2, 30-2, 0)
|
||||
|
||||
gfx2.text(xx+30, yy+32, 0, sc:"High Res Bitmap Example")
|
||||
monogfx.text(xx+30, yy+32, 0, sc:"High Res Bitmap Example")
|
||||
|
||||
; gfx2.monochrome_stipple(true)
|
||||
gfx2.horizontal_line(10, 240, 620, 1)
|
||||
gfx2.vertical_line(320, 10, 460, 1)
|
||||
gfx2.text(320, 242, 1, sc:"0,0")
|
||||
gfx2.text(322, 10, 1, sc:"Y-axis")
|
||||
gfx2.text(590, 242, 1, sc:"X-axis")
|
||||
; monogfx.stipple(true)
|
||||
monogfx.horizontal_line(10, 240, 620, 1)
|
||||
monogfx.vertical_line(320, 10, 460, 1)
|
||||
monogfx.text(320, 242, 1, sc:"0,0")
|
||||
monogfx.text(322, 10, 1, sc:"Y-axis")
|
||||
monogfx.text(590, 242, 1, sc:"X-axis")
|
||||
for ww in -10 to 10 {
|
||||
xx = (ww*30) + 320 as uword
|
||||
gfx2.vertical_line(xx, 239, 3, 1)
|
||||
monogfx.vertical_line(xx, 239, 3, 1)
|
||||
}
|
||||
for ww in -7 to 7 {
|
||||
yy = (ww*30) + 240 as uword
|
||||
gfx2.horizontal_line(319, yy, 3, 1)
|
||||
monogfx.horizontal_line(319, yy, 3, 1)
|
||||
}
|
||||
|
||||
gfx2.monochrome_stipple(false)
|
||||
monogfx.stipple(false)
|
||||
float y_f
|
||||
for ww in -600 to 600 {
|
||||
y_f = floats.sin(ww as float / 60.0)*150
|
||||
gfx2.plot(ww/2 + 320 as uword, (y_f + 240) as uword, 1)
|
||||
monogfx.plot(ww/2 + 320 as uword, (y_f + 240) as uword, 1)
|
||||
}
|
||||
gfx2.text(480, 100, 1, sc:"sin(x)")
|
||||
monogfx.text(480, 100, 1, sc:"sin(x)")
|
||||
|
||||
for ww in -300 to 300 {
|
||||
y_f = floats.cos(ww as float/30.0)*60 - (ww as float)/1.7
|
||||
gfx2.plot(ww + 320 as uword, (y_f + 240) as uword, 1)
|
||||
monogfx.plot(ww + 320 as uword, (y_f + 240) as uword, 1)
|
||||
}
|
||||
gfx2.text(80, 420, 1, sc:"cos(x)+x")
|
||||
monogfx.text(80, 420, 1, sc:"cos(x)+x")
|
||||
|
||||
sys.wait(3*60)
|
||||
|
||||
gfx2.circle(320, 240, 220, 1)
|
||||
gfx2.circle(320, 240, 210, 1)
|
||||
gfx2.circle(320, 240, 200, 1)
|
||||
gfx2.circle(320, 240, 190, 1)
|
||||
gfx2.monochrome_stipple(true)
|
||||
gfx2.disc(320, 240, 140, 1)
|
||||
gfx2.monochrome_stipple(false)
|
||||
gfx2.disc(320, 240, 90, 1)
|
||||
gfx2.disc(320, 240, 40, 0)
|
||||
monogfx.circle(320, 240, 220, 1)
|
||||
monogfx.circle(320, 240, 210, 1)
|
||||
monogfx.circle(320, 240, 200, 1)
|
||||
monogfx.circle(320, 240, 190, 1)
|
||||
monogfx.stipple(true)
|
||||
monogfx.disc(320, 240, 140, 1)
|
||||
monogfx.stipple(false)
|
||||
monogfx.disc(320, 240, 90, 1)
|
||||
monogfx.disc(320, 240, 40, 0)
|
||||
|
||||
sys.wait(2*60)
|
||||
|
||||
repeat 255
|
||||
gfx2.line(math.rndw() % 640, math.rndw() % 480, math.rndw() % 640, math.rndw() % 480, 1)
|
||||
monogfx.line(math.rndw() % 640, math.rndw() % 480, math.rndw() % 640, math.rndw() % 480, 1)
|
||||
|
||||
sys.wait(1*60)
|
||||
}
|
||||
|
208
examples/cx16/testmonogfx.p8
Normal file
208
examples/cx16/testmonogfx.p8
Normal file
@ -0,0 +1,208 @@
|
||||
%import monogfx
|
||||
%import textio
|
||||
%import math
|
||||
|
||||
%option no_sysinit
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
monogfx.lores()
|
||||
demofill()
|
||||
sys.wait(2*60)
|
||||
monogfx.hires()
|
||||
demo1()
|
||||
sys.wait(2*60)
|
||||
demo2()
|
||||
|
||||
monogfx.textmode()
|
||||
txt.print("done!\n")
|
||||
}
|
||||
|
||||
sub demofill() {
|
||||
monogfx.circle(160, 120, 110, 1)
|
||||
monogfx.rect(180, 5, 25, 190, 1)
|
||||
monogfx.line(100, 150, 240, 10, 1)
|
||||
monogfx.line(101, 150, 241, 10, 1)
|
||||
monogfx.stipple(true)
|
||||
sys.wait(60)
|
||||
monogfx.fill(100,100,2)
|
||||
}
|
||||
|
||||
sub demo1() {
|
||||
uword yy = 10
|
||||
uword xx
|
||||
uword cnt
|
||||
|
||||
monogfx.stipple(true)
|
||||
monogfx.disc(320,240,200,1)
|
||||
for xx in 0 to 639 {
|
||||
monogfx.vertical_line(xx, 0, 480, 1)
|
||||
}
|
||||
for xx in 0 to 639 {
|
||||
monogfx.vertical_line(xx, 0, 480, 0)
|
||||
}
|
||||
|
||||
xx=monogfx.width/2
|
||||
yy=10
|
||||
monogfx.stipple(false)
|
||||
linesy()
|
||||
linesx()
|
||||
monogfx.stipple(true)
|
||||
linesy()
|
||||
linesx()
|
||||
|
||||
|
||||
|
||||
sub linesx() {
|
||||
repeat 8 {
|
||||
monogfx.horizontal_line(10,yy,300,3)
|
||||
yy++
|
||||
}
|
||||
yy+=4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.line(10,yy,309,yy,4)
|
||||
yy++
|
||||
}
|
||||
yy+=4
|
||||
|
||||
repeat 8 {
|
||||
for cnt in 10 to 309 {
|
||||
monogfx.plot(cnt, yy, 1)
|
||||
}
|
||||
yy+=1
|
||||
}
|
||||
yy += 4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.horizontal_line(10,yy,100,3)
|
||||
yy++
|
||||
}
|
||||
yy+=4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.line(10,yy,109,yy,4)
|
||||
yy++
|
||||
}
|
||||
yy+=4
|
||||
|
||||
repeat 8 {
|
||||
for cnt in 10 to 109 {
|
||||
monogfx.plot(cnt, yy, 1)
|
||||
}
|
||||
yy++
|
||||
}
|
||||
yy+=4
|
||||
}
|
||||
|
||||
sub linesy() {
|
||||
repeat 8 {
|
||||
monogfx.vertical_line(xx,10,300,3)
|
||||
xx++
|
||||
}
|
||||
xx+=4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.line(xx,10, xx, 309, 4)
|
||||
xx++
|
||||
}
|
||||
xx+=4
|
||||
|
||||
repeat 8 {
|
||||
for cnt in 10 to 309 {
|
||||
monogfx.plot(xx, cnt, 1)
|
||||
}
|
||||
xx+=1
|
||||
}
|
||||
xx += 4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.vertical_line(xx,10,100,3)
|
||||
xx++
|
||||
}
|
||||
xx+=4
|
||||
|
||||
repeat 8 {
|
||||
monogfx.line(xx,10,xx,109,4)
|
||||
xx++
|
||||
}
|
||||
xx+=4
|
||||
|
||||
repeat 8 {
|
||||
for cnt in 10 to 109 {
|
||||
monogfx.plot(xx, cnt, 1)
|
||||
}
|
||||
xx++
|
||||
}
|
||||
xx+=4
|
||||
}
|
||||
}
|
||||
|
||||
sub demo2 () {
|
||||
monogfx.text_charset(3)
|
||||
monogfx.lores()
|
||||
draw()
|
||||
sys.wait(200)
|
||||
monogfx.hires()
|
||||
draw()
|
||||
sys.wait(200)
|
||||
}
|
||||
|
||||
sub draw() {
|
||||
|
||||
monogfx.rect(10,10, 1, 1, 4)
|
||||
monogfx.rect(20,10, 2, 1, 4)
|
||||
monogfx.rect(30,10, 3, 1, 4)
|
||||
monogfx.rect(40,10, 1, 2, 4)
|
||||
monogfx.rect(50,10, 1, 3, 4)
|
||||
monogfx.rect(60,10, 2, 2, 4)
|
||||
monogfx.rect(70,10, 3, 3, 4)
|
||||
monogfx.rect(80,10, 4, 4, 4)
|
||||
monogfx.rect(90,10, 5, 5, 4)
|
||||
monogfx.rect(100,10, 8, 8, 4)
|
||||
monogfx.rect(110,10, 20, 5, 4)
|
||||
monogfx.rect(80, 80, 200, 140, 4)
|
||||
|
||||
monogfx.fillrect(10,40, 1, 1, 5)
|
||||
monogfx.fillrect(20,40, 2, 1, 5)
|
||||
monogfx.fillrect(30,40, 3, 1, 5)
|
||||
monogfx.fillrect(40,40, 1, 2, 5)
|
||||
monogfx.fillrect(50,40, 1, 3, 5)
|
||||
monogfx.fillrect(60,40, 2, 2, 5)
|
||||
monogfx.fillrect(70,40, 3, 3, 5)
|
||||
monogfx.fillrect(80,40, 4, 4, 5)
|
||||
monogfx.fillrect(90,40, 5, 5, 5)
|
||||
monogfx.fillrect(100,40, 8, 8, 5)
|
||||
monogfx.fillrect(110,40, 20, 5, 5)
|
||||
monogfx.fillrect(82, 82, 200-4, 140-4, 5)
|
||||
|
||||
ubyte i
|
||||
for i in 0 to 254 step 4 {
|
||||
uword x1 = ((monogfx.width-256)/2 as uword) + math.sin8u(i)
|
||||
uword y1 = (monogfx.height-128)/2 + math.cos8u(i)/2
|
||||
uword x2 = ((monogfx.width-64)/2 as uword) + math.sin8u(i)/4
|
||||
uword y2 = (monogfx.height-64)/2 + math.cos8u(i)/4
|
||||
monogfx.line(x1, y1, x2, y2, i+1)
|
||||
}
|
||||
|
||||
sys.wait(60)
|
||||
monogfx.clear_screen()
|
||||
|
||||
ubyte radius
|
||||
|
||||
for radius in 110 downto 8 step -4 {
|
||||
monogfx.circle(monogfx.width/2, (monogfx.height/2 as ubyte), radius, radius)
|
||||
}
|
||||
|
||||
monogfx.disc(monogfx.width/2, monogfx.height/2, 80, 2)
|
||||
|
||||
ubyte tp
|
||||
for tp in 0 to 15 {
|
||||
monogfx.text(19+tp,20+tp*11, 7, sc:"ScreenCODE text! 1234![]<>#$%&*()")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,20 +1,80 @@
|
||||
%import textio
|
||||
;%import math
|
||||
;%import verafx
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
alignblock.flags[0] = 222
|
||||
cx16.r0++
|
||||
cx16.r1++
|
||||
txt.print_uwhex(alignblock.flags, true)
|
||||
txt.spc()
|
||||
txt.print_ub(alignblock.flags[0])
|
||||
word w1 = -123
|
||||
word w2 = 222
|
||||
ubyte b2 = 222
|
||||
byte sb2 = 111
|
||||
txt.print_w(w1*w2)
|
||||
txt.nl()
|
||||
txt.print_w(w1*222)
|
||||
txt.nl()
|
||||
w1 = -123
|
||||
w1 *= 222
|
||||
txt.print_w(w1)
|
||||
txt.nl()
|
||||
w1 = -123
|
||||
w1 *= w2
|
||||
txt.print_w(w1)
|
||||
txt.nl()
|
||||
w1 = -123
|
||||
w1 *= (w2-1)
|
||||
txt.print_w(w1)
|
||||
txt.nl()
|
||||
w1 = -123
|
||||
w1 *= b2
|
||||
txt.print_w(w1)
|
||||
txt.nl()
|
||||
w1 = -123
|
||||
w1 *= sb2
|
||||
txt.print_w(w1)
|
||||
txt.nl()
|
||||
|
||||
; txt.print_uw(math.mul16_last_upper())
|
||||
; txt.nl()
|
||||
; uword value1=5678
|
||||
; uword value2=9999
|
||||
; uword result = value1*value2
|
||||
; uword upper16 = math.mul16_last_upper()
|
||||
; txt.print_uw(result)
|
||||
; txt.spc()
|
||||
; txt.print_uw(upper16)
|
||||
; txt.nl()
|
||||
|
||||
|
||||
; const word MULTIPLIER = 431
|
||||
;
|
||||
; ; verify results:
|
||||
; for value in -50 to 50 {
|
||||
; if value*MULTIPLIER != verafx.muls(value, MULTIPLIER) {
|
||||
; txt.print("verafx muls error\n")
|
||||
; sys.exit(1)
|
||||
; }
|
||||
; }
|
||||
;
|
||||
;
|
||||
; word value
|
||||
; txt.print("verafx muls...")
|
||||
; cbm.SETTIM(0,0,0)
|
||||
; for value in -50 to 50 {
|
||||
; repeat 250 void verafx.muls(value, MULTIPLIER)
|
||||
; }
|
||||
; txt.print_uw(cbm.RDTIM16())
|
||||
; txt.nl()
|
||||
;
|
||||
; txt.print("6502 muls...")
|
||||
; cbm.SETTIM(0,0,0)
|
||||
; for value in -50 to 50 {
|
||||
; repeat 250 cx16.r0s = value*MULTIPLIER
|
||||
; }
|
||||
; txt.print_uw(cbm.RDTIM16())
|
||||
; txt.nl()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
alignblock {
|
||||
%option align_page
|
||||
ubyte[10] flags
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user