xdef Transform
xdef point2
xdef writexy
xdef tmatrix
xdef lmatrix
xdef rmatrix
xdef mmult3x1
xdef segloop
xdef inexit
xdef chkvert
xdef vertdone
xdef okcnt
xdef flatlp
xdef no_Yneg
xdef EndOfPack
xdef ttime1
xdef ttime2
xdef ttime3

; Here are the defines for the CLIP values. Used by the texture mapping
; primitive.
	GPXMNCL         EQU     0
	GPXMXCL         EQU     319
	GPYMNCL         EQU     0
	GPYMXCL         EQU     199

; 9/10/93 DLF -
;*======================================================================*
;*                TITLE:      TEXTDRAW.GAS                              *
;*                Function:   Polyhedron Transform, Texture Mapping     *
;*                            Gouraud Shading.  No z-buffering.         *
;*                                                                      *
;*                                                                      *
;*                Authors:    Denis L. Fung/Rob Zydbel                  *
;*                                                                      *
;*          COPYRIGHT 1992,1993,1994 Atari Computer Corporation         *
;*          UNATHORIZED REPRODUCTION, ADAPTATION, DISTRIBUTION,         *
;*          PERFORMANCE OR DISPLAY OF THIS COMPUTER PROGRAM OR          *
;*        THE ASSOCIATED AUDIOVISUAL WORK IS STRICTLY PROHIBITED.       *
;*                            ALL RIGHTS RESERVED.                      *
;*                                                                      *
;*======================================================================*
;*
;* The data is organized in the following fashion in memory:
;*
;*      *** WARNING *** WARNING *** WARNING ***
;*
;*      All pointers MUST BE long aligned
;*
;*      *** WARNING *** WARNING *** WARNING ***
;*
;*              68000|GPU (32 bits)     GPU (32 bits)
;*              +-------------------+    +---------------+
;*              |   #VERT |  #FACE  |<---|  PTR to ARG1  | INPUT1
;*              +-------------------+    +---------------+
;*              |    PTR to VERTS   |--+
;*              +-------------------+  |
;*        +-----|    PTR to TMAPS   |  |        ****** WARNING ******
;*        |     +-------------------+  |         Change to model to
;*     +--|-----|    PTR to TARRAYS |  |          add texture maps
;*     |  |     +-------------------+  |
;*     |  |     |   VCNT  |  COLOR  |  |        One Entry/Face
;*     |  |     +-------------------+  |
;*     |  |               | VRT IDX |  |        VCNT Vertex Indices
;*     |  |               ----------+  |
;*     |  | ...              ...      ...
;*     |  |               +---------+  |
;*     |  |               | VRT IDX |  |
;*     |  |               +---------+  |
;*     |  | ...          ...          ...
;*     |  |     +-------------------+  |
;*     |  |     |    X    |    Y    |<-+        One Entry per Vertex
;*     |  |     +-------------------+
;*     |  |     |    Z    |    Nx   |
;*     |  |     +-------------------+
;*     |  |     |    Ny   |    Nz   |
;*     |  |     +-------------------+
;*     |  |              ...         
;*     |  |     +-------------------+
;*     |  +---->| PTR to TextureMap |           One per texture map
;*     |        +-------------------+
;*     |        | TextMap Blit Flag |           Pitch, pixelsize, width
;*     |        +-------------------+
;*     |                 ...
;*     |        +-------------------+
;*     +------->| Ptr to TexMap Box |           Ptr to array of words
;*              +-------------------+
;*                       ...
;*              +-------------------+    +---------------+
;*              |  Xrite  |  Yrite  |<---|  PTR to ARG2  | INPUT2
;*              +-------------------+    +---------------+
;*              |  Zrite  |  Xdown  |
;*              +-------------------+           Viewer Matrix
;*              |  Ydown  |  Zdown  |           +-             -+
;*              +-------------------+           | L11  L12  L13 |
;*              |  Xhead  |  Yhead  |           | L21  L22  L23 |
;*              +-------------------+           | L31  L32  L33 |
;*              |  Zhead  |  Xposn  |           |  X    Y    Z  |
;*              +-------------------+           +-             -+
;*              |  Yposn  |  Zposn  |
;*              +-------------------+
;*                       ...         
;*              +-------------------+    +---------------+
;*              |  Xrite  |  Yrite  |<---|  PTR to ARG6  | INPUT3
;*              +-------------------+    +---------------+
;*              |  Zrite  |  Xdown  |
;*              +-------------------+           Object's Matrix
;*              |  Ydown  |  Zdown  |           +-             -+
;*              +-------------------+           | R11  R12  R13 |
;*              |  Xhead  |  Yhead  |           | R21  R22  R23 |
;*              +-------------------+           | R31  R32  R33 |
;*              |  Zhead  |  Xposn  |           |  X    Y    Z  |
;*              +-------------------+           +-             -+
;*              |  Yposn  |  Zposn  |
;*              +-------------------+
;*                       ...
;*              +-------------------+    +---------------+
;*              | AMBIENT |  SrcI   |<---|  PTR to ARG3  | INPUT4
;*              +-------------------+    +---------------+
;*              |  SrcX   |  SrcY   |
;*              +-------------------+           Lighting Model
;*              |  SrcZ   |  SrcI   |
;*              +-------------------+
;*                       ...         
;*              +-------------------+
;*              |  SrcI=0 |         |
;*              +-------------------+
;*                       ...         
;*              +-------------------+    +---------------+
;*              | DRAW BUFFER PTR   |<---|  PTR to ARG5  | INPUT5
;*              +-------------------+    +---------------+
;*                       ...                    Active Draw Buffer
;*                       ...         
;*              +-------------------+    +---------------+
;*              | VERTEX BUFFER PTR |<---|  PTR to ARG6  | INPUT6
;*              +-------------------+    +---------------+
;*                                              Scratch Vertex Buffer
;*
;*======================================================================*
	XDEF    text3D  
	XDEF    textMap
	XDEF    TEXTDATA
	XDEF    TexVertPtr
	XDEF    DESTADDR
	XDEF    NumVerts
;       for debug purposes only
	XDEF    LeftEdge
	XDEF    RightEdge
	XDEF    SetUpEdge
	XDEF    StepEdge
	XDEF    lineDraw
	XDEF    VertexPtr
	XDEF    TexVertPtr

	xdef    truepoly
	xdef    facend
	xdef    varray

DEBUG_ON        EQU     0

MAXVERTS        EQU     16              ; <-- MAX #SIDES/POLYGON

PTRSIZE         EQU     (1*4)           ; 1 LONG

INPUT6          EQU     G_ENDRAM-PTRSIZE
INPUT5          EQU     INPUT6-PTRSIZE
INPUT4          EQU     INPUT5-PTRSIZE
INPUT3          EQU     INPUT4-PTRSIZE
INPUT2          EQU     INPUT3-PTRSIZE
INPUT1          EQU     INPUT2-PTRSIZE
GPUSTACK        EQU     INPUT1

;*======================================================================*
	NOLIST

	include "jaguar.inc"
	include "blit.inc"
	include "gpu.inc"
	include "macros.inc"

        .gpu

	LIST
;*======================================================================*
ALIGN PHRASE
	ORG     G_RAM

;*======================================================================*
;*      GLOBAL REGISTER EQUATES
;*======================================================================*
temp            REGEQU  r0
temp2           REGEQU  r1
himask          REGEQU  r2
lomask          REGEQU  r3

;*======================================================================*
;*      MATRIX MULTIPLY AND POINT TRANSFORM REGISTER EQUATES
;*======================================================================*
temp3           REGEQU  r4
jumpr           REGEQU  r5
vcnt            REGEQU  r6
vertptr         REGEQU  r7
riteptr         REGEQU  r8
rptr            REGEQU  r9
ptr             REGEQU  r10
left1           REGEQU  r11
left2           REGEQU  r12
left3           REGEQU  r13
intensity       REGEQU  r14
xtrans          REGEQU  r15
ytrans          REGEQU  r16
ztrans          REGEQU  r17
mtxa            REGEQU  r18
x               REGEQU  r19
y               REGEQU  r20
z               REGEQU  r21
ambient         REGEQU  r22
lptr            REGEQU  r23
xnorm           REGEQU  r24
ynorm           REGEQU  r25
znorm           REGEQU  r26

elemptr         REGEQU  r27
leftptr         REGEQU  r28
idx             REGEQU  r29

rsubr           REGEQU  r30
return          REGEQU  r31

rntnslp         REGEQU  r28     ; *CAUTION REDEFINED*
rinexit         REGEQU  r29     ; *CAUTION REDEFINED*
rsunlit         REGEQU  r30     ; *CAUTION REDEFINED*
rvarray         REGEQU  r31     ; *CAUTION REDEFINED*

;*======================================================================*
;*      LOCAL MACROS
;*======================================================================*
;
;       Special Case - One Level Only JSR
;       NOTE: Register RSUBR Contains the subroutine address
;
MACRO   JSR_MMULT
	move    PC,return
	jump    (rsubr)
	addq    #6,return       ; Determine Return Address
ENDM

MACRO   RTS_MMULT
	jump    (return)
ENDM

;*======================================================================*
;*      CODE SEGMENT
;*======================================================================*
;
;       System Initialization
;
	DEBUG_INIT
text3D:
	moveq   #1,temp2
	movei   #PIT0,temp
	neg     temp2
	store   temp2,(temp)

	moveq   #1,himask
	neg     himask
	move    himask,lomask
	shlq    #16,himask              ; HIMASK = $ffff0000
	shrq    #16,lomask              ; LOMASK = $0000ffff
;
;       Initialize for [3x3] x [3x4] Matrix Multiply
;
	movei   #mmult3x1,rsubr         ; Init for subroutine calls
	movei   #G_MTXC,ptr
	movei   #(MATRIX3|MATROW),temp ; Righthand matrix is [3x1] - COLUMN major
	movei   #G_MTXA,mtxa            ; Prepare GPU for ROW MAJOR multiply
	store   temp,(ptr)              ; Since we wish to multiply by the TRANSPOSE of the Viewer's Matrix

	movei   #INPUT2,ptr
	movei   #lmatrix,leftptr        ; LEFTPTR = Viewer's Matrix
	load    (ptr),lptr              ; LPTR = 68000 ptr to Viewer Matrix
	movei   #rmatrix,riteptr        ; RITEPTR = Object's Matrix
	movei   #INPUT3,ptr
	movei   #tmatrix,elemptr        ; TMATRIX = Resultant Instance Xform Matrix
	load    (ptr),rptr              ; RPTR = 68000 ptr to Model Matrix
