diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bed5d7d --- /dev/null +++ b/Makefile @@ -0,0 +1,77 @@ +# +# gslaplay/Makefile +# + +# This makefile was created by Jason Andersen +# +# I build on Windows-10 64-bit, this makefile is designed to run under +# a Windows-10 Command Prompt, and makes use of DOS shell commands +# +# As far a free stuff, I setup a c:\bin directory, in my path +# the following packages and executables are in there +# +# Fine Tools from Brutal Deluxe +# http://www.brutaldeluxe.fr/products/crossdevtools/ +# Cadius.exe +# Merlin32.exe +# OMFAnalyzer.exe +# LZ4.exe +# +# gnumake-4.2.1-x64.exe (with a symbolic link that aliases this to "make") +# +# https://apple2.gs/plus/ +# gsplus32.exe (KEGS based GS Emulator fork by Dagen Brock) +# I configure this to boot the player.po image directly +# once that's done "make run" will build, update the disk image +# and boot into the player. +# + +# Make and Build Variables + +TARGETNAME = play + +VPATH = src:obj +ASMFILES = $(wildcard asm/*.s) +ASM = merlin32 + +help: + @echo. + @echo $(TARGETNAME) Makefile + @echo ------------------------------------------------- + @echo build commands: + @echo make gs - Apple IIgs + @echo make image - Build Bootable .PO File + @echo make run - Build / Run IIgs on emulator + @echo make clean - Clean intermediate/target files + @echo make depend - Build dependencies + @echo ------------------------------------------------- + @echo. + +$(TARGETNAME).sys16: $(ASMFILES) $(OBJFILES) + $(ASM) -v macros asm/link.s + move /y asm\$(TARGETNAME).sys16 . + +gs: $(TARGETNAME).sys16 + +disk image: gs + @echo Updating $(TARGETNAME).po + @echo Remove $(TARGETNAME).sys16 + cadius deletefile $(TARGETNAME).po /$(TARGETNAME)/$(TARGETNAME).sys16 + @echo Add $(TARGETNAME).sys16 + cadius addfile $(TARGETNAME).po /$(TARGETNAME) ./$(TARGETNAME).sys16 + +run: image + gsplus32 + +clean: + @echo Remove $(TARGETNAME).sys16 + $(shell if exist $(TARGETNAME).sys16 echo Y | del $(TARGETNAME).sys16) +# @echo Remove Intermediate Files +# @del /q obj\* + +depend: + @echo TODO - make dependencies + +# Create all the directories +#$(shell if not exist $(DIRS) mkdir $(DIRS)) + diff --git a/README.md b/README.md index 1ed4917..384ec0d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,138 @@ # gslaplay Apple IIgs GSLA Player + +Example of a GS LZB Animation Player + +Inspired by Deluxe Animation Run/Skip/Dump, and FLI/FLC with similar properties + +I replace the "Run" with a dictionary/frame buffer copy from the existing +buffer to the existing buffer. This is able to runlength not just a single +byte, but a repeating pattern of arbitrary length. + +-------------------------------------------------------------------------------- +New Apple IIgs Animation file format +GS LZ Byte Compressed Animation +Why? When there are so many image formats would we need another one? It’s +because $C2/Paintworks animation format is just terribly inefficient. + +Care is taken in the encoder, to make sure the 65816 does not have to cross bank +boundaries during any copy. This is so we can use the MVN instruction, and so +we can reduce the number of bank checks in the code. + +We have an opcode, that says “source data bank has changed” + +Goals include a good balance between file size, and playback performance +(since one often makes a trade off with the other). + +The file is defined as a byte stream. + +I will attempt to define the format as + +file-offset: the thing that is at the offset + +Header of the File is 20 bytes as follows + +File Offset Data Commentary +------------------------------------------------------------------ +0 0x47 ; ‘G’ Graphics +1 0x53 ; ‘S’ +2 0x4C ; ‘L’ LZB +3 0x41 ; ‘A’ Animation + +; File Length, is the total length of the file +4 FileLengthLow ; Low byte, 32-bit file length +5 LengthLowHigh ; High byte of low word +6 LengthHighLow ; Low byte, of high word +7 LengthHighHigh ; High Byte, of high word + +; 16 bit word with version # +8 VL ; Version # of the file format, currently only version 0 +9 VH ; Version High Byte + ; %RVVV_VVVV_VVVV_VVVV + ; V is a version #, 0 for now + ; R is the MSB, R = 0 no ring frame + ; R = 1, there is a ring frame + ; A Ring Frame is a frame that will delta from the last + ; frame of the animation, back to the first, for smoother + ; looping , If a ring frame exists, it’s also in the + ; frame count + +// next is a word, width in bytes (only 160 for now) +0xA WL ; Display Width in bytes low byte +0xB WH ; Display Width in bytes high byte +// next is a word, height (likely 200 for now, in tiled mode a multiple of 16) +0xC HL ; Display Height in bytes, low byte +0xD HH ; Display Height in bytes, high byte +// 2 bytes, Frame Size in Bytes, since a “Frame” may contain more than just the +// width * height, worth of pixels, for now this is $8000, or 32768 +0xE FBL ; Frame Buffer Length Low +0xF FBH ; Frame Buffer Length High + +// 4 byte, 32-bit, Frame Count (includes total frame count, so if there is a +// ring frame, this is included in the total) +0x10 FrameCountLow +0x11 FrameCountLowHigh +0x12 FrameCountHighLow +0x13 FrameCountHigh + + +After this comes AIFF style chunks of data, basically a 4 byte chunk name, +followed by a 4 byte length (inclusive of the chunk size). The idea is that +you can skip chunks you don’t understand. + +File Offset: +0x14 First Chunk (followed by more Chunks, until end of file) + +Chunk Definitions +Name: ‘INIT’ - Initial Frame Chunk, this is the data used to first + initialize the playback buffer +0: 0x49 ; ‘I’ +1: 0x4E ; ‘N’ +2: 0x49 ; ‘I’ +3: 0x54 ; ‘T’ +// 32 bit long, length, little endian, including the 8 byte header +4: length low low +5: length low high +6: length high low +7: length high high + +8: This is a single frame of data, that decodes/decompresses into frame sized +bytes (right now 0x8000) +This data stream includes, an end of animation opcode, so that the normal +animation decompressor, can be called on this data, and it will emit the initial +frame onto the screen + +Name: ‘ANIM’ - Frames +0: 0x41 ‘A’ +1: 0x4E ‘N’ +2: 0x49 ‘I’ +3: 0x4D ‘M’ +// 32 bit long, length, little endian, including chunk header +4: length low low +5: length low high +6: length high low +7: length high high + +// This is followed by the frames, with the intention of decompressing them at +// 60FPS, which is why no play speed is included, if you need a play-rate slower +// than this, blank frame’s should be inserted into the animation data + +// Every attempt is made to delta encode the image, meaning we just encode +// information about what changed each frame. We attempt to make the size +// efficient by supporting dictionary copies (where the dictionary is made up of +// existing pixels in the frame buffer). + +Command Word, encoded low-high, what the bits mean: + +// xxx_xxxx_xxxx_xxx is the number of bytes 1-16384 to follow (0 == 1 byte) + +* %0xxx_xxxx_xxxx_xxx1 - Copy Bytes - straight copy bytes +* %1xxx_xxxx_xxxx_xxx1 - Skip Bytes - skip bytes / move the cursor +* %1xxx_xxxx_xxxx_xxx0 - Dictionary Copy Bytes from frame buffer to frame buffer +* +* %0000_0000_0000_0000- Source Skip -> Source pointer skips to next bank of data +* %0000_0000_0000_0010- End of Frame - end of frame +* %0000_0000_0000_0110- End of Animation / End of File / no more frames + +// other remaining codes, are reserved for future expansion + diff --git a/_FileInformation.txt b/_FileInformation.txt new file mode 100644 index 0000000..228e3fd --- /dev/null +++ b/_FileInformation.txt @@ -0,0 +1,7 @@ +PLAY.SYS16=Type(B3),AuxType(DB07),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +XRICK.SYS16=Type(B3),AuxType(DB07),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +FUN2GS.SYS16=Type(B3),AuxType(DB07),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +FUNK.SYSTEM=Type(FF),AuxType(2000),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +BASIC.SYSTEM=Type(FF),AuxType(2000),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +XHD=Type(FF),AuxType(2000),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +PRODOS=Type(FF),AuxType(0000),VersionCreate(24),MinVersion(00),Access(21),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) diff --git a/asm/link.s b/asm/link.s new file mode 100644 index 0000000..a3adb07 --- /dev/null +++ b/asm/link.s @@ -0,0 +1,24 @@ +; +; GSLA Player Merlin32 linker file +; + dsk play.sys16 + typ $b3 ; filetype + aux $db07 ; auxtype + ;xpl ; Add ExpressLoad + +*---------------------------------------------- + asm shell.s + ds 0 ; padding + knd #$1100 ; kind + ali None ; alignment + lna play ; load name + sna start ; segment name +*---------------------------------------------- + asm play.s + ds 0 ; padding + knd #$1100 ; kind + ali None ; alignment + lna play ; load name + sna start ; segment name, doesn't work to try and merge segments here +*---------------------------------------------- + diff --git a/asm/play.s b/asm/play.s new file mode 100644 index 0000000..d38166b --- /dev/null +++ b/asm/play.s @@ -0,0 +1,174 @@ +* +* New Animated File Format +* +* +* xxx_xxxx_xxxx_xxx is the number of bytes 1-16384 to follow (0 == 1 byte) +* +* %0xxx_xxxx_xxxx_xxx1 - Copy Bytes - straight copy bytes +* %1xxx_xxxx_xxxx_xxx1 - Skip Bytes - skip bytes / move the cursor +* %1xxx_xxxx_xxxx_xxx0 - Dictionary Copy Bytes from frame buffer to frame buffer +* +* %0000_0000_0000_0000- Source Skip -> Source pointer skips to next bank of data +* %0000_0000_0000_0010- End of Frame - end of frame +* %0000_0000_0000_0110- End of Animation / End of File / no more frames +* +* other remaining codes, are reserved for future expansion +* +* +* 16 bit opcode +* +* %1 xxx xxxx xxxx xxx 0 +* %0 xxx xxxx xxxx xxx 0 +* +* X = SRC +* Y = DST +* +* Source Data Stream Copy +* Dictionary Copy +* xx xxxx xxxx xxxx // up to 16384 length of copy (0 is a copy length of 1 byte, so it's length-1) +* +* Copy this code to your direct page, please make sure it's aligned to a page +* The buffer is hardcoded to be at $012000, to take advantage of fast reads +* +* pass in a pointer to the start of the compressed stream +* ldx #offset in source bank +* lda #source bank +* we assume all next bank data is sequential from this first bank, but it +* wouldn't be hard to work from a list of banks, to make the player more +* friendly + +*--- this code sits at location $0 in the DP register +*--- DP may be anywhere in bank 0, but make sure it's PAGE aligned +*---- for performance reasons + + dsk play.l + + ext EndOfAnimFrame + +; +; Defines, for the list of allocated memory banks +; +banks_count equ $80 +banks_data equ $82 + + +player ent + org $0 + mx %00 + phb + sep #$20 ; preserve X + sta >' + ASC ]1 + ASC '\H' + DA ]mnum + DO ]0>1 + ASC ]2 + FIN + DB 0 +]mnum = ]mnum+1 + <<< + +* Menu Contents and Equates + +Bold = 'B' ; bold menu item +Disable = 'D' ; disabled menu item +Italic = 'I' ; italic menu item +Underline = 'U' ; underlined menu item +Divide = 'V' ; menu dividing line +ColorHi = 'X' ; color hilite menu item +Kybd = '*' ; keyboard menu equivalent +Check = $1243 ; menu item with checkmark +Blank = $2043 ; menu item with blank + +* Dialog Equates + +CheckItem = 11 +RadioItem = 12 +ScrollBarItem = 13 +PicItem = 19 +UserItem = 20 +ButtonItem EQU $0A +EditLine equ $11 +StatText EQU $0F +StatTextItem = $f +ItemDisable EQU $8000 + +* macros + +test mac + sep #$30 + ldal $e1c034 + inc + stal $e1c034 + rep #$30 + eom + +_HideCursor mac + Tool $9004 + eom + +_ShowCursor mac + Tool $9104 + eom +