Table of Contents

ANIMTOOL

Part of Color Max Deluxe available from the Color Computer Archive and in source form from https://github.com/milliluk/colormax

Allows to load and view MGE files, and save memory buffers to MGE files.

ANNOTATED ASSEMBLY SOURCE

Original Source: https://github.com/milliluk/colormax/blob/master/ANIMTOOL.TXT

NOTE: my comments may be wildly inaccurate.

Please contact me on the Color Computer Discord in the #programming channel if you have corrections.

;*****************************************************************************
;* ANIMTOOL
;*****************************************************************************

            NAM   MGE file utility

                              ; BEWARE !!
                              ; ERIK'S BEEN HERE!

;*****************************************************************************
;* EQUATES
;*****************************************************************************

PRSNXT:     equ   $9F         ; Parse NEXT char
PRSLST:     equ   $A5         ; Parse current char

;*****************************************************************************
; START
;*****************************************************************************

START:      lda   $200        ; POKE &H200,frame # (0-12)
            cmpa  #12         ; check for valid frame number (0-12)
            lbhi  FNCERR      ; >12 is a FN? error

                              ;***********************************************
                              ; calculate graphics page numbers in Extended RAM
            lsla              ; multiply frame number ...
            lsla              ; ... by 4 (4 x 8KB blocks per image)
            pshs  A           ; ... and store on stack
            lda   #$30        ; Now set up the default start 8K block num for frame 0
            suba  ,S+         ; subract the framebuffer size
            tfr   A,B         ; and move that to B for the first 8K block number of top half
            incb              ; and make the second 8K block number of top half
            std   GRP1+1,PCR  ; set the two 8K block values for top half of frame
            adda  #2          ; now add 2 to the first 8K block number
            addb  #2          ; now add 2 to the second 8K block number
            std   GRP2+1,PCR  ; set the second two 8K block numbers for bottom half of frame

                              ;***********************************************
            jsr   PRSLST      ; Get next character from command line
            cmpa  #':         ; Is it the ':' we expect?
            lbne  HELP        ; No; show help and exit
            jsr   PRSNXT      ; look ahead one character
            cmpa  #135        ; "?" TOKEN?
            lbeq  INFO        ; Yes, go show INFO and exit - same as help

                              ;***********************************************
            anda  #$DF        ; kill possible lowercase
            clrb              ; flag for monitor type
            cmpa  #'R         ; RGB? 
            beq   A@          ; or
            cmpa  #'C         ; CMP?
            lbne  SYNERR      ; No; SN? error
            ldb   #1          ; 1=CMP
A@          stb   MONTYP,PCR  ; save 0=RGB or 1=CMP to MONTYPE

                              ;***********************************************
            jsr   PRSNXT      ; Get next character from command line
            cmpa  #':         ; Is it the ':' we expect?
            lbne  SYNERR      ; No; SN? error
     
                              ;***********************************************
            jsr   PRSNXT      ; Get next character from command line
            anda  #$DF        ; kill possible lowercase
            cmpa  #'L         ; LOAD?
            beq   E@          ; or
            cmpa  #'S         ; SAVE?
            lbne  SYNERR      ; No; SN? error
            clra              ; 0=SAVE, >0=LOAD
E@          sta   TODO,PCR    ; store action in TODO

                              ;***********************************************
            jsr   PRSNXT      ; Get next character from command line
            cmpa  #':         ; Is it the ':' we expect?
            lbne  SYNERR      ; No; SN? error
      
                              ;***********************************************
            jsr   PRSNXT      ; Rest of the command is filename to work on
            lbsr  PRSENM      ; Parse the filename string

            lda   TODO,PCR    ; Now, are we loading or saving? Check TODO
            lbeq  SVEPIX      ; TODO=0 for SAVE so go do that

                              ;***********************************************
                              ;* Start loading the picture
                              ;***********************************************
            lbsr  OPENI       ; open file - input

            lbsr  GETBYT      ; get MGE resolution byte
            tsta              ; Not low-res!
            lbne  BADRES      ; Go report BADRES error and exit

                              ;***********************************************
                              ; now - read in the 16 palettes*
            leax  TEMP,PCR    ; Point to temp place to store
            ldb   #16         ; Going to read and save 16 values