;
;       Copy Matrices into GPU space
;
	moveq   #9,idx
	move    leftptr,ptr             ; PTR = ptr to local Viewer Matrix
	move    riteptr,temp3           ; TEMP3 = ptr to local Object Matrix
matlp:
	loadw   (rptr),temp             ; get RIGHT element from external memory
	loadw   (lptr),temp2            ; get LEFT element from external memory
	addq    #2,rptr
	addq    #2,lptr
	shlq    #16,temp
	shlq    #16,temp2
	sharq   #16,temp
	sharq   #16,temp2               ; Sign-Extend to Long
	store   temp,(temp3)            ; copy RIGHT element into GPU space
	store   temp2,(ptr)             ; copy LEFT element into GPU space
	subq    #1,idx
	addqt   #4,temp3
	jr      NE,matlp
	addq    #4,ptr                  ; *Branch Optimization*

	moveq   #3,idx
deltlp:                                 ; Compute Deltas and store into GPU space
	loadw   (rptr),temp             ; get RIGHT element from external memory
	loadw   (lptr),temp2            ; get LEFT element from external memory
	addq    #2,rptr
	addq    #2,lptr
	shlq    #16,temp2
	shlq    #16,temp
	sharq   #16,temp2
	sharq   #16,temp                ; Sign-Extend to Long
	store   temp2,(temp3)           ; Save Original Viewer Coords into GPU space
	addq    #4,temp3
	sub     temp2,temp              ; TEMP = Viewed - Viewer
	subq    #1,idx
	store   temp,(ptr)              ; copy DELTA element into GPU space
	jr      NE,deltlp
	addq    #4,ptr                  ; *Branch Optimization*
;
;       Instance Xform = [ViewerMatrix][ObjectMatrix]
;       Perform [3x3][3x3] matrix multiply using MMULT3x1.
;
	move    leftptr,lptr            ; LPTR = Viewer's Matrix
	move    riteptr,rptr            ; RPTR = Object's Matrix
	JSR_MMULT                       ; [E11 E12 E13]

	move    riteptr,rptr            ; RPTR = Object's Matrix
	JSR_MMULT                       ; [E21 E22 E23]

	move    riteptr,rptr            ; RPTR = Object's Matrix
	JSR_MMULT                       ; [E31 E32 E33]
;
;       Rotate Delta X,Y,Z into Viewer Space
;
	move    leftptr,rptr            ; RPTR = Viewer's Matrix
	JSR_MMULT                       ; [E41 E42 E43]

;
;       Rotate and Translate Light Sources into Viewer Space
;
	move    leftptr,ptr
	subq    #12,ptr
	load    (ptr),xtrans            ; XTRANS = Viewer Xposn
	addq    #4,ptr
	load    (ptr),ytrans            ; YTRANS = Viewer Yposn
	addq    #4,ptr
	load    (ptr),ztrans            ; ZTRANS = Viewer Zposn
	movei   #INPUT4,temp
	addq    #20,rsubr               ; *DANGER* Adjust for special entry point
	load    (temp),lptr             ; LPTR = ptr to lighting model
;       movei   #varray,elemptr         ; NOTE: Elemptr is left pointing to Varray already
	movei   #litelp,jumpr           ; JUMPR = Top of loop address
	loadw   (lptr),ambient
	addq    #2,lptr
	shlq    #8,ambient              ; AMBIENT = Ambient intensity
litelp: loadw   (lptr),temp
	addq    #2,lptr
	cmpq    #0,temp                 ; WHILE (Light Sources Remain) DO
	store   temp,(elemptr)          ; Save Source Intensity
	addqt   #4,elemptr
	jr      NE,10$
	btst    #15,temp                ; *Branch Optimization*
	movei   #litexit,temp
	jump    (temp)
	nop
10$:    jr      NE,20$                  ; IF (SunLight) THEN
	loadw   (lptr),left1            ; Li1
	addq    #2,lptr
	loadw   (lptr),temp             ; Li2
	addq    #2,lptr
	shlq    #16,temp
	loadw   (lptr),left2            ; LEFT2 = Li3
	or      temp,left1              ; LEFT1 = Li2 | Li1
	addq    #2,lptr
	move    leftptr,rptr            ; RPTR = Viewer's Matrix
	JSR_MMULT                       ; Rotate SunLight Vector
	jump    (jumpr)
	nop
20$:                                    ; ELSE (InScene Lighting)
	addq    #2,lptr                 ; LEFT1 = InScene Xposn
	shlq    #16,left1
	loadw   (lptr),y                ; Y = InScene Yposn
	addq    #2,lptr
	shlq    #16,y
	loadw   (lptr),z                ; Z = InScene Zposn
	addq    #2,lptr
	shlq    #16,z
	sharq   #16,left1
	sharq   #16,y
	sharq   #16,z
	sub     xtrans,left1
	sub     ytrans,y
	sub     ztrans,z                ; Translate InScene Vector into Viewer Space
	and     lomask,left1
	shlq    #16,y
	move    z,left2                 ; LEFT2 = Li3
	or      y,left1                 ; LEFT1 = Li2 | Li1
	move    leftptr,rptr            ; RPTR = Viewer's Matrix
	JSR_MMULT                       ; Rotate InScene vector
	jump    (jumpr)
	nop
litexit:

;
;       Jump Around our only subroutine. It wants to be here 
;       because it is near its callers and register equates.
;       Someday it should move .. No, no point to it really.
;
	movei   #Transform,temp
	jump    (temp)
	nop

;*======================================================================*
;* mmult3x1() - do a [3x3][3x1] matrix multiply using MMULT.
;*              place the result in the destination matrix.
;*
;*      input:
;*              lptr    = the address of the left-hand matrix (GPU memory)
;*              rptr    = the address of the right-hand matrix (GPU memory)
;*              elemptr = the address of the result matrix element (GPU memory)
;*
;*      +-             -+   +-             -+   +-             -+
;*      | L11  L12  L13 | X | R11  R12  R13 | = | E11  E12  E13 |
;*      +-             _+   | R21  R22  R13 |   +-             -+
;*                          | R31  R32  R13 |
;*                          +-             -+
;*
;*      E11 = (L11*R11)+(L12*R12)+(L13*R13)
;*      E12 = (L11*R21)+(L12*R22)+(L13*R23)
;*      E13 = (L11*R31)+(L12*R32)+(L13*R33)
;*
;*======================================================================*

mmult3x1:
	load    (lptr),left1            ;* Li1
	addq    #4,lptr
	and     lomask,left1
	load    (lptr),temp             ;* Li2
	addq    #4,lptr
	shlq    #16,temp
	load    (lptr),left2            ;* Li3
	or      temp,left1              ;* Li2 | Li1
	addq    #4,lptr
	and     lomask,left2
;
;       CAUTION: Entry point here for light sources
;
	store   rptr,(mtxa)             ;* tell the GPU where to find the right-hand matrix

	moveta  left1,left1
	moveta  left2,left2
	nop                             ; *** WHY IS THIS NOP REQUIRED? ***
	mmult   left1,left3             ;* left3 = Ei1
	sharq   #14,left3               ;* re-normalize the multiply
	store   left3,(elemptr)         ;* Ei1 = (Li1*R11)+(Li2*R21)+(Li3*R31)
	addq    #4,elemptr              ;* Ei2

	addq    #12,rptr                ; Increment matrix ptr for ROW addressing
	store   rptr,(mtxa)             ;* MTXADDR = &R21
	moveta  left1,left1
	moveta  left2,left2
	nop                             ; *** WHY IS THIS NOP REQUIRED? ***
	mmult   left1,left3             ;* left3 = Ei2
	sharq   #14,left3               ;* re-normalize the multiply
	store   left3,(elemptr)         ;* Ei2 = (Li1*R12)+(Li2*R22)+(Li3*R32)
	addq    #4,elemptr              ;* Ei3

	addq    #12,rptr                ; Increment matrix ptr for ROW addressing
	store   rptr,(mtxa)             ;* MTXADDR = &R31
	moveta  left1,left1
	moveta  left2,left2
	nop                             ; *** WHY IS THIS NOP REQUIRED? ***
	mmult   left1,left3             ;* left3 = Ei3
	sharq   #14,left3               ;* re-normalize the multiply
	store   left3,(elemptr)         ;* Ei3 = (Li1*R13)+(Li2*R23)+(Li3*R33)
	RTS_MMULT                       ;* End of MULT3X1
	addq    #4,elemptr

;*==================================================================
;* Moved the perspective tranform up to right after the transform
;* to viewer space.  In doing this, must reuse the following registers.
;*==================================================================
	x2center                REGEQU          R29
	y2center                REGEQU          R30
	x2scale         REGEQU          R27
	y2scale         REGEQU          R28
 
;*======================================================================*
;* Transform() - For each vertex in the instance do a [3x1][3x3] matrix multiply
;*               and then add the translation components to transform the vertex.
;*               Next, the vertex normal must be transformed without translation.
;*               Finally, use the vertex normal vector to compute the total intensity
;*               at that vertex. These operations will compress the vertex list of the
;*               instance from 6-tuples to quads, which are used by the polydraw.
;*======================================================================*
Transform:
	movei   #299,x2scale            ; **KLUDGE** This information should be acquired
	movei   #299,y2scale            ; **KLUDGE** This information should be acquired
	movei   #159,x2center           ; **KLUDGE** This information should be acquired
	movei   #99,y2center            ; **KLUDGE** This information should be acquired

	movei   #tmatrix,riteptr        ; RITEPTR = Ptr to Final Transformation Matrix

;       Initialize input registers *** WARNING *** WARNING *** long boundaries

	movei   #INPUT1,temp
	load    (temp),ptr              ; PTR = ptr to 68000 parameters
	loadw   (ptr),vcnt              ; VCOUNT = #Vertices in model
	addq    #4,ptr
	load    (ptr),vertptr           ; VERTPTR = Pointer to VERTEX data

	move    riteptr,ptr             ; Extract the translation components from the matrix
	addq    #18,ptr
	addq    #18,ptr                 ; PTR = Ptr to translation components
	load    (ptr),xtrans
	addq    #4,ptr
	load    (ptr),ytrans
	addq    #4,ptr
	load    (ptr),ztrans
  
	movei   #varray,rvarray

	movei   #INPUT6,temp            ; now load up the WRITE LOCATION

	movei   #vertlp,jumpr           ; JUMPR = Top of loop address
	move    vertptr,ptr             ; VERTPTR = WRITE LOCATION
					; PTR    = READ  LOCATION
	load    (temp),vertptr          ; load up the vertex buffer

vertlp:
	load    (ptr),left1             ;*  X|Y
	addq    #4,ptr
	load    (ptr),left2             ;*  Z|Ix
	addq    #4,ptr
	rorq    #16,left1               ;*  Y|X
	move    left2,xnorm
	shrq    #16,left2               ;*  0|Z
