/**************
 ******##****** Filename:                 >> AAP_DLTA.C <<
 *****####***** Edit Date: 11.04.92
 ****######****
 ***##*##*##*** By: Wolfgang Hofer,
 **##**##**##**     Jim Kent (PD Code for ANIM5 DLTA decoding in Assembler)
 ******##******
 ******##****** Compiler: AztecC 5.0
 ******##****** Link:     see makefile
 ************** Computer: AMIGA 500
 **************
 **************
 */


/* include <aap.h>  */  /* include Syms */

short  g_ytable[128];

/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   MakeYTable
	Setup a Multiplication Table for the
	skip opcode.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

MakeYTable(f_BytesPerRow)

register short f_BytesPerRow;
{
   register short *pt;
   register short  acc, height;
   static   short  Old_BytesPerRow = 0;

   /* if no changes in Width we can re-use the previous Table */
   if (Old_BytesPerRow == f_BytesPerRow)  return;

   Old_BytesPerRow = f_BytesPerRow;

   pt  = &g_ytable[0];
   acc = 0;
   height = 128;    /* max. line skip range */
   while (height--)
   {
      *(pt++) = acc;
      acc += f_BytesPerRow;
   }
}               /* end MakeYTable */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   DeltaUnpack
	Unpack a DLTA Chunk into the corresponding frame bitmap.
	This code handles:
	- Anim5 standard DLTA Chunks       (IFF standard)
	- Anim7 short and long DLTA Chunks (nonstandard format !!)

	The DLTA Chunk contains
	- 8 opcode list pointers (one for each plane) followed by
	- 8 corresponding data list pointers (only in Anim7) followd by
	- opcode and data
	Unused Bitplanes have a deltadata[i] == 0
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */


DeltaUnpack(f_bm, f_dlta_adr, f_mode)

register struct BitMap *f_bm;   /* Write-Bitmap */
long            f_dlta_adr;     /* Pointer to DLTA Chunk data */
long            f_mode;         /* 0 .. Anim5 Vert. Byte DLTA
				 * 1 .. Anim7 Vert. Word DLTA
				 * 2 .. Anim7 Vert. Long DLTA
				 */
{
   register unsigned char *opclist;
	    unsigned char *dtalist;
   register short          i;

   unsigned char *ptr;
   long          *deltadata;

   deltadata = (long *)(f_dlta_adr);
   /* Loop for max. 8 Bitplanes */
   for (i=0; i<8; i++)
   {
      if (deltadata[i])
      {
	 opclist = (unsigned char *)deltadata + deltadata[i];
	 dtalist = (unsigned char *)deltadata + deltadata[i+8];
	 decode_plane(opclist,        /* in   (opc list)  */
		      dtalist,        /* dta  (data list) */
		      f_bm->Planes[i],  /* out  (bitplane)  */
		      (long)f_bm->BytesPerRow,
		      &g_ytable[0],
		      f_mode
		      );
      }
   }
   return;
}               /* end DeltaUnpack */


#asm
; unvscomp.asm       Copyright 1987 Dancing Flame all rights reserved.
; I copied the code from the file above and did some changes
; and extensions. (word and longword method added)
;                                             Wolfgang HOFER.
;
; This function is set up to be called from C.
; The parameters are on the stack instead of registers.
;       decode_vkplane(in, dta, out, linebytes, ytable_ptr, mode)
;
; mode = 0:
; Anim5 description
;       Jim Kent
;       Dancing Flame
;       739A 16th Ave.
;       San Francisco, CA 94118
;       or jim_kent on BIX.
;
; dta is an unused pointer in Anim5 (mode == 0)
; in is a bit-plane's worth of vertical-byte-run-with-skips data
; and out is a bit-plane that STILL has the image from last frame on it.
; Linebytes is the number of bytes-per-line in the out bitplane, and it
; should certainly be noted that the external pointer variable ytable
; must be initialized to point to a multiplication table of
; 0*linebytes, 1*linebytes ... n*linebytes  before this routine is called.
;
; The format of "in":
;   Each column of the bitplane is compressed separately.  A 320x200
;   bitplane would have 40 columns of 200 bytes each.  The linebytes
;   parameter is used to count through the columns, it is not in the
;   "in" data, which is simply a concatenation of columns.
;
;   Each columns is an op-count followed by a number of ops.
;   If the op-count is zero, that's ok, it just means there's no change
;   in this column from the last frame.
;   The ops are of three classes, and followed by a varying amount of
;   data depending on which class.
;       1. Skip ops - this is a byte with the hi bit clear that says how many
;          rows to move the "dest" pointer forward, ie to skip. It is non-
;          zero
;       2. Uniq ops - this is a byte with the hi bit set.  The hi bit is
;          masked down and the remainder is a count of the number of bytes
;          of data to copy literally.  It's of course followed by the
;          data to copy.
;       3. Same ops - this is a 0 byte followed by a count byte, followed
;          by a byte value to repeat count times.
;   Do bear in mind that the data is compressed vertically rather than
;   horizontally, so to get to the next byte in the destination (out)
;   we add linebytes instead of one!
;
;
; Anim7 description
;       Wolfgang Hofer
;       A-2722 Winzendorf 140 (Austria)
;
; dta is a pointer to a seperate list of datawords
;   if mode == 1 this list contains short words, mode ==2 uses long words
; The format of "in":
;   Each column of the bitplane is compressed separately.
;   a column is 2 (short) or 4 (long) bytes wide.
; The linebytes
;   parameter is used to count through the columns, it is not in the
;   "in" data, which is simply a concatenation of columns.
;
;   Each columns is an op-count followed by a number of ops.
;   If the op-count is zero, that's ok, it just means there's no change
;   in this column from the last frame.
;   The ops are of three classes.
;   For each op there exists a varying amount of data in a seperate
;   data list, depending on which class.
;       1. Skip ops - this is a byte with the hi bit clear that says how many
;          rows to move the "dest" pointer forward, ie to skip. It is non-
;          zero. (requires no data in the data list)
;       2. Uniq ops - this is a byte with the hi bit set.  The hi bit is
;          masked down and the remainder is a count of the number of data
;          of data to copy literally; from data list into the
;          destination bitplane.
;       3. Same ops - this is a 0 byte followed by a count byte, followed
;          by a byte value to repeat count times.
;   Do bear in mind that the data is compressed vertically rather than
;   horizontally, so to get to the next byte in the destination (out)
;   we add linebytes instead of one!
;

	public _decode_plane

