imageviewer now uses gfx2 for full-screen graphics. gfx2 promoted to built-in library on the cx16 target.

This commit is contained in:
Irmen de Jong 2020-12-25 17:00:11 +01:00
parent 4c1c595f14
commit 6734ae3c88
9 changed files with 251 additions and 173 deletions

View File

@ -1,9 +1,4 @@
%target cx16
%import textio
%import graphics
%import test_stack
%zeropage basicsafe
%option no_sysinit
; Bitmap pixel graphics module for the CommanderX16
; Custom routines to use the full-screen 640x480 and 320x240 screen modes.
@ -11,54 +6,55 @@
; For compatible graphics code that words on C64 too, use the "graphics" module instead.
; TODO this is in development.
; TODO this is in development. Add line drawing, circles and discs (like the graphics module has)
main {
sub start () {
ubyte[] modes = [0, 1, 128]
ubyte mode
for mode in modes {
gfx2.set_mode(mode)
; gfx2.location(20, 50)
;main {
;
; sub start () {
; ubyte[] modes = [0, 1, 128]
; ubyte mode
; for mode in modes {
; gfx2.set_mode(mode)
;
; gfx2.position(20, 50)
; repeat 200 {
; gfx2.next_pixel(255)
; }
;
; draw()
; cx16.wait(120)
; }
; }
;
; sub draw() {
; uword offset
; ubyte angle
; uword x
; uword y
; when gfx2.active_mode {
; 0, 1 -> {
; for offset in 0 to 90 step 3 {
; for angle in 0 to 255 {
; x = $0008+sin8u(angle)/2
; y = $0008+cos8u(angle)/2
; gfx2.plot(x+offset*2,y+offset, lsb(x+y))
; }
; }
; }
; 128 -> {
; for offset in 0 to 190 step 6 {
; for angle in 0 to 255 {
; x = $0008+sin8u(angle)
; y = $0008+cos8u(angle)
; gfx2.plot(x+offset*2,y+offset, 1)
; }
; }
; }
; }
; }
;}
draw()
cx16.wait(120)
}
}
sub draw() {
uword offset
ubyte angle
uword x
uword y
when gfx2.active_mode {
0, 1 -> {
for offset in 0 to 90 step 3 {
for angle in 0 to 255 {
x = $0008+sin8u(angle)/2
y = $0008+cos8u(angle)/2
gfx2.plot(x+offset*2,y+offset, lsb(x+y))
}
}
}
128 -> {
for offset in 0 to 190 step 6 {
for angle in 0 to 255 {
x = $0008+sin8u(angle)
y = $0008+cos8u(angle)
gfx2.plot(x+offset*2,y+offset, 1)
}
}
}
}
}
}
gfx2 {
@ -111,16 +107,22 @@ gfx2 {
height = 480
bpp = 1
}
255 -> {
; back to default text mode and colors
cx16.VERA_CTRL = %10000000 ; reset VERA and palette
c64.CINT() ; back to text mode
width = 0
height = 0
bpp = 0
}
}
active_mode = mode
clear_screen()
if bpp
clear_screen()
}
sub clear_screen() {
cx16.VERA_CTRL = 0
cx16.VERA_ADDR_H = %00010000
cx16.VERA_ADDR_M = 0
cx16.VERA_ADDR_L = 0
position(0, 0)
when active_mode {
0 -> {
; 320 x 240 x 1c
@ -138,6 +140,7 @@ gfx2 {
cs_innerloop640()
}
}
position(0, 0)
}
sub plot(uword x, uword y, ubyte color) {
@ -148,17 +151,17 @@ gfx2 {
0 -> {
addr = x/8 + y*(320/8)
value = bits[lsb(x)&7]
cx16.vpoke_or(addr, 0, value)
cx16.vpoke_or(0, addr, value)
}
128 -> {
addr = x/8 + y*(640/8)
value = bits[lsb(x)&7]
cx16.vpoke_or(addr, 0, value)
cx16.vpoke_or(0, addr, value)
}
1 -> {
void addr_mul_320_add_24(y, x) ; 24 bits result is in r0 and r1L
ubyte bank = lsb(cx16.r1)
cx16.vpoke(cx16.r0, bank, color)
cx16.vpoke(bank, cx16.r0, color)
}
}
; activate vera auto-increment mode so next_pixel() can be used after this
@ -166,21 +169,21 @@ gfx2 {
return
}
sub location(uword x, uword y) {
sub position(uword x, uword y) {
uword address
when active_mode {
0 -> {
address = y*(320/8) + x/8
cx16.vaddr(address, 0, 0, 1)
cx16.vaddr(0, address, 0, 1)
}
128 -> {
address = y*(640/8) + x/8
cx16.vaddr(address, 0, 0, 1)
cx16.vaddr(0, address, 0, 1)
}
1 -> {
void addr_mul_320_add_24(y, x) ; 24 bits result is in r0 and r1L
ubyte bank = lsb(cx16.r1)
cx16.vaddr(cx16.r0, bank, 0, 1)
cx16.vaddr(bank, cx16.r0, 0, 1)
}
}
}
@ -207,6 +210,22 @@ gfx2 {
}
}
asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) {
%asm {{
phx
ldx #8
- asl cx16.r0
bcc +
sta cx16.VERA_DATA0
bra ++
+ sty cx16.VERA_DATA0
+ dex
bne -
plx
rts
}}
}
asmsub cs_innerloop640() {
%asm {{
ldy #80

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import diskio
bmp_module {
@ -46,7 +46,7 @@ bmp_module {
total_read += size
repeat bm_data_offset - total_read
void c64.CHRIN()
graphics.clear_screen(1, 0)
gfx2.clear_screen()
palette.set_bgra(&palette0, num_colors)
decode_bitmap()
load_ok = true
@ -62,14 +62,14 @@ bmp_module {
sub start_plot() {
offsetx = 0
offsety = 0
if width < graphics.WIDTH
offsetx = (graphics.WIDTH - width - 1) / 2
if height < graphics.HEIGHT
offsety = (graphics.HEIGHT - height - 1) / 2
if width > graphics.WIDTH
width = graphics.WIDTH
if height > graphics.HEIGHT-1
height = graphics.HEIGHT-1
if width < gfx2.width
offsetx = (gfx2.width - width - 1) / 2
if height < gfx2.height
offsety = (gfx2.height - height - 1) / 2
if width > gfx2.width
width = gfx2.width
if height > gfx2.height
height = gfx2.height
}
sub decode_bitmap() {
@ -81,31 +81,31 @@ bmp_module {
uword y
ubyte b
for y in height-1 downto 0 {
cx16.FB_cursor_position(offsetx, offsety+y)
gfx2.position(offsetx, offsety+y)
when bpp {
8 -> {
for x in 0 to width-1
cx16.FB_set_pixel(c64.CHRIN())
gfx2.next_pixel(c64.CHRIN())
}
4 -> {
for x in 0 to width-1 step 2 {
b = c64.CHRIN()
cx16.FB_set_pixel(b>>4)
cx16.FB_set_pixel(b&15)
gfx2.next_pixel(b>>4)
gfx2.next_pixel(b&15)
}
}
2 -> {
for x in 0 to width-1 step 4 {
b = c64.CHRIN()
cx16.FB_set_pixel(b>>6)
cx16.FB_set_pixel(b>>4 & 3)
cx16.FB_set_pixel(b>>2 & 3)
cx16.FB_set_pixel(b & 3)
gfx2.next_pixel(b>>6)
gfx2.next_pixel(b>>4 & 3)
gfx2.next_pixel(b>>2 & 3)
gfx2.next_pixel(b & 3)
}
}
1 -> {
for x in 0 to width-1 step 8
cx16.FB_set_8_pixels_opaque(c64.CHRIN(), 255, 255, 0)
gfx2.set_8_pixels_from_bits(c64.CHRIN(), 1, 0)
}
}

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import textio
%import diskio
%option no_sysinit
@ -77,7 +77,7 @@ ci_module {
uword palette_size = num_colors*2
if palette_format
palette_size += num_colors ; 3
if width > graphics.WIDTH {
if width > gfx2.width {
txt.print("image is too wide for the display!\n")
} else if compression!=0 {
txt.print("compressed image not yet supported!\n") ; TODO implement the various decompressions
@ -91,23 +91,20 @@ ci_module {
} else {
; uncompressed bitmap data. read it a scanline at a time and display as we go.
; restrict height to the maximun that can be displayed
if height > graphics.HEIGHT
height = graphics.HEIGHT
graphics.enable_bitmap_mode()
if height > gfx2.height
height = gfx2.height
if palette_format
palette.set_rgb8(buffer, num_colors)
else
palette.set_rgb4(buffer, num_colors)
graphics.clear_screen(1,0)
cx16.r0 = 0
cx16.r1 = 0
cx16.FB_cursor_position()
gfx2.clear_screen()
gfx2.position(0 ,0)
uword scanline_size = width * bpp / 8
ubyte y
for y in 0 to lsb(height)-1 {
void diskio.f_read(buffer, scanline_size)
when bpp {
8 -> cx16.FB_set_pixels_from_buf(buffer, scanline_size) ; FB_set_pixels in rom v38 crashes with a size > 255 so we use our own replacement for now
8 -> gfx2.next_pixels(buffer, scanline_size)
4 -> display_scanline_16c(buffer, scanline_size)
2 -> display_scanline_4c(buffer, scanline_size)
1 -> display_scanline_2c(buffer, scanline_size)

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import textio
%import diskio
@ -104,7 +104,7 @@ iff_module {
skip_chunk()
}
else if chunk_id == "body" {
graphics.clear_screen(1, 0)
gfx2.clear_screen()
if camg & $0004
height /= 2 ; interlaced: just skip every odd scanline later
if camg & $0080 and have_cmap
@ -178,14 +178,14 @@ iff_module {
interleave_stride = (bitplane_stride as uword) * num_planes
offsetx = 0
offsety = 0
if width < graphics.WIDTH
offsetx = (graphics.WIDTH - width - 1) / 2
if height < graphics.HEIGHT
offsety = (graphics.HEIGHT - height - 1) / 2
if width > graphics.WIDTH
width = graphics.WIDTH
if height > graphics.HEIGHT-1
height = graphics.HEIGHT-1
if width < gfx2.width
offsetx = (gfx2.width - width - 1) / 2
if height < gfx2.height
offsety = (gfx2.height - height - 1) / 2
if width > gfx2.width
width = gfx2.width
if height > gfx2.height
height = gfx2.height
}
sub decode_raw() {
@ -196,7 +196,7 @@ iff_module {
diskio.f_read_exact(scanline_data_ptr, interleave_stride)
if interlaced
diskio.f_read_exact(scanline_data_ptr, interleave_stride)
cx16.FB_cursor_position(offsetx, offsety+y)
gfx2.position(offsetx, offsety+y)
planar_to_chunky_scanline()
}
}
@ -209,7 +209,7 @@ iff_module {
decode_rle_scanline()
if interlaced
decode_rle_scanline()
cx16.FB_cursor_position(offsetx, offsety+y)
gfx2.position(offsetx, offsety+y)
planar_to_chunky_scanline()
}
}
@ -296,7 +296,7 @@ _masks .byte 128, 64, 32, 16, 8, 4, 2, 1
; }
; bits >>= 8-num_planes
cx16.FB_set_pixel(bits)
gfx2.next_pixel(bits)
}
}
}
@ -305,6 +305,8 @@ _masks .byte 128, 64, 32, 16, 8, 4, 2, 1
if num_cycles==0
return
; TODO implement Blend Shifting see http://www.effectgames.com/demos/canvascycle/palette.js
ubyte changed = false
ubyte ci
for ci in 0 to num_cycles-1 {

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import textio
%import diskio
%import koala_module
@ -10,8 +10,6 @@
%zeropage basicsafe
; TODO use the gfx2 graphics module for full-screen 320x240 display instead of 320x200 truncated.
main {
sub start() {
; trick to check if we're running on sdcard or host system shared folder
@ -19,20 +17,19 @@ main {
if strlen(diskio.status(8)) {
txt.print("enter image file name or just enter for all on disk: ")
ubyte i = txt.input_chars(diskio.filename)
graphics.enable_bitmap_mode()
gfx2.set_mode(1) ; 320*240, 256c
if i
attempt_load(diskio.filename)
else
show_pics_sdcard()
txt.print("\nnothing more to do.\n")
; txt.print("\nnothing more to do.\n")
}
else
txt.print("files are read with sequential file loading.\nin the emulator this currently only works with files on an sd-card image.\nsorry :(\n")
repeat {
;
}
gfx2.set_mode(255) ; back to default text mode and palette
txt.print("that was all folks!\n")
}
sub show_pics_sdcard() {
@ -53,64 +50,71 @@ main {
}
sub attempt_load(uword filenameptr) {
txt.print(">> ")
txt.print(filenameptr)
txt.chrout('\n')
;txt.print(">> ")
;txt.print(filenameptr)
;txt.chrout('\n')
uword extension = filenameptr + rfind(filenameptr, '.')
if strcmp(extension, ".iff")==0 {
txt.print("loading ")
txt.print("iff\n")
if iff_module.show_image(filenameptr)
txt.clear_screen()
else
txt.print("load error!\n")
if iff_module.num_cycles {
repeat 500 {
cx16.wait(1)
iff_module.cycle_colors_each_jiffy()
;txt.print("loading ")
;txt.print("iff\n")
if iff_module.show_image(filenameptr) {
if iff_module.num_cycles {
repeat 500 {
cx16.wait(1)
iff_module.cycle_colors_each_jiffy()
}
}
else
cx16.wait(180)
} else {
load_error(filenameptr)
}
else
cx16.wait(120)
}
else if strcmp(extension, ".pcx")==0 {
txt.print("loading ")
txt.print("pcx\n")
if pcx_module.show_image(filenameptr)
txt.clear_screen()
else
txt.print("load error!\n")
cx16.wait(120)
;txt.print("loading ")
;txt.print("pcx\n")
if pcx_module.show_image(filenameptr) {
cx16.wait(180)
} else {
load_error(filenameptr)
}
}
else if strcmp(extension, ".koa")==0 {
txt.print("loading ")
txt.print("koala\n")
if koala_module.show_image(filenameptr)
txt.clear_screen()
else
txt.print("load error!\n")
cx16.wait(120)
;txt.print("loading ")
;txt.print("koala\n")
if koala_module.show_image(filenameptr) {
cx16.wait(180)
} else {
load_error(filenameptr)
}
}
else if strcmp(extension, ".bmp")==0 {
txt.print("loading ")
txt.print("bmp\n")
if bmp_module.show_image(filenameptr)
txt.clear_screen()
else
txt.print("load error!\n")
cx16.wait(120)
;txt.print("loading ")
;txt.print("bmp\n")
if bmp_module.show_image(filenameptr) {
cx16.wait(180)
} else {
load_error(filenameptr)
}
}
; else if strcmp(extension, ".ci")==0 {
; txt.print("loading ")
; txt.print("ci\n")
; if ci_module.show_image(filenameptr)
; txt.clear_screen()
; else
; txt.print("load error!\n")
; cx16.wait(120)
; if bmp_module.ci_module(filenameptr) {
; cx16.wait(180)
; } else {
; load_error(filenameptr)
; }
; }
}
sub load_error(uword filenameptr) {
gfx2.set_mode(255) ; back to default text mode and palette
txt.print(filenameptr)
txt.print(": load error\n")
exit(1)
}
sub extension_equals(uword stringptr, uword extensionptr) -> ubyte {
ubyte ix = rfind(stringptr, '.')
return ix<255 and strcmp(stringptr+ix, extensionptr)==0

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import diskio
%import c64colors
@ -33,14 +33,17 @@ koala_module {
; theoretically you could put the 8-pixel array in zeropage to squeeze out another tiny bit of performance
ubyte[8] pixels
graphics.clear_screen(1, 0)
gfx2.clear_screen()
uword offsety = (gfx2.height - 200) / 2
for cy in 0 to 24*8 step 8 {
uword posy = cy + offsety
for cx in 0 to 39 {
uword posx = cx as uword * 8
for d in 0 to 7 {
cx16.FB_cursor_position(cx as uword * 8, cy as uword + d)
gfx2.position(posx, posy + d)
get_8_pixels()
cx16.FB_set_pixels(pixels, 8)
gfx2.next_pixels(pixels, 8)
}
}
cy_times_forty += 40

View File

@ -1,5 +1,5 @@
%target cx16
%import graphics
%import gfx2
%import textio
%import diskio
@ -22,7 +22,7 @@ pcx_module {
uword num_colors = 2**bits_per_pixel
if number_of_planes == 1 {
if (width & 7) == 0 {
graphics.clear_screen(1, 0)
gfx2.clear_screen()
if palette_format==2
palette.set_grayscale()
else if num_colors == 16
@ -76,24 +76,24 @@ bitmap {
y_ok = true
py = 0
px = 0
if width < graphics.WIDTH
offsetx = (graphics.WIDTH - width - 1) / 2
if height < graphics.HEIGHT
offsety = (graphics.HEIGHT - height - 1) / 2
if width < gfx2.width
offsetx = (gfx2.width - width) / 2
if height < gfx2.height
offsety = (gfx2.height - height) / 2
status = (not c64.READST()) or c64.READST()==64
}
sub next_scanline() {
px = 0
py++
y_ok = py < graphics.HEIGHT-1
cx16.FB_cursor_position(offsetx, offsety+py)
y_ok = py < gfx2.height
gfx2.position(offsetx, offsety+py)
status = (not c64.READST()) or c64.READST()==64
}
sub do1bpp(uword width, uword height) -> ubyte {
start_plot(width, height)
cx16.FB_cursor_position(offsetx, offsety)
gfx2.position(offsetx, offsety)
while py < height and status {
ubyte b = c64.CHRIN()
if b>>6==3 {
@ -101,12 +101,12 @@ bitmap {
ubyte dat = c64.CHRIN()
repeat b {
if y_ok
cx16.FB_set_8_pixels_opaque(dat, 255, 255, 0)
gfx2.set_8_pixels_from_bits(dat, 1, 0)
px += 8
}
} else {
if y_ok
cx16.FB_set_8_pixels_opaque(b, 255, 255, 0)
gfx2.set_8_pixels_from_bits(b, 1, 0)
px += 8
}
if px==width
@ -118,7 +118,7 @@ bitmap {
sub do4bpp(uword width, uword height) -> ubyte {
start_plot(width, height)
cx16.FB_cursor_position(offsetx, offsety)
gfx2.position(offsetx, offsety)
while py < height and status {
ubyte b = c64.CHRIN()
if b>>6==3 {
@ -126,14 +126,14 @@ bitmap {
ubyte dat = c64.CHRIN()
if y_ok
repeat b {
cx16.FB_set_pixel(dat>>4)
cx16.FB_set_pixel(dat & 15)
gfx2.next_pixel(dat>>4)
gfx2.next_pixel(dat & 15)
}
px += b*2
} else {
if y_ok {
cx16.FB_set_pixel(b>>4)
cx16.FB_set_pixel(b & 15)
gfx2.next_pixel(b>>4)
gfx2.next_pixel(b & 15)
}
px += 2
}
@ -146,7 +146,7 @@ bitmap {
sub do8bpp(uword width, uword height) -> ubyte {
start_plot(width, height)
cx16.FB_cursor_position(offsetx, offsety)
gfx2.position(offsetx, offsety)
while py < height and status {
ubyte b = c64.CHRIN()
if b>>6==3 {
@ -154,11 +154,11 @@ bitmap {
ubyte dat = c64.CHRIN()
if y_ok
repeat b
cx16.FB_set_pixel(dat)
gfx2.next_pixel(dat)
px += b
} else {
if y_ok
cx16.FB_set_pixel(b)
gfx2.next_pixel(b)
px++
}
if px==width

46
examples/cx16/testgfx2.p8 Normal file
View File

@ -0,0 +1,46 @@
%target cx16
%import gfx2
%import textio
%zeropage basicsafe
main {
sub start () {
ubyte[] modes = [0, 1, 128]
ubyte mode
for mode in modes {
gfx2.set_mode(mode)
draw()
cx16.wait(120)
}
gfx2.set_mode(255)
txt.print("done!\n")
}
sub draw() {
uword offset
ubyte angle
uword x
uword y
when gfx2.active_mode {
0, 1 -> {
for offset in 0 to 90 step 3 {
for angle in 0 to 255 {
x = $0008+sin8u(angle)/2
y = $0008+cos8u(angle)/2
gfx2.plot(x+offset*2,y+offset, lsb(x+y))
}
}
}
128 -> {
for offset in 0 to 190 step 6 {
for angle in 0 to 255 {
x = $0008+sin8u(angle)
y = $0008+cos8u(angle)
gfx2.plot(x+offset*2,y+offset, 1)
}
}
}
}
}
}

View File

@ -8,6 +8,13 @@
main {
; TODO the R0 is loaded as a WORD even though its type is specified as a BYTE...:
asmsub set_8_pixels_from_bits(ubyte bits @R0, ubyte oncolor @A, ubyte offcolor @Y) {
}
asmsub derp(ubyte value @A, uword address @R0) {
%asm {{
rts