A@          lbsr  GETBYT      ; Go get one into A ...
            sta   ,X+         ; ... and store it to where X points, then add 1 to X
            decb              ; Count down one in palette read loop
            bne   A@          ; Hit zero? No, go back and read next

                              ;***********************************************
            lbsr  GETBYT      ; Next byte is monitor type 

                              ;***********************************************
                              ; A now holds which monitor type that the picture was made on
                              ; 0=RGB
                              ; 1=composite
                              ; Make 0/1 rather than 0/nz
            tsta              ; So, what is file palette type?
            beq   A@          ; Was A zero? if so, RGB and keep going
            lda   #1          ; Force A to 1 for Composite rather than "anything not zero"
A@

                              ;***********************************************
            cmpa  MONTYP,PCR  ; Should I convert the palettes?
            lbeq  NOCNV       ; NOPE! File palette type matches our monitor

            leax  RGBCMP,PCR  ; Go from RGB to Composite?
            tsta              ; Check previous result
            beq   A@          ; Yes; skip next
            leax  CMPRGB,PCR  ; Go from Composite to RGB?
A@

                              ;***********************************************
                              ; converts palettes from RGB to COMP or vice-versa
            leay  TEMP,PCR    ; Set Y to address of TEMP palette buffer
            ldb   #16         ; Set our loop counter to size of palettes
A@          lda   ,Y          ; Get file palette entry from addr in Y into A
            lda   A,X         ; Get matching conversion entry from table in X offset by A, back into A
            sta   ,Y+         ; Store A to temp palette entry and move Y pointer to next in table
            decb              ; Count down loop by 1
            bne   A@          ; Are we done? No; go back

                              ;***********************************************
                              ; Don't convert
NOCNV:      ldy   #$FFB0      ; Set Y to start of GIME palette registers
            leax  TEMP,PCR    ; Set X to start of TEMP palette buffer
            ldb   #16         ; Set loop counter to 16
A@          lda   ,X+         ; Load from TEMP into A and move X pointer 1
            sta   ,Y+         ; Start from A into GIME palette and move Y pointer by 1
            decb              ; Count down loop by 1
            bne   A@          ; Are we done? No; go back

                              ;***********************************************
                              ; PALETTES ARE SET!
                              ;***********************************************

                              ;***********************************************
            lbsr  GETBYT      ; get compression flag
            pshs  A           ; Store on stack for a few

                              ;***********************************************
                              ; ignore 32 byte picture-name*
            ldb   #32         ; Set B to count 32 characters of file name
A@          lbsr  GETBYT      ; Get a character
            decb              ; Count down one
            bne   A@          ; Done counting?

                              ;***********************************************
            puls  A           ; Get A back from stack
            tsta              ; compressed?
            lbne  NTCMP       ; Nope; do non-compressed read

                              ;***********************************************
                              ; COMPRESSED READ
                              ; read in the bitmap
            ldx   #$8000      ; Set X to start of framebuffer
CMPLP:      lbsr  GETBYT      ; get # of times to repeat
            tfr   A,B         ; Save repeat count into B
            lbsr  GETBYT      ; get byte to repeat

            tstb              ; length=0??
            beq   CMPEND      ; end.. close file and done

            lbsr  GRPPGE      ; page RAM in and ROM out
A@          sta   ,X+         ; repeat that
            decb              ; byte..
            bne   A@          ; done repeating? No; go back
            lbsr  NRMPGE      ; yes; page back ROMs into memory map
            bra   CMPLP       ; Go back to get next repeat count and byte to repeat

                              ;***********************************************
                              ; NON COMPRESSED READ
                              ; read in bitmap
NTCMP:      ldx   #$8000      ; Set X to start of framebuffer
NTLP:       lbsr  GETBYT      ; Get a byte from file
            lbsr  GRPPGE      ; flip pages - ROM out and RAM in
            sta   ,X+         ; Store value from file direct to RAM
            lbsr  NRMPGE      ; flip back - ROM in and RAM out
            cmpx  #$8000+32000  ; done? 
            blo   NTLP        ; nope; go back and keep reading and drawing

CMPEND:                       ; yes, time to finish
            lbsr  CLOSE       ; close the file
            rts               ; and return to BASIC

;*****************************************************************************
; SAVE PIX
;*****************************************************************************
SVEPIX:     lbsr  OPENO       ; open file for output

                              ;***********************************************
            clra              ; 0 for res=320x200 16 color
            lbsr  WRTBYT      ; Write that RES out to file

                              ;***********************************************
                              ; write the palette out
            ldb   #16         ; Set loop counter to 16 for palettes
            ldx   #$FFB0      ; Setup to read from GIME palette registers