dcv_reglist reg a2/a3/a5/d4/d5/d7
dcv_regspc  EQU (6*4)           ;Space for 6 registers on stack
dcv_ofs     EQU dcv_regspc+4    ;stackoffset = returnadress + saved regspace

; Parameter-Offsets to Stackpointer after registersave (movem)
;
in              EQU dcv_ofs+(0*4)
dta             EQU dcv_ofs+(1*4)
out             EQU dcv_ofs+(2*4)
linebytes       EQU dcv_ofs+(3*4)
ytable_ptr      EQU dcv_ofs+(4*4)
mode            EQU dcv_ofs+(5*4)

_decode_plane
	movem.l dcv_reglist,-(sp)  ; save registers for Aztec C
	move.l  #7,d7               ; used as 'fast' constant value
	move.l  in(sp),a0
	move.l  dta(sp),a5
	move.l  out(sp),a2
	move.l  linebytes(sp),d2
	move.l  ytable_ptr(sp),a3
	move.w  d2,d4        ; make a copy of linebytes to use as a counter
	move.l  mode(sp),d0  ; test type of DLTA chunk
	beq     zdcp         ; 0 -> Anim5 Vertical Byterun with skips
	asr.l   #1,d4        ; columncounter / 2 (assume words)
	cmp.b   #1,d0
	beq     w_zdcp       ; 1 -> Anim7 Vertical Wordrun with skips
	asr.l   #1,d4        ; columncounter / 2 (assume long words)
	bra     l_zdcp       ; 2 -> Anim7 Vertical Longword with skips


; --------------------------
; long word
; --------------------------

l_dcp
	move.l  a2,a1       ; get copy of dest pointer
	clr.w   d0          ; clear hi byte of op_count
	move.b  (a0)+,d0    ; fetch number of ops in this column
	bra     l_zdcvclp   ; and branch to the "op" loop.

l_dcvclp
	clr.w   d1          ; clear hi byte of op
	move.b  (a0)+,d1    ; fetch next op
	bmi l_dcvskuniq     ; if hi-bit set branch to "uniq" decoder
	beq l_dcvsame       ; if it's zero branch to "same" decoder

l_skip                      ; otherwise it's just a skip
	add.w   d1,d1       ; use amount to skip as index into word-table
	adda.w  0(a3,d1),a1
	dbra    d0,l_dcvclp ; go back to top of op loop
	bra     l_z1dcp     ; go back to column loop

l_dcvsame                 ; here we decode a "vertical same run"
	move.b  (a0)+,d1  ; fetch the count
	move.l  (a5)+,d3  ; fetch the data value to repeat
	move.w  d1,d5     ; and do what it takes to fall into a "tower"
	asr.w   #3,d5     ; d5 holds # of times to loop through tower
	and.w   d7,d1     ; d1 is the remainder
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+l_same_tower(pc,d1) ;why 34?  8*size of tower
			      ;instruction pair, but the extra 2's
			      ;pure voodoo.
l_same_tower
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	move.l  d3,(a1)
	adda.w  d2,a1
	dbra    d5,l_same_tower
	dbra    d0,l_dcvclp
	bra     l_z1dcp

l_dcvskuniq                   ; here we decode a "unique" run
	and.b   #$7f,d1       ; setting up a tower as above....
	move.w  d1,d5
	asr.w   #3,d5
	and.w   d7,d1
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+l_uniq_tower(pc,d1)
l_uniq_tower
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	move.l  (a5)+,(a1)
	adda.w  d2,a1
	dbra    d5,l_uniq_tower  ; branch back up to "op" loop
l_zdcvclp
	dbra    d0,l_dcvclp      ; branch back up to "column loop"

	; now we've finished decoding a single column