;
;       Transform Vertex
;
	move    riteptr,rptr            ; Point to transformation matrix
	store   rptr,(mtxa)             ;* MTXADDR = &R11
	moveta  left1,left1
	moveta  left2,left2
	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,x                 ; X = Transformed Xcomponent
	addq    #12,rptr
	sharq   #14,x                   ;* restore the decimal in the multiply
	store   rptr,(mtxa)             ;* MTXADDR = &R21
	add     xtrans,x                ;* add translation component

	moveta  left1,left1
	moveta  left2,left2
	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,y                 ; Y = Transformed Ycomponent
;       move    x,temp
	sharq   #14,y                   ;* restore the decimal in the multiply
;       shlq    #16,temp                ; TEMP = X|0
	add     ytrans,y                ;* add translation component

	addq    #12,rptr
;       move    y,temp2
	store   rptr,(mtxa)             ;* MTXADDR = &R31
;       and     lomask,temp2            ; TEMP2 = 0|Y
	moveta  left1,left1
;       or      temp2,temp
	moveta  left2,left2

;       store   temp,(vertptr)          ; Write X|Y back into vertex list
;       addq    #4,vertptr

	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,z                 ; Z = E13
	sharq   #14,z                   ;* restore the decimal in the multiply
	load    (ptr),left2             ;* Iy|Iz
	add     ztrans,z                ;* add translation component

;
;       Transform the Vertex Normal
;
	addq    #4,ptr          ; leave this in for the mainloop
	move    left2,left1
	and     lomask,xnorm            ;*  0|Ix
	and     himask,left1            ;* Iy|0
	and     lomask,left2            ;*  0|Iz
	or      xnorm,left1             ;* Iy|Ix

	move    riteptr,rptr            ; point to Final Transformation matrix
	moveta  left1,left1
	store   rptr,(mtxa)             ;* MTXADDR = &R11
	moveta  left2,left2
	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,xnorm             ; XNORM = E11
	addq    #12,rptr
	sharq   #14,xnorm               ;* restore the decimal in the multiply

	store   rptr,(mtxa)             ;* MTXADDR = &R21
	moveta  left1,left1
	moveta  left2,left2
	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,ynorm             ; YNORM = E12
	addq    #12,rptr
	sharq   #14,ynorm               ;* restore the decimal in the multiply

	store   rptr,(mtxa)             ;* MTXADDR = &R31
	moveta  left1,left1
	moveta  left2,left2
	nop                             ;*** WHY IS THIS NOP REQUIRED ??? ***
	mmult   left1,znorm             ; ZNORM = E13
	sharq   #14,znorm               ;* restore the decimal in the multiply
;
;       Vertex Intensity = Sum of Intensities from all Light Sources
;
	move    rvarray,lptr            ; LPTR = Ptr to Internalized LiteModel
	move    ambient,intensity       ; Initialize to the ambient component
intenslp:
	load    (lptr),left3            ; LEFT3 = Intensity component
	addq    #4,lptr
	cmpq    #0,left3
	jr      NE,10$                  ; WHILE (Light Sources Remain) DO
	btst    #15,left3               ; *Branch Optimization*
	movei   #inexit,temp
	jump    (temp)
	nop
10$:    jr      NE,11$
	bclr    #15,left3               ; Clear flag bit
	movei   #sunlit,temp
	jump    (temp)
	nop
;
; Find the InScene vector and Vertex normal vector DOT product and attenuate
;
11$:
	load    (lptr),left1            ; LEFT1 = SourceX
	addq    #4,lptr
	sub     x,left1                 ; LEFT1 = DeltaX = SourceX - VertexX
	move    left1,left2
	imult   left1,left1             ; LEFT1 = (DeltaX)^2
	imult   xnorm,left2             ; LEFT2 = (DeltaX*Nx)

	load    (lptr),temp             ; TEMP = SourceY
	addq    #4,lptr
	sub     y,temp                  ; TEMP = DeltaY = SourceY - VertexY
	move    temp,temp2
	imult   temp,temp               ; TEMP = (DeltaY)^2
	imult   ynorm,temp2             ; TEMP2 = (DeltaY*Ny)
	add     temp,left1              ; LEFT1 = (DeltaX)^2 + (DeltaY)^2
	add     temp2,left2             ; LEFT2 = (DeltaX*Nx) + (DeltaY*Ny)

	load    (lptr),temp             ; TEMP = SourceZ
	addq    #4,lptr
	sub     z,temp                  ; TEMP = DeltaZ = SourceZ - VertexZ
	move    temp,temp2
	imult   temp,temp               ; TEMP = (DeltaZ)^2
	imult   znorm,temp2             ; TEMP2 = (DeltaZ*Nz)
	add     temp,left1              ; LEFT1 = (DeltaX)^2 + (DeltaY)^2 + (DeltaZ)^2
	add     temp2,left2             ; LEFT2 = (DeltaX*Nx) + (DeltaY*Ny) + (DeltaZ*Nz)
	jr      MI,13$                  ; IF (Positive Reflectance) THEN Sum InScene Intensity
					; *NOTICE* InScene Attenuation Scaling Factor *NOTICE*
	shrq    #12,left1               ; <-- 1/4 of SunLight (#14 would give equality with SunLight)
					; *NOTICE* InScene Attenuation Scaling Factor *NOTICE*
	addq    #1,left1                ; Avoid divide-by-zero
	div     left1,left2             ; LEFT2 = Attenuation Factor
	mult    left3,left2             ; I*Attenuation
	shrq    #6,left2                ; Increase Intensity magnitude (to 8.8)
	add     left2,intensity         ; Intensity += InScene Source
13$:
	movei   #intenslp,temp
	jump    (temp)
;       jump    (rntnslp)
	nop
;
; Find the SunLight vector and Vertex normal vector DOT product
;
sunlit: load    (lptr),temp2            ; TEMP2 = SourceX
	addq    #4,lptr
	imult   xnorm,temp2             ; TEMP2 = (Sx*Nx)
	load    (lptr),temp             ; TEMP = SourceY
	addq    #4,lptr
	imult   ynorm,temp              ; TEMP = (Sy*Ny)
	add     temp,temp2              ; TEMP2 = (Sx*Nx)+(Sy*Ny)
	load    (lptr),temp             ; TEMP = SourceZ
	addq    #4,lptr
	imult   znorm,temp
	add     temp,temp2              ; TEMP2 = (Sx*Nx)+(Sy*Ny)+(Sz*Nz)
	sharq   #14,temp2               ; Restore fixed floating point
	jr      MI,13$                  ; IF (Positive Reflectance) THEN Sum it
	mult    left3,temp2             ; I((Sx*Nx)+(Sy*Ny)+(Sz*Nz))
	shrq    #6,temp2                ; Increase Intensity magnitude (to 8.8)
	add     temp2,intensity         ; Intensity += Sunlight Source
13$:
	movei   #intenslp,temp
	jump    (temp)
;       jump    (rntnslp)
	nop
inexit:
	sharq   #8,intensity            ; DLF BUG?
	cmp     lomask,intensity        ;* I = IaK + IsK(Vsn*N)         [K=1]
	jr      MI,oksun
	nop
	move    lomask,intensity        ; Max Intensity at $ffff
oksun:
 
	cmpq    #5,z
	jr      PL,40$
	nop
	moveq   #5,z
40$:
;;      nop
	imult   x2scale,x
	imult   y2scale,y
 
	abs     x
	jr      CC,10$
	div     z,x
	neg     x
10$:
	abs     y
	jr      CC,20$
	div     z,y
	neg     y
20$:
;; testing limits
;       movei   #okyneg,temp
;       cmpq    #15,z
;       jump    PL,(temp)
;       nop
;       movei   #($800),temp
;       cmp     temp,x          ; is x bigger than $0800
;       jr      MI,okx800
;       nop
;       move    temp,x
;okx800: cmp    temp,y
;       jr      MI,oky800
;       nop
;       move    temp,y
;oky800: movei  #(-$800),temp
;       cmp     x,temp
;       jr      MI,okxneg
;       nop
;       move    temp,x
;okxneg: cmp    y,temp
;       jr      MI,okyneg
;       nop
;       move    temp,y
;okyneg:
;;      end testing!!!
 
	add     x2center,x
	add     y2center,y
 
	shlq    #16,x
	and     lomask,y
	or      y,x
	store   x,(vertptr)
	addq    #4,vertptr
;
;       Combine calculated intensity with Z vertex and store
;
	shlq    #16,z                   ; Z = Z|0
	or      z,intensity
;;      store   z,(vertptr)             ; write back only z, DLF
	store   intensity,(vertptr)     ; Write Z|I back into vertex list
	addq    #4,vertptr

	subq    #1,vcnt
	jump    NE,(jumpr)              ; UNTIL (All vertices done)
	nop

;*==============================================================*
;*      ACTUALLY DRAW THE POLYHEDRON
;*==============================================================*

REGUNDEF        z
REGUNDEF        vertptr
REGUNDEF        ptr
REGUNDEF        jumpr
REGUNDEF        temp3
REGUNDEF        return

;*======================================================================*
;*      ALTERNATE REGISTER EQUATES
;*======================================================================*
;; DLF - Removed the use of these alternate registers to facilitate
;;       adding in texture mapping.  Could be put back in.

;*======================================================================*
;*      REGISTER EQUATES  (SubPolygon Draw)
;*======================================================================*
rb_cmd          REGEQU  r4
texptr          REGEQU  r5
tboxptr         REGEQU  r6

texindex        REGEQU  r10
tboxindex       REGEQU  r11
saveint         REGEQU  R13             ; just to save intensity
color           REGEQU  r12
left            REGEQU  r13
xleft           REGEQU  r14
yleft           REGEQU  r15
ileft           REGEQU  r16
rite            REGEQU  r17
xrite           REGEQU  r18
yrite           REGEQU  r19
irite           REGEQU  r20

;*======================================================================*
;*      REGISTER EQUATES  (Draw Polygon)
;*======================================================================*
vcount          REGEQU  r26     ; *CAUTION: Alternate Saved*
verts           REGEQU  r27     ; *CAUTION: Alternate Saved*

next            REGEQU  r28     ; *CAUTION: ReDefined*
ynext           REGEQU  r29     ; *CAUTION: ReDefined*
temp3           REGEQU  r12

clipsum         REGEQU  r24
ptr             REGEQU  r25