A@          lda   ,X+         ; Read from palette into A, then move pointer 1
            lbsr  WRTBYT      ; Write palette value out to file
            decb              ; Count down one in loop
            bne   A@          ; Loop done? No; loop back

                              ;***********************************************
                              ; write out the montype
            lda   MONTYP,PCR  ; MONTYPE 0=RGB, 1=CMP
            lbsr  WRTBYT      ; Write it to file

                              ;***********************************************
                              ; no compression
            lda   #255        ; COMPRESSION 0=compressed, not zero=uncompressed
            lbsr  WRTBYT      ; write it to file

                              ;***********************************************
                              ; Bozo title
            leax  UNT,PCR     ; Set X to point to UNTitled file name buffer
            ldb   #32         ; Set loop counter for 32 byte file name size
R@          lda   ,X+         ; Store the UNTitled buffer char to A and move X one
            lbsr  WRTBYT      ; Write title character to file
            decb              ; Count down loop by one
            bne   R@          ; Loop done? No; go back and keep writing name

                              ;***********************************************
                              ; write out the bitmap
            ldx   #$8000      ; Set X to point to start of bitmap
A@          lbsr  GRPPGE      ; Page out ROM and expose bitmap RAM
            lda   ,X+         ; Read a byte of bitmap into A and move X by 1
            lbsr  NRMPGE      ; Page out bitmap RAM and restore ROM before ...
            lbsr  WRTBYT      ; ... using ROM to write the byte to file
            cmpx  #$8000+32000  ; Has X reached end of bitmap?
            bne   A@          ; No; go back and keep writing bitmap

                              ;***********************************************
            lbsr  CLOSE       ; Yes; done so close the file
            rts               ; and return to basic

                              ; Bozo title
UNT:        fcc   "BASIC Pix",0


;*****************************************************************************
;* BADRES
;* Tells 'em that they're in a bad resolution!
;*****************************************************************************

            org   UNT+32      ; keep going after filename buffer ...

A@          fcc   "This file is at an incompatible",13
            fcc   "resolution",13,0

BADRES:     leax  A@,PCR      ; Set pointer X to start of BADRES error message
            bsr   PRTMS       ; Print characters until NUL
            lbra  FNCERR      ; and exit to BASIC ROM FN? error

;*****************************************************************************
;* GRPPGE
;* Pages in graphics screen at
;* $8000.. Kills interrupts, too.
;*****************************************************************************

GRPPGE:     pshs  X,D,Y,U     ; Save registers to stack
            lda   #52         ; Setup to ...
            sta   $FF03       ; ... disable interrupts in PIA
            lda   $FF02       ; ... and acknowledge any pending interrupt
GRP1:       ldd   #$3031      ; Setup 8K blocks to ...
            std   $FFA4       ; ... config MMU for extended RAM at 8000 and A000
GRP2:       ldd   #$3233      ; Setup 8K blocks to ...
            std   $FFA6       ; ... config MMU for extended RAM at C000 and E000
            puls  X,D,Y,U,PC  ; Restore registers and return

;*****************************************************************************
;* NRMPGE
;* Pages in normal memory
;* and re-enables interrupts.
;*****************************************************************************

NRMPGE:     pshs  X,D,Y,U     ; Save registers to stack
            ldd   #$3C3D      ; Setup 8K block numbers to ...
            std   $FFA4       ; ... config MMU for ROM at 8000 and A000
            ldd   #$3E3F      ; Setup 8K block numbers to ...
            std   $FFA6       ; ... config MMU for ROM at C000 and E000
            lda   #53         ; Setup to ...
            sta   $FF03       ; ... configure PIA for interrupts
            puls  X,D,Y,U,PC  ; Restore registers and return


;*****************************************************************************
;* OPENI
;* Opens a file for input
;* Entry: filename setup
;* Exit: file is opened!
;*****************************************************************************

OPENI:      pshs  X,D,Y,U     ; Save registers on stack
            ldx   #$C959      ; Rom 1.0 file input
            ldd   $C004       ; Which ROM??? Check DSKCON
            cmpd  #$D66C      ; Rom 1.0!
            beq   A@          ; !
            ldx   #$CA07      ; Rom 1.1 file input
A@          jsr   ,X          ; make call
            puls  X,D,Y,U,PC  ; Restore registers from stack and return

;*****************************************************************************
;* GETBYT
;* Gets a byte from the file
;* Entry: none
;* Exit : Byte's in A
;*****************************************************************************

GETBYT:     jmp   $A176       ; COLOR BASIC ROM CONSOLE IN

;*****************************************************************************
;* WRTBYT
;* writes a byte to file
;*****************************************************************************

WRTBYT:     jmp   [$A002]     ; Indirect jump through CHROUT to ROM PUTCHR