l_z1dcp
	addq.l  #4,a2    ; so move the dest pointer to next column
			 ; in long data mode a column hs a width of 4 bytes
l_zdcp
	dbra    d4,l_dcp ; and go do it again what say?
	bra dcv_all_done

; --------------------------
; short word
; --------------------------

w_dcp
	move.l  a2,a1       ; get copy of dest pointer
	clr.w   d0          ; clear hi byte of op_count
	move.b  (a0)+,d0    ; fetch number of ops in this column
	bra     w_zdcvclp   ; and branch to the "op" loop.

w_dcvclp
	clr.w   d1          ; clear hi byte of op
	move.b  (a0)+,d1    ; fetch next op
	bmi w_dcvskuniq     ; if hi-bit set branch to "uniq" decoder
	beq w_dcvsame       ; if it's zero branch to "same" decoder

w_skip                      ; otherwise it's just a skip
	add.w   d1,d1       ; use amount to skip as index into word-table
	adda.w  0(a3,d1),a1
	dbra    d0,w_dcvclp ; go back to top of op loop
	bra     w_z1dcp     ; go back to column loop

w_dcvsame                 ; here we decode a "vertical same run"
	move.b  (a0)+,d1  ; fetch the count
	move.w  (a5)+,d3  ; fetch the data value to repeat
	move.w  d1,d5     ; and do what it takes to fall into a "tower"
	asr.w   #3,d5     ; d5 holds # of times to loop through tower
	and.w   d7,d1     ; d1 is the remainder
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+w_same_tower(pc,d1) ;why 34?  8*size of tower
			      ;instruction pair, but the extra 2's
			      ;pure voodoo.
w_same_tower
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	move.w  d3,(a1)
	adda.w  d2,a1
	dbra    d5,w_same_tower
	dbra    d0,w_dcvclp
	bra     w_z1dcp

w_dcvskuniq                   ; here we decode a "unique" run
	and.b   #$7f,d1       ; setting up a tower as above....
	move.w  d1,d5
	asr.w   #3,d5
	and.w   d7,d1
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+w_uniq_tower(pc,d1)
w_uniq_tower
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	move.w  (a5)+,(a1)
	adda.w  d2,a1
	dbra    d5,w_uniq_tower  ; branch back up to "op" loop
w_zdcvclp
	dbra    d0,w_dcvclp      ; branch back up to "column loop"

	; now we've finished decoding a single column
w_z1dcp
	addq.l  #2,a2    ; so move the dest pointer to next column
			 ; in short data mode a column hs a width of 2 bytes
w_zdcp
	dbra    d4,w_dcp ; and go do it again what say?
	bra dcv_all_done

; --------------------------
; byte
; (Anim5 standard by Jim Kent)
; --------------------------

dcp
	move.l  a2,a1     ; get copy of dest pointer
	clr.w   d0        ; clear hi byte of op_count
	move.b  (a0)+,d0  ; fetch number of ops in this column
	bra     zdcvclp   ; and branch to the "op" loop.

dcvclp  clr.w   d1        ; clear hi byte of op
	move.b  (a0)+,d1  ; fetch next op
	bmi     dcvskuniq ; if hi-bit set branch to "uniq" decoder
	beq dcvsame       ; if it's zero branch to "same" decoder

skip                      ; otherwise it's just a skip
	add.w   d1,d1     ; use amount to skip as index into word-table
	adda.w  0(a3,d1),a1
	dbra    d0,dcvclp ; go back to top of op loop
	bra     z1dcp     ; go back to column loop

dcvsame                   ; here we decode a "vertical same run"
	move.b  (a0)+,d1  ; fetch the count
	move.b  (a0)+,d3  ; fetch the value to repeat
	move.w  d1,d5     ; and do what it takes to fall into a "tower"
	asr.w   #3,d5     ; d5 holds # of times to loop through tower
	and.w   d7,d1     ; d1 is the remainder
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+same_tower(pc,d1) ; why 34?  8*size of tower
			      ;instruction pair, but the extra 2's
			      ;pure voodoo.
same_tower
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	move.b  d3,(a1)
	adda.w  d2,a1
	dbra    d5,same_tower
	dbra    d0,dcvclp
	bra     z1dcp

dcvskuniq                     ; here we decode a "unique" run
	and.b   #$7f,d1       ; setting up a tower as above....
	move.w  d1,d5
	asr.w   #3,d5
	and.w   d7,d1
	add.w   d1,d1
	add.w   d1,d1
	neg.w   d1
	jmp     34+uniq_tower(pc,d1)
uniq_tower
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	move.b  (a0)+,(a1)
	adda.w  d2,a1
	dbra    d5,uniq_tower  ; branch back up to "op" loop
zdcvclp dbra    d0,dcvclp      ; branch back up to "column loop"

	; now we've finished decoding a single column
z1dcp   addq.l  #1,a2  ; so move the dest pointer to next column
zdcp    dbra    d4,dcp ; and go do it again what say?


dcv_all_done:
	movem.l (sp)+,dcv_reglist
	rts

#endasm
