mirror of
https://github.com/irmen/prog8.git
synced 2025-02-21 10:29:03 +00:00
bmx can load "stamps"
This commit is contained in:
parent
278e2f5605
commit
5d9caef45f
@ -2,6 +2,12 @@
|
|||||||
; Only uncompressed images, of width 320 or 640, are supported for now.
|
; Only uncompressed images, of width 320 or 640, are supported for now.
|
||||||
; BMX Specification: https://cx16forum.com/forum/viewtopic.php?t=6945
|
; BMX Specification: https://cx16forum.com/forum/viewtopic.php?t=6945
|
||||||
|
|
||||||
|
|
||||||
|
; TODO: refactor loading: bmx.open() - reads header . bmx.continue_load() - reads the palette+bitmap. bmx.close() -cleanup bmx.save() stays the same
|
||||||
|
; TODO: ability to save "stamps" , bitmaps that are only a region of the screen.
|
||||||
|
; TODO: load 4bpp/2bpp/1bpp images
|
||||||
|
; TODO: save 4bpp/2bpp/1bpp images
|
||||||
|
|
||||||
%import diskio
|
%import diskio
|
||||||
|
|
||||||
bmx {
|
bmx {
|
||||||
@ -47,7 +53,8 @@ bmx {
|
|||||||
goto load_end
|
goto load_end
|
||||||
}
|
}
|
||||||
if width!=320 and width!=640 {
|
if width!=320 and width!=640 {
|
||||||
error_message = "width not 320 or 640" ; TODO: deal with other widths
|
; note: use load_stamp() to read other sizes
|
||||||
|
error_message = "width not 320 or 640"
|
||||||
goto load_end
|
goto load_end
|
||||||
}
|
}
|
||||||
if compression {
|
if compression {
|
||||||
@ -66,6 +73,57 @@ bmx {
|
|||||||
} else
|
} else
|
||||||
error_message = diskio.status()
|
error_message = diskio.status()
|
||||||
|
|
||||||
|
load_end:
|
||||||
|
diskio.f_close()
|
||||||
|
diskio.drivenumber = old_drivenumber
|
||||||
|
return error_message==0
|
||||||
|
}
|
||||||
|
|
||||||
|
sub load_stamp(ubyte drivenumber, str filename, ubyte vbank, uword vaddr, uword screenwidth) -> bool {
|
||||||
|
; Loads a BMX bitmap "stamp" image and palette into vram. (and Header info into the bmx.* variables)
|
||||||
|
; "Stamp" means: load an image that is smaller than the screen (so we need to pad around it)
|
||||||
|
; Parameters:
|
||||||
|
; the drive number and filename to load,
|
||||||
|
; and the vram bank and address where the bitmap data should go,
|
||||||
|
; finally the screen width that the stamp image is loaded into.
|
||||||
|
; You can set the max_width and max_height variables first, if you want this routine to check those.
|
||||||
|
; Note: does not change vera screen mode or colordepth! You have to do that yourself!
|
||||||
|
; Returns: success status. If false, error_message points to the error message string.
|
||||||
|
error_message = 0
|
||||||
|
ubyte old_drivenumber = diskio.drivenumber
|
||||||
|
diskio.drivenumber = drivenumber
|
||||||
|
if diskio.f_open(filename) {
|
||||||
|
diskio.reset_read_channel()
|
||||||
|
if read_header() {
|
||||||
|
if parse_header() {
|
||||||
|
if max_width and width>max_width {
|
||||||
|
error_message = "image too large"
|
||||||
|
goto load_end
|
||||||
|
}
|
||||||
|
if max_height and height>max_height {
|
||||||
|
error_message = "image too large"
|
||||||
|
goto load_end
|
||||||
|
}
|
||||||
|
if width>screenwidth {
|
||||||
|
error_message = "image too large"
|
||||||
|
goto load_end
|
||||||
|
}
|
||||||
|
if compression {
|
||||||
|
error_message = "compression not supported"
|
||||||
|
goto load_end
|
||||||
|
}
|
||||||
|
if read_palette() {
|
||||||
|
if not read_bitmap_padded(vbank, vaddr, screenwidth)
|
||||||
|
error_message = "bitmap error"
|
||||||
|
} else
|
||||||
|
error_message = "palette error"
|
||||||
|
} else
|
||||||
|
error_message = "invalid bmx file"
|
||||||
|
} else
|
||||||
|
error_message = "invalid bmx file"
|
||||||
|
} else
|
||||||
|
error_message = diskio.status()
|
||||||
|
|
||||||
load_end:
|
load_end:
|
||||||
diskio.f_close()
|
diskio.f_close()
|
||||||
diskio.drivenumber = old_drivenumber
|
diskio.drivenumber = old_drivenumber
|
||||||
@ -129,14 +187,14 @@ load_end:
|
|||||||
; drive number and filename to save to,
|
; drive number and filename to save to,
|
||||||
; vram bank and address of the bitmap data to save.
|
; vram bank and address of the bitmap data to save.
|
||||||
; Returns: success status. If false, error_message points to the error message string.
|
; Returns: success status. If false, error_message points to the error message string.
|
||||||
; TODO: how to save bitmaps that are not the full visible screen width (non-contiguous scanlines)
|
; TODO: how to save bitmaps that are not the full visible screen width (non-contiguous scanlines)?
|
||||||
if compression {
|
if compression {
|
||||||
error_message = "compression not supported"
|
error_message = "compression not supported"
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
error_message = 0
|
error_message = 0
|
||||||
if width!=320 and width!=640 {
|
if width!=320 and width!=640 {
|
||||||
error_message = "width not 320 or 640" ; TODO: deal with other widths
|
error_message = "width not 320 or 640"
|
||||||
goto save_end
|
goto save_end
|
||||||
}
|
}
|
||||||
ubyte old_drivenumber = diskio.drivenumber
|
ubyte old_drivenumber = diskio.drivenumber
|
||||||
@ -211,14 +269,28 @@ save_end:
|
|||||||
return cbm.READST()==0 or cbm.READST()&$40 ; no error or eof?
|
return cbm.READST()==0 or cbm.READST()&$40 ; no error or eof?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub read_bitmap_padded(ubyte vbank, uword vaddr, uword screenwidth) -> bool {
|
||||||
|
; load bitmap "stamp" into vram from the currently active input file
|
||||||
|
cx16.r3 = bytes_per_scanline(width) ; num bytes per image scanline
|
||||||
|
cx16.r2 = bytes_per_scanline(screenwidth) ; num bytes per screen scanline
|
||||||
|
repeat height {
|
||||||
|
cx16.vaddr(vbank, vaddr, 0, 1)
|
||||||
|
read_scanline(cx16.r3)
|
||||||
|
vaddr += cx16.r2
|
||||||
|
if_cs
|
||||||
|
vbank++
|
||||||
|
}
|
||||||
|
return cbm.READST()==0 or cbm.READST()&$40 ; no error or eof?
|
||||||
|
}
|
||||||
|
|
||||||
sub read_bitmap(ubyte vbank, uword vaddr) -> bool {
|
sub read_bitmap(ubyte vbank, uword vaddr) -> bool {
|
||||||
; load contiguous bitmap into vram from the currently active input file
|
; load contiguous bitmap into vram from the currently active input file
|
||||||
; TODO how to deal with bitmaps that are smaller than the screen?
|
|
||||||
cx16.vaddr(vbank, vaddr, 0, 1)
|
|
||||||
cx16.r3 = bytes_per_scanline(width)
|
cx16.r3 = bytes_per_scanline(width)
|
||||||
|
cx16.vaddr(vbank, vaddr, 0, 1)
|
||||||
repeat height
|
repeat height
|
||||||
read_scanline(cx16.r3)
|
read_scanline(cx16.r3)
|
||||||
return cbm.READST()==0 or cbm.READST()&$40 ; no error or eof?
|
return cbm.READST()==0 or cbm.READST()&$40 ; no error or eof?
|
||||||
|
}
|
||||||
|
|
||||||
sub read_scanline(uword size) {
|
sub read_scanline(uword size) {
|
||||||
while size {
|
while size {
|
||||||
@ -231,8 +303,6 @@ save_end:
|
|||||||
}
|
}
|
||||||
size -= cx16.r0
|
size -= cx16.r0
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub write_header() -> bool {
|
sub write_header() -> bool {
|
||||||
@ -268,7 +338,6 @@ save_end:
|
|||||||
|
|
||||||
sub write_bitmap(ubyte vbank, uword vaddr) -> bool {
|
sub write_bitmap(ubyte vbank, uword vaddr) -> bool {
|
||||||
; save contiguous bitmap from vram to the currently active output file
|
; save contiguous bitmap from vram to the currently active output file
|
||||||
; TODO how to deal with bitmaps that are smaller than the screen
|
|
||||||
cx16.vaddr(vbank, vaddr, 0, 1)
|
cx16.vaddr(vbank, vaddr, 0, 1)
|
||||||
cx16.r3 = bytes_per_scanline(width)
|
cx16.r3 = bytes_per_scanline(width)
|
||||||
repeat height
|
repeat height
|
||||||
@ -293,14 +362,8 @@ save_end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub bytes_per_scanline(uword w) -> uword {
|
sub bytes_per_scanline(uword w) -> uword {
|
||||||
when bitsperpixel {
|
ubyte[4] shifts = [3,2,1,0]
|
||||||
1 -> cx16.r0L = 3
|
return w >> shifts[vera_colordepth]
|
||||||
2 -> cx16.r0L = 2
|
|
||||||
4 -> cx16.r0L = 1
|
|
||||||
8 -> return w
|
|
||||||
else -> return 0
|
|
||||||
}
|
|
||||||
return w >> cx16.r0L
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parse_header() -> bool {
|
sub parse_header() -> bool {
|
||||||
|
@ -281,7 +281,8 @@ close_end:
|
|||||||
; note: only a single iteration loop can be active at a time!
|
; note: only a single iteration loop can be active at a time!
|
||||||
; Returns true if the file is successfully opened and readable.
|
; Returns true if the file is successfully opened and readable.
|
||||||
; No need to check status(), unlike f_open_w() !
|
; No need to check status(), unlike f_open_w() !
|
||||||
; NOTE: the default input isn't yet set to this logical file, you can use reset_read_channel() to do this!
|
; NOTE: the default input isn't yet set to this logical file, you must use reset_read_channel() to do this,
|
||||||
|
; if you're going to read from it yourself instead of using f_read()!
|
||||||
f_close()
|
f_close()
|
||||||
|
|
||||||
cbm.SETNAM(string.length(filenameptr), filenameptr)
|
cbm.SETNAM(string.length(filenameptr), filenameptr)
|
||||||
|
@ -273,7 +273,8 @@ close_end:
|
|||||||
; note: only a single iteration loop can be active at a time!
|
; note: only a single iteration loop can be active at a time!
|
||||||
; Returns true if the file is successfully opened and readable.
|
; Returns true if the file is successfully opened and readable.
|
||||||
; No need to check status(), unlike f_open_w() !
|
; No need to check status(), unlike f_open_w() !
|
||||||
; NOTE: the default input isn't yet set to this logical file, you can use reset_read_channel() to do this!
|
; NOTE: the default input isn't yet set to this logical file, you must use reset_read_channel() to do this,
|
||||||
|
; if you're going to read from it yourself instead of using f_read()!
|
||||||
f_close()
|
f_close()
|
||||||
|
|
||||||
cbm.SETNAM(string.length(filenameptr), filenameptr)
|
cbm.SETNAM(string.length(filenameptr), filenameptr)
|
||||||
|
@ -18,6 +18,7 @@ main {
|
|||||||
repeat {
|
repeat {
|
||||||
txt.print("\nenter bmx image filename: ")
|
txt.print("\nenter bmx image filename: ")
|
||||||
if txt.input_chars(&filename) {
|
if txt.input_chars(&filename) {
|
||||||
|
|
||||||
if bmx.load_header(8, filename) {
|
if bmx.load_header(8, filename) {
|
||||||
txt.print("\nsize: ")
|
txt.print("\nsize: ")
|
||||||
txt.print_uw(bmx.width)
|
txt.print_uw(bmx.width)
|
||||||
@ -34,16 +35,37 @@ main {
|
|||||||
bmx.palette_buffer_ptr = memory("palette", 512, 0)
|
bmx.palette_buffer_ptr = memory("palette", 512, 0)
|
||||||
sys.memset(bmx.palette_buffer_ptr, 512, 0)
|
sys.memset(bmx.palette_buffer_ptr, 512, 0)
|
||||||
palette.set_rgb(bmx.palette_buffer_ptr, 256)
|
palette.set_rgb(bmx.palette_buffer_ptr, 256)
|
||||||
|
bmx.max_width = 320
|
||||||
|
bmx.max_height = 240
|
||||||
|
|
||||||
; switch to correct screen mode and color depth
|
; switch to bitmap screen mode and color depth: 320*240
|
||||||
void cx16.screen_mode($80, false)
|
void cx16.screen_mode($80, false) ; we're lazy and just use a kernal routine to set up the basics
|
||||||
cx16.VERA_L0_CONFIG = cx16.VERA_L0_CONFIG & %11111100 | bmx.vera_colordepth
|
cx16.VERA_L0_CONFIG = cx16.VERA_L0_CONFIG & %11111100 | bmx.vera_colordepth
|
||||||
|
|
||||||
; now load the image
|
; now load the image
|
||||||
|
if bmx.width==320 {
|
||||||
|
; can use the fast, full-screen load routine
|
||||||
if bmx.load(8, filename, 0, 0) {
|
if bmx.load(8, filename, 0, 0) {
|
||||||
|
if bmx.height<240 {
|
||||||
|
; fill the remaining bottom part of the screen
|
||||||
|
cx16.GRAPH_set_colors(bmx.border, bmx.border, 99)
|
||||||
|
cx16.GRAPH_draw_rect(0, bmx.height, 320, 240-bmx.height, 0, true)
|
||||||
|
}
|
||||||
activate_palette()
|
activate_palette()
|
||||||
void txt.waitkey()
|
void txt.waitkey()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
; clear the screen with the border color
|
||||||
|
cx16.GRAPH_set_colors(0, 0, bmx.border)
|
||||||
|
cx16.GRAPH_clear()
|
||||||
|
; need to use the slower load routine that does padding
|
||||||
|
; center the image on the screen nicely
|
||||||
|
uword offset = (320-bmx.width)/2 + (240-bmx.height)/2*320
|
||||||
|
if bmx.load_stamp(8, filename, 0, offset, 320) {
|
||||||
|
activate_palette()
|
||||||
|
void txt.waitkey()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cbm.CINT() ; reset screen
|
cbm.CINT() ; reset screen
|
||||||
@ -60,6 +82,7 @@ main {
|
|||||||
|
|
||||||
sub activate_palette() {
|
sub activate_palette() {
|
||||||
; copies the pallette data from the memory buffer into vram
|
; copies the pallette data from the memory buffer into vram
|
||||||
|
cx16.VERA_DC_BORDER = bmx.border
|
||||||
cx16.r1 = bmx.palette_buffer_ptr
|
cx16.r1 = bmx.palette_buffer_ptr
|
||||||
cx16.r2L = bmx.palette_start
|
cx16.r2L = bmx.palette_start
|
||||||
cx16.r3L = bmx.palette_entries
|
cx16.r3L = bmx.palette_entries
|
||||||
|
@ -13,6 +13,9 @@ main {
|
|||||||
txt.print("\nprog8's parse_f: ")
|
txt.print("\nprog8's parse_f: ")
|
||||||
float value = floats.parse_f(buffer)
|
float value = floats.parse_f(buffer)
|
||||||
floats.print_f(value)
|
floats.print_f(value)
|
||||||
|
|
||||||
|
; floats.VAL_1 is defined as:
|
||||||
|
; romsub $fe09 = VAL_1(uword string @XY, ubyte length @A) clobbers(A,X,Y) -> float @FAC1
|
||||||
txt.print("\nrom val_1: ")
|
txt.print("\nrom val_1: ")
|
||||||
value = floats.VAL_1(buffer, string.length(buffer))
|
value = floats.VAL_1(buffer, string.length(buffer))
|
||||||
floats.print_f(value)
|
floats.print_f(value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user