;*======================================================================*
;*      REGISTER EQUATES  (Draw Polyhedron)
;*======================================================================*
faceptr         REGEQU  r28     ; *CAUTION: Alternate Saved*
segptr          REGEQU  r29     ; *CAUTION: Alternate Saved*
vertptr         REGEQU  r30     ; *CAUTION: Alternate Saved*
facecnt         REGEQU  r31     ; *CAUTION: Alternate Saved*

jumpr           REGEQU  r24

z               REGEQU  r16
xscale          REGEQU  r20
yscale          REGEQU  r21
xcenter         REGEQU  r22
ycenter         REGEQU  r23

segcnt          REGEQU  r21     ; *CAUTION: ReDefined*
xnew            REGEQU  r22     ; *CAUTION: ReDefined*
ynew            REGEQU  r23     ; *CAUTION: ReDefined*

;*****************************************************************************
;* Alternate bank registers used by textMap and its subroutines
;*****************************************************************************
	a_R_DestI       REGEQU          R2
	a_lomask        REGEQU          R3
	a_himask        REGEQU          R4
	a_DestY         REGEQU          R5
	a_L_DestI       REGEQU          R9
	a_lineDraw      REGEQU          R11
	a_B_IINC        REGEQU          R18
	a_GPXMNCL       REGEQU          R8
	a_R_DestX       REGEQU          R14
	a_L_DestX       REGEQU          R15
	a_L_SourceX     REGEQU          R16
	a_R_SourceX     REGEQU          R17
	a_DestFlags     REGEQU          R19
	a_DESTADDR      REGEQU          R20
	a_B_PATD        REGEQU          R21
	a_B_I3          REGEQU          R22
	a_B_CMD         REGEQU          R23
	a_B_COUNT       REGEQU          R24
	a_StepEdge      REGEQU          R25
	a_GPXMXCL       REGEQU          R26
	a_TexFlags      REGEQU          R27
	a_A1_FLAGS      REGEQU          R28
	a_A1_BASE       REGEQU          R29
	a_A1_PIXEL      REGEQU          R1
	a_A1_INC        REGEQU          R0
	a_do_tmap       REGEQU          R6
	a_FFFFFF        REGEQU          R7

	movei   #A1_INC,R0
	movei   #R_DestI,R1
	movei   #$0000ffff,R2
	movei   #DestY,R4
	move    R2,R3
	movei   #do_tmap,R5
	not     R3
	moveta  R0,a_A1_INC
	moveta  R1,a_R_DestI
	moveta  R2,a_lomask
	moveta  R3,a_himask
	moveta  R4,a_DestY
	moveta  R5,a_do_tmap
	movei   #$0ffffff,R0
	movei   #L_DestI,R2
	movei   #lineDraw,R3
	movei   #B_IINC,R5
	moveta  R0,a_FFFFFF
	moveta  R2,a_L_DestI
	moveta  R3,a_lineDraw
	moveta  R5,a_B_IINC

	movei   #R_DestX,R1
	moveq   #GPXMNCL,R0
	movei   #L_DestX,R2
	movei   #L_SourceX,R3
	movei   #R_SourceX,R4
	moveta  R0,a_GPXMNCL
	moveta  R1,a_R_DestX
	moveta  R2,a_L_DestX
	moveta  R3,a_L_SourceX
	moveta  R4,a_R_SourceX
	movei   #DestFlags,R0
	movei   #B_PATD,R2
	movei   #B_I3,R3
	movei   #B_CMD,R4
	movei   #B_COUNT,R5
	moveta  R0,a_DestFlags
	moveta  R2,a_B_PATD
	moveta  R3,a_B_I3
	moveta  R4,a_B_CMD
	moveta  R5,a_B_COUNT
	movei   #StepEdge,R0
	movei   #GPXMXCL,R1
	movei   #TexFlags,R2
	movei   #A1_FLAGS,R3
	movei   #A1_BASE,R4
	movei   #A1_PIXEL,R5
	moveta  R0,a_StepEdge
	moveta  R1,a_GPXMXCL
	moveta  R2,a_TexFlags
	moveta  R3,a_A1_FLAGS
	moveta  R4,a_A1_BASE
	moveta  R5,a_A1_PIXEL

	movei   #INPUT5,temp
	load    (temp),temp3            ; Current DRAW buffer address
	moveta  temp3,a_DESTADDR

	movei   #DestFlags,ptr
	movei   #(PITCH2|PIXEL16|WID320),temp   ; flags
	store   temp,(ptr)
	addq    #4,ptr

;*==============================================================*
;
;       Fetch Model Parameters - Model Initialization
;
point2:
	movei   #INPUT1,temp
	load    (temp),ptr              ; PTR = ptr to 68000 parameters
	loadw   (ptr),vcount            ; VCOUNT = #Vertices in model
	addq    #2,ptr
	loadw   (ptr),facecnt           ; FACECNT = #Faces in model
	addq    #6,ptr
	load    (ptr),texptr            ; TEXPTR = Pointer to texture maps
	addq    #4,ptr
	load    (ptr),tboxptr           ; TBOXPTR = Ptr to arrays of vertices
	addq    #4,ptr                  ; for the texture maps

	movei   #INPUT6,temp
	move    ptr,faceptr             ; FACEPTR = Pointer into FACE data
	load    (temp),vertptr          ; VERTPTR = Pointer to VERTEX data

;*======================================================================*
;*      POLYHEDRON RENDERING
;*======================================================================*


	movei   #PIT0,temp
	movei   #ttime1,temp2
	load    (temp),temp3
	store   temp3,(temp2)

;
;       Model Draw
;
faceloop:                               ; FOR (All Faces) DO
	movefa  a_lomask,lomask

	moveq   #0,texindex             ; clear out
	moveq   #0,tboxindex
	loadw   (faceptr),texindex
	addq    #2,faceptr
	shlq    #16,texindex
	loadw   (faceptr),tboxindex
	sharq   #16,texindex
	addq    #2,faceptr
	moveta  texindex,texindex       ; save off as flag for text/gouraud

	loadw   (faceptr),segcnt        ; SEGCNT = #Segments in Face
	addq    #2,faceptr
	loadw   (faceptr),color
	addq    #2,faceptr
	shlq    #8,color                ; COLOR = Face Color
	move    color,temp
	shlq    #16,color
	or      temp,color              ; C|0|C|0
	moveta  color,color             ; save off the color

;
;       Model Decode
;
	movei   #varray,verts           ; VERTS = Ptr to local vertex array
	move    verts,vcount            ; vcount = Ptr to next free slot in vertex array
	movei   #segloop,jumpr          ; **KLUDGE** Change this NAME
segloop:                                ; FOR (All Segments) DO

	loadw   (faceptr),temp
	addq    #2,faceptr
	shlq    #16,temp
	sharq   #16,temp
	add     vertptr,temp
	load    (temp),xleft            ; XLEFT = vertex X|Y    
	addq    #4,temp
	move    xleft,yleft

	store   xleft,(vcount)          ; Save X|Y
	addq    #4,vcount
	load    (temp),ileft            ; ILEFT = vertex Z|I
	shlq    #16,yleft
	sharq   #16,xleft
	sharq   #16,yleft
	store   ileft,(vcount)          ; Save Z|I
	addq    #4,vcount
	sharq   #16,ileft

	subq    #1,segcnt               ; UNTIL (All Segments decoded)
	jump    NE,(jumpr)
	nop

;
;       Polygon Clipping
;
	movei   #qfaceptr,temp
	store   faceptr,(temp)
	addq    #8,temp
	store   facecnt,(temp)
	addq    #4,temp
	store   texptr,(temp)
	addq    #4,temp
	store   tboxptr,(temp)

exitclip:
	subq    #8,vcount               ; VCOUNT = Ptr to Last Vertex

;
;       Perspective Transform and Find TopLeftMost Vertex
;
;       Also find TopY,BotY,LeftX,RightX for clipping to the screen.
;       Note: TopY is the same as yleft.
	BotY            REGEQU          R7
	LeftX           REGEQU          R8
	RightX          REGEQU          R23
	BackZ           REGEQU          R29
; LeftX is being used for the backface culling
	Left2X          REGEQU          R28
 

chkvert:
	movei   #varray,verts
	movefa  a_lomask,lomask
	move    verts,ptr               ; PTR = Ptr to VertList
	move    lomask,yleft

	move    lomask,LeftX
	move    lomask,Left2X
	move    LeftX,BotY
	not     BotY
	shlq    #8,BotY                 ; make it $FF000000
	move    BotY,RightX
	move    BotY,BackZ
 
	movei   #topvert,jumpr          ; Prepare to Loop
	moveq   #0,temp3                ; initialize count of vertices

topvert:                                ; FOR (All Vertices) DO
	addq    #1,temp3
	load    (ptr),xrite
	move    xrite,yrite
	sharq   #16,xrite               ; XRITE = 16-bit Xviewed
	addq    #4,ptr
	and     lomask,yrite            ; YRITE = 16-bit Yviewed
	load    (ptr),z
	subq    #4,ptr
	sharq   #16,z

	shlq    #16,yrite
	sharq   #16,yrite               ; restore sign!

	cmp     BotY,yrite              ; is new Y bottom-most?
	jr      MI,ygt
	cmp     yrite,yleft             ; is new Y top-most? (yrite < yleft)?
	move    yrite,BotY
ygt:
	jr      NE,30$
	nop
	cmp     xrite,xleft             ; Is topmost, is it the leftmost? (xrite < xleft)?
30$:    jr      MI,vertdone             ; no,skip it
	cmp     xrite,LeftX             ; is new X left-most?

	move    yrite,yleft             ; record new top-left-most vertex
	move    xrite,xleft
	move    ptr,left                ; LEFT = Top-left vertex ptr
vertdone:
	jr      MI,notleft
	cmp     RightX,xrite            ; is new X right-most?
	move    xrite,LeftX
notleft:
	jr      MI,notrite
	cmp     BackZ,z
	move    xrite,RightX
notrite:
	jr      MI,nleft2
	cmp     xrite,Left2X
	move    z,BackZ
nleft2:
	jr      MI,vdone2
	cmp     vcount,ptr
	move    xrite,Left2X
vdone2:
	jump    MI,(jumpr)
	addq    #8,ptr
;
;       INPUT COMPLETE...and we found the top-left-most vertex
;
;       Now compare values with screen clip values
 
scrnclp:
	movei   #facend,temp
	moveq   #20,temp2
	cmp     temp2,BackZ
	jump    MI,(temp)
	moveq   #GPXMNCL,temp2
	cmp     temp2,RightX            ; is rightmost X > XMNCL?
	jump    MI,(temp)
	moveq   #GPYMNCL,temp2
	cmp     temp2,BotY
	jump    MI,(temp)
	nop
	movei   #GPXMXCL,temp2
	cmp     Left2X,temp2
	jump    MI,(temp)
	nop
	movei   #GPYMXCL,temp2
	cmp     yleft,temp2
	jump    MI,(temp)

	move    vcount,temp
	movei   #NumVerts,temp2
	store   temp3,(temp2)           ; save the number of vertices
	sub     verts,temp
