split up cx16.gfx2 module into gfx_lores and gfx_hires4 modules

This commit is contained in:
Irmen de Jong 2024-10-30 22:21:07 +01:00
parent 94d76aa82c
commit 4ce130dc8b
13 changed files with 500 additions and 727 deletions

View File

@ -1,117 +1,49 @@
; Bitmap pixel graphics routines for the CommanderX16
; Custom routines to use the full-screen 640x480 and 320x240 screen modes.
; Custom routines to use the full-screen 640x480 in 4 color mode.
; (monochrome mode can be used via the monogfx module)
; (These modes are not supported by the documented GRAPH_xxxx kernal routines)
;
; No text layer is currently shown, text can be drawn as part of the bitmap itself.
; Note: for similar graphics routines that also work on the C-64, use the "graphics" module instead.
; Note: for identical routines for a monochrome 1 bpp screen, use the "monogfx" module instead.
; Note: for color palette manipulation, use the "palette" module or write Vera registers yourself.
; Note: this library implements code for various resolutions and color depths. This takes up memory.
; If you're memory constrained you should probably not use this built-in library,
; but make a copy in your project only containing the code for the required resolution.
;
; NOTE: For sake of speed, NO BOUNDS CHECKING is performed in most routines!
; You'll have to make sure yourself that you're not writing outside of bitmap boundaries!
; NOTE: the bitmap screen data is positioned in vram at $00000
; This is compatible with the CX16's screen mode 128. (void cx16.set_screen_mode(128))
;
; NOTE: the bitmap screen data is positioned in vram at $0:0000
;
; NOTE: In the future, these routines might be split out to separate modules, 1 for each screen mode,
; so they can be optimized a lot better. There's already a "gfx_lores" module with a few routines for lores 256C mode.
;
; SCREEN MODE LIST:
; mode 0 = reset back to default text mode
; mode 1 = bitmap 320 x 240 x 256c (8 bpp)
; mode 2 = bitmap 640 x 480 x 4c (2 bpp)
; mode 3 = bitmap 320 x 240 x 4c (not yet implemented: just use 256c, there's enough vram for that)
; mode 4 = bitmap 320 x 240 x 16c (not yet implemented: just use 256c, there's enough vram for that)
; mode 5 = bitmap 640 x 400 x 16c (not yet implemented)
gfx2 {
gfx_hires4 {
%option ignore_unused
; read-only control variables:
ubyte active_mode = 0
uword width = 0
uword height = 0
ubyte bpp = 0
const uword WIDTH = 640
const uword HEIGHT = 480
sub screen_mode(ubyte mode) {
sub graphics_mode() {
; set hires 4c mode
cx16.VERA_CTRL=0
when mode {
1 -> {
; lores 256c
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
}
2 -> {
; highres 4c
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 = %00000101
cx16.VERA_L1_MAPBASE = 0
cx16.VERA_L1_TILEBASE = %00000001
}
else -> {
; back to default text mode
if active_mode!=0 {
cx16.r15L = cx16.VERA_DC_VIDEO & %00000111 ; retain chroma + output mode
cbm.CINT()
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11111000) | cx16.r15L
}
}
}
init_mode(mode)
if active_mode!=0
clear_screen(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 = %00000101
cx16.VERA_L1_MAPBASE = 0
cx16.VERA_L1_TILEBASE = %00000001
clear_screen(0)
}
sub init_mode(ubyte mode) {
; set the internal configuration variables corresponding to the given screenmode
; doesn't manipulate Vera / the actual display mode
active_mode = mode
when mode {
1 -> {
width = 320
height = 240
bpp = 8
}
2 -> {
width = 640
height = 480
bpp = 2
}
else -> {
width = 0
height = 0
bpp = 0
active_mode = 0
}
}
sub text_mode() {
; 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(ubyte color) {
position(0, 0)
when active_mode {
1 -> {
; lores 256c
repeat 240/2
cs_innerloop640(color)
}
2 -> {
; highres 4c
ubyte[] colors = [%00000000, %01010101, %10101010, %11111111]
color = colors[color&3]
repeat 480/4
cs_innerloop640(color)
}
}
ubyte[] colors = [%00000000, %01010101, %10101010, %11111111]
color = colors[color&3]
repeat 480/4
cs_innerloop640(color)
position(0, 0)
}
@ -155,22 +87,22 @@ gfx2 {
; Draw a filled rectangle of the given size and color.
; To fill the whole screen, use clear_screen(color) instead - it is much faster.
; This safe version does bounds checking and clipping.
if xx>=width or yy>=width
if xx>=WIDTH or yy>=WIDTH
return
if msb(xx)&$80!=0 {
rwidth += xx
xx = 0
}
if xx>=width
if xx>=WIDTH
return
if xx+rwidth>width
rwidth = width-xx
if rwidth>width
if xx+rwidth>WIDTH
rwidth = WIDTH-xx
if rwidth>WIDTH
return
if yy + rheight > height
rheight = height-yy
if rheight>height
if yy + rheight > HEIGHT
rheight = HEIGHT-yy
if rheight>HEIGHT
return
repeat rheight {
@ -182,137 +114,93 @@ gfx2 {
sub horizontal_line(uword xx, uword yy, uword length, ubyte color) {
if length==0
return
when active_mode {
1 -> {
; lores 256c
position(xx, yy)
%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 -
+
}}
}
2 -> {
; highres 4c ....also mostly usable for lores 4c?
color &= 3
ubyte[4] colorbits
ubyte ii
for ii in 3 downto 0 {
colorbits[ii] = color
color <<= 2
}
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
lda cx16.VERA_ADDR_H
and #%00000111 ; no auto advance
sta cx16.VERA_ADDR_H
stz cx16.VERA_CTRL ; setup vera addr 0
lda cx16.r1
and #1
sta cx16.VERA_ADDR_H
lda cx16.r0
sta cx16.VERA_ADDR_L
lda cx16.r0+1
sta cx16.VERA_ADDR_M
ldx p8v_xx
}}
; highres 4c ....also mostly usable for lores 4c?
color &= 3
ubyte[4] colorbits
ubyte ii
for ii in 3 downto 0 {
colorbits[ii] = color
color <<= 2
}
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
lda cx16.VERA_ADDR_H
and #%00000111 ; no auto advance
sta cx16.VERA_ADDR_H
stz cx16.VERA_CTRL ; setup vera addr 0
lda cx16.r1
and #1
sta cx16.VERA_ADDR_H
lda cx16.r0
sta cx16.VERA_ADDR_L
lda cx16.r0+1
sta cx16.VERA_ADDR_M
ldx p8v_xx
}}
repeat length {
%asm {{
txa
and #3
tay
lda cx16.VERA_DATA0
and p8b_gfx2.p8s_plot.p8v_mask4c,y
ora p8v_colorbits,y
sta cx16.VERA_DATA0
cpy #%00000011 ; next vera byte?
bne ++
inc cx16.VERA_ADDR_L
bne ++
inc cx16.VERA_ADDR_M
repeat length {
%asm {{
txa
and #3
tay
lda cx16.VERA_DATA0
and p8b_gfx_hires4.p8s_plot.p8v_mask4c,y
ora p8v_colorbits,y
sta cx16.VERA_DATA0
cpy #%00000011 ; next vera byte?
bne ++
inc cx16.VERA_ADDR_L
bne ++
inc cx16.VERA_ADDR_M
+ bne +
inc cx16.VERA_ADDR_H
inc cx16.VERA_ADDR_H
+ inx ; next pixel
}}
}
}
}}
}
}
sub safe_horizontal_line(uword xx, uword yy, uword length, ubyte color) {
; does bounds checking and clipping
if msb(yy)&$80!=0 or yy>=height
if msb(yy)&$80!=0 or yy>=HEIGHT
return
if msb(xx)&$80!=0 {
length += xx
xx = 0
}
if xx>=width
if xx>=WIDTH
return
if xx+length>width
length = width-xx
if length>width
if xx+length>WIDTH
length = WIDTH-xx
if length>WIDTH
return
horizontal_line(xx, yy, length, color)
}
sub vertical_line(uword xx, uword yy, uword lheight, ubyte color) {
when active_mode {
1 -> {
; lores 256c
; set vera auto-increment to 320 pixel increment (=next line)
position(xx,yy)
cx16.VERA_ADDR_H = cx16.VERA_ADDR_H & %00000111 | (14<<4)
%asm {{
ldy p8v_lheight
beq +
lda p8v_color
- sta cx16.VERA_DATA0
dey
bne -
+
}}
}
2 -> {
; highres 4c
; use TWO vera adress pointers simultaneously one for reading, one for writing, so auto-increment is possible
if lheight==0
return
position2(xx,yy,true)
set_both_strides(13) ; 160 increment = 1 line in 640 px 4c mode
;; color &= 3
;; color <<= gfx2.plot.shift4c[lsb(xx) & 3]
cx16.r2L = lsb(xx) & 3
when color & 3 {
0 -> color = 0
1 -> color = gfx2.plot.shiftedleft_4c_1[cx16.r2L]
2 -> color = gfx2.plot.shiftedleft_4c_2[cx16.r2L]
3 -> color = gfx2.plot.shiftedleft_4c_3[cx16.r2L]
}
ubyte @shared mask = gfx2.plot.mask4c[lsb(xx) & 3]
repeat lheight {
%asm {{
lda cx16.VERA_DATA0
and p8v_mask
ora p8v_color
sta cx16.VERA_DATA1
}}
}
}
; highres 4c
; use TWO vera adress pointers simultaneously one for reading, one for writing, so auto-increment is possible
if lheight==0
return
position2(xx,yy,true)
set_both_strides(13) ; 160 increment = 1 line in 640 px 4c mode
;; color &= 3
;; color <<= gfx2.plot.shift4c[lsb(xx) & 3]
cx16.r2L = lsb(xx) & 3
when color & 3 {
0 -> color = 0
1 -> color = gfx_hires4.plot.shiftedleft_4c_1[cx16.r2L]
2 -> color = gfx_hires4.plot.shiftedleft_4c_2[cx16.r2L]
3 -> color = gfx_hires4.plot.shiftedleft_4c_3[cx16.r2L]
}
ubyte @shared mask = gfx_hires4.plot.mask4c[lsb(xx) & 3]
repeat lheight {
%asm {{
lda cx16.VERA_DATA0
and p8v_mask
ora p8v_color
sta cx16.VERA_DATA1
}}
}
sub set_both_strides(ubyte stride) {
@ -327,17 +215,17 @@ gfx2 {
sub safe_vertical_line(uword xx, uword yy, uword lheight, ubyte color) {
; does bounds checking and clipping
if msb(yy)&$80!=0 or yy>=height
if msb(yy)&$80!=0 or yy>=HEIGHT
return
if msb(xx)&$80!=0 or xx>=width
if msb(xx)&$80!=0 or xx>=WIDTH
return
if msb(yy)&$80!=0 {
lheight += yy
yy = 0
}
if yy+lheight>height
lheight = height-yy
if lheight>height
if yy+lheight>HEIGHT
lheight = HEIGHT-yy
if lheight>HEIGHT
return
vertical_line(xx, yy, lheight, color)
@ -622,107 +510,68 @@ gfx2 {
ubyte[4] shiftedleft_4c_2 = [2<<6, 2<<4, 2<<2, 2<<0]
ubyte[4] shiftedleft_4c_3 = [3<<6, 3<<4, 3<<2, 3<<0]
when active_mode {
1 -> {
; lores 256c
void addr_mul_24_for_lores_256c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1
ora #%00010000 ; enable auto-increment so next_pixel() can be used after this
sta cx16.VERA_ADDR_H
lda cx16.r0+1
sta cx16.VERA_ADDR_M
lda cx16.r0
sta cx16.VERA_ADDR_L
lda p8v_color
sta cx16.VERA_DATA0
}}
}
2 -> {
; highres 4c ....also mostly usable for lores 4c?
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
cx16.r2L = lsb(xx) & 3 ; xbits
; color &= 3
; color <<= shift4c[cx16.r2L]
when color & 3 {
0 -> color = 0
1 -> color = shiftedleft_4c_1[cx16.r2L]
2 -> color = shiftedleft_4c_2[cx16.r2L]
3 -> color = shiftedleft_4c_3[cx16.r2L]
}
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1L
sta cx16.VERA_ADDR_H
lda cx16.r0H
sta cx16.VERA_ADDR_M
lda cx16.r0L
sta cx16.VERA_ADDR_L
ldy cx16.r2L ; xbits
lda p8v_mask4c,y
and cx16.VERA_DATA0
ora p8v_color
sta cx16.VERA_DATA0
}}
}
; highres 4c ....also mostly usable for lores 4c?
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
cx16.r2L = lsb(xx) & 3 ; xbits
; color &= 3
; color <<= shift4c[cx16.r2L]
when color & 3 {
0 -> color = 0
1 -> color = shiftedleft_4c_1[cx16.r2L]
2 -> color = shiftedleft_4c_2[cx16.r2L]
3 -> color = shiftedleft_4c_3[cx16.r2L]
}
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1L
sta cx16.VERA_ADDR_H
lda cx16.r0H
sta cx16.VERA_ADDR_M
lda cx16.r0L
sta cx16.VERA_ADDR_L
ldy cx16.r2L ; xbits
lda p8v_mask4c,y
and cx16.VERA_DATA0
ora p8v_color
sta cx16.VERA_DATA0
}}
}
sub safe_plot(uword xx, uword yy, ubyte color) {
; A plot that does bounds checks to see if the pixel is inside the screen.
if msb(xx)&$80!=0 or msb(yy)&$80!=0
return
if xx >= width or yy >= height
if xx >= WIDTH or yy >= HEIGHT
return
plot(xx, yy, color)
}
sub pget(uword @zp xx, uword yy) -> ubyte {
when active_mode {
1 -> {
; lores 256c
void addr_mul_24_for_lores_256c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1
sta cx16.VERA_ADDR_H
lda cx16.r0+1
sta cx16.VERA_ADDR_M
lda cx16.r0
sta cx16.VERA_ADDR_L
lda cx16.VERA_DATA0
}}
}
2 -> {
; hires 4c
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1L
sta cx16.VERA_ADDR_H
lda cx16.r0H
sta cx16.VERA_ADDR_M
lda cx16.r0L
sta cx16.VERA_ADDR_L
lda cx16.VERA_DATA0
pha
lda p8v_xx
and #3
tay
lda p8b_gfx2.p8s_plot.p8v_shift4c,y
tay
pla
cpy #0
beq +
- lsr a
dey
bne -
+ and #3
}}
}
else -> return 0
}
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
%asm {{
stz cx16.VERA_CTRL
lda cx16.r1L
sta cx16.VERA_ADDR_H
lda cx16.r0H
sta cx16.VERA_ADDR_M
lda cx16.r0L
sta cx16.VERA_ADDR_L
lda cx16.VERA_DATA0
pha
lda p8v_xx
and #3
tay
lda p8b_gfx_hires4.p8s_plot.p8v_shift4c,y
tay
pla
cpy #0
beq +
- lsr a
dey
bne -
+ and #3
rts
}}
}
sub fill(uword x, uword y, ubyte new_color) {
@ -754,7 +603,7 @@ gfx2 {
if cx16.r12L==MAXDEPTH
return
cx16.r0s = sy+sdy
if cx16.r0s>=0 and cx16.r0s<=height-1 {
if cx16.r0s>=0 and cx16.r0s<=HEIGHT-1 {
;; stack_xl[cx16.r12L] = sxl
;; stack_xr[cx16.r12L] = sxr
;; stack_y[cx16.r12L] = sy
@ -811,29 +660,23 @@ gfx2 {
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
if xx<0 or xx>WIDTH-1 or yy<0 or yy>HEIGHT-1
return
if gfx2.active_mode == 2 set_color_masks()
set_color_masks()
push_stack(xx, xx, yy, 1)
push_stack(xx, xx, yy + 1, -1)
word left = 0
while cx16.r12L!=0 {
pop_stack()
xx = x1
when active_mode {
1 -> if fill_scanline_left_8bpp() goto skip
2 -> if fill_scanline_left_2bpp() goto skip
}
if fill_scanline_left_2bpp() goto skip
left = xx + 1
if left < x1
push_stack(left, x1 - 1, yy, -dy)
xx = x1 + 1
do {
when active_mode {
1 -> fill_scanline_right_8bpp()
2 -> fill_scanline_right_2bpp()
}
fill_scanline_right_2bpp()
push_stack(left, xx - 1, yy, dy)
if xx > x2 + 1
push_stack(x2 + 1, xx - 1, yy, -dy)
@ -859,35 +702,9 @@ skip:
cx16.VERA_CTRL = 0
}
sub fill_scanline_left_8bpp() -> bool {
void addr_mul_24_for_lores_256c(yy as uword, xx as uword) ; 24 bits result is in r0 and r1L (highest byte)
cx16.r1L |= %00011000 ; auto decrement enabled
set_vera_address()
cx16.r9s = xx
while xx >= 0 {
if cx16.VERA_DATA0 != cx16.r11L
break
cx16.VERA_DATA1 = cx16.r10L
xx--
}
return xx==cx16.r9s
}
sub fill_scanline_right_8bpp() {
void addr_mul_24_for_lores_256c(yy as uword, xx as uword) ; 24 bits result is in r0 and r1L (highest byte)
cx16.r1L |= %00010000 ; auto increment enabled
set_vera_address()
while xx <= width-1 {
if cx16.VERA_DATA0 != cx16.r11L
break
cx16.VERA_DATA1 = cx16.r10L
xx++
}
}
sub fill_scanline_left_2bpp() -> bool {
uword vx = xx as uword
void gfx2.addr_mul_24_for_highres_4c(yy as uword,vx)
void gfx_hires4.addr_mul_24_for_highres_4c(yy as uword,vx)
cx16.r1L |= %0001_1000 ; auto decrement
set_vera_address()
cmask = amask[lsb(vx) & 3] ; set the color mask for the first color pel
@ -931,7 +748,7 @@ set_byte:
}
sub fill_scanline_right_2bpp() {
void gfx2.addr_mul_24_for_highres_4c(yy as uword,xx as uword)
void gfx_hires4.addr_mul_24_for_highres_4c(yy as uword,xx as uword)
cx16.r1L |= %00010000 ; auto increment
set_vera_address()
cmask = amask[lsb(xx) & 3] ; set the color mask for the first color pel
@ -965,7 +782,7 @@ set_byte:
}
set_byte:
cx16.VERA_DATA1 = nvub
if xx >= gfx2.width-1 break
if xx >= WIDTH-1 break
cmask = $C0
}
}
@ -977,16 +794,7 @@ set_byte:
}
sub position(uword @zp xx, uword yy) {
when active_mode {
1 -> {
; lores 256c
void addr_mul_24_for_lores_256c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
}
2 -> {
; highres 4c
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
}
}
void addr_mul_24_for_highres_4c(yy, xx) ; 24 bits result is in r0 and r1L (highest byte)
cx16.r2L = cx16.r1L
cx16.vaddr(cx16.r2L, cx16.r0, 0, 1)
}
@ -1068,83 +876,36 @@ set_byte:
ubyte[8] @shared char_bitmap_bytes_left
ubyte[8] @shared char_bitmap_bytes_right
when active_mode {
1 -> {
; lores 256c
while @(sctextptr)!=0 {
chardataptr = charset_addr + (@(sctextptr) as uword)*8
cx16.vaddr(charset_bank, chardataptr, 1, 1)
repeat 8 {
position(xx,yy)
yy++
%asm {{
ldx p8v_color
lda cx16.VERA_DATA1
sta P8ZP_SCRATCH_B1
ldy #8
- asl P8ZP_SCRATCH_B1
bcc +
stx cx16.VERA_DATA0 ; write a pixel
bra ++
+ lda cx16.VERA_DATA0 ; don't write a pixel, but do advance to the next address
+ dey
bne -
}}
}
xx+=8
yy-=8
sctextptr++
}
}
2 -> {
; hires 4c
; we're going to use a few cx16 registers to make sure every variable is in zeropage in the inner loop.
cx16.r11L = color
while @(sctextptr)!=0 {
chardataptr = charset_addr + (@(sctextptr) as uword)*8
cx16.vaddr(charset_bank, chardataptr, 1, 1) ; for reading the chardata from Vera data channel 1
position(xx, yy) ; only calculated once, we update vera address in the loop instead
cx16.VERA_ADDR_H &= $0f ; no auto increment
repeat 8 {
cx16.r10L = cx16.VERA_DATA1 ; get the next 8 horizontal character bits
cx16.r7 = xx
repeat 8 {
cx16.r10L <<= 1
if_cs {
cx16.r2L = cx16.r7L & 3 ; xbits
when cx16.r11L & 3 {
1 -> cx16.r12L = gfx2.plot.shiftedleft_4c_1[cx16.r2L]
2 -> cx16.r12L = gfx2.plot.shiftedleft_4c_2[cx16.r2L]
3 -> cx16.r12L = gfx2.plot.shiftedleft_4c_3[cx16.r2L]
else -> cx16.r12L = 0
}
cx16.VERA_DATA0 = cx16.VERA_DATA0 & gfx2.plot.mask4c[cx16.r2L] | cx16.r12L
}
cx16.r7++
if (cx16.r7 & 3) == 0 {
; increment the pixel address by one
%asm {{
stz cx16.VERA_CTRL
clc
lda cx16.VERA_ADDR_L
adc #1
sta cx16.VERA_ADDR_L
lda cx16.VERA_ADDR_M
adc #0
sta cx16.VERA_ADDR_M
lda cx16.VERA_ADDR_H
adc #0
sta cx16.VERA_ADDR_H
}}
}
; we're going to use a few cx16 registers to make sure every variable is in zeropage in the inner loop.
cx16.r11L = color
while @(sctextptr)!=0 {
chardataptr = charset_addr + (@(sctextptr) as uword)*8
cx16.vaddr(charset_bank, chardataptr, 1, 1) ; for reading the chardata from Vera data channel 1
position(xx, yy) ; only calculated once, we update vera address in the loop instead
cx16.VERA_ADDR_H &= $0f ; no auto increment
repeat 8 {
cx16.r10L = cx16.VERA_DATA1 ; get the next 8 horizontal character bits
cx16.r7 = xx
repeat 8 {
cx16.r10L <<= 1
if_cs {
cx16.r2L = cx16.r7L & 3 ; xbits
when cx16.r11L & 3 {
1 -> cx16.r12L = gfx_hires4.plot.shiftedleft_4c_1[cx16.r2L]
2 -> cx16.r12L = gfx_hires4.plot.shiftedleft_4c_2[cx16.r2L]
3 -> cx16.r12L = gfx_hires4.plot.shiftedleft_4c_3[cx16.r2L]
else -> cx16.r12L = 0
}
; increment pixel address to the next line
cx16.VERA_DATA0 = cx16.VERA_DATA0 & gfx_hires4.plot.mask4c[cx16.r2L] | cx16.r12L
}
cx16.r7++
if (cx16.r7 & 3) == 0 {
; increment the pixel address by one
%asm {{
stz cx16.VERA_CTRL
clc
lda cx16.VERA_ADDR_L
adc #(640-8)/4
adc #1
sta cx16.VERA_ADDR_L
lda cx16.VERA_ADDR_M
adc #0
@ -1154,10 +915,25 @@ set_byte:
sta cx16.VERA_ADDR_H
}}
}
xx+=8
sctextptr++
}
; increment pixel address to the next line
%asm {{
stz cx16.VERA_CTRL
clc
lda cx16.VERA_ADDR_L
adc #(640-8)/4
sta cx16.VERA_ADDR_L
lda cx16.VERA_ADDR_M
adc #0
sta cx16.VERA_ADDR_M
lda cx16.VERA_ADDR_H
adc #0
sta cx16.VERA_ADDR_H
}}
}
xx+=8
sctextptr++
}
}
@ -1228,50 +1004,4 @@ set_byte:
rts
}}
}
asmsub addr_mul_24_for_lores_256c(uword yy @R0, uword xx @AY) clobbers(A) -> uword @R0, ubyte @R1 {
; yy * 320 + xx (24 bits calculation)
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r0
sta P8ZP_SCRATCH_B1
lda cx16.r0+1
sta cx16.r1
sta P8ZP_SCRATCH_REG
lda cx16.r0
asl a
rol P8ZP_SCRATCH_REG
asl a
rol P8ZP_SCRATCH_REG
asl a
rol P8ZP_SCRATCH_REG
asl a
rol P8ZP_SCRATCH_REG
asl a
rol P8ZP_SCRATCH_REG
asl a
rol P8ZP_SCRATCH_REG
sta cx16.r0
lda P8ZP_SCRATCH_B1
clc
adc P8ZP_SCRATCH_REG
sta cx16.r0+1
bcc +
inc cx16.r1
+ ; now add the value to this 24-bits number
lda cx16.r0
clc
adc P8ZP_SCRATCH_W1
sta cx16.r0
lda cx16.r0+1
adc P8ZP_SCRATCH_W1+1
sta cx16.r0+1
bcc +
inc cx16.r1
+ lda cx16.r1
rts
}}
}
}

View File

@ -28,7 +28,7 @@ verafx {
sub clear(ubyte vbank, uword vaddr, ubyte data, uword num_longwords) {
; use cached 4-byte write to quickly clear a portion of the video memory to a given byte value
; this routine is around 3 times faster as gfx2.clear_screen()
; this routine is around 3 times faster as gfx_hires4/gfx_lores.clear_screen()
cx16.VERA_CTRL = 0
cx16.VERA_ADDR_H = vbank | %00110000 ; 4-byte increment
cx16.VERA_ADDR_M = msb(vaddr)

View File

@ -142,7 +142,8 @@ class TestCompilerOnExamplesCx16: FunSpec({
"spotlight",
"starszoom",
"tehtriz",
"testgfx2",
"test_gfx_lores",
"test_gfx_hires4",
"testmonogfx",
),
listOf(false, true)

View File

@ -687,7 +687,7 @@ Bitmap graphics routines:
This library is available both on the C64 and the cx16.
It uses the ROM based graphics routines on the latter, and it is a very small library because of that.
On the cx16 there's also the ``gfx2`` library if you want more features and different screen modes. See below for that one.
On the cx16 there's also various other graphics modules if you want more features and different screen modes. See below for those.
Read the `graphics source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/c64/graphics.p8>`_
to see what's in there. (Note: slight variations for different compiler targets)
@ -899,9 +899,9 @@ Information about the exposed debug registers is in the `emulator's documentatio
monogfx (cx16 and virtual)
---------------------------
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.
- lores 320*240 or hires 640*480 bitmap mode, monochrome
- 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
- drawing and reading individual pixels
- drawing lines, rectangles, filled rectangles, circles, discs
@ -913,30 +913,25 @@ Read the `monogfx source code <https://github.com/irmen/prog8/tree/master/compil
to see what's in there.
gfx2 (cx16 only)
-----------------
gfx_lores and gfx_hires (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
- gfx_lores: optimized routines for 320x240 256 color bitmap graphics mode. Compatible with X16 screen mode 128.
- gfx_hires4: optimized routines for 640x480 4 color bitmap graphics mode
- bitmap mode
- enable bitmap graphics 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
Read the `gfx2 source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx2.p8>`_
to see what's in there.
gfx_lores (cx16 only)
----------------------
Heavily optimized graphics routines for just the single screen mode: lores 320*240, 256c (8bpp)
This is screen mode 1 from the gfx2 module (and also compatible with X16's basic screen mode 128).
Read the `gfx_lores source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_lores.p8>`_
or `gfx_hires4 source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/gfx_hires4.p8>`_
to see what's in there.
They share the same routines.
palette (cx16 only)
--------------------

View File

@ -1,8 +1,7 @@
TODO
====
Transform gfx2 into gfx_hires
Add a eor mode to gfx_lores / gfx_hires
Add a eor mode to gfx_lores / gfx_hires. Once that's done in gfx_lores, convert Paint to use this module
Improve register load order in subroutine call args assignments:
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
@ -53,7 +52,6 @@ Future Things and Ideas
Libraries:
- gfx2: add EOR mode support like in monogfx and see PAINT for inspiration. Self modifying code to keep it optimized?
- fix the problems in atari target, and flesh out its libraries.
- c128 target: make syslib more complete (missing kernal routines)?
- pet32 target: make syslib more complete (missing kernal routines)?

View File

@ -1,38 +1,38 @@
%import textio
%import palette
%import string
%import gfx2
%import gfx_hires4
; Mockup of a classic Amiga Workbench screen.
main {
sub start() {
gfx2.screen_mode(2) ; select 640*480 mode, 4 colors
gfx_hires4.graphics_mode() ; select 640*480 mode, 4 colors
mouse.set_pointer_image()
cx16.mouse_config(-1, 640/8, 240/8)
uword[4] amigacolors = [$aaa, $000, $fff, $68c] ; gray, black, white, lightblue
palette.set_rgb(amigacolors, len(amigacolors))
cx16.VERA_DC_VSCALE = 64 ; have the vertical resolution so it is 640*240 - more or less Amiga's default non interlaced mode
gfx2.text_charset(1)
gfx_hires4.text_charset(1)
screen_titlebar()
window_workbench()
window_system()
window_shell()
gfx2.text(280, 210, 1, iso:"640x480(240) 4 colors")
gfx2.text(280, 220, 1, iso:"Mockup drawn using Prog8 gfx2 library")
gfx_hires4.text(240, 210, 1, iso:"640x480(240) 4 colors")
gfx_hires4.text(240, 220, 1, iso:"Mockup drawn using Prog8 gfx_hires4 library")
repeat {
}
}
sub screen_titlebar() {
gfx2.fillrect(0, 0, gfx2.width, 10, 2)
gfx2.text(8,1, 1, iso:"AmigaOS 3.1 2,002,448 graphics mem 16,504,384 other mem")
gfx2.horizontal_line(0, 10, gfx2.width, 1)
widget.window_order_icon(gfx2.width-widget.window_order_icon.width, 0, false)
gfx_hires4.fillrect(0, 0, gfx_hires4.WIDTH, 10, 2)
gfx_hires4.text(8,1, 1, iso:"AmigaOS 3.1 2,002,448 graphics mem 16,504,384 other mem")
gfx_hires4.horizontal_line(0, 10, gfx_hires4.WIDTH, 1)
widget.window_order_icon(gfx_hires4.WIDTH-widget.window_order_icon.width, 0, false)
}
@ -43,25 +43,25 @@ main {
const uword height = 220
widget.window_titlebar(win_x, win_y, width, iso:"Workbench", false)
; gfx2.fillrect(win_x+3, win_y+11, width-4, height-11-2,0) ; clear window pane
; gfx_hires4.fillrect(win_x+3, win_y+11, width-4, height-11-2,0) ; clear window pane
widget.window_leftborder(win_x, win_y, height, false)
widget.window_bottomborder(win_x, win_y, width, height)
widget.window_rightborder(win_x, win_y, width, height, false)
vector_v(win_x+width - 390, win_y+height-20)
vector_v(win_x+width - 390 -14, win_y+height-20)
vector_v(win_x+width - 430, win_y+height-20)
vector_v(win_x+width - 430 -14, win_y+height-20)
widget.icon(45,40, iso:"Ram Disk")
widget.icon(45,90, iso:"Workbench3.1")
}
sub vector_v(uword x, uword y) {
gfx2.horizontal_line(x, y, 12, 1)
gfx2.horizontal_line(x+16, y+16, 11,1)
gfx2.line(x,y,x+16,y+16,1)
gfx2.line(x+11,y,x+16+5,y+10,1)
gfx2.line(x+16+5,y+10,x+47,y-16,1)
gfx2.line(x+16+10,y+16,x+46+12,y-16,1)
gfx_hires4.horizontal_line(x, y, 12, 1)
gfx_hires4.horizontal_line(x+16, y+16, 11,1)
gfx_hires4.line(x,y,x+16,y+16,1)
gfx_hires4.line(x+11,y,x+16+5,y+10,1)
gfx_hires4.line(x+16+5,y+10,x+47,y-16,1)
gfx_hires4.line(x+16+10,y+16,x+46+12,y-16,1)
}
sub window_system() {
@ -71,7 +71,7 @@ main {
const uword win_y = 40
widget.window_titlebar(win_x, win_y, width, iso:"System", false)
gfx2.fillrect(win_x+3, win_y+11, width-4, height-11-2, 0) ; clear window pane
gfx_hires4.fillrect(win_x+3, win_y+11, width-4, height-11-2, 0) ; clear window pane
widget.window_leftborder(win_x, win_y, height, false)
widget.window_bottomborder(win_x, win_y, width, height)
widget.window_rightborder(win_x, win_y, width, height, false)
@ -90,14 +90,14 @@ main {
const uword height = 65
widget.window_titlebar(win_x, win_y, width, iso:"AmigaShell", true)
gfx2.fillrect(win_x+3, win_y+11, width-4, height-11-2,0) ; clear window pane
gfx_hires4.fillrect(win_x+3, win_y+11, width-4, height-11-2,0) ; clear window pane
widget.window_leftborder(win_x, win_y, height, true)
widget.window_bottomborder(win_x, win_y, width, height)
widget.window_rightborder(win_x, win_y, width, height, true)
gfx2.text(win_x+5, win_y+12, 1, iso:"New Shell process 3")
gfx2.text(win_x+5, win_y+12+8, 1, iso:"3.Workbench3.1:>")
gfx2.fillrect(win_x+5+17*8, win_y+12+8, 8, 8, 1) ; cursor
gfx_hires4.text(win_x+5, win_y+12, 1, iso:"New Shell process 3")
gfx_hires4.text(win_x+5, win_y+12+8, 1, iso:"3.Workbench3.1:>")
gfx_hires4.fillrect(win_x+5+17*8, win_y+12+8, 8, 8, 1) ; cursor
}
}
@ -147,15 +147,15 @@ mouse {
widget {
sub highlightedrect(uword x, uword y, uword width, uword height, bool fill, bool active) {
gfx2.horizontal_line(x, y, width, 2)
gfx2.vertical_line(x, y+1, height-1, 2)
gfx2.vertical_line(x+width-1, y+1, height-1, 1)
gfx2.horizontal_line(x+1, y+height-1, width-2, 1)
gfx_hires4.horizontal_line(x, y, width, 2)
gfx_hires4.vertical_line(x, y+1, height-1, 2)
gfx_hires4.vertical_line(x+width-1, y+1, height-1, 1)
gfx_hires4.horizontal_line(x+1, y+height-1, width-2, 1)
if fill {
if active
gfx2.fillrect(x+1,y+1,width-2,height-2, 3)
gfx_hires4.fillrect(x+1,y+1,width-2,height-2, 3)
else
gfx2.fillrect(x+1,y+1,width-2,height-2, 0)
gfx_hires4.fillrect(x+1,y+1,width-2,height-2, 0)
}
}
@ -165,17 +165,17 @@ widget {
highlightedrect(x, y, width, height, false, false)
uword middlex = x+width/2+1
ubyte halfstring = string.length(caption) * 4
gfx2.text(middlex-halfstring,y+height+1,1,caption)
gfx2.disc(x+width/4+4, y+height/2, height/2-3, 1)
gfx2.fillrect(x+20,y+12,width/2,height/2-4,3)
gfx_hires4.text(middlex-halfstring,y+height+1,1,caption)
gfx_hires4.disc(x+width/4+4, y+height/2, height/2-3, 1)
gfx_hires4.fillrect(x+20,y+12,width/2,height/2-4,3)
}
sub window_titlebar(uword x, uword y, uword width, uword titlestr, bool active) {
const ubyte height = 11
widget.highlightedrect(x+widget.window_close_icon.width, y, width-64, height, true, active)
gfx2.plot(x+widget.window_close_icon.width, y+height-1, 1) ; correct bottom left corner
gfx2.text(x+26, y+1, 1, titlestr)
gfx_hires4.plot(x+widget.window_close_icon.width, y+height-1, 1) ; correct bottom left corner
gfx_hires4.text(x+26, y+1, 1, titlestr)
widget.window_close_icon(x, y, active)
widget.window_order_icon(x+width-22, y, active)
widget.window_flipsize_icon(x+width-44, y, active)
@ -185,66 +185,66 @@ widget {
const uword width = 22
const uword height = 11
highlightedrect(x, y, width, height, true, active)
gfx2.plot(x, y+height-1, 1) ; correct bottom left corner
gfx2.rect(x+5, y+2, width-9, height-4, 1)
gfx2.rect(x+5, y+2, 7, 4, 1)
gfx2.fillrect(x+6, y+3, 5, 2, 2)
gfx_hires4.plot(x, y+height-1, 1) ; correct bottom left corner
gfx_hires4.rect(x+5, y+2, width-9, height-4, 1)
gfx_hires4.rect(x+5, y+2, 7, 4, 1)
gfx_hires4.fillrect(x+6, y+3, 5, 2, 2)
}
sub window_order_icon(uword x, uword y, bool active) {
const uword width = 22
const uword height = 11
highlightedrect(x, y, width, height, true, active)
gfx2.plot(x, y+height-1, 1) ; correct bottom left corner
gfx2.rect(x+4, y+2, 10, 5, 1) ; back
gfx2.fillrect(x+9, y+5, 8, 3, 2) ; white front
gfx2.rect(x+8, y+4, 10, 5, 1) ; front
gfx_hires4.plot(x, y+height-1, 1) ; correct bottom left corner
gfx_hires4.rect(x+4, y+2, 10, 5, 1) ; back
gfx_hires4.fillrect(x+9, y+5, 8, 3, 2) ; white front
gfx_hires4.rect(x+8, y+4, 10, 5, 1) ; front
}
sub window_close_icon(uword x, uword y, bool active) {
const uword width = 20
const uword height = 11
highlightedrect(x, y, width, height, true, active)
gfx2.plot(x, y+height-1, 1) ; correct bottom left corner
gfx2.rect(x+7, y+3, 5, 5, 1)
gfx2.fillrect(x+8, y+4, 3, 3, 2)
gfx_hires4.plot(x, y+height-1, 1) ; correct bottom left corner
gfx_hires4.rect(x+7, y+3, 5, 5, 1)
gfx_hires4.fillrect(x+8, y+4, 3, 3, 2)
}
sub window_leftborder(uword x, uword y, uword height, bool active) {
gfx2.vertical_line(x, y, height, 2)
gfx_hires4.vertical_line(x, y, height, 2)
ubyte color = 0
if active
color = 3
gfx2.vertical_line(x+1, y+11, height-11, color)
gfx2.vertical_line(x+2, y+11, height-11, 1)
gfx_hires4.vertical_line(x+1, y+11, height-11, color)
gfx_hires4.vertical_line(x+2, y+11, height-11, 1)
}
sub window_bottomborder(uword x, uword y, uword width, uword height) {
gfx2.horizontal_line(x+3, y+height-2, width-3, 2)
gfx2.horizontal_line(x, y+height-1, width, 1)
gfx_hires4.horizontal_line(x+3, y+height-2, width-3, 2)
gfx_hires4.horizontal_line(x, y+height-1, width, 1)
}
sub window_rightborder(uword x, uword y, uword width, uword height, bool active) {
gfx2.vertical_line(x+width-1-16, y+11, height-13,2)
gfx2.vertical_line(x+width-1, y+11, height-11,1)
gfx_hires4.vertical_line(x+width-1-16, y+11, height-13,2)
gfx_hires4.vertical_line(x+width-1, y+11, height-11,1)
ubyte color = 0
if active
color = 3
gfx2.fillrect(x+width-1-15, y+11, 15, height-12, color)
gfx_hires4.fillrect(x+width-1-15, y+11, 15, height-12, color)
gfx2.horizontal_line(x+width-1-13, y+height-3, 11, 1)
gfx2.vertical_line(x+width-1-3, y+height-3-5, 5, 1)
gfx2.line(x+width-1-13,y+height-3, x+width-1-3, y+height-3-5, 1)
gfx2.horizontal_line(x+width-1-16, y+height-10, 16, 2)
gfx_hires4.horizontal_line(x+width-1-13, y+height-3, 11, 1)
gfx_hires4.vertical_line(x+width-1-3, y+height-3-5, 5, 1)
gfx_hires4.line(x+width-1-13,y+height-3, x+width-1-3, y+height-3-5, 1)
gfx_hires4.horizontal_line(x+width-1-16, y+height-10, 16, 2)
highlightedrect(x+width-13, y+12, 10, height-43, false, false)
gfx2.horizontal_line(x+width-1-16, y+height-11, 16, 1)
gfx2.horizontal_line(x+width-1-16, y+height-20, 16, 2)
gfx2.horizontal_line(x+width-1-16, y+height-21, 16, 1)
gfx2.horizontal_line(x+width-1-16, y+height-30, 16, 2)
gfx2.line(x+width-1-13, y+height-23, x+width-9, y+height-28, 1)
gfx2.line(x+width-1-3, y+height-23, x+width-9, y+height-28, 1)
gfx2.line(x+width-1-13, y+height-18, x+width-9, y+height-13, 1)
gfx2.line(x+width-1-3, y+height-18, x+width-9, y+height-13, 1)
gfx_hires4.horizontal_line(x+width-1-16, y+height-11, 16, 1)
gfx_hires4.horizontal_line(x+width-1-16, y+height-20, 16, 2)
gfx_hires4.horizontal_line(x+width-1-16, y+height-21, 16, 1)
gfx_hires4.horizontal_line(x+width-1-16, y+height-30, 16, 2)
gfx_hires4.line(x+width-1-13, y+height-23, x+width-9, y+height-28, 1)
gfx_hires4.line(x+width-1-3, y+height-23, x+width-9, y+height-28, 1)
gfx_hires4.line(x+width-1-13, y+height-18, x+width-9, y+height-13, 1)
gfx_hires4.line(x+width-1-3, y+height-18, x+width-9, y+height-13, 1)
}
}

View File

@ -1,4 +1,4 @@
%import gfx2
%import gfx_lores
%import math
@ -12,11 +12,11 @@ main {
ubyte background_color
sub start() {
gfx2.screen_mode(1)
gfx_lores.graphics_mode()
repeat {
background_color = math.rnd()
gfx2.clear_screen(background_color)
gfx_lores.clear_screen(background_color)
num_circles = 0
draw_circles()
}
@ -28,8 +28,8 @@ main {
ubyte @zp radius
while num_circles<MAX_NUM_CIRCLES {
x = math.rndw() % gfx2.width
y = math.rndw() % gfx2.height
x = math.rndw() % gfx_lores.WIDTH
y = math.rndw() % gfx_lores.HEIGHT
radius = GROWTH_RATE * 2 ; use a bit of a buffer between circles.
if not_colliding() {
radius -= GROWTH_RATE
@ -37,7 +37,7 @@ main {
while color==background_color
color = math.rnd()
while not_edge() and not_colliding() {
gfx2.disc(x, y as ubyte, radius, color)
gfx_lores.disc(x, y as ubyte, radius, color)
sys.waitvsync()
radius += GROWTH_RATE
}
@ -70,11 +70,11 @@ main {
sub not_edge() -> bool {
if x as word - radius < 0
return false
if x + radius >= gfx2.width
if x + radius >= gfx_lores.WIDTH
return false
if y as word - radius < 0
return false
if y + radius >= gfx2.height
if y + radius >= gfx_lores.HEIGHT
return false
return true
}

View File

@ -1,6 +1,6 @@
%import palette
%import math
%import gfx2
%import gfx_lores
%option no_sysinit
; Vertical rasterbars a.k.a. "Kefren bars"
@ -22,7 +22,7 @@ main {
]
palette.set_rgb(&colors, len(colors))
gfx2.screen_mode(1) ; lores 256 colors
gfx_lores.graphics_mode() ; lores 256 colors
cx16.VERA_DC_VSCALE = 0 ; display trick spoiler.......: stretch 1 line of display all the way to the bottom
cx16.enable_irq_handlers(true)
cx16.set_line_irq_handler(0, &irq.irqhandler)
@ -54,15 +54,15 @@ irq {
anim2 = av2
next_irq_line = 0
; erase the bars
gfx2.horizontal_line(0, 0, 320, 3)
; gfx2.position(0, 0)
gfx_lores.horizontal_line(0, 0, 320, 3)
; gfx_lores.position(0, 0)
; repeat 10 {
; gfx2.next_pixels(pixels, len(pixels))
; gfx_lores.next_pixels(pixels, len(pixels))
; }
} else {
; add new bar on top
gfx2.position(math.sin8u(anim1)/2 + math.cos8u(anim2)/2 + $0010, 0)
gfx2.next_pixels(pixels, len(pixels))
gfx_lores.position(math.sin8u(anim1)/2 + math.cos8u(anim2)/2 + $0010, 0)
gfx_lores.next_pixels(pixels, len(pixels))
}
sys.set_rasterline(next_irq_line)

View File

@ -1,21 +1,21 @@
%import math
%import gfx2
%import gfx_lores
main {
sub start() {
gfx2.screen_mode(1)
gfx_lores.graphics_mode()
uword[128] @split flakes1_xx
uword[128] @split flakes1_yy
ubyte[128] flakes1_yy
uword[128] @split flakes2_xx
uword[128] @split flakes2_yy
ubyte[128] flakes2_yy
ubyte @zp idx
for idx in 0 to 127 {
flakes1_xx[idx] = math.rndw() % 320
flakes1_yy[idx] = math.rndw() % 240
flakes1_yy[idx] = math.rnd() % 240
flakes2_xx[idx] = math.rndw() % 320
flakes2_yy[idx] = math.rndw() % 240
flakes2_yy[idx] = math.rnd() % 240
}
draw_screen()
@ -28,18 +28,19 @@ main {
repeat {
for idx in 0 to len(flakes1_xx)-1 {
gfx2.plot(flakes1_xx[idx], flakes1_yy[idx], FALLING_SNOW_COLOR)
gfx2.plot(flakes2_xx[idx], flakes2_yy[idx], FALLING_SNOW_COLOR2)
gfx_lores.plot(flakes1_xx[idx], flakes1_yy[idx], FALLING_SNOW_COLOR)
gfx_lores.plot(flakes2_xx[idx], flakes2_yy[idx], FALLING_SNOW_COLOR2)
}
sys.waitvsync()
sys.waitvsync()
for idx in 0 to len(flakes1_xx)-1 {
if flakes1_yy[idx]==239 {
; reached the floor
gfx2.plot(flakes1_xx[idx], flakes1_yy[idx], PILED_SNOW_COLOR)
gfx_lores.plot(flakes1_xx[idx], flakes1_yy[idx], PILED_SNOW_COLOR)
flakes1_yy[idx] = 0
flakes1_xx[idx] = math.rndw() % 320
} else if gfx2.pget(flakes1_xx[idx], flakes1_yy[idx]+1) in PILED_SNOW_COLORS {
} else if gfx_lores.pget(flakes1_xx[idx], flakes1_yy[idx]+1) in PILED_SNOW_COLORS {
; pile up
; TODO somehow prevent growing horizontally/diagonally like a crystal
uword @zp snowx = flakes1_xx[idx]
@ -53,23 +54,23 @@ main {
pilex1 = snowx+1
pilex2 = snowx-1
}
ubyte pixel_side1 = gfx2.pget(pilex1, flakes1_yy[idx]+1)
ubyte pixel_side2 = gfx2.pget(pilex2, flakes1_yy[idx]+1)
ubyte pixel_side1 = gfx_lores.pget(pilex1, flakes1_yy[idx]+1)
ubyte pixel_side2 = gfx_lores.pget(pilex2, flakes1_yy[idx]+1)
if pixel_side1 == 0 or pixel_side1 == FALLING_SNOW_COLOR2 {
gfx2.plot(snowx, flakes1_yy[idx], 0)
gfx2.plot(pilex1, flakes1_yy[idx]+1, PILED_SNOW_COLOR)
gfx_lores.plot(snowx, flakes1_yy[idx], 0)
gfx_lores.plot(pilex1, flakes1_yy[idx]+1, PILED_SNOW_COLOR)
} else if pixel_side2 == 0 or pixel_side2 == FALLING_SNOW_COLOR2 {
gfx2.plot(snowx, flakes1_yy[idx], 0)
gfx2.plot(pilex2, flakes1_yy[idx]+1, PILED_SNOW_COLOR)
gfx_lores.plot(snowx, flakes1_yy[idx], 0)
gfx_lores.plot(pilex2, flakes1_yy[idx]+1, PILED_SNOW_COLOR)
} else {
gfx2.plot(snowx, flakes1_yy[idx], PILED_SNOW_COLOR)
gfx_lores.plot(snowx, flakes1_yy[idx], PILED_SNOW_COLOR)
}
}
flakes1_yy[idx] = 0
flakes1_xx[idx] = math.rndw() % 320
} else {
; fall
gfx2.plot(flakes1_xx[idx], flakes1_yy[idx], 0)
gfx_lores.plot(flakes1_xx[idx], flakes1_yy[idx], 0)
flakes1_yy[idx]++
when math.rnd() & 3 {
1 -> {
@ -93,13 +94,13 @@ main {
; reached the floor, don't pile up just fall again
flakes2_yy[idx] = 0
flakes2_xx[idx] = math.rndw() % 320
} else if gfx2.pget(flakes2_xx[idx], flakes2_yy[idx]+1) in PILED_SNOW_COLORS {
} else if gfx_lores.pget(flakes2_xx[idx], flakes2_yy[idx]+1) in PILED_SNOW_COLORS {
; reached an obstruction, don't pile up just fall again
flakes2_yy[idx] = 0
flakes2_xx[idx] = math.rndw() % 320
} else {
; fall normally
gfx2.plot(flakes2_xx[idx], flakes2_yy[idx], 0)
gfx_lores.plot(flakes2_xx[idx], flakes2_yy[idx], 0)
flakes2_yy[idx]+=1
when math.rnd() & 3 {
1 -> {
@ -121,10 +122,10 @@ main {
}
sub draw_screen() {
gfx2.text(32, 130, 2, sc: "******************" )
gfx2.text(40, 140, 5, sc: "happy holidays !" )
gfx2.text(32, 150, 5, sc: "from commander x16" )
gfx2.text(32, 160, 2, sc: "******************" )
gfx_lores.text(32, 130, 2, sc: "******************" )
gfx_lores.text(40, 140, 5, sc: "happy holidays !" )
gfx_lores.text(32, 150, 5, sc: "from commander x16" )
gfx_lores.text(32, 160, 2, sc: "******************" )
; draw a tree
@ -132,11 +133,11 @@ main {
ubyte maxwidth = 20
ubyte branchesy = 100
gfx2.fillrect(TREEX-5, 210, 10, 30, 9)
gfx_lores.fillrect(TREEX-5, 210, 10, 30, 9)
repeat 5 {
ubyte width
for width in 1 to maxwidth {
gfx2.horizontal_line(TREEX-width/2, branchesy, width, 5)
gfx_lores.horizontal_line(TREEX-width/2, branchesy, width, 5)
branchesy++
}
branchesy -= maxwidth/2

View File

@ -0,0 +1,73 @@
%import gfx_hires4
%import textio
%import math
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
gfx_hires4.graphics_mode()
draw()
sys.wait(120)
gfx_hires4.text_mode()
txt.print("done!\n")
}
sub draw() {
gfx_hires4.rect(10,10, 1, 1, 4)
gfx_hires4.rect(20,10, 2, 1, 4)
gfx_hires4.rect(30,10, 3, 1, 4)
gfx_hires4.rect(40,10, 1, 2, 4)
gfx_hires4.rect(50,10, 1, 3, 4)
gfx_hires4.rect(60,10, 2, 2, 4)
gfx_hires4.rect(70,10, 3, 3, 4)
gfx_hires4.rect(80,10, 4, 4, 4)
gfx_hires4.rect(90,10, 5, 5, 4)
gfx_hires4.rect(100,10, 8, 8, 4)
gfx_hires4.rect(110,10, 20, 5, 4)
gfx_hires4.rect(80, 80, 200, 140, 4)
gfx_hires4.fillrect(10,40, 1, 1, 5)
gfx_hires4.fillrect(20,40, 2, 1, 5)
gfx_hires4.fillrect(30,40, 3, 1, 5)
gfx_hires4.fillrect(40,40, 1, 2, 5)
gfx_hires4.fillrect(50,40, 1, 3, 5)
gfx_hires4.fillrect(60,40, 2, 2, 5)
gfx_hires4.fillrect(70,40, 3, 3, 5)
gfx_hires4.fillrect(80,40, 4, 4, 5)
gfx_hires4.fillrect(90,40, 5, 5, 5)
gfx_hires4.fillrect(100,40, 8, 8, 5)
gfx_hires4.fillrect(110,40, 20, 5, 5)
gfx_hires4.fillrect(82, 82, 200-4, 140-4, 5)
ubyte i
for i in 0 to 254 step 4 {
uword x1 = ((gfx_hires4.WIDTH-256)/2 as uword) + math.sin8u(i)
uword y1 = (gfx_hires4.HEIGHT-128)/2 + math.cos8u(i)/2
uword x2 = ((gfx_hires4.WIDTH-64)/2 as uword) + math.sin8u(i)/4
uword y2 = (gfx_hires4.HEIGHT-64)/2 + math.cos8u(i)/4
gfx_hires4.line(x1, y1, x2, y2, i+1)
}
sys.wait(60)
gfx_hires4.clear_screen(2)
gfx_hires4.clear_screen(0)
ubyte radius
for radius in 110 downto 8 step -4 {
gfx_hires4.circle(gfx_hires4.WIDTH/2, (gfx_hires4.HEIGHT/2 as ubyte), radius, radius)
}
gfx_hires4.disc(gfx_hires4.WIDTH/2, gfx_hires4.HEIGHT/2, 80, 2)
ubyte tp
for tp in 0 to 15 {
gfx_hires4.text(19+tp,20+tp*11, 7, sc:"ScreenCODE text! 1234![]<>#$%&*()")
}
}
}

View File

@ -0,0 +1,93 @@
%import gfx_lores
%import textio
%import math
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
demofill()
sys.wait(120)
demo2()
gfx_lores.text_mode()
txt.print("done!\n")
}
sub demofill() {
gfx_lores.graphics_mode()
gfx_lores.circle(160, 120, 110, 1)
gfx_lores.rect(180, 5, 25, 190, 1)
gfx_lores.line(100, 150, 240, 10, 1)
gfx_lores.line(101, 150, 241, 10, 1)
sys.wait(60)
gfx_lores.fill(100,100,2)
gfx_lores.fill(182,140,3)
gfx_lores.fill(182,40,1)
}
sub demo2 () {
gfx_lores.text_charset(3)
draw()
sys.wait(120)
}
sub draw() {
gfx_lores.rect(10,10, 1, 1, 4)
gfx_lores.rect(20,10, 2, 1, 4)
gfx_lores.rect(30,10, 3, 1, 4)
gfx_lores.rect(40,10, 1, 2, 4)
gfx_lores.rect(50,10, 1, 3, 4)
gfx_lores.rect(60,10, 2, 2, 4)
gfx_lores.rect(70,10, 3, 3, 4)
gfx_lores.rect(80,10, 4, 4, 4)
gfx_lores.rect(90,10, 5, 5, 4)
gfx_lores.rect(100,10, 8, 8, 4)
gfx_lores.rect(110,10, 20, 5, 4)
gfx_lores.rect(80, 80, 200, 140, 4)
gfx_lores.fillrect(10,40, 1, 1, 5)
gfx_lores.fillrect(20,40, 2, 1, 5)
gfx_lores.fillrect(30,40, 3, 1, 5)
gfx_lores.fillrect(40,40, 1, 2, 5)
gfx_lores.fillrect(50,40, 1, 3, 5)
gfx_lores.fillrect(60,40, 2, 2, 5)
gfx_lores.fillrect(70,40, 3, 3, 5)
gfx_lores.fillrect(80,40, 4, 4, 5)
gfx_lores.fillrect(90,40, 5, 5, 5)
gfx_lores.fillrect(100,40, 8, 8, 5)
gfx_lores.fillrect(110,40, 20, 5, 5)
gfx_lores.fillrect(82, 82, 200-4, 140-4, 5)
ubyte i
for i in 0 to 254 step 4 {
uword x1 = ((gfx_lores.WIDTH-256)/2 as uword) + math.sin8u(i)
ubyte y1 = (gfx_lores.HEIGHT-128)/2 + math.cos8u(i)/2
uword x2 = ((gfx_lores.WIDTH-64)/2 as uword) + math.sin8u(i)/4
ubyte y2 = (gfx_lores.HEIGHT-64)/2 + math.cos8u(i)/4
gfx_lores.line(x1, y1, x2, y2, i+1)
}
sys.wait(60)
gfx_lores.clear_screen(2)
gfx_lores.clear_screen(0)
ubyte radius
for radius in 110 downto 8 step -4 {
gfx_lores.circle(gfx_lores.WIDTH/2, (gfx_lores.HEIGHT/2 as ubyte), radius, radius)
}
gfx_lores.disc(gfx_lores.WIDTH/2, gfx_lores.HEIGHT/2, 80, 2)
ubyte tp
for tp in 0 to 15 {
gfx_lores.text(19+tp,20+tp*11, 7, sc:"ScreenCODE text! 1234![]<>#$%&*()")
}
}
}

View File

@ -1,98 +0,0 @@
%import gfx2
%import textio
%import math
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
gfx2.screen_mode(1)
demofill()
sys.wait(120)
demo2()
gfx2.screen_mode(0)
txt.print("done!\n")
}
sub demofill() {
gfx2.circle(160, 120, 110, 1)
gfx2.rect(180, 5, 25, 190, 1)
gfx2.line(100, 150, 240, 10, 1)
gfx2.line(101, 150, 241, 10, 1)
sys.wait(60)
gfx2.fill(100,100,2)
gfx2.fill(182,140,3)
gfx2.fill(182,40,1)
}
sub demo2 () {
gfx2.text_charset(3)
gfx2.screen_mode(1)
draw()
sys.wait(120)
gfx2.screen_mode(2)
draw()
sys.wait(120)
}
sub draw() {
gfx2.rect(10,10, 1, 1, 4)
gfx2.rect(20,10, 2, 1, 4)
gfx2.rect(30,10, 3, 1, 4)
gfx2.rect(40,10, 1, 2, 4)
gfx2.rect(50,10, 1, 3, 4)
gfx2.rect(60,10, 2, 2, 4)
gfx2.rect(70,10, 3, 3, 4)
gfx2.rect(80,10, 4, 4, 4)
gfx2.rect(90,10, 5, 5, 4)
gfx2.rect(100,10, 8, 8, 4)
gfx2.rect(110,10, 20, 5, 4)
gfx2.rect(80, 80, 200, 140, 4)
gfx2.fillrect(10,40, 1, 1, 5)
gfx2.fillrect(20,40, 2, 1, 5)
gfx2.fillrect(30,40, 3, 1, 5)
gfx2.fillrect(40,40, 1, 2, 5)
gfx2.fillrect(50,40, 1, 3, 5)
gfx2.fillrect(60,40, 2, 2, 5)
gfx2.fillrect(70,40, 3, 3, 5)
gfx2.fillrect(80,40, 4, 4, 5)
gfx2.fillrect(90,40, 5, 5, 5)
gfx2.fillrect(100,40, 8, 8, 5)
gfx2.fillrect(110,40, 20, 5, 5)
gfx2.fillrect(82, 82, 200-4, 140-4, 5)
ubyte i
for i in 0 to 254 step 4 {
uword x1 = ((gfx2.width-256)/2 as uword) + math.sin8u(i)
uword y1 = (gfx2.height-128)/2 + math.cos8u(i)/2
uword x2 = ((gfx2.width-64)/2 as uword) + math.sin8u(i)/4
uword y2 = (gfx2.height-64)/2 + math.cos8u(i)/4
gfx2.line(x1, y1, x2, y2, i+1)
}
sys.wait(60)
gfx2.clear_screen(2)
gfx2.clear_screen(0)
ubyte radius
for radius in 110 downto 8 step -4 {
gfx2.circle(gfx2.width/2, (gfx2.height/2 as ubyte), radius, radius)
}
gfx2.disc(gfx2.width/2, gfx2.height/2, 80, 2)
ubyte tp
for tp in 0 to 15 {
gfx2.text(19+tp,20+tp*11, 7, sc:"ScreenCODE text! 1234![]<>#$%&*()")
}
}
}

View File

@ -1,35 +1,15 @@
%import textio
%import gfx2
%import gfx_lores
%import gfx_hires4
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
gfx_lores.graphics_mode()
; gfx2.screen_mode(1)
gfx_lores.text_charset(1)
for cx16.r9L in 0 to 10 {
gfx_lores.text(50+cx16.r9L, 20+cx16.r9L, cx16.r9L, sc:"the quick brown fox 12345")
}
gfx_lores.text_charset(2)
for cx16.r9L in 0 to 10 {
gfx_lores.text(50+cx16.r9L, 40+cx16.r9L, cx16.r9L, sc:"the quick brown fox 12345")
}
gfx_lores.text_charset(3)
for cx16.r9L in 0 to 10 {
gfx_lores.text(50+cx16.r9L, 60+cx16.r9L, cx16.r9L, sc:"the quick brown fox 12345")
}
gfx_lores.text_charset(4)
for cx16.r9L in 0 to 10 {
gfx_lores.text(50+cx16.r9L, 80+cx16.r9L, cx16.r9L, sc:"the quick brown fox 12345")
}
gfx_lores.text_charset(5)
for cx16.r9L in 0 to 10 {
gfx_lores.text(50+cx16.r9L, 100+cx16.r9L, cx16.r9L, sc:"the quick brown fox 12345")
}
gfx_hires4.graphics_mode()
gfx_hires4.circle(300, 250, 200, 3)
gfx_hires4.rect(320, 10, 20, 200, 3)
gfx_hires4.fill(310, 310, 2)
repeat {
}