;*****************************************************************************
;* OPENO
;* Open it for output
;*****************************************************************************

OPENO:      pshs  X,D,Y,U     ; Save registers on stack
            ldx   #$C956      ; DECB 1.0 Open Sequential for I/O
            ldd   $C004       ; Get value of DSKCON vector
            cmpd  #$D66C      ; Is it the DEBC ROM 1.0 version?
            beq   A@          ; Yes; go open file for output
            ldx   #$CA04      ; No; load addr of DECB 1.1 open
A@          jsr   ,X          ; Go open the for output file using chosen ROM
            puls  X,D,Y,U,PC  ; Restore registers from stack and return

;*****************************************************************************
;* CLOSE
;* Closes an open file
;* Entry: None
;* Exit: None
;*****************************************************************************

CLOSE:      jmp   $A42D       ; COLOR BASIC ROM CLOSE FILE HANDLER

;*****************************************************************************
;* PRTMS
;* Enter: X pointing to msg
;* Exit : Well.. It PRINTS the msg!
;*****************************************************************************

PRTMS:      lda   ,X+         ; Get next character to print from addr X+ into A
            beq   ?RTS        ; End of message (NUL)? yes; return
            jsr   [$A002]     ; No; print character
            bra   PRTMS       ; and keep going until we hit a NUL

;*****************************************************************************
;* PRSENM
;* Parse filename/extension:drivenumber using Disk BASIC ROM calls
;*****************************************************************************

PRSENM:     pshs  X,D,Y,U     ; Save regs on stack before use
            leax  A@,PCR      ; where is extension we're looking for?
            ldy   #$C88A      ; Address of Disk rom 1.0 get filename/ext
            ldd   $C004       ; Look at what is stored in DSKCON vector
            cmpd  #$D66C      ; Izzit 1.0
            beq   B@          ; yep
            ldy   #$C938      ; nope; setup addr of Disk rom 1.1 get filename/ext
B@          jsr   ,Y          ; Call DECB ROM get filename/ext:drivenum
            puls  X,D,Y,U,PC  ; Restore regs from stack and return

A@          fcc   "MGE"

;*****************************************************************************
;* SYNTAX ERROR
;*****************************************************************************

SYNERR:     jmp   $B277       ; ?SN ERROR

;*****************************************************************************
;* FUNCTION CALL ERROR
;*****************************************************************************

FNCERR:     jmp   $B44A       ; ?FC ERROR

;*****************************************************************************
;* PALETTE CONVERSION DATA
;*****************************************************************************

RGBCMP:
            fcb   00,14,02,14,05,10,03,16,13,11,30,28,11,12,30,29
            fcb   17,17,18,34,20,19,34,33,46,45,47,31,46,45,47,46
            fcb   07,06,21,06,07,24,38,29,26,43,27,43,25,09,41,42
            fcb   36,35,50,51,53,54,36,37,32,60,49,61,56,59,52,63

CMPRGB:
            fcb   00,02,02,06,00,04,33,32,32,45,05,09,13,08,01,00
            fcb   07,16,18,21,20,34,38,36,37,44,40,42,11,15,10,27
            fcb   56,23,19,49,48,55,38,39,37,46,47,41,11,25,24,26
            fcb   63,58,50,51,62,52,53,60,60,46,61,61,57,59,58,63


TODO:       rmb   1           ; 0=Load or !0=Save?
TEMP:       rmb   16          ; Temporarily hold 16 palette entries
MONTYP:     rmb   1           ; 0=RGB or !0=CMP

;*****************************************************************************
;* HELP / INFO
;*****************************************************************************

A@          fcc   "ANIMTOOL/BIN Version 1.0",13
            fcc   "(C) 1987 Milliluk Technologies",13
            fcc   "All rights reserved",13
            fcc   ' EXEC:montype:cmd:"name"',13
            fcc   "   montype=R or C",13
            fcc   "   cmd=S (save)",13
            fcc   "       L (load)",13
            fcc   "   POKE &H200,frame # (0-12)",13,0

HELP:
INFO:       jsr   $A928       ; COLOR BASIC ROM CLEAR SCREEN
            leax  A@,PCR      ; Set pointer to start of help/info text above
            lbsr  PRTMS       ; Print characters using BASIC ROM until NUL
            jsr   PRSNXT      ; Go get next character (GETNCH at $9F)
            rts               ; return to BASIC

;*****************************************************************************
;* END
;*****************************************************************************
            end   START

RTS

Return to Tandy Color Computer