;
;       Perspective Xform complete...and we found the top-left-most vertex
;
okcnt:

;
;       FLAT-SHADING Determine intensity for entire face
;
	movei   #skp_flat,temp
	cmpq    #0,texindex
	jump    MI,(temp)
	nop

	moveq   #0,temp                 ; TEMP = Total Intensity
	moveq   #0,temp3
	move    verts,next              ; NEXT = Vertex ptr
	addq    #4,next
flatlp:                                 ; FOR (All Vertices) DO
	load    (next),temp2
	and     lomask,temp2            ; TEMP2 = Intensity (8.8)
	add     temp2,temp              ; Sum Intensities
	addq    #1,temp3
	cmp     next,vcount
	jr      PL,flatlp
	addq    #8,next
intense:
	div     temp3,temp              ; TEMP = Average Intensity (8.8)

	shlq    #16,temp
;       sharq   #8,temp
	sharq   #10,temp                        ; too bright.  Lower intensity
	moveta  temp,saveint
skp_flat:


truepoly:                               ; ELSE This is a true polygon
	move    left,rite
	move    yleft,yrite
;
;       BACKFACE CULLING by Counter-Clockwise ordering
;
	move    left,next
	subq    #8,next
	cmp     verts,next
	jr      PL,mod0                 ; next = (LEFT-1) mod VERTCNT
	nop
	move    vcount,next             ; NEXT = Ptr to Previous vertex
mod0:   load    (next),ynew
	move    ynew,xnew
	and     lomask,ynew             ; YNEW = Last.Y
;; BUG? does this not work for negatives?
	shlq    #16,ynew
	sharq   #16,xnew
	sharq   #16,ynew
;;      shrq    #16,xnew                ; XNEW = Last.X

	move    left,next
	addq    #8,next
	cmp     next,vcount
	jr      PL,mod1                 ; next = (RIGHT+1) mod VERTCNT
	nop
	move    verts,next              ; NEXT = Next vertex
mod1:   load    (next),temp
	move    temp,temp2
	and     lomask,temp             ; TEMP = Next.Y
;; BUG? see above
	shlq    #16,temp
	sharq   #16,temp2
	sharq   #16,temp
;;      shrq    #16,temp2               ; TEMP2 = Next.X

	neg     temp
	add     yleft,temp              ; TEMP = Top.Y - Next.Y
	neg     temp2
	add     xleft,temp2             ; TEMP2 = Top.X - Next.X
	sub     xnew,xleft              ; XLEFT = Top.X - Last.X
	sub     ynew,yleft              ; YLEFT = Top.Y - Last.Y

	imult   temp2,yleft
	imult   temp,xleft

	movei   #facend,temp
	cmp     xleft,yleft
	jump    MI,(temp)               ; IF (Counter-Clockwise) THEN Reject this face
	nop
	move    yrite,yleft
;****************************************************
; set up texture map!!!!
; assuming inputs verts - pointer to vertices
;                 vcount - pointer to last vertex
; can mess with all registers except the above two!
;*****************************************************

; set up all blitter variables that are once per face!
; can use all registers except texindex and temp(2), r10, r0, r1
	movefa  a_B_PATD,R28
	movefa  color,R27
	move    R28,R25
	addq    #4,R25
	move    R27,R26

	movefa  a_B_CMD,temp

	moveq   #0,R3
	bset    #16,R3
	movefa  a_DESTADDR,R22
	movefa  a_A1_BASE,R21

bwait2:
	load    (temp),temp2
	btst    #0,temp2
	jr      EQ,bwait2
	nop

	store   R27,(R28)
	store   R26,(R25)
	store   R22,(R21)

	movei   #TEXTDATA,ptr
	movei   #TexVertPtr,temp3
	cmpq    #0,texindex
	jr      MI,skp_ind
	nop
	shlq    #3,texindex     ; make index (2 longs per texturemap)
	add     texptr,texindex
	load    (texindex),temp
	store   temp,(ptr)
	shlq    #2,tboxindex            ; make it index longs
	add     tboxptr,tboxindex
	load    (tboxindex),temp
	store   temp,(temp3)
	addq    #4,texindex
	addq    #4,temp3
	load    (texindex),temp 
	store   temp,(temp3)
skp_ind:
	movei   #textMap,R0
	jump    (R0)
	nop
tmapret:

;
;       Face Done - Go on to the next face
;
facend:
;;      movefa  qfaceptr,faceptr        ; "Pop" saved Polyhedron variables
	movei   #qfaceptr,temp
	load    (temp),faceptr
;;      movefa  qsegptr,segptr
;       addq    #4,temp
;       load    (temp),segptr
;;      movefa  qvertptr,vertptr
;       addq    #4,temp

;       load    (temp),vertptr
;;      movefa  qfacecnt,facecnt
;       addq    #4,temp
	addq    #8,temp
	load    (temp),facecnt
	addq    #4,temp
	load    (temp),texptr
	addq    #4,temp
	movei   #INPUT6,temp2
	load    (temp),tboxptr
	load    (temp2),vertptr

	movei   #faceloop,temp          ; NEXT FACE
	subq    #1,facecnt
	jump    NE,(temp)
	nop

;*==============================================================*
;*      GPU RTS
;*==============================================================*

gpuend:
	movefa  a_B_CMD,temp2
bwait:
	load    (temp2),temp3
	btst    #0,temp3
	jr      EQ,bwait
	nop
	movei   #PIT0,temp
	movei   #ttime3,temp2
	load    (temp),temp3
	store   temp3,(temp2)

	movei   #G_CTRL,temp2           ; GPU control/status register
	load    (temp2),temp
	bclr    0,temp                  ; clear GPUGO bit
	store   temp,(temp2)            ; stop the GPU

endloop:
	jr      endloop                 ; infinite loop
	nop


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; textMap
;;
;; This routine is an implementation of texture mapping.  As inputs, it
;; takes a source polygon containing texture data and a destination polygon,
;; and it maps the texture onto the destination.  Both polygons must have
;; the same number of vertices, the vertices must be ordered clock-wise,
;; and the polygons must be convex (and non-intersecting).  Before using,
;; the widths of the source and destination windows must be specified.
;; The defaults are embedded in the setting of the A1 and A2 flags.
;;
;; Algorithm adapted from Dr.Dobb's Sept-Oct. 1992
;;
;; NOTES:  This routine calls three other routines: lineDraw, SetUpEdge,
;; and StepEdge.  Whenever textMap calls any of these routines, the
;; register set will be switched
;;
;; Author: Denis L. Fung
;;
;; Inputs:
;;      NUMVERT         The number of vertices in the polygons
;;      SRCPLY          The address of the array describing the vertices,
;;                      with each vertex being a word.  This address must
;;                      be long-aligned.
;;      SRCADDR         The address of the texture data.
;;      DSTPLY          The address of the array describing the vertices,
;;                      with each vertex being a word.  This address must
;;                      be long-aligned.
;;      DSTADDR         The destination address of the draw window.
;;      GPCLIP          Clip flag, 1 = on, 0 = off.
;;      GPXMNCL...      Clip variables
;;      RETADDR         Return address, if 0, then it will stop the GPU
;;
;;      Destroys:  All registers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

textMap:
	movei   #PIT0,R0
	movei   #ttime2,R2
	load    (R0),R1
	store   R1,(R2)

	REGUNDEF        vertptr
	REGUNDEF        ptr
	MAXY    REGSET          R26
	MINY    REGSET          R25
	NUMVERT REGSET          R24
	MAXVERT REGSET          R23
	INDEX   REGSET          R22
	MINVERT REGSET          R21
	VERTPTR REGSET          R20
	MASK    REGSET          R19
	VERTY   REGSET          R18

	movei   #NumVerts,R0
	load    (R0),NUMVERT
	moveq   #0,INDEX
	cmpq    #2,NUMVERT              ; Reject faces < 3 vertices
	jr      PL,cont_tm
	nop
	movei   #tmapret,R1
	jump    (R1)
