Simple image display
This commit is contained in:
parent
a46d1ee224
commit
78ba46877a
|
@ -0,0 +1,3 @@
|
|||
out/
|
||||
bin/
|
||||
*~
|
|
@ -0,0 +1,38 @@
|
|||
MAKEADF=../tools/makeadf
|
||||
FLOPPY=bin/image.adf
|
||||
IMAGE_DATA=out/image-copper.s out/image-data.bin
|
||||
|
||||
all: bin out $(MAKEADF) $(FLOPPY)
|
||||
|
||||
gdrive: all
|
||||
cp $(FLOPPY) ~/Google\ Drive
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
out:
|
||||
mkdir out
|
||||
|
||||
$(MAKEADF): ../tools/makeadf.c
|
||||
gcc ../tools/makeadf.c -o $(MAKEADF)
|
||||
|
||||
$(FLOPPY): out/bootblock.bin
|
||||
$(MAKEADF) out/bootblock.bin > $(FLOPPY)
|
||||
|
||||
out/bootblock.bin: out/bootblock.o
|
||||
vlink -brawbin1 $< -o $@
|
||||
|
||||
out/bootblock.o: bootblock.s out/main.bin
|
||||
vc -c $< -o $@
|
||||
|
||||
out/main.o: image.s $(IMAGE_DATA)
|
||||
vc -c $< -o $@
|
||||
|
||||
out/main.bin: out/main.o
|
||||
vlink -brawbin1 $< -o $@
|
||||
|
||||
$(IMAGE_DATA): images/hello.png ../tools/bitplanify.py
|
||||
../tools/bitplanify.py images/hello.png --copper $(IMAGE_DATA)
|
||||
|
||||
clean:
|
||||
rm -rf out bin
|
|
@ -0,0 +1,6 @@
|
|||
Display a simple image
|
||||
======================
|
||||
|
||||
Building on trackdisk.device, we now display a simple color image
|
||||
|
||||
Image display code and conversion tools from https://github.com/vilcans/amiga-startup
|
|
@ -0,0 +1,30 @@
|
|||
include exec/io.i
|
||||
include lvo/exec_lib.i
|
||||
|
||||
bootblock:
|
||||
dc.b "DOS",0
|
||||
dc.l 0
|
||||
dc.l 880
|
||||
|
||||
bootEntry:
|
||||
;; a6 = Exec base
|
||||
;; a1 = trackdisk.device I/O request pointer
|
||||
|
||||
lea $70000,a5 ; main.s entry point
|
||||
|
||||
;; Load the progam from the floppy using trackdisk.device
|
||||
move.l #mainEnd-mainStart,IO_LENGTH(a1)
|
||||
move.l a5,IO_DATA(a1)
|
||||
move.l #mainStart-bootblock,IO_OFFSET(a1)
|
||||
jsr _LVODoIO(a6)
|
||||
|
||||
jmp (a5) ; -> main.s entry point
|
||||
|
||||
;; Pad the remainder of the bootblock
|
||||
cnop 0,1024
|
||||
|
||||
mainStart:
|
||||
incbin "out/main.bin"
|
||||
cnop 0,512
|
||||
mainEnd:
|
||||
end
|
|
@ -0,0 +1,69 @@
|
|||
include ../include/registers.i
|
||||
include hardware/dmabits.i
|
||||
include hardware/intbits.i
|
||||
|
||||
LVL3_INT_VECTOR equ $6c
|
||||
SCREEN_WIDTH_BYTES equ (320/8)
|
||||
SCREEN_BIT_DEPTH equ 4
|
||||
|
||||
|
||||
entry:
|
||||
lea level3InterruptHandler(pc),a3
|
||||
move.l a3,LVL3_INT_VECTOR
|
||||
|
||||
lea CUSTOM,a1
|
||||
|
||||
;; install copper list and enable DMA
|
||||
lea copper(pc),a0
|
||||
move.l a0,cop1lc(a1)
|
||||
move.w COPJMP1(a1),d0
|
||||
move.w #(DMAF_SETCLR!DMAF_COPPER!DMAF_RASTER!DMAF_MASTER),dmacon(a1)
|
||||
|
||||
.mainLoop:
|
||||
bra.b .mainLoop
|
||||
|
||||
level3InterruptHandler:
|
||||
movem.l d0-a6,-(sp)
|
||||
|
||||
.checkVerticalBlank:
|
||||
lea CUSTOM,a5
|
||||
move.w INTREQR(a5),d0
|
||||
and.w #INTF_VERTB,d0
|
||||
beq.s .checkCopper
|
||||
|
||||
.verticalBlank:
|
||||
move.w #INTF_VERTB,INTREQ(a5) ; Clear interrupt bit
|
||||
|
||||
.resetBitplanePointers:
|
||||
lea bitplanes,a1
|
||||
lea $dff0e0,a2
|
||||
moveq #SCREEN_BIT_DEPTH,d0
|
||||
.bitplaneloop:
|
||||
move.l a1,(a2)
|
||||
lea SCREEN_WIDTH_BYTES(a1),a1 ; Bit plane data is interleaved
|
||||
addq #4,a2
|
||||
dbra d0,.bitplaneloop
|
||||
|
||||
.checkCopper:
|
||||
lea CUSTOM,a5
|
||||
move.w INTREQR(a5),d0
|
||||
and.w #INTF_COPER,d0
|
||||
beq.s .interruptComplete
|
||||
.copperInterrupt:
|
||||
move.w #INTF_COPER,INTREQ(a5) ; Clear interrupt bit
|
||||
|
||||
.interruptComplete:
|
||||
movem.l (sp)+,d0-a6
|
||||
rte
|
||||
|
||||
copper:
|
||||
dc.w BPLCON0,(SCREEN_BIT_DEPTH<<12)|$200 ; Set color depth and enable COLOR
|
||||
dc.w BPL1MOD,SCREEN_WIDTH_BYTES*SCREEN_BIT_DEPTH-SCREEN_WIDTH_BYTES
|
||||
dc.w BPL2MOD,SCREEN_WIDTH_BYTES*SCREEN_BIT_DEPTH-SCREEN_WIDTH_BYTES
|
||||
|
||||
include "out/image-copper.s"
|
||||
|
||||
dc.l $fffffffe
|
||||
bitplanes:
|
||||
incbin "out/image-data.bin"
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,59 @@
|
|||
from array import array
|
||||
|
||||
|
||||
class BitplaneImage(object):
|
||||
def __init__(self, byte_width, height, bitplanes):
|
||||
self.byte_width = byte_width
|
||||
self.height = height
|
||||
self.bitplanes = bitplanes
|
||||
|
||||
|
||||
def image_to_bitplanes(image, bit_depth):
|
||||
"""
|
||||
Convert a PIL image into bitplanes.
|
||||
|
||||
Returns a bitmap image.
|
||||
"""
|
||||
bitplanes = [array('c') for _ in xrange(bit_depth)]
|
||||
width, height = image.size
|
||||
byte_width = (width + 7) // 8
|
||||
|
||||
for row in xrange(height):
|
||||
for byte in xrange(byte_width):
|
||||
planes = [0] * bit_depth
|
||||
for bit in xrange(8):
|
||||
palette_index = image.getpixel((byte * 8 + 7 - bit, row))
|
||||
for plane_index in range(bit_depth):
|
||||
planes[plane_index] |= ((palette_index >> plane_index) & 1) << bit
|
||||
for plane_index in range(bit_depth):
|
||||
bitplanes[plane_index].append(chr(planes[plane_index]))
|
||||
|
||||
return BitplaneImage(byte_width, height, bitplanes)
|
||||
|
||||
|
||||
def write_interleaved(file, image):
|
||||
"""Write all bitplanes in interleaved mode to a file."""
|
||||
for row in xrange(image.height):
|
||||
offset = row * image.byte_width
|
||||
for plane in image.bitplanes:
|
||||
plane[offset:offset + image.byte_width].write(file)
|
||||
|
||||
|
||||
def write_bitplane(file, image, bitplane_index):
|
||||
"""Write a single bitplane to a file."""
|
||||
image.bitplanes[bitplane_index].write(file)
|
||||
|
||||
|
||||
def to_amiga_colors(palette):
|
||||
"""
|
||||
Convert 24 bit colors to Amiga 12 bit colors.
|
||||
palette is a sequence of integers: [r, g, b, ...]
|
||||
"""
|
||||
number_of_colors = len(palette) // 3
|
||||
amiga_colors = []
|
||||
for color_index in xrange(number_of_colors):
|
||||
r, g, b = [c for c in palette[color_index * 3:(color_index + 1) * 3]]
|
||||
rgb = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4)
|
||||
amiga_colors.append(rgb)
|
||||
|
||||
return amiga_colors
|
Binary file not shown.
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import math
|
||||
from PIL import Image
|
||||
from bitmap import (
|
||||
image_to_bitplanes,
|
||||
write_bitplane,
|
||||
write_interleaved,
|
||||
to_amiga_colors,
|
||||
)
|
||||
|
||||
|
||||
def main(args):
|
||||
source_file = args.source
|
||||
bit_depth = args.depth
|
||||
verbose = args.verbose
|
||||
|
||||
img = Image.open(source_file)
|
||||
if img.mode != 'P':
|
||||
print 'Image is not palette-based'
|
||||
sys.exit(1)
|
||||
|
||||
palette = img.getpalette() # always 256*3 values
|
||||
if not bit_depth:
|
||||
max_index = img.getextrema()[1]
|
||||
bit_depth = int(math.log(max_index) / math.log(2)) + 1
|
||||
if verbose:
|
||||
print 'Maximum palette index used: %d: assuming bit depth %d' % (max_index, bit_depth)
|
||||
|
||||
amiga_palette = to_amiga_colors(
|
||||
palette[:(1 << bit_depth) * 3]
|
||||
)
|
||||
|
||||
width, height = img.size
|
||||
if (width & 7) != 0:
|
||||
print 'Width is not divisable by 8:', width
|
||||
sys.exit(1)
|
||||
|
||||
bitmap_image = image_to_bitplanes(img, bit_depth)
|
||||
if verbose:
|
||||
print 'Image width: %d pixels = %d bytes. Height: %d pixels' % (
|
||||
width, bitmap_image.byte_width, height)
|
||||
|
||||
if args.separate:
|
||||
for plane_index in range(bit_depth):
|
||||
with open(args.out % (plane_index + 1), 'wb') as out:
|
||||
write_bitplane(out, bitmap_image, plane_index)
|
||||
else:
|
||||
with open(args.out, 'wb') as out:
|
||||
write_interleaved(out, bitmap_image)
|
||||
|
||||
if args.copper:
|
||||
with open(args.copper, 'w') as out:
|
||||
for index, rgb in enumerate(amiga_palette):
|
||||
out.write('\tdc.w\t$%x,$%03x\n' % (0x180 + index * 2, rgb))
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description='Convert an image to Amiga bitplanes')
|
||||
parser.add_argument(
|
||||
'--depth', metavar='N', type=int, default=None,
|
||||
help='Set number of bitplanes in output')
|
||||
parser.add_argument(
|
||||
'--copper',
|
||||
help='Write palette as copper source code (default is to auto-detect)')
|
||||
parser.add_argument(
|
||||
'--separate', action='store_true',
|
||||
help='Write one bitplane per file. Use %%s in filename as replacement for bitplane number.')
|
||||
parser.add_argument(
|
||||
'--verbose', '-v', action='store_true',
|
||||
help='Write more information to stdout')
|
||||
parser.add_argument('source', metavar='IMAGE_FILE',
|
||||
help='Image file to convert to bitplanes')
|
||||
parser.add_argument('out', metavar='BITPLANES_FILE',
|
||||
help='File to write bitmaps to')
|
||||
|
||||
args = parser.parse_args()
|
||||
main(args)
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
MAKEADF=bin/makeadf
|
||||
MAKEADF=../tools/makeadf
|
||||
FLOPPY=bin/test.adf
|
||||
|
||||
all: bin out $(MAKEADF) $(FLOPPY)
|
||||
|
@ -12,8 +12,8 @@ bin:
|
|||
out:
|
||||
mkdir out
|
||||
|
||||
$(MAKEADF): makeadf.c
|
||||
gcc makeadf.c -o $(MAKEADF)
|
||||
$(MAKEADF): ../tools/makeadf.c
|
||||
gcc ../tools/makeadf.c -o $(MAKEADF)
|
||||
|
||||
$(FLOPPY): out/bootblock.bin
|
||||
$(MAKEADF) out/bootblock.bin > $(FLOPPY)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
include registers.i
|
||||
include ../include/registers.i
|
||||
include hardware/dmabits.i
|
||||
include hardware/intbits.i
|
||||
|
||||
|
|
Loading…
Reference in New Issue