cont_tm:
	; scan through the dest polygon vertices and find the top of
	; the left and right edges, assuming that the vertices run in
	; a clockwise direction (else this polygon wouldn't be visible
	; due to backface removal
	moveq   #0,MAXY
	movefa  a_lomask,MASK
	bset    #15,MAXY
	movei   #varray,VERTPTR
	move    MAXY,MINY
	movei   #do_textM,R29
	neg     MAXY
	movei   #tm_loop,R28
	subq    #1,MINY
	cmp     NUMVERT,INDEX
tm_loop:
	jr      MI,tm_lcnt
	load    (VERTPTR),VERTY
	jump    (R29)
	nop
tm_lcnt:
	and     MASK,VERTY      ; mask out the x-value
	shlq    #16,VERTY
	sharq   #16,VERTY
	cmp     MINY,VERTY
	jr      PL,do_max
	nop
	move    VERTY,MINY
	move    INDEX,MINVERT
do_max:
	cmp     VERTY,MAXY
	jr      PL,min_max
	addq    #8,VERTPTR              ; skip to next vertex
	move    VERTY,MAXY
	move    INDEX,MAXVERT
min_max:
	addq    #1,INDEX
	jump    (R28)
	cmp     NUMVERT,INDEX
do_textM:
	; reject 0-pixel high polygons
	cmp     MAXY,MINY
	jr      MI,text_cont
	moveq   #1,R0
	movei   #tmapret,R29
	jump    (R29)
	nop
text_cont:
	movei   #MaxVert,R3
	movei   #G_REMAIN,R1
	store   MAXVERT,(R3)
	movefa  a_DestY,R2
	subq    #4,R3
	store   R0,(R1)
	store   MINVERT,(R3)
	; set up to scan the initial left and right edges fo the source and
	; dest polygns.  We always tep the dest poly edges by one in Y,
	; so calc corresponding dest Xstep for each edge, and then the
	; corresponding source image X and Y steps
	movei   #LeftEdge,R27
	store   MINY,(R2)
	movefa  a_himask,R17
	movei   #done_left,R29
	store   R17,(R27)       ; set up edge direction
	movei   #SetUpEdge,R20
	move    MINVERT,R28
	jump    (R20)
	nop
done_left:
	moveq   #0,R17
	movei   #RightEdge,R27
	bset    #16,R17
	movei   #MinVert,R19
	store   R17,(R27)       ; set up edge direction
	movei   #SetUpEdge,R20
	load    (R19),R28
	movei   #done_right,R29
	jump    (R20)
	nop
done_right:
	; step down dest edges one scan line at a time.  At each scan
	; line, find corresponding edge points in the source image.  Scan
	; between the edge points in the source, drawing the corresponding
	; pixels across the current scan line in the dest plygn. (We know
	; which way teh left and right edges run through the vertex list
	; because visible (non-backfage-culled) plygns always have vertices
	; in clockwise order as seen from the viewpoint)
loop_tmap:
	; the dest Y coordinate is not edge specific; it applies to both
	; edges since we always step Y by 1
	movefa  a_DestY,R17
	movei   #GPYMXCL,R16
	load    (R17),R11
	cmp     R16,R11
	; done if off bottom of clip rectangle
	jr      MI,no_ymxcl
	moveq   #GPYMNCL,R13
	movei   #text_stop,R1
	jump    (R1)
	nop
no_ymxcl:
	cmp     R13,R11
	; draw only if inside Y bounds of clip rectangle
	jr      MI,scn_ln_ret
	nop
	movei   #scn_ln_ret,R29
	movefa  a_lineDraw,R20
	jump    (R20)
	nop
scn_ln_ret:
	; advance the source and dest polygn edges, ending if we've
	; scanned all the way to the bottom of the plygn

	movei   #fin_stpl,R29
	movefa  a_StepEdge,R20
	movei   #LeftEdge,R27
	jump    (R20)
	nop
fin_stpl:
	; R0 has the return code, 0 means quit
	cmpq    #0,R0
	jr      NE,nxt_e
	nop
	movei   #text_stop,R20
	jump    (R20)
	nop
nxt_e:
	movei   #RightEdge,R27
	movefa  a_StepEdge,R20
	movei   #fin_stpr,R29
	jump    (R20)
	nop

fin_stpr:
	cmpq    #0,R0
	jr      EQ,text_stop
	movefa  a_DestY,R10
	load    (R10),R11
	addq    #1,R11
	store   R11,(R10)
	movei   #loop_tmap,R20
	jump    (R20)
	nop
text_stop:
; turn off 16.16 divides
	movei   #G_REMAIN,R4
	moveq   #0,R3
	movei   #tmapret,R1
	store   R3,(R4)         ; set up for 16.16 divides
	jump    (R1)
	nop


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; StepEdge
;;
;; This routine steps an edge one scan line in the destination, and the
;; corresponding distance in the source.  If an edge runs out, starts a
;; new edge if there is one.
;;
;; Input:
;;      R27     Pointer to edge structure
;;      R29     Return address
;;      NOTE: Same as SetupEdge, since we call that routine.
;; Output:
;;      R0      Returns 1 if successful, 0 if no more edges to scan.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; parameters
	EdgePtr         REGSET          R27
	RetAd           REGSET          R29
StepEdge:
	DestX           REGSET          R1
	ADestX          REGSET          R2
	XErrTerm        REGSET          R3
	AXErrTerm       REGSET          R4
	XAdjUp          REGSET          R5
	XDir            REGSET          R6
	XAdjDown        REGSET          R7
	TexFlag         REGSET          R8
	SourceX         REGSET          R9
	ASourceX        REGSET          R10
	SourceY         REGSET          R11
	ASourceY        REGSET          R12
	SStepX          REGSET          R13
	SStepY          REGSET          R14
	XIntStep        REGSET          R15
	DestI           REGSET          R16
	ADestI          REGSET          R17
	IStep           REGSET          R18
	EPtr            REGSET          R19

	move    EdgePtr,EPtr
	addq    #4,EPtr
	load    (EPtr),R26
	move    EPtr,ADestX
	; count off the scan line we stepped the last time; if this
	; edge is finished, try to start another one
	subq    #1,R26
	jr      NE,cont_step
	store   R26,(EPtr)
	addq    #4,EPtr
	movei   #SetUpEdge,R2
	load    (EPtr),R28      ; load up CurrentEnd
	jump    (R2)            ; jsr to SetUpEdge, let it do the return
	nop
cont_step:
	; Step dest X Bresenham-style, to get precise dest pixel placement
	; and to avoid gaps
	addq    #32,ADestX
	move    ADestX,R26      ; for loading up XIntStep
	move    ADestX,AXErrTerm
	addq    #4,R26
	load    (ADestX),DestX
	addq    #8,AXErrTerm
	load    (R26),XIntStep
	move    ADestX,R25      ; for loading XAdjUp
	add     XIntStep,DestX
	addq    #12,R25
	load    (AXErrTerm),XErrTerm
	load    (R25),XAdjUp
	movefa  texindex,TexFlag
	add     XAdjUp,XErrTerm
	subq    #1,XErrTerm
	jr      MI,no_err       ; Did we overflow the error term?
	addq    #1,XErrTerm
	move    EPtr,R24
	addq    #4,R25
	move    EPtr,R23
	subq    #4,R23
	load    (R25),XAdjDown
	load    (R23),XDir
	sub     XAdjDown,XErrTerm
	shlq    #16,XDir
	sharq   #16,XDir
	add     XDir,DestX
no_err:
	store   DestX,(ADestX)
	moveq   #1,R0           ; for the return code
	store   XErrTerm,(AXErrTerm)
	cmpq    #-1,TexFlag
	jr      NE,tex_ed       ; Is this Gouraud shaded?
	move    ADestX,ADestI
	move    ADestX,R25      ; to point to IStep
	subq    #8,ADestI
	subq    #4,R25
	load    (ADestI),DestI
	load    (R25),IStep
	movefa  a_FFFFFF,R24
	add     IStep,DestI
	cmp     R24,DestI
	jr      MI,max_i
	nop
	move    R24,DestI
max_i:
	store   DestI,(ADestI)
	jump    (R29)
tex_ed:
	; step the current source edge
	move    EPtr,ASourceX
	move    EPtr,ASourceY
	addq    #8,ASourceX
	addq    #12,ASourceY
	move    EPtr,R23
	load    (ASourceX),SourceX
	move    EPtr,R24
	load    (ASourceY),SourceY
	addq    #16,R23
	addq    #20,R24
	load    (R23),SStepX
	load    (R24),SStepY
	add     SStepX,SourceX
	add     SStepY,SourceY
	store   SourceX,(ASourceX)      ; SourceX + SourceStepX
	store   SourceY,(ASourceY)      ; SourceY + SourceStepY
	jump    (R29)
	nop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; SetUpEdge
;;
;; This routine sets up an edge to be scanned; the edge starts at StartVert
;; and proceeds in direction Edge->Direction through the vertex list.
;; Edge->Direction must be set prior to call: -1 to scan a left edge 
;; (backwars through the vertex list), 1 to scan a right edge (forward
;; through the vertext list).  Automatically skips over 0-height edges.
;;
;; Input:
;;      R27     Pointer to the edge structure
;;      R28     Start vertex
;;      R29     Return address
;;
;; Output:
;;      R0      1 if successful, 0 if no more edges to scan
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; parameters
	EdgePtr         REGSET          R27
	StartVert       REGSET          R28
	RetAd           REGSET          R29
SetUpEdge:
	; local variables
	NextVert        REGSET          R26
	TexGour         REGSET          R25

	; done if this edge starts at the bottom vertex
	movei   #MaxVert,R20
	move    EdgePtr,R21     ; copy for later
	load    (R20),R19
	cmp     StartVert,R19
	jr      NE,cnt_set
	load    (EdgePtr),NextVert      ; load Edge->Direction
	moveq   #0,R0           ; return 0
	movei   #SetUpQuit,R1
	jump    (R1)
cnt_set:
	; advance to nex vertex, wrapping if we run off the start or
	; end of the vertex list
	sharq   #16,NextVert            ; shift out lower word (XDir)
	movei   #NumVerts,R1
	add     StartVert,NextVert
	load    (R1),R2
	cmpq    #0,NextVert
	jr      MI,max_vrt
	move    StartVert,R10
	cmp     R2,NextVert     ; is NumVerts > NextVert
	jr      MI,cont_vrt
	movefa  a_lomask,R18
	jr      zero_vrt
	nop
max_vrt:
	subq    #1,R2
	move    R2,NextVert
	jr      cont_vrt
	movefa  a_lomask,R18
zero_vrt:
	moveq   #0,NextVert
cont_vrt:
	; Calculate the vars for this edge and done if this isn't a zero-
	; height edge.  R21 has EdgePtr copy
	move    NextVert,R12
	shlq    #3,R10
	movei   #varray,R19
	shlq    #3,R12
	move    R19,R20         ; R19 & R20 have the VertexPtr address
	add     R10,R19
	add     R12,R20
	load    (R19),R10
	load    (R20),R12
	move    R10,R11
	move    R12,R13
	sharq   #16,R10
	and     R18,R11
	sharq   #16,R12
	and     R18,R13
	shlq    #16,R11
	shlq    #16,R13
	sharq   #16,R11
	sharq   #16,R13
	; just calculated:  R10 = VertexPtr[StartVert].X
	;                   R11 = VertexPtr[StartVert].Y
	;                   R12 = VertexPtr[NextVert].X
	;                   R13 = VertexPtr[NextVert].Y
	; now check if this is a zero-height edge.  If not, then do 
	; all the calcs for TexVertPtr.
	move    R13,R22
	sub     R11,R22
	jr      NE,cont_clc
	movefa  texindex,TexGour
	movei   #SetUpEdge,R19          ; go back to the beginning and keep
	move    NextVert,StartVert      ; looking for a non-0-height edge
	jump    (R19)
	nop
cont_clc:
	shlq    #16,R22                 ; make remainScans 16.16 for divides
	movei   #no_intns,R1
	cmpq    #-1,TexGour
	jump    NE,(R1)
	; about to calculate: R1 = Intensity
	;                     R2 = Intensity Deltas
	;       R18 contains a low word mask from above
	addq    #4,R19
	addq    #4,R20
	load    (R19),R1
	load    (R20),R2
	and     R18,R1
	and     R18,R2
	shlq    #8,R1
	shlq    #8,R2
	sub     R1,R2   ; VertexPtr[NextVert].I - VertexPtr[StartVert].I
;       sharq   #16,R2  ; make integer for divide!
	abs     R2
	jr      CC,calc_di
	div     R22,R2  ; divide by RemainScans
	move    R21,R19
	addq    #28,R19
	store   R1,(R19)
	addq    #4,R19
	jr      div_skp
	neg     R2
calc_di:
	move    R21,R19
	addq    #28,R19
	store   R1,(R19)
	addq    #4,R19
div_skp:
	store   R2,(R19)
no_intns:
	; R21 still has EdgePtr
	; R22 contains RemainScans

	RemainScans     REGSET          R22

	sharq   #16,RemainScans ; convert to int from 16.16
	addq    #4,R21          ; point to RemainScans
	store   RemainScans,(R21)
	addq    #4,R21
	move    R21,R20
	store   NextVert,(R21)  ; save CurrentEnd
	addq    #28,R20
	movei   #draw_rl,R8     ; for below
	store   R10,(R20)       ; save VertexPtr[Start].X
	movei   #done_dr,R7     ; for below
;;;;;;;

	; now finish up the dest. calcs
	sub     R10,R12         ; calc DestXWidth

	move    R21,R19         ; point to DirXDir
	subq    #8,R19
	;

	DestXWidth      REGSET          R12

	cmpq    #0,R12  
	jump    MI,(R8)         ; jump to draw_rl
	moveq   #1,R9
	; do left to right
	movefa  a_himask,R5
	addq    #8,R20          ; point to DestXErrTerm
	load    (R19),R6        ; DirXDir
	and     R5,R6
	or      R9,R6
	store   R6,(R19)
	moveq   #0,R5
	store   R5,(R20)

	addq    #8,R20          ; point to XAdjDown
	move    DestXWidth,R6
	move    RemainScans,R4
	abs     R6
	div     R4,R6
; interlace for the divide
	move    R20,R19
	store   RemainScans,(R20)
	move    RemainScans,R5
	subq    #4,R20          ; XAdjUp
	subq    #12,R19         ; XIntStep
	sharq   #16,R6
	store   R6,(R19)
	abs     R6
	; already preloaded with done_dr
	jump    (R7)
	imult   R5,R6
draw_rl:
	; do right to left
	movefa  a_lomask,R9
	addq    #8,R20          ; point to DestXErrTerm
	move    R9,R5           ; use as mask
	load    (R19),R6        ; DirXDir
	not     R5              ; invert mask
	moveq   #1,R3           
	and     R5,R6
	sub     RemainScans,R3  ; 1 - RemainScans
	or      R9,R6           ; or in XDir part
	store   R3,(R20)
	store   R6,(R19)        ; save away
	addq    #8,R20          ; point to XAdjDown
	abs     DestXWidth
	move    DestXWidth,R6
	move    RemainScans,R4
	div     R4,R6
	move    R20,R19
	store   RemainScans,(R20)
	move    RemainScans,R5
	subq    #4,R20          ; XAdjUp
	subq    #12,R19         ; XIntStep
	sharq   #16,R6
	neg     R6
	store   R6,(R19)
	abs     R6      
	imult   R5,R6
done_dr:
	sub     R6,DestXWidth
	store   DestXWidth,(R20)
;;;;;;
	cmpq    #-1,TexGour
	jr      NE,go_txt
	move    StartVert,R14
	moveq   #1,R0
	jump    (R29)
	nop
go_txt:
	; calculate the texture coordinates
	movei   #TexVertPtr,R20
	move    NextVert,R16
	load    (R20),R19
	shlq    #2,R14          ; multiply by 4
	move    R19,R20         ; R19 & R20 have the TexVertPtr address
	shlq    #2,R16          ; for calc address
	add     R14,R19
; don't need this because already loaded above
	add     R16,R20
	load    (R19),R14
	load    (R20),R16
; don't need to extend the values to longs since the
; texture map coordinates should always be positive
	move    R14,R15
	move    R16,R17
	sharq   #16,R14
	and     R18,R15
	sharq   #16,R16
	and     R18,R17
	; just calculated:  R14 = TexVertPtr[StartVert].X
	;                   R15 = TexVertPtr[StartVert].Y
	;                   R16 = TexVertPtr[NextVert].X
	;                   R17 = TexVertPtr[NextVert].Y

	addq    #4,R21          ; point to SourceX
	move    R14,R0
	move    R15,R9
	shlq    #16,R0
	store   R0,(R21)
	shlq    #16,R9
	addq    #4,R21
	store   R9,(R21)

	sub     R14,R16         ; TexVertPtr[Next].X - TexVertPtr[Start].X
	; make copies of R16 and R17 to do XOR for sign check!
	move    R16,R14
	move    RemainScans,R13
	abs     R16
	div     R13,R16
	; interlace some code for the divide.
	sub     R15,R17         ; same as above, but Y
	move    R17,R15
	abs     R17
	xor     R13,R14
	xor     R13,r15

	div     R13,R17
	; interlace some code for the divide.
	move    R21,R19 
	subq    #16,R19         ; point to DirXDir

	btst    #31,R14         ; does SourceStepX have to be negated?
	jr      EQ,no_Xneg
	addq    #4,R21          ; point to StepX
	neg     R16
no_Xneg:
	store   R16,(R21)
	btst    #31,R15         ; does SourceStepY have to be negated?
	jr      EQ,no_Yneg
	addq    #4,R21          ; point to StepY
	neg     R17
no_Yneg:
	store   R17,(R21)
	moveq   #1,R0           ; success
SetUpQuit:
	jump    (R29)
	nop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; lineDraw
;;
;; This routine is a specialized line drawing routine that takes pixel
;; data from the source data and transfers them to the destination.  The
;; source uses a DDA to walk the data, whereas the destination is a non-
;; scaled horizontal line.  Note that the A1 and A2 registers must be
;; switched when called.  In addition, the algorithm uses the approach of
;; pre-stepping 1/2 pixel into the source image and rounding to the
;; nearest source pixel at each step, so that the texture maps will appear
;; reasonably similar at all angles.
;;
;; Input
;;      R29     Return address
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
lineDraw:
	XMNCL           REGSET          R0
	XMXCL           REGSET          R1
	DestX           REGSET          R2
	DestXMax        REGSET          R3
	TexFlag         REGSET          R4
	DestWidth       REGSET          R5
	I               REGSET          R6
	StepI           REGSET          R7

;;; Load up destination stuff and clip variables to see if we should bail
	movefa  a_R_DestX,R28
	movefa  a_GPXMNCL,XMNCL
	load    (R28),DestXMax
	movefa  a_L_DestX,R27
	load    (R27),DestX
	move    DestXMax,DestWidth
	movefa  a_GPXMXCL,XMXCL
	cmp     XMNCL,DestXMax
	movefa  texindex,TexFlag
	jump    MI,(R29)
	cmp     DestX,XMXCL
	movefa  a_do_tmap,R28
	jump    MI,(R29)
	sub     DestX,DestWidth
	subq    #1,DestWidth
	jump    MI,(R29)
	addq    #1,DestWidth
	shlq    #16,DestWidth           ; make 16.16 for divides
	cmpq    #-1,TexFlag
	jump    NE,(R28)
	cmp     XMXCL,DestXMax
	movefa  a_R_DestI,R26
	jr      MI,gmx_ok
	movefa  a_L_DestI,R27
	move    XMXCL,DestXMax
gmx_ok:
	load    (R27),I
	move    XMNCL,R28
	load    (R26),StepI
	sub     I,StepI
;       sharq   #16,StepI
	abs     StepI
	jr      CC,negI
	div     DestWidth,StepI
	moveq   #17,R8
	shlq    #12,R8
	movefa  a_B_CMD,R10
	movefa  a_B_IINC,R11
	movefa  a_B_COUNT,R12
	movefa  a_A1_PIXEL,R13
	movefa  a_DestFlags,R20
	movefa  a_A1_FLAGS,R22
	load    (R20),R21
	movefa  a_DestY,R24
	movefa  a_FFFFFF,R9
	load    (R24),R15
	jr      nonegI
	neg     StepI
negI:
	moveq   #17,R8
	shlq    #12,R8
	movefa  a_B_CMD,R10
	movefa  a_B_IINC,R11
	movefa  a_B_COUNT,R12
	movefa  a_A1_PIXEL,R13
	movefa  a_DestFlags,R20
	movefa  a_A1_FLAGS,R22
	load    (R20),R21
	movefa  a_DestY,R24
	movefa  a_FFFFFF,R9
	load    (R24),R15
nonegI:
	sub     DestX,XMNCL
	jr      MI,do_gblit
	shlq    #16,R15
	move    R28,DestX
	move    StepI,R23
	sharq   #16,R23
	imult   XMNCL,R23
	shlq    #16,R23
	add     R23,I
	move    StepI,R23
	mult    XMNCL,R23
	add     R23,I
do_gblit:
	movefa  a_B_I3,R14
	or      DestX,R15
	sub     DestX,DestXMax
	cmpq    #15,DestXMax
	jr      PL,phr_mode
	bset    #16,DestXMax
	and     R9,StepI
	bset    #16,R21         ; set addpixel bit
.blwait:
	load    (R10),R27
	btst    #0,R27
	jr      EQ,.blwait
	nop
	store   StepI,(R11)
	store   R21,(R22)
	store   I,(R14)
	store   DestXMax,(R12)
	store   R15,(R13)
	store   R8,(R10)
	jump    (R29)
phr_mode:
	; can trash DestX
	shlq    #30,DestX
	movei   #doneI,R23
	shrq    #30,DestX       ; DestX mod (32 * 8)
	jr      NE,not_palign   ; zero means phrase aligned
	cmpq    #1,DestX
	move    I,R25
	move    R25,R26
	add     StepI,R26
	move    R26,R27
	add     StepI,R27
	move    R27,R28
	jump    (R23)
	add     StepI,R28
not_palign:
	jr      NE,not_1
	cmpq    #2,DestX
	move    I,R25
	move    I,R26
	sub     StepI,R25
	move    R26,R27
	add     StepI,R27
	move    R27,R28
	jump    (R23)
	add     StepI,R28
not_1:
	jr      NE,not_2
	move    I,R27
	move    I,R26
	sub     StepI,R26
	move    R26,R25
	sub     StepI,R25
	move    I,R28
	jr      doneI
	add     StepI,R28
not_2:
	move    I,R28
	sub     StepI,R27
	move    R27,R26
	sub     StepI,R26
	move    R26,R25
	sub     StepI,R25
doneI:
	move    R14,R17
	addq    #4,R17
	move    R17,R18
	addq    #4,R18
	move    R18,R19
	shlq    #2,StepI
	addq    #4,R19
	and     R9,StepI
blwait2:
	load    (R10),R1
	btst    #0,R1
	jr      EQ,blwait2
	nop

	store   StepI,(R11)
	store   R21,(R22)
	store   R28,(R14)
	store   R27,(R17)
	store   R26,(R18)
	store   R25,(R19)
	store   DestXMax,(R12)
	store   R15,(R13)
	store   R8,(R10)
	jump    (R29)
	nop
do_tmap:
;       XMNCL           REGSET          R0
;       XMXCL           REGSET          R1
;       DestX           REGSET          R2
;       DestXMax        REGSET          R3
;       TexFlag         REGSET          R4
;       DestWidth       REGSET          R5
	SourceStepX     REGSET          R6
	SourceStepY     REGSET          R7
	LeftSX          REGSET          R8
	LeftSY          REGSET          R9

	jr      MI,no_cl
	movefa  a_L_SourceX,R27
	move    XMXCL,DestXMax
no_cl:
	movefa  a_R_SourceX,R28
	load    (R27),LeftSX
	load    (R28),SourceStepX
	sub     LeftSX,SourceStepX
	jr      MI,x_neg
	nop
;       shrq    #16,SourceStepX
	div     DestWidth,SourceStepX
	addq    #4,R27
	addq    #4,R28
	load    (R27),LeftSY
	load    (R28),SourceStepY
	movefa  a_A1_PIXEL,R22
	movefa  a_A1_INC,R21
	movefa  a_B_IINC,R16
	movefa  saveint,R15
	jr      x_cont
	nop
x_neg:
	abs     SourceStepX
;       shrq    #16,SourceStepX
	div     DestWidth,SourceStepX
	addq    #4,R27
	addq    #4,R28
	load    (R27),LeftSY
	load    (R28),SourceStepY
	movefa  a_A1_PIXEL,R22
	movefa  a_A1_INC,R21
	movefa  a_B_IINC,R16
	movefa  saveint,R15
	neg     SourceStepX
x_cont:
	sub     LeftSY,SourceStepY
	jr      MI,y_neg
	movefa  a_A1_BASE,R23
;       shrq    #16,SourceStepY
	div     DestWidth,SourceStepY
	movei   #A1_FINC,R20
	movei   #A1_FPIXEL,R19
;;;     movei   #SRCEN|LFU_S|DSTA2|SRCSHADE|ZBUFF,R17
	movei   #SRCEN|LFU_S|DSTA2|ZBUFF,R17
	jr      y_cont
	movefa  a_B_CMD,R18
y_neg:
	abs     SourceStepY
;       shrq    #16,SourceStepY
	div     DestWidth,SourceStepY
	movei   #A1_FINC,R20
	movei   #A1_FPIXEL,R19
	movefa  a_B_CMD,R18
;;;     movei   #SRCEN|LFU_S|DSTA2|SRCSHADE|ZBUFF,R17
	movei   #SRCEN|LFU_S|DSTA2|ZBUFF,R17
	neg     SourceStepY
; Advance 1/2 step in stepping direction, to space scanned pixels evenly
; between left and right edges.  We rename LeftSX and LeftSY to use them
; as SourceX and SourceY.
y_cont:
	move    XMNCL,R26
	move    SourceStepX,R27
	move    SourceStepY,R28
	sharq   #1,R27
	movei   #no_cl_le,R14
	sharq   #1,R28
	add     R27,LeftSX
	add     R28,LeftSY
	cmp     DestX,XMNCL
; Clip left edge?
;       jr      MI,no_cl_le
	jump    MI,(R14)
	movefa  a_DestFlags,R10
	sub     DestX,R26
	movefa  a_lomask,R14
	move    SourceStepX,R27
	move    SourceStepY,R28
	and     R14,R27
	move    XMNCL,DestX
	and     R14,R28
	move    SourceStepX,R24
	mult    R26,R27
	move    SourceStepY,R25
	mult    R26,R28
	sharq   #16,R24
	add     R27,LeftSX
	add     R28,LeftSY
	sharq   #16,R25
	imult   R26,R24
	imult   R26,R25
	shlq    #16,R24
	shlq    #16,R25
	add     R24,LeftSX
	add     R25,LeftSy
no_cl_le:
	sub     DestX,DestXMax
	jump    EQ,(R29)                ; did the clip make it zero pixels wide?
	movefa  a_DestY,R11
	load    (R10),R14
	load    (R11),R13
	bset    #16,R14         ; xaddpix
	shlq    #16,R13
	or      DestX,R13
	movefa  a_DESTADDR,R12
	bset    #16,DestXMax
	movei   #TEXTDATA,R28
	movei   #TexFlags,R27
	load    (R28),R11
	load    (R27),R10       ; XADDINC must be set already!
	movefa  a_himask,R4
	move    LeftSX,R0
	move    LeftSY,R1
	and     R4,R0
	and     R4,R1
	move    SourceStepX,R2
	shrq    #16,R0
	move    SourceStepY,R5
	or      R1,R0
	and     R4,R2
	movefa  a_lomask,R1
	and     R4,R5
	and     R1,LeftSX
	and     R1,LeftSY
	and     R1,SourceStepX
	shlq    #16,LeftSY
	and     R1,SourceStepY
	shrq    #16,R2
	or      LeftSY,LeftSX
	shlq    #16,SourceStepY
	or      R5,R2
	or      SourceStepY,SourceStepX

	movei   #A2_FLAGS,R28
	movei   #A2_BASE,R27
	movefa  a_B_COUNT,R26
	movei   #A2_PIXEL,R25
	movefa  a_A1_FLAGS,R24
;
; All of this code is stuck after the above divides...
;
;       movefa  a_A1_BASE,R23
;       movefa  a_A1_PIXEL,R22
;       movefa  a_A1_INC,R21
;       movei   #A1_FINC,R20
;       movei   #A1_FPIXEL,R19
;       movefa  a_B_CMD,R18
;       movei   #SRCEN|LFU_S|DSTA2|SRCSHADE|ZBUFF,R17
;       movefa  a_B_IINC,R16
;       movefa  saveint,R15

; Wait until blitter is not busy
; check if blitter is done
blitwait:
	load    (R18),R9
	btst    #0,R9
	jr      EQ,blitwait
	nop
	
	store   R14,(R28)
	store   R12,(R27)
	store   DestXMax,(R26)
	store   R13,(R25)
	store   R11,(R23)
	store   R10,(R24)
	store   R0,(R22)
	store   R2,(R21)
	store   SourceStepX,(R20)
	store   LeftSX,(R19)
	store   R15,(R16)
	store   R17,(R18)
	jump    (R29)
	nop

;*======================================================================*
;*      END OF PROGRAM SEGMENT
;*======================================================================*

;*======================================================================*
;*      RANDOM DATA SEGMENT
;*======================================================================*

	ALIGN PHRASE

rmatrix:
	ds.l    12              ;* enough for [3x3] plus 3
				; NOTE: These two matrices must remain in
lmatrix:                        ;       Contiguous Memory
	ds.l    12              ;* enough for [4x3]

tmatrix:
	ds.l    12              ;* enough for [3x4]

varray:                         ; G.P. GPU RAM Buffer - used for lotsa stuff
	ds.l    3*MAXVERTS      ; But only one thing at a time (I hope)

qfaceptr:       ds.l    1       ; Polyhedron Registers
;qsegptr:       ds.l    1
qvertptr:       ds.l    1       
qfacecnt:       ds.l    1               
qtexptr:        ds.l    1       ; ptr to list of texture maps
qtboxptr:       ds.l    1       ; ptr to list of texture map boxes


	
		.Align  LONG
TEXTDATA:       DS.L    1       ; source address, texture data
DESTADDR:       DS.L    1       ; destination address

; variables used by the subroutines
MinVert:        DS.L    1
MaxVert:        DS.L    1
NumVerts:       DS.L    1
DestY:          DS.L    1
;VertexPtr:     DS.L    1       ; ptr to dest coordinates
DestFlags:      DS.L    1       ; blitter flags to characterize the destination
TexVertPtr:     DS.L    1       ; ptr to texture map coordinates
TexFlags:       DS.L    1       ; blitter flags to characterize the texture map
ttime1:         DS.L    1
ttime2:         DS.L    1
ttime3:         DS.L    1

; Edge structures:  representation of a scan down an edge
LeftEdge:
     L_DirXDir:         DS.L    1       ; Upper word: 1, right edge, -1, left
					; Lower word: direction for dest X stepping
     L_RemainScans:     DS.L    1       ; height left to scan out in dest
     L_CurrentEnd:      DS.L    1       ; vertex of end of current edge
     L_SourceX:         DS.L    1       ; current X for this edge
     L_SourceY:         DS.L    1       ; current Y for this edge
;;     L_SourceZ:               DS.L    1       ; current Z for this edge
     L_SourceStepX:     DS.L    1       ; X step in src for Y step of 1 in dest
     L_SourceStepY:     DS.L    1       ; Y step in src for Y step of 1 in dest
;;     L_SourceStepZ:   DS.L    1       ; Z step in src for Y step of 1 in dest
     L_DestI:           DS.L    1       ; intensity value, 8.16
     L_DestIStep:       DS.L    1       ; intensity increment, 8.16
     ; variables used for all-ints Bresenham-type X stepping through the
     ; dest. needed for precise pixel placement to avoid gaps
     L_DestX:           DS.L    1       ; current X location for this edge
     L_DestXIntStep:    DS.L    1       ; whole part of dest X step per scan-
					; line Y step
     L_XErrTerm:        DS.L    1       ; current error term for dest X stepping
     L_XAdjUp:          DS.L    1       ; amount to add to error term per scan-
					; line move
     L_XAdjDown:        DS.L    1       ; amount to sub from error term when 
					; error term turns over
RightEdge:
     R_DirXDir:         DS.L    1       ; Upper word: 1, right edge, -1, left
					; Lower word: direction for dest X stepping
     R_RemainScans:     DS.L    1       ; height left to scan out in dest
     R_CurrentEnd:      DS.L    1       ; vertex of end of current edge
     R_SourceX:         DS.L    1       ; current X for this edge
     R_SourceY:         DS.L    1       ; current Y for this edge
;;     R_SourceZ:               DS.L    1       ; current Z for this edge
     R_SourceStepX:     DS.L    1       ; X step in src for Y step of 1 in dest
     R_SourceStepY:     DS.L    1       ; Y step in src for Y step of 1 in dest
;;     R_SourceStepZ:   DS.L    1       ; Z step in src for Y step of 1 in dest
     R_DestI:           DS.L    1       ; intensity value, 8.16
     R_DestIStep:       DS.L    1       ; intensity increment, 8.16
     ; variables used for all-ints Bresenham-type X stepping through the
     ; dest. needed for precise pixel placement to avoid gaps
     R_DestX:           DS.L    1       ; current X location for this edge
     R_DestXIntStep:    DS.L    1       ; whole part of dest X step per scan-
					; line Y step
     R_XErrTerm:        DS.L    1       ; current error term for dest X stepping
     R_XAdjUp:          DS.L    1       ; amount to add to error term per scan-
					; line move
     R_XAdjDown:        DS.L    1       ; amount to sub from error term when 
					; error term turns over
EndOfPack:
	.align phrase
;*======================================================================*
;*                                 EOF                                  *
;*======================================================================*


