Microsoft (R) Macro Assembler Version 6.14.8444		    06/20/00 17:18:57
xdraw2.asm						     Page 1 - 1


				;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
				;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
				;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
				;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
				;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
				;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
				;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
				;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
				;; 
				;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
				;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
				;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
				;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
				;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
				;; THE UNITED STATES.  
				;; 
				;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
				;;
				;; $Header$
				;; $Revision$
				;; $Log$
				;; Revision 1.1  2000/06/15 00:27:43  joseph
				;; Initial checkin into SourceForge.
				;;
				;; 
				;; 12    4/05/99 11:34a Atai
				;; added GLIDE_ALT_TAB for xdraw2.inc to query context in the retail build
				;; 
				;; 11    3/19/99 11:26a Peter
				;; expose direct fifo for gl
				;; 
				;; 10    10/14/98 12:05p Peter
				;; fixed my effed up assumption about non-volatile regs
				;; 
				;; 9     10/12/98 9:51a Peter
				;; dynamic 3DNow!(tm)
				;; 
				;; 8     9/24/98 11:17a Dow
				;; AMD 3DNow! (tm) mods
				;; 
				;; 7     8/30/98 1:34p Dow
				;; State & other optimizations
				;; 
				;; 6     8/29/98 8:12p Dow
				;; Clip optimization
				;; 
				;; 5     7/01/98 8:41a Jdt
				;; removed gc arg from trisetup funcs
				;; 
				;; 4     8/03/98 6:36a Jdt
				;; Add GC to trisetup arglist
				;; 
				;; 3     6/09/98 11:59a Atai
				;; 1. update glide header
				;; 2. fix cull mode
				;; 3. fix tri stats
				;; 
				;; 8     5/18/98 3:21p Peter
				;; dynamic culling changes
				; 
				; 6     1/15/98 1:12p Peter
				; dispatch w/o packing
				; 
				; 5     11/06/97 3:47p Peter
				; dispatch code w/ simulator
				; 
				; 4     11/04/97 5:04p Peter
				; cataclysm part deux
				; 
				; 3     11/01/97 10:01a Peter
				; tri dispatch stuff
				; 
				; 2     10/30/97 6:53p Peter
				; first real cut at tri asm
				; 
				; 1     10/30/97 4:29p Peter
				; asm tri code
				; 
				; 2     7/07/97 2:14p Jdt
				; assembly now on par with C code.
				; 
				; 1     7/07/97 8:37a Jdt
				; B4 Chip field fix.
				;;
				
				TITLE   xdraw2.asm
				OPTION OLDSTRUCTS       
				
				.586P
				.MMX
				.K3D
				
				;;; Definitions of cvg regs and glide root structures.
				INCLUDE fxgasm.h    
			      C 
			      C ;----------------------------------------------------------------------
			      C ; Assembler offsets for SSTREGS struct
			      C ;----------------------------------------------------------------------
			      C 
			      C 
			      C 
			      C ;----------------------------------------------------------------------
			      C ; Assembler offsets for GC struct
			      C ;----------------------------------------------------------------------
			      C 
 = 0074			      C base_ptr		= 00000074h
 = 0078			      C reg_ptr			= 00000078h
 = 0080			      C lfb_ptr			= 00000080h
 = 01E0			      C cull_mode		= 000001e0h
 = 0124			      C tsuDataList		= 00000124h
 = 0DD8			      C triPacketHdr	= 00000dd8h
 = 0DDC			      C cullStripHdr	= 00000ddch
 = 0DE0			      C paramMask	= 00000de0h
 = 0E04			      C fifoStart	= 00000e04h
 = 0E08			      C fifoEnd	= 00000e08h
 = 0E0C			      C fifoOffset	= 00000e0ch
 = 0E10			      C fifoSize	= 00000e10h
 = 0E14			      C fifoJmpHdr	= 00000e14h
 = 0DE4			      C fifoPtr	= 00000de4h
 = 0DE8			      C fifoRead	= 00000de8h
 = 0DEC			      C fifoRoom	= 00000dech
 = 0E1C			      C roomToReadPtr	= 00000e1ch
 = 0E20			      C roomToEnd	= 00000e20h
 = 0E24			      C lfbLockCount	= 00000e24h
 = 0DC4			      C triSetupProc	= 00000dc4h
 = 0DC8			      C drawTrianglesProc	= 00000dc8h
 = 0DC4			      C drawVertexList	= 00000dc4h
 = 0B70			      C vertexSize	= 00000b70h
 = 0B6C			      C vertexStride	= 00000b6ch
 = 0B78			      C invalid	= 00000b78h
 = 0D98			      C CoordinateSpace	= 00000d98h
 = 01E4			      C paramIndex	= 000001e4h
 = 0B00			      C vp_hwidth	= 00000b00h
 = 0B04			      C vp_hheight	= 00000b04h
 = 0B08			      C vp_hdepth	= 00000b08h
 = 0AF4			      C vp_ox	= 00000af4h
 = 0AF8			      C vp_oy	= 00000af8h
 = 0AFC			      C vp_oz	= 00000afch
 = 0B74			      C colorType	= 00000b74h
 = 0B20			      C wInfo_offset	= 00000b20h
 = 0B54			      C qInfo_mode	= 00000b54h
 = 0B58			      C qInfo_offset	= 00000b58h
 = 0B60			      C q0Info_offset	= 00000b60h
 = 0B68			      C q1Info_offset	= 00000b68h
 = 0B5C			      C q0Info_mode	= 00000b5ch
 = 0B64			      C q1Info_mode	= 00000b64h
 = 0B30			      C fogInfo_offset	= 00000b30h
 = 0B2C			      C fogInfo_mode	= 00000b2ch
 = 0A44			      C depth_range	= 00000a44h
 = 0A0C			      C tmu0_s_scale	= 00000a0ch
 = 0A10			      C tmu0_t_scale	= 00000a10h
 = 0A28			      C tmu1_s_scale	= 00000a28h
 = 0A2C			      C tmu1_t_scale	= 00000a2ch
 = 0210			      C fbi_fbzMode	= 00000210h
 = 004C			      C curTriSize		= 0000004ch
 = 000C			      C trisProcessed		= 0000000ch
 = 0010			      C trisDrawn		= 00000010h
 = 96BC			      C lostContext		= 000096bch
 = 96C4			      C windowed		= 000096c4h
 = 011C			      C bInfo		= 0000011ch
			      C 
			      C ;----------------------------------------------------------------------
			      C ; Assembler offsets for GlideRoot struct
			      C ;----------------------------------------------------------------------
			      C 
 = 0000			      C p6Fencer		= 00000000h
 = 000C			      C current_sst		= 0000000ch
 = 0010			      C CPUType			= 00000010h
 = 0008			      C tlsOffset			= 00000008h
 = 002C			      C pool_f255	= 0000002ch
 = 0028			      C pool_f1	= 00000028h
 = 0BBC			      C SIZEOF_GrState		= 00000bbch
 = 9714			      C SIZEOF_GC		= 00009714h
			      C 
 = 000BCFC4		      C SIZEOF_GlideRoot	= 000bcfc4h
			      C 
			      C 
				
				EXTRN   __GlideRoot:    DWORD
				EXTRN   __grCommandTransportMakeRoom@12: NEAR
				EXTRN   __grValidateState:NEAR
				EXTRN   _hwcQueryContext:NEAR
				
				IFDEF HAL_CSIM
				EXTRN   _halStore32@8:  NEAR
				ENDIF
				
 00000000			_DATA   SEGMENT
 00000000 3F800000		    One         DD  03f800000r
 00000004 00000000		    Area        DD  0
 0008				_DATA   ENDS
				
 00000000			CONST   SEGMENT
 00000000 46400000		$T2003  DD  046400000r          ; 12288
 00000004 3F800000		$T2005  DD  03f800000r          ; 1
 00000008 43800000		$T2006  DD  043800000r          ; 256
 000C				CONST   ENDS
				
				; Arguments (STKOFF = 16 from 4 pushes)
 = 0010				STKOFF  = 16
 = 0014				_va$    =  4 + STKOFF
 = 0018				_vb$    =  8 + STKOFF
 = 001C				_vc$    = 12 + STKOFF    
				
				    ;; coordinate offsets into vertex.
				    ;; NB:  These are constants and are not
				    ;;      user settable like the rest of the
				    ;;      parameter offset. Weird.
 = 0000				X       = 0
 = 0004				Y       = 4
				
				PROC_TYPE MACRO procType:=<Default>
				    IFDEF GL_AMD3D
				        EXITM <__trisetup_3DNow_&procType&@12>
				    ELSE
        EXITM <__trisetup_Default_&procType&@12>
				    ENDIF
    ENDM        
				
				;; enables/disables trisProcessed and trisDrawn counters
				STATS = 1
				
 = 0001				;; offsets into vertex struct
				X       = 0
				Y       = 4
 = 0000				
 = 0004				    ;; NB:  All of the base triangle procs expect to have the gc
				    ;;      passed from the caller in edx so that we can avoid
				    ;;      the agi from the far pointer. Screw w/ this at your
				    ;;      own peril.
				    ;;
				    ;;      YOU HAVE BEEN WARNED
				
				;--------------------------------------------------------------------------
				
				_TEXT       SEGMENT PAGE PUBLIC USE32 'CODE'
				            ASSUME DS: FLAT, SS: FLAT
 00000000			
				            ALIGN    32
				            PUBLIC   PROC_TYPE(clip_nocull_invalid)
				PROC_TYPE(clip_nocull_invalid)        PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_invalid@12>
				           
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_invalid@12>
 00000000			GLIDE_VALIDATE_STATE textequ <1>
				GLIDE_CLIP_COORDS    textequ <1>
 = 1				GLIDE_CULLING        textequ <0>
 = 1				GLIDE_PACK_RGB       textequ <0>
 = 0				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
			      C     push    esi
			      C     push    edi
			      C     
			      C     push    ebx
			      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
			      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
			      C    test gc, gc
			      C    je   __triDone
			      C    mov edx, [gc + windowed]
			      C    test edx, 1
			      C    jnz  pastContextTest         ; 
			      C    mov  edx, DWORD PTR [gc+lostContext]
			      C    mov ebx, [edx]
			      C    test ebx, 1
			      C    jnz  __triDone
			      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C     mov     eax, [gc + curTriSize]
			      C     mov     ebx, [gc + fifoRoom]
			      C 
			      C     add     eax, 4
			      C     cmp     ebx, eax
			      C 
			      C     jge     __triBegin
			      C     
			      C     push    @Line
			      C     push    0h
			      C     
			      C     push    eax
			      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
			      C vertex  TEXTEQU     <edx>       ; the current vertex
			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
			      C packCol TEXTEQU     <edi>
			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
			      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
			      C 
			      C             align 32   
			      C __vertexStart:
			      C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
			      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
			      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
			      C 
			      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
			      C 
			      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
			      C 
			      C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     je      __nextVertex
			      C 
			      C     ;; Not using align directive here because it sometimes
			      C     ;; introduces an agi for the eax use below.
			      C     nop
			      C     nop
			      C         
			      C __paramLoop:
			      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
			      C     
			      C     jne     SHORT __paramLoop
			      C 
			      C                 align 4        
			      C __nextVertex:   
			      C     ;; On to the next vertex
			      C     add     vOffset, 4
			      C 
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
			      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
			      C     
			      C     mov     [gc + fifoPtr], fifo
			      C     sub     eax, ebx
			      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
			      C 
			      C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
			      C 
			      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
			      C 
			      C __triDone:    
			      C     ;; Restore trashed registers
			      C     mov     ecx, [gc + trisProcessed]
			      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
			      C     pop     ebx
			      C     
			      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
			      C         
			      C     pop     esi
			      C     ret     12
			      C ENDIF ; !GLIDE_CLIP_COOR
			      C ENDIF ; !GL_AMD3D
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(clip_nocull_invalid) ENDP    
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_invalid@12>
 00000000			            ALIGN  32
				            PUBLIC   PROC_TYPE(clip_cull_invalid)
				PROC_TYPE(clip_cull_invalid)   PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_invalid@12>
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_invalid@12>
 00000000			GLIDE_VALIDATE_STATE textequ <1>
				GLIDE_CLIP_COORDS    textequ <1>
 = 1				GLIDE_CULLING        textequ <1>
 = 1				GLIDE_PACK_RGB       textequ <0>
 = 1				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
			      C     push    esi
			      C     push    edi
			      C     
			      C     push    ebx
			      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
			      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
			      C    test gc, gc
			      C    je   __triDone
			      C    mov edx, [gc + windowed]
			      C    test edx, 1
			      C    jnz  pastContextTest         ; 
			      C    mov  edx, DWORD PTR [gc+lostContext]
			      C    mov ebx, [edx]
			      C    test ebx, 1
			      C    jnz  __triDone
			      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C     mov     eax, [gc + curTriSize]
			      C     mov     ebx, [gc + fifoRoom]
			      C 
			      C     add     eax, 4
			      C     cmp     ebx, eax
			      C 
			      C     jge     __triBegin
			      C     
			      C     push    @Line
			      C     push    0h
			      C     
			      C     push    eax
			      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
			      C vertex  TEXTEQU     <edx>       ; the current vertex
			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
			      C packCol TEXTEQU     <edi>
			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
			      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
			      C 
			      C             align 32   
			      C __vertexStart:
			      C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
			      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
			      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
			      C 
			      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
			      C 
			      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
			      C 
			      C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     je      __nextVertex
			      C 
			      C     ;; Not using align directive here because it sometimes
			      C     ;; introduces an agi for the eax use below.
			      C     nop
			      C     nop
			      C         
			      C __paramLoop:
			      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
			      C     
			      C     jne     SHORT __paramLoop
			      C 
			      C                 align 4        
			      C __nextVertex:   
			      C     ;; On to the next vertex
			      C     add     vOffset, 4
			      C 
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
			      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
			      C     
			      C     mov     [gc + fifoPtr], fifo
			      C     sub     eax, ebx
			      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
			      C 
			      C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
			      C 
			      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
			      C 
			      C __triDone:    
			      C     ;; Restore trashed registers
			      C     mov     ecx, [gc + trisProcessed]
			      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
			      C     pop     ebx
			      C     
			      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
			      C         
			      C     pop     esi
			      C     ret     12
			      C ENDIF ; !GLIDE_CLIP_COOR
			      C ENDIF ; !GL_AMD3D
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(clip_cull_invalid)   ENDP
				        
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_invalid@12>
 00000000			            ALIGN    32
				            PUBLIC   PROC_TYPE(clip_cull_valid)
				PROC_TYPE(clip_cull_valid)  PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_valid@12>
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_valid@12>
 00000000			GLIDE_VALIDATE_STATE textequ <0>
				GLIDE_CLIP_COORDS    textequ <1>   
 = 0				GLIDE_CULLING        textequ <1>
 = 1				GLIDE_PACK_RGB       textequ <0>
 = 1				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
			      C     push    esi
			      C     push    edi
			      C     
			      C     push    ebx
			      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
			      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
			      C    test gc, gc
			      C    je   __triDone
			      C    mov edx, [gc + windowed]
			      C    test edx, 1
			      C    jnz  pastContextTest         ; 
			      C    mov  edx, DWORD PTR [gc+lostContext]
			      C    mov ebx, [edx]
			      C    test ebx, 1
			      C    jnz  __triDone
			      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C     mov     eax, [gc + curTriSize]
			      C     mov     ebx, [gc + fifoRoom]
			      C 
			      C     add     eax, 4
			      C     cmp     ebx, eax
			      C 
			      C     jge     __triBegin
			      C     
			      C     push    @Line
			      C     push    0h
			      C     
			      C     push    eax
			      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
			      C vertex  TEXTEQU     <edx>       ; the current vertex
			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
			      C packCol TEXTEQU     <edi>
			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
			      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
			      C 
			      C             align 32   
			      C __vertexStart:
			      C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
			      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
			      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
			      C 
			      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
			      C 
			      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
			      C 
			      C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     je      __nextVertex
			      C 
			      C     ;; Not using align directive here because it sometimes
			      C     ;; introduces an agi for the eax use below.
			      C     nop
			      C     nop
			      C         
			      C __paramLoop:
			      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
			      C     
			      C     jne     SHORT __paramLoop
			      C 
			      C                 align 4        
			      C __nextVertex:   
			      C     ;; On to the next vertex
			      C     add     vOffset, 4
			      C 
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
			      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
			      C     
			      C     mov     [gc + fifoPtr], fifo
			      C     sub     eax, ebx
			      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
			      C 
			      C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
			      C 
			      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
			      C 
			      C __triDone:    
			      C     ;; Restore trashed registers
			      C     mov     ecx, [gc + trisProcessed]
			      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
			      C     pop     ebx
			      C     
			      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
			      C         
			      C     pop     esi
			      C     ret     12
			      C ENDIF ; !GLIDE_CLIP_COOR
			      C ENDIF ; !GL_AMD3D
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(clip_cull_valid) ENDP
				    
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_cull_valid@12>
 00000000			            ALIGN    32
				            PUBLIC   PROC_TYPE(clip_nocull_valid)
				PROC_TYPE(clip_nocull_valid)  PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_valid@12>
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_valid@12>
 00000000			GLIDE_VALIDATE_STATE textequ <0>
				GLIDE_CLIP_COORDS    textequ <1>   
 = 0				GLIDE_CULLING        textequ <0>
 = 1				GLIDE_PACK_RGB       textequ <0>
 = 0				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
			      C     push    esi
			      C     push    edi
			      C     
			      C     push    ebx
			      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
			      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
			      C    test gc, gc
			      C    je   __triDone
			      C    mov edx, [gc + windowed]
			      C    test edx, 1
			      C    jnz  pastContextTest         ; 
			      C    mov  edx, DWORD PTR [gc+lostContext]
			      C    mov ebx, [edx]
			      C    test ebx, 1
			      C    jnz  __triDone
			      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C     mov     eax, [gc + curTriSize]
			      C     mov     ebx, [gc + fifoRoom]
			      C 
			      C     add     eax, 4
			      C     cmp     ebx, eax
			      C 
			      C     jge     __triBegin
			      C     
			      C     push    @Line
			      C     push    0h
			      C     
			      C     push    eax
			      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
			      C vertex  TEXTEQU     <edx>       ; the current vertex
			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
			      C packCol TEXTEQU     <edi>
			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
			      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
			      C 
			      C             align 32   
			      C __vertexStart:
			      C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
			      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
			      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
			      C 
			      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
			      C 
			      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
			      C 
			      C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     je      __nextVertex
			      C 
			      C     ;; Not using align directive here because it sometimes
			      C     ;; introduces an agi for the eax use below.
			      C     nop
			      C     nop
			      C         
			      C __paramLoop:
			      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
			      C     add     dlp, 4                              ; dlp++
			      C     
			      C     cmp     eax, 0                              ; Are we done?
			      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
			      C     
			      C     jne     SHORT __paramLoop
			      C 
			      C                 align 4        
			      C __nextVertex:   
			      C     ;; On to the next vertex
			      C     add     vOffset, 4
			      C 
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
			      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
			      C     
			      C     mov     [gc + fifoPtr], fifo
			      C     sub     eax, ebx
			      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
			      C 
			      C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
			      C 
			      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
			      C 
			      C __triDone:    
			      C     ;; Restore trashed registers
			      C     mov     ecx, [gc + trisProcessed]
			      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
			      C     pop     ebx
			      C     
			      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
			      C         
			      C     pop     esi
			      C     ret     12
			      C ENDIF ; !GLIDE_CLIP_COOR
			      C ENDIF ; !GL_AMD3D
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(clip_nocull_valid) ENDP
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_clip_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_clip_nocull_valid@12>
 00000000			            ALIGN    32
				            PUBLIC   PROC_TYPE(win_nocull_invalid)
				PROC_TYPE(win_nocull_invalid) PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_invalid@12>
				         
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_invalid@12>
 00000000			GLIDE_VALIDATE_STATE textequ <1>
				GLIDE_CLIP_COORDS    textequ <0>
 = 1				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_PACK_RGB       textequ <0>
 = 0				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
 00000000  56		      C     push    esi
 00000001  57		      C     push    edi
			      C     
 00000002  53		      C     push    ebx
 00000003  55		      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
 00000004  8B F2	      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
 00000006  85 F6	      C    test gc, gc
 00000008  0F 84 000000DA     C    je   __triDone
 0000000E  8B 96 000096C4     C    mov edx, [gc + windowed]
 00000014  F7 C2 00000001     C    test edx, 1
 0000001A  75 14	      C    jnz  pastContextTest         ; 
 0000001C  8B 96 000096BC     C    mov  edx, DWORD PTR [gc+lostContext]
 00000022  8B 1A	      C    mov ebx, [edx]
 00000024  F7 C3 00000001     C    test ebx, 1
 0000002A  0F 85 000000B8     C    jnz  __triDone
 00000030		      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
 00000030  8B 96 00000B78     C     mov     edx, DWORD PTR [gc+invalid]
 00000036  85 D2	      C     test    edx, edx
 00000038  74 05	      C     je      SHORT no_validatioin
 0000003A  E8 00000000 E      C     call    __grValidateState
 0000003F		      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
 00000040  8B 46 4C	      C     mov     eax, [gc + curTriSize]
 00000043  8B 9E 00000DEC     C     mov     ebx, [gc + fifoRoom]
			      C 
 00000049  83 C0 04	      C     add     eax, 4
 0000004C  3B D8	      C     cmp     ebx, eax
			      C 
 0000004E  7D 10	      C     jge     __triBegin
			      C     
 00000050  68 00000338	      C     push    @Line
 00000055  6A 00	      C     push    0h
			      C     
 00000057  50		      C     push    eax
 00000058  E8 00000000 E      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
 = ebx			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
 = ebp			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
 = edx			      C vertex  TEXTEQU     <edx>       ; the current vertex
 = ecx			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
 = edi			      C packCol TEXTEQU     <edi>
 = edi			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
    pushfd
    
    push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
    call    halStore32@8
			      C 
			      C     popfd
    popad
ELSE
    mov    [__addr + __offset], __data
			      C ENDIF
ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
 00000060		      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
 00000060  8B AE 00000DE4     C 
 00000066  B9 00000004	      C             align 32   
			      C __vertexStart:
 0000006B  8B 86 00000DD8     C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
 00000071  90		      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, 0
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000072  89 45 00	     1C     mov    [fifo + 0], eax
			     1C ENDIF
 00000075  83 C5 04	      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
 00000080		      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
 00000080  8B 54 0C 10	      C 
 00000084  83 C5 08	      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
 00000087  90		      C 
 00000088  90		      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
 00000089  8B 02	      C 
 0000008B  8D 9E 00000124     C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -8
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000091  89 45 F8	     1C     mov    [fifo + -8], eax
			     1C ENDIF
 00000094  8B 42 04	      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000097  33 FF	      C     je      __nextVertex
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000099  89 45 FC	     1C     mov    [fifo + -4], eax
			     1C ENDIF
			      C     ;; Not using align directive here because it sometimes
 0000009C		      C     ;; introduces an agi for the eax use below.
 0000009C  8B 03	      C     nop
 0000009E  83 C3 04	      C     nop
			      C         
 000000A1  83 F8 00	      C __paramLoop:
 000000A4  74 16	      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
 000000A6  90		      C     add     dlp, 4                              ; dlp++
 000000A7  90		      C     
			      C     cmp     eax, 0                              ; Are we done?
 000000A8		      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
 000000A8  8B 3C 02	      C     
 000000AB  83 C5 04	      C     jne     SHORT __paramLoop
			      C 
 000000AE  8B 03	      C                 align 4        
 000000B0  83 C3 04	      C __nextVertex:   
			      C     ;; On to the next vertex
 000000B3  83 F8 00	      C     add     vOffset, 4
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    tempVal
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 000000B6  89 7D FC	     1C     mov    [fifo + -4], tempVal
			     1C ENDIF
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
 000000B9  75 ED	      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
 000000BC		      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
 000000BC  83 C1 04	      C     
			      C     mov     [gc + fifoPtr], fifo
 000000BF  83 F9 10	      C     sub     eax, ebx
 000000C2  75 BC	      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
 000000C4  8B C5	      C 
 000000C6  8B 9E 00000DE4     C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
 000000CC  89 AE 00000DE4     C 
 000000D2  2B C3	      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
 000000D4  8B 5E 10	      C 
 000000D7  29 86 00000DEC     C __triDone:    
			      C     ;; Restore trashed registers
 000000DD  83 C3 01	      C     mov     ecx, [gc + trisProcessed]
 000000E0  89 5E 10	      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
 000000E3  B8 00000001	      C     pop     ebx
			      C     
 000000E8		      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
 000000E8  8B 4E 0C	      C         
 000000EB  5D		      C     pop     esi
			      C     ret     12
 000000EC  83 C1 01	      C ENDIF ; !GLIDE_CLIP_COOR
 000000EF  5B		      C ENDIF ; !GL_AMD3D
			      C 
 000000F0  5F		      C 
 000000F1  89 4E 0C	      C 
			      C 
 000000F4  5E		      C 
 000000F5  C2 000C	      C 
			      C 
			      C 
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(win_nocull_invalid) ENDP    
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_invalid@12>
 000000F8			            ALIGN    32
				            PUBLIC   PROC_TYPE(win_cull_invalid)
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_invalid@12>
				PROC_TYPE(win_cull_invalid)  PROC    NEAR
				  
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_invalid@12>
 00000100			GLIDE_VALIDATE_STATE textequ <1>
				GLIDE_CLIP_COORDS    textequ <0>
 = 1				GLIDE_CULLING        textequ <1>
 = 0				GLIDE_PACK_RGB       textequ <0>
 = 1				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
 00000100  56		      C     push    esi
 00000101  57		      C     push    edi
			      C     
 00000102  53		      C     push    ebx
 00000103  55		      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
 00000104  8B F2	      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
 00000106  85 F6	      C    test gc, gc
 00000108  0F 84 0000015A     C    je   __triDone
 0000010E  8B 96 000096C4     C    mov edx, [gc + windowed]
 00000114  F7 C2 00000001     C    test edx, 1
 0000011A  75 14	      C    jnz  pastContextTest         ; 
 0000011C  8B 96 000096BC     C    mov  edx, DWORD PTR [gc+lostContext]
 00000122  8B 1A	      C    mov ebx, [edx]
 00000124  F7 C3 00000001     C    test ebx, 1
 0000012A  0F 85 00000138     C    jnz  __triDone
 00000130		      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
 00000130  8B 96 00000B78     C     mov     edx, DWORD PTR [gc+invalid]
 00000136  85 D2	      C     test    edx, edx
 00000138  74 05	      C     je      SHORT no_validatioin
 0000013A  E8 00000000 E      C     call    __grValidateState
 0000013F		      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
 = eax			      C fa      TEXTEQU     <eax>       ; vtx a from caller
 = ebx			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
 = ecx			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
 = edx			      C cull    TEXTEQU     <edx>
 = ebp			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
 = fld  DWORD PTR	      C flds    TEXTEQU <fld  DWORD PTR>
 = fsub DWORD PTR	      C fsubs   TEXTEQU <fsub DWORD PTR>
 = fmul DWORD PTR	      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
 00000140  8B 44 24 14	      C     mov     fa, [esp + _va$]
 00000144  8B 5C 24 18	      C     mov     fb, [esp + _vb$]
			      C         
 00000148  8B 96 000001E0     C     mov     cull, [gc + cull_mode]    
 0000014E  8B 4C 24 1C	      C     mov     fc, [esp + _vc$]
			      C 
 00000152  85 D2	      C     test    cull, cull    
 00000154  74 53	      C     jz      nocull
			      C 
 00000156  C1 E2 1F	      C     shl     cull, 31                    ; culltest << 31    
			      C         
 00000159		      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
 00000159  D9 00	      C     flds    [fa + X]            ;  xa
 0000015B  D8 23	      C     fsubs   [fb + X]            ;  dxAB
 0000015D  D9 03	      C     flds    [fb + X]            ;  |    xb
 0000015F  D8 21	      C     fsubs   [fc + X]            ;  |    dxBC
 00000161  D9 43 04	      C     flds    [fb + Y]            ;  |    |    yb
 00000164  D8 61 04	      C     fsubs   [fc + Y]            ;  |    |    dyBC
 00000167  D9 40 04	      C     flds    [fa + Y]            ;  |    |    |    ya
 0000016A  D8 63 04	      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
 0000016D  D9 C3	      C     fld     st(3)               ;  |    |    |    |    dxAB
 0000016F  D8 CA	      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
 00000171  D9 C3	      C     fld     st(3)               ;  |    |    |    |    |    dxBC
 00000173  D8 CA	      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
 00000175  DE E9	      C     fsubp   st(1),st            ;  |    |    |    |    area
 00000177  D9 15 00000004 R   C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
 0000017D  DD D8	      C     fstp    st(0)   ; 4
 0000017F  DD D8	      C     fstp    st(0)   ; 3
 00000181  DD D8	      C     fstp    st(0)   ; 2
 00000183  DD D8	      C     fstp    st(0)   ; 1
 00000185  DD D8	      C     fstp    st(0)   ; 0    
			      C 
 00000187  8B 2D 00000004 R   C     mov     intArea, zArea        ; j = *(long *)&area
 0000018D  33 C0	      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
 0000018F  81 E5 7FFFFFFF     C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
 00000195  0F 84 000000CD     C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
 0000019B  8B 2D 00000004 R   C     mov     intArea, zArea              ; reload area just in case we're culling
 000001A1  33 EA	      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
 000001A3  0F 8D 000000BF     C     jge     __triDone
 000001A9		      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
 000001AC  8B 46 4C	      C     mov     eax, [gc + curTriSize]
 000001AF  8B 9E 00000DEC     C     mov     ebx, [gc + fifoRoom]
			      C 
 000001B5  83 C0 04	      C     add     eax, 4
 000001B8  3B D8	      C     cmp     ebx, eax
			      C 
 000001BA  7D 24	      C     jge     __triBegin
			      C     
 000001BC  68 00000338	      C     push    @Line
 000001C1  6A 00	      C     push    0h
			      C     
 000001C3  50		      C     push    eax
 000001C4  E8 00000000 E      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
 = ebx			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
 = ebp			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
 = edx			      C vertex  TEXTEQU     <edx>       ; the current vertex
 = ecx			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
 = edi			      C packCol TEXTEQU     <edi>
 = edi			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
    pushfd
    
    push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
    call    halStore32@8
			      C 
			      C     popfd
    popad
ELSE
    mov    [__addr + __offset], __data
			      C ENDIF
ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
 000001E0		      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
 000001E0  8B AE 00000DE4     C 
 000001E6  B9 00000004	      C             align 32   
			      C __vertexStart:
 000001EB  8B 86 00000DD8     C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
 000001F1  90		      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, 0
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 000001F2  89 45 00	     1C     mov    [fifo + 0], eax
			     1C ENDIF
 000001F5  83 C5 04	      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
 00000200		      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
 00000200  8B 54 0C 10	      C 
 00000204  83 C5 08	      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
 00000207  90		      C 
 00000208  90		      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
 00000209  8B 02	      C 
 0000020B  8D 9E 00000124     C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -8
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000211  89 45 F8	     1C     mov    [fifo + -8], eax
			     1C ENDIF
 00000214  8B 42 04	      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000217  33 FF	      C     je      __nextVertex
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000219  89 45 FC	     1C     mov    [fifo + -4], eax
			     1C ENDIF
			      C     ;; Not using align directive here because it sometimes
 0000021C		      C     ;; introduces an agi for the eax use below.
 0000021C  8B 03	      C     nop
 0000021E  83 C3 04	      C     nop
			      C         
 00000221  83 F8 00	      C __paramLoop:
 00000224  74 16	      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
 00000226  90		      C     add     dlp, 4                              ; dlp++
 00000227  90		      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000228		      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
 00000228  8B 3C 02	      C     
 0000022B  83 C5 04	      C     jne     SHORT __paramLoop
			      C 
 0000022E  8B 03	      C                 align 4        
 00000230  83 C3 04	      C __nextVertex:   
			      C     ;; On to the next vertex
 00000233  83 F8 00	      C     add     vOffset, 4
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    tempVal
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000236  89 7D FC	     1C     mov    [fifo + -4], tempVal
			     1C ENDIF
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
 00000239  75 ED	      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
 0000023C		      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
 0000023C  83 C1 04	      C     
			      C     mov     [gc + fifoPtr], fifo
 0000023F  83 F9 10	      C     sub     eax, ebx
 00000242  75 BC	      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
 00000244  8B C5	      C 
 00000246  8B 9E 00000DE4     C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
 0000024C  89 AE 00000DE4     C 
 00000252  2B C3	      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
 00000254  8B 5E 10	      C 
 00000257  29 86 00000DEC     C __triDone:    
			      C     ;; Restore trashed registers
 0000025D  83 C3 01	      C     mov     ecx, [gc + trisProcessed]
 00000260  89 5E 10	      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
 00000263  B8 00000001	      C     pop     ebx
			      C     
 00000268		      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
 00000268  8B 4E 0C	      C         
 0000026B  5D		      C     pop     esi
			      C     ret     12
 0000026C  83 C1 01	      C ENDIF ; !GLIDE_CLIP_COOR
 0000026F  5B		      C ENDIF ; !GL_AMD3D
			      C 
 00000270  5F		      C 
 00000271  89 4E 0C	      C 
			      C 
 00000274  5E		      C 
 00000275  C2 000C	      C 
			      C 
			      C 
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(win_cull_invalid) ENDP    
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_invalid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_invalid@12>
 00000278			            ALIGN    32
				            PUBLIC   PROC_TYPE(win_cull_valid)
				PROC_TYPE(win_cull_valid)  PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_valid@12>
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_valid@12>
 00000280			GLIDE_VALIDATE_STATE textequ <0>
				GLIDE_CLIP_COORDS    textequ <0>   
 = 0				GLIDE_CULLING        textequ <1>
 = 0				GLIDE_PACK_RGB       textequ <0>
 = 1				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
 00000280  56		      C     push    esi
 00000281  57		      C     push    edi
			      C     
 00000282  53		      C     push    ebx
 00000283  55		      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
 00000284  8B F2	      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
 00000286  85 F6	      C    test gc, gc
 00000288  0F 84 0000013A     C    je   __triDone
 0000028E  8B 96 000096C4     C    mov edx, [gc + windowed]
 00000294  F7 C2 00000001     C    test edx, 1
 0000029A  75 14	      C    jnz  pastContextTest         ; 
 0000029C  8B 96 000096BC     C    mov  edx, DWORD PTR [gc+lostContext]
 000002A2  8B 1A	      C    mov ebx, [edx]
 000002A4  F7 C3 00000001     C    test ebx, 1
 000002AA  0F 85 00000118     C    jnz  __triDone
 000002B0		      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
 = eax			      C fa      TEXTEQU     <eax>       ; vtx a from caller
 = ebx			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
 = ecx			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
 = edx			      C cull    TEXTEQU     <edx>
 = ebp			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
 = fld  DWORD PTR	      C flds    TEXTEQU <fld  DWORD PTR>
 = fsub DWORD PTR	      C fsubs   TEXTEQU <fsub DWORD PTR>
 = fmul DWORD PTR	      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
 000002B0  8B 44 24 14	      C     mov     fa, [esp + _va$]
 000002B4  8B 5C 24 18	      C     mov     fb, [esp + _vb$]
			      C         
 000002B8  8B 96 000001E0     C     mov     cull, [gc + cull_mode]    
 000002BE  8B 4C 24 1C	      C     mov     fc, [esp + _vc$]
			      C 
 000002C2  85 D2	      C     test    cull, cull    
 000002C4  74 53	      C     jz      nocull
			      C 
 000002C6  C1 E2 1F	      C     shl     cull, 31                    ; culltest << 31    
			      C         
 000002C9		      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
 000002C9  D9 00	      C     flds    [fa + X]            ;  xa
 000002CB  D8 23	      C     fsubs   [fb + X]            ;  dxAB
 000002CD  D9 03	      C     flds    [fb + X]            ;  |    xb
 000002CF  D8 21	      C     fsubs   [fc + X]            ;  |    dxBC
 000002D1  D9 43 04	      C     flds    [fb + Y]            ;  |    |    yb
 000002D4  D8 61 04	      C     fsubs   [fc + Y]            ;  |    |    dyBC
 000002D7  D9 40 04	      C     flds    [fa + Y]            ;  |    |    |    ya
 000002DA  D8 63 04	      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
 000002DD  D9 C3	      C     fld     st(3)               ;  |    |    |    |    dxAB
 000002DF  D8 CA	      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
 000002E1  D9 C3	      C     fld     st(3)               ;  |    |    |    |    |    dxBC
 000002E3  D8 CA	      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
 000002E5  DE E9	      C     fsubp   st(1),st            ;  |    |    |    |    area
 000002E7  D9 15 00000004 R   C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
 000002ED  DD D8	      C     fstp    st(0)   ; 4
 000002EF  DD D8	      C     fstp    st(0)   ; 3
 000002F1  DD D8	      C     fstp    st(0)   ; 2
 000002F3  DD D8	      C     fstp    st(0)   ; 1
 000002F5  DD D8	      C     fstp    st(0)   ; 0    
			      C 
 000002F7  8B 2D 00000004 R   C     mov     intArea, zArea        ; j = *(long *)&area
 000002FD  33 C0	      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
 000002FF  81 E5 7FFFFFFF     C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
 00000305  0F 84 000000BD     C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
 0000030B  8B 2D 00000004 R   C     mov     intArea, zArea              ; reload area just in case we're culling
 00000311  33 EA	      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
 00000313  0F 8D 000000AF     C     jge     __triDone
 00000319		      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
 0000031C  8B 46 4C	      C     mov     eax, [gc + curTriSize]
 0000031F  8B 9E 00000DEC     C     mov     ebx, [gc + fifoRoom]
			      C 
 00000325  83 C0 04	      C     add     eax, 4
 00000328  3B D8	      C     cmp     ebx, eax
			      C 
 0000032A  7D 14	      C     jge     __triBegin
			      C     
 0000032C  68 00000338	      C     push    @Line
 00000331  6A 00	      C     push    0h
			      C     
 00000333  50		      C     push    eax
 00000334  E8 00000000 E      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
 = ebx			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
 = ebp			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
 = edx			      C vertex  TEXTEQU     <edx>       ; the current vertex
 = ecx			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
 = edi			      C packCol TEXTEQU     <edi>
 = edi			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
    pushfd
    
    push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
    call    halStore32@8
			      C 
			      C     popfd
    popad
ELSE
    mov    [__addr + __offset], __data
			      C ENDIF
ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
 00000340		      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
 00000340  8B AE 00000DE4     C 
 00000346  B9 00000004	      C             align 32   
			      C __vertexStart:
 0000034B  8B 86 00000DD8     C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
 00000351  90		      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, 0
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000352  89 45 00	     1C     mov    [fifo + 0], eax
			     1C ENDIF
 00000355  83 C5 04	      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
 00000360		      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
 00000360  8B 54 0C 10	      C 
 00000364  83 C5 08	      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
 00000367  90		      C 
 00000368  90		      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
 00000369  8B 02	      C 
 0000036B  8D 9E 00000124     C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -8
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000371  89 45 F8	     1C     mov    [fifo + -8], eax
			     1C ENDIF
 00000374  8B 42 04	      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000377  33 FF	      C     je      __nextVertex
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000379  89 45 FC	     1C     mov    [fifo + -4], eax
			     1C ENDIF
			      C     ;; Not using align directive here because it sometimes
 0000037C		      C     ;; introduces an agi for the eax use below.
 0000037C  8B 03	      C     nop
 0000037E  83 C3 04	      C     nop
			      C         
 00000381  83 F8 00	      C __paramLoop:
 00000384  74 16	      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
 00000386  90		      C     add     dlp, 4                              ; dlp++
 00000387  90		      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000388		      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
 00000388  8B 3C 02	      C     
 0000038B  83 C5 04	      C     jne     SHORT __paramLoop
			      C 
 0000038E  8B 03	      C                 align 4        
 00000390  83 C3 04	      C __nextVertex:   
			      C     ;; On to the next vertex
 00000393  83 F8 00	      C     add     vOffset, 4
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    tempVal
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000396  89 7D FC	     1C     mov    [fifo + -4], tempVal
			     1C ENDIF
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
 00000399  75 ED	      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
 0000039C		      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
 0000039C  83 C1 04	      C     
			      C     mov     [gc + fifoPtr], fifo
 0000039F  83 F9 10	      C     sub     eax, ebx
 000003A2  75 BC	      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
 000003A4  8B C5	      C 
 000003A6  8B 9E 00000DE4     C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
 000003AC  89 AE 00000DE4     C 
 000003B2  2B C3	      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
 000003B4  8B 5E 10	      C 
 000003B7  29 86 00000DEC     C __triDone:    
			      C     ;; Restore trashed registers
 000003BD  83 C3 01	      C     mov     ecx, [gc + trisProcessed]
 000003C0  89 5E 10	      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
 000003C3  B8 00000001	      C     pop     ebx
			      C     
 000003C8		      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
 000003C8  8B 4E 0C	      C         
 000003CB  5D		      C     pop     esi
			      C     ret     12
 000003CC  83 C1 01	      C ENDIF ; !GLIDE_CLIP_COOR
 000003CF  5B		      C ENDIF ; !GL_AMD3D
			      C 
 000003D0  5F		      C 
 000003D1  89 4E 0C	      C 
			      C 
 000003D4  5E		      C 
 000003D5  C2 000C	      C 
			      C 
			      C 
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(win_cull_valid) ENDP
				    
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_cull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_cull_valid@12>
 000003D8			            ALIGN    32
				            PUBLIC   PROC_TYPE(win_nocull_valid)
				PROC_TYPE(win_nocull_valid)  PROC    NEAR
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_valid@12>
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_valid@12>
 000003E0			GLIDE_VALIDATE_STATE textequ <0>
				GLIDE_CLIP_COORDS    textequ <0>   
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_PACK_RGB       textequ <0>
 = 0				GLIDE_PACK_ALPHA     textequ <0>
 = 0				GLIDE_GENERIC_SETUP  textequ <0>
 = 0				INCLUDE xdraw2.inc
 = 0				GLIDE_GENERIC_SETUP  textequ <0>    
				GLIDE_PACK_ALPHA     textequ <0>
			      C ;; -*-asm-*-
			      C ;; THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
			      C ;; PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
			      C ;; TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
			      C ;; INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE 
			      C ;; DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com). 
			      C ;; THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
			      C ;; EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
			      C ;; FULL TEXT OF THE NON-WARRANTY PROVISIONS.  
			      C ;; 
			      C ;; USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
			      C ;; RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
			      C ;; TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
			      C ;; AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
			      C ;; SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
			      C ;; THE UNITED STATES.  
			      C ;; 
			      C ;; COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
			      C ;;
			      C ;; $Header$
			      C ;; $Revision$
			      C ;; $Log$
			      C ;; Revision 1.1  2000/06/15 00:27:43  joseph
			      C ;; Initial checkin into SourceForge.
			      C ;;
			      C ; 
			      C ; 2     10/30/97 6:53p Peter
			      C ; first real cut at tri asm
			      C ; 
			      C ; 1     10/30/97 4:29p Peter
			      C ; asm tri code
			      C ; 
			      C ; 2     7/07/97 2:14p Jdt
			      C ; assembly now on par with C code.
			      C ; 
			      C ; 1     7/07/97 8:37a Jdt
			      C ; B4 Chip field fix.
			      C ;;
			      C 
			      C     ;; NB:  All of the base triangle procs expect to have the gc
			      C     ;;      passed from the caller in edx so that we can avoid
			      C     ;;      the agi from the far pointer. Screw w/ this at your
			      C     ;;      own peril.
			      C     ;;
			      C     ;;      YOU HAVE BEEN WARNED    
			      C 
			      C ifdef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; start 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C .MMX
			      C .K3D
			      C 
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
			      C     pushfd
			      C     
			      C     push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
			      C     call    halStore32@8
			      C 
			      C     popfd
			      C     popad
			      C ELSE
			      C     mov    [__addr + __offset], __data
			      C ENDIF
			      C ENDM ; GR_FIFO_WRITE
			      C 
			      C 
			      C WRITE_MM1_FIFO_ALIGNED MACRO __offset
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, __offset, tempVal  
			      C     punpckhdq mm1, mm1              ; current param
			      C     movd      tempValm, mm1         ;
			      C     GR_FIFO_WRITE fifo, __offset+4, tempVal  
			      C ELSE
			      C     movq      [fifo+__offset], mm1  ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1_FIFO_ALIGNED
			      C 
			      C 
			      C WRITE_MM1LOW_FIFO MACRO
			      C IFDEF HAL_CSIM
			      C     movd      tempVal, mm1          ; previous param
			      C     GR_FIFO_WRITE fifo, 0, tempVal  ;
			      C ELSE
			      C     movd      [fifo], mm1           ; store current param | previous param
			      C ENDIF
			      C ENDM ; WRITE_MM1LOW_FIFO
			      C 
			      C 
			      C ; Arguments (STKOFF = 16 from 4 pushes)
			      C STKOFF  = 16
			      C _va$    =  4 + STKOFF
			      C _vb$    =  8 + STKOFF
			      C _vc$    = 12 + STKOFF
			      C 
			      C 
			      C gc      TEXTEQU     <edi>           ; points to graphics context
			      C fifo    TEXTEQU     <ebp>           ; points to fifo entries
			      C tempVal TEXTEQU     <esi>
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  Currently, the 3DNow!(tm) clip coordinate stuff
			      C     ;;      thunks through to the grDrawTriangles functions
			      C     ;;      which has already been specialized for 3DNow!(tm).
			      C     ;;      This means that we should never get here.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE    
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>           ; vtx a from caller
			      C fb      TEXTEQU     <ebx>           ; vtx b from caller
			      C fc      TEXTEQU     <ecx>           ; vtx c from caller
			      C cull    TEXTEQU     <edx>           ; cull mode
			      C intArea TEXTEQU     <ecx>           ; area temp storage
			      C 
			      C     ;; Prologue stuff
			      C     push      edi                   ; save caller's register variable
			      C     mov       gc, edx               ; our hoopti calling conventions pass this here    
			      C 
			      C     push      esi                   ; save caller's register variable
			      C     push      ebx                   ; save caller's register variable 
			      C 
			      C     mov       fb, [esp + _vb$ - 4]  ; get base address of vertex B
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       esi, [gc+CoordinateSpace] ; which coord. space (clip/window)?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      esi, esi              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in clip coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C win_coordinates:
			      C endif  ; GLIDE_CLIP_COORDS
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:    
			      C 
			      C endif  ; GLIDE_VALIDATE_STATE 
			      C 
			      C     mov       cull, [gc + cull_mode]; get cull mode
			      C     nop                             ; filler
			      C 
			      C     mov       fc, [esp + _vc$]      ; get base address of vertex C
			      C     nop                             ; filler
			      C 
			      C     ALIGN 16
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     test      cull, cull            ; culling enabled ?
			      C     mov       tempVal, [gc + curTriSize]
			      C 
			      C     ;; Cull Check
			      C 
			      C     jz        nocull                ; nope, no culling
			      C     mov       fa, [esp + _va$]      ; get base address of vertex A
			      C 
			      C     movq      mm2, [fc + X]         ; yc | xc
			      C     shl       cull, 31              ; culltest << 31
			      C 
			      C     movq      mm1, [fb + X]         ; yb | xb
			      C     add       tempVal, 4            ; space required in fifo
			      C 
			      C     movq      mm0, [fa + X]         ; ya | xa
			      C     mov       ebx, [gc + fifoRoom]  ; space available in fifo
			      C 
			      C     ;; Area_Computation
			      C 
			      C     pfsubr    mm2, mm1              ; dyBC | dxBC
			      C     pfsub     mm0, mm1              ; dyAB | dxAB
			      C 
			      C     movq      mm5, mm2              ; dyBC | dxBC
			      C     punpckhdq mm2, mm2              ; dyBC | dyBC
			      C 
			      C     movq      mm4, mm0              ; dyAB | dxAB
			      C     punpckhdq mm0, mm0              ; dyAB | dyAB
			      C 
			      C     pfmul     mm5, mm0              ; dyAB*dxBC
			      C     pfmul     mm4, mm2              ; dxAB*dyBC
			      C 
			      C     pfsub     mm4, mm5              ; dxAB*dyBC - dxBC*dyAB
			      C 
			      C     movd      intArea, mm4          ; vectored !
			      C 
			      C     ; Zero Area Triangle Check
			      C 
			      C     test      intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz        __cullFail            ; area zero, triangle culled
			      C 
			      C     xor       intArea, cull         ; if (j ^ (culltest << 31))
			      C     jge       __cullFail            ; triangle facing away from viewer, culled
			      C 
			      C     cmp       ebx, tempVal          ; fifo space required >= space available ?
			      C     jge       __triBegin            ; yup, push out triangle data to Voodoo
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space required
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; merge back with short path
			      C 
			      C     ;; culling disabled
			      C 
			      C     ALIGN     16
			      C 
			      C nocull:
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
			      C 
			      C     add       tempVal, 4            ; fifo space needed
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C ELSE   ; !GLIDE_CULLING
			      C 
			      C     ;; Prologue stuff
			      C 
			      C     push      edi                   ; save caller's register variable
			      C     push      esi                   ; save caller's register variable 
			      C 
			      C     mov       gc, edx               ; gc in edx from caller
			      C     push      ebx                   ; save caller's register variable
			      C 
			      C     push      ebp                   ; save frame pointer
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     mov       edx, [gc+CoordinateSpace]; window coordinates or clip coordinates ?
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     mov       ebp, [gc + invalid]   ; state validated?
			      C endif
			      C 
			      C if GLIDE_CLIP_COORDS
			      C     lea       eax, [esp+ _va$]      ; pointer to vertex pointers
			      C     test      edx, edx              ; window coordinates ?
			      C 
			      C     jz        win_coordinates       ; yup
			      C     push      eax                   ; pointer to vertex pointers
			      C 
			      C     push      3                     ; 3 vertices
			      C     push      1                     ; mode = grDrawVertexArray
			      C 
			      C     call      __grDrawTriangles@12  ; draw the triangle in coordinate space
			      C 
			      C     pop       ebp                   ; restore frame pointer
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     ret       12                    ; return, pop 3 DWORD arguments off stack
			      C 
			      C     ALIGN  16
			      C win_coordinates:
			      C 
			      C endif
			      C 
			      C if GLIDE_VALIDATE_STATE
			      C     test      ebp, ebp              ; does state need validation?
			      C     jz        no_validation         ; valid, don't need to validate
			      C 
			      C     call      __grValidateState     ; validate state
			      C 
			      C no_validation:
			      C 
			      C endif
			      C 
			      C     mov       tempVal, [gc + curTriSize] ; data for whole triangle in bytes
			      C     add       tempVal, 4            ; fifo space needed (include 4-byte header)
			      C     mov       ebx, [gc + fifoRoom]  ; fifo space available
			      C 
			      C     femms                           ; will use AMD3D, clear FPU/MMX registers
			      C 
			      C     cmp       ebx, tempVal          ; fifo spce available >= space needed ?
			      C     jge       __triBegin            ; yup, ready to draw triangle
			      C 
			      C     push      @Line                 ; line number inside this function
			      C     push      0h                    ; pointer to function name = NULL
			      C 
			      C     push      tempVal               ; fifo space needed
			      C     call      __grCommandTransportMakeRoom@12 ; note: updates fifoPtr
			      C     
			      C     jmp       __triBegin            ; large distance due to alignment
			      C endif ; GLIDE_CULLING
			      C 
			      C 
			      C dlp     TEXTEQU     <ebx>           ; points to dataList structure
			      C dlpstrt TEXTEQU     <ecx>           ; points to begin of dataList structure
			      C vertex  TEXTEQU     <edx>           ; the current vertex
			      C 
			      C     ALIGN 32                        
			      C 
			      C __triBegin:
			      C     mov       eax, [gc+triPacketHdr]; Packet 3 header
			      C     lea       dlp,[gc + tsuDataList]; Reset the dataList
			      C 
			      C     mov       fifo, [gc + fifoPtr]  ; Fetch Fifo Ptr
			      C     mov       vertex, [esp + _va$]  ; Current vertex = A
			      C 
			      C     mov       dlpstrt, dlp          ; save pointer to start of dataList
			      C     test      fifo, 4               ; is fifo pointer qword aligned ?
			      C 
			      C     jz        __fifo_aligned        ; yes, it is qword aligned
			      C     movq      mm1, [vertex+X]       ; y | x
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax      ; write header to fifo; now qword aligned
			      C     add       fifo, 12              ; fifoPtr += 3*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero1; yes, "write buffer" empty
			      C           
			      C __paramLoop1a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone1 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop1a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero1; write buffer empty
			      C 
			      C __fifo_aligned:
			      C     movd      mm2, [vertex+X]       ; y | x of vertex A
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [gc+triPacketHdr]; Packet 3 header
			      C     punpckldq mm1, mm2              ; x | header
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write x | header
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex A
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone1 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop1b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero1; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop1b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone1:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex A
			      C 
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex B
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex B
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone2 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop2b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero2; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop2b         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBone2 ; write buffer contains one DWORD
			      C 
			      C __paramLoopDoneWBzero1:
			      C 
			      C     mov       vertex, [esp + _vb$]  ; Current vertex = B
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex B
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex B
			      C     nop                             ; filler
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     cmp       eax, 0                ; at end of list ?
			      C     jz        __paramLoopDoneWBzero2; yes, "write buffer" empty
			      C           
			      C __paramLoop2a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     cmp       eax, 0                ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone2 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop2a         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBzero2:
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; Reset the dataList
			      C 
			      C     movq      mm1, [vertex+X]       ; y | x of vertex C
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write y | x of vertex C
			      C 
			      C     ;; here: "write buffer" empty
			      C 
			      C     mov       eax, [dlp]            ; Get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; at end of list ?
			      C     jz        __paramLoopDoneWBzero3; yes, "write buffer" empty
			      C           
			      C __paramLoop3a:
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jz        __paramLoopDoneWBone3 ; exit, write buffer contains one DWORD
			      C 
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jnz       __paramLoop3a         ; nope, copy next parameter
			      C 
			      C     jmp       __paramLoopDoneWBzero3; write buffer empty
			      C 
			      C __paramLoopDoneWBone2:
			      C 
			      C     ;; here: "write buffer" has one DWORD left over from vertex B
			      C 
			      C     mov       vertex, [esp + _vc$]  ; Current vertex = C
			      C     mov       dlp, dlpstrt          ; reset the dataList
			      C 
			      C     movd      mm2, [vertex+X]       ; 0 | x if vertex C
			      C     punpckldq mm1, mm2              ; x | old param
			      C 
			      C     WRITE_MM1_FIFO_ALIGNED 0        ; PCI write: x | old param
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     movd      mm1, [vertex+Y]       ; 0 | y of vertex C
			      C     nop                             ; filler
			      C 
			      C     mov       eax, [dlp]            ; get first offset from the data list
			      C     add       dlp, 4                ; dlp++
			      C 
			      C     test      eax, eax              ; end of list ?
			      C     jz        __paramLoopDoneWBone3 ; yes, "write buffer" has y data
			      C 
			      C __paramLoop3b:
			      C     movd      mm2, [eax+vertex]     ; get next parameter
			      C     add       fifo, 8               ; fifoPtr += 2*sizeof(FxU32)
			      C 
			      C     mov       eax, [dlp]            ; offset = *(dlp + 1)
			      C     add       dlp, 8                ; dlp += 2
			      C 
			      C     punpckldq mm1, mm2              ; current param | previous param
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C   
			      C     WRITE_MM1_FIFO_ALIGNED -8       ; PCI write current param | previous param
			      C     jz        __paramLoopDoneWBzero3; exit, "write buffer" empty
			      C 
			      C     movd      mm1, [eax+vertex]     ; get next parameter
			      C     mov       eax, [dlp-4]          ; offset = *(dlp + 1)
			      C 
			      C     test      eax, eax              ; at end of offset list (offset == 0) ?
			      C     jnz       __paramLoop3b         ; nope, copy next parameter
			      C 
			      C __paramLoopDoneWBone3:
			      C 
			      C ; "write buffer" contains one DWORD that needs to be flushed
			      C 
			      C     WRITE_MM1LOW_FIFO               ; 
			      C     add       fifo, 4               ;
			      C 
			      C __paramLoopDoneWBzero3:
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
			      C 
			      C     mov       ecx, [gc + trisDrawn]             ; _GlideRoot.stats.trisDrawn
			      C     mov       eax, fifo                         ; new fifo pointer
			      C     
			      C     mov       ebx, [gc + fifoPtr]               ; old fifo pointer
			      C     mov       [gc + fifoPtr], fifo              ; save new fifo pointer
			      C 
			      C     mov       edx, [gc + fifoRoom]              ; old fifo space available
			      C     inc       ecx                               ; _GlideRoot.stats.trisDrawn++
			      C 
			      C     mov       esi, [gc + trisProcessed]         ; _GlideRoot.stats.trisProcessed
			      C     sub       eax, ebx                          ; new fifo ptr - old fifo ptr = additional fifo space used
			      C 
			      C     mov       [gc + trisDrawn], ecx             ;
			      C     sub       edx, eax                          ; new fifo space available
			      C 
			      C     mov       eax, 1h                           ; return value = triangle drawn
			      C     mov       [gc + fifoRoom], edx              ; new fifo space available
			      C 
			      C     ;; Restore trashed registers    
			      C 
			      C __triDone_nocull:
			      C 
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi ;
			      C     pop       ebx                   ; restore caller's register variable
			      C     
			      C     pop       esi                   ; restore caller's register variable
			      C     pop       edi                   ; restore caller's register variable
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C     ret       12                    ; return to caller
			      C 
			      C 
			      C IF GLIDE_CULLING
			      C __cullFail:
			      C     mov       esi, [gc + trisProcessed]; triangles processed so far
			      C     xor       eax, eax              ; return value = triangle not drawn
			      C 
			      C     femms                           ; no more AMD3D code, clear FPU/MMX regs
			      C 
			      C __triDone_cull:
			      C     ;; Restore trashed registers    
			      C     inc       esi                   ; _GlideRoot.stats.trisProcessed++;    
			      C     pop       ebp                   ; restore frame pointer
			      C 
			      C     mov       [gc + trisProcessed], esi
			      C     pop       ebx
			      C     
			      C     pop       esi
			      C     pop       edi
			      C 
			      C     ret       12
			      C ENDIF ; GLIDE_CULLING
			      C ENDIF ; !GLIDE_CLIP_COORDS
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; end 3DNow! version
			      C ;---------------------------------------------------------------------------
			      C 
			      C endif ; GL_AMD3D
			      C 
			      C 
			      C ifndef GL_AMD3D
			      C 
			      C ;---------------------------------------------------------------------------
			      C ; original code
			      C ;---------------------------------------------------------------------------
			      C 
			      C TITLE   xdraw2.inc
			      C .586P
			      C         
			      C IFDEF HAL_CSIM
			      C EXTRN   halStore32@8:NEAR
			      C ENDIF
			      C         
			      C ; Ugly, but seems to workaround the problem with locally defined
			      C ; data segment globals not getting relocated properly when using
			      C ; djgpp.
			      C 
 = One+04h		      C zArea   TEXTEQU <One+04h>
 = One+08h		      C zdxAB   TEXTEQU <One+08h>
 = One+0ch		      C zdxBC   TEXTEQU <One+0ch>
 = One+10h		      C zdyAB   TEXTEQU <One+10h>
 = One+14h		      C zdyBC   TEXTEQU <One+14h>
 = One+18h		      C zculltest TEXTEQU <One+18h>
			      C 
 = esi			      C gc      TEXTEQU     <esi>       ; points to graphics context
			      C 
			      C IF GLIDE_CLIP_COORDS
			      C     ;; NB:  We should never hit this because the proc is
			      C     ;;      either specialized or we thunk through to
			      C     ;;      grDrawTriangles for the clipping etc.
			      C IFDEF GLIDE_DEBUG    
			      C     xor     eax, eax
			      C     mov     [eax], eax
			      C ENDIF    
			      C ELSE        
			      C     ;; Prologue stuff
 000003E0  56		      C     push    esi
 000003E1  57		      C     push    edi
			      C     
 000003E2  53		      C     push    ebx
 000003E3  55		      C     push    ebp
			      C 
			      C ;;   call    getThreadValueSLOW
			      C ;;   mov     gc, eax    
			      C     
			      C IF 0
			      C ;;; TRICKY STUFF HERE:
			      C ;;; The following code could be expressed like this but MASM had difficulty with it
			      C ;;; mov eax, DWORD PTR fs:[18h]
			      C ;;; Remember, gc == esi
			      C    db 064h
			      C    db 0a1h
			      C    db 018h
			      C    db 00
			      C     
			      C    db 00h
			      C    db 00h
			      C   
			      C    add eax, DWORD PTR __GlideRoot + tlsOffset
			      C    mov gc, [eax]
			      C ELSE
 000003E4  8B F2	      C    mov gc, edx
			      C ENDIF
			      C IFDEF GLIDE_ALT_TAB
 000003E6  85 F6	      C    test gc, gc
 000003E8  0F 84 000000DA     C    je   __triDone
 000003EE  8B 96 000096C4     C    mov edx, [gc + windowed]
 000003F4  F7 C2 00000001     C    test edx, 1
 000003FA  75 14	      C    jnz  pastContextTest         ; 
 000003FC  8B 96 000096BC     C    mov  edx, DWORD PTR [gc+lostContext]
 00000402  8B 1A	      C    mov ebx, [edx]
 00000404  F7 C3 00000001     C    test ebx, 1
 0000040A  0F 85 000000B8     C    jnz  __triDone
 00000410		      C pastContextTest:    
			      C 
			      C ENDIF
			      C             align 4
			      C IF GLIDE_VALIDATE_STATE
			      C ;;;     GR_FLUSH_STATE()
			      C     mov     edx, DWORD PTR [gc+invalid]
			      C     test    edx, edx
			      C     je      SHORT no_validatioin
			      C     call    __grValidateState
			      C no_validatioin:
			      C ENDIF
			      C             align 4
			      C IF GLIDE_CULLING
			      C fa      TEXTEQU     <eax>       ; vtx a from caller
			      C fb      TEXTEQU     <ebx>       ; vtx b from caller
			      C fc      TEXTEQU     <ecx>       ; vtx c from caller
			      C 
			      C cull    TEXTEQU     <edx>
			      C intArea TEXTEQU     <ebp>       ; temp Y storage
			      C 
			      C ; some useful floating load and store macros <ala gmt>
			      C flds    TEXTEQU <fld  DWORD PTR>
			      C fsubs   TEXTEQU <fsub DWORD PTR>
			      C fmuls   TEXTEQU <fmul DWORD PTR>        
			      C 
			      C     ;; Pre-load the current culling mode before all of the
			      C     ;; floating point area stuff.    
			      C     mov     fa, [esp + _va$]
			      C     mov     fb, [esp + _vb$]
			      C         
			      C     mov     cull, [gc + cull_mode]    
			      C     mov     fc, [esp + _vc$]
			      C 
			      C     test    cull, cull    
			      C     jz      nocull
			      C 
			      C     shl     cull, 31                    ; culltest << 31    
			      C         
			      C Area_Computation:    
			      C ; 47-3
			      C ; jmp ret_pop0f
			      C     flds    [fa + X]            ;  xa
			      C     fsubs   [fb + X]            ;  dxAB
			      C     flds    [fb + X]            ;  |    xb
			      C     fsubs   [fc + X]            ;  |    dxBC
			      C     flds    [fb + Y]            ;  |    |    yb
			      C     fsubs   [fc + Y]            ;  |    |    dyBC
			      C     flds    [fa + Y]            ;  |    |    |    ya
			      C     fsubs   [fb + Y]            ;  |    |    |    dyAB
			      C     fld     st(3)               ;  |    |    |    |    dxAB
			      C     fmul    st, st(2)           ;  |    |    |    |    t0         t0=dxAB*dyBC
			      C     fld     st(3)               ;  |    |    |    |    |    dxBC
			      C     fmul    st, st(2)           ;  |    |    |    |    |    t1    t1=dxBC*dyAB
			      C     fsubp   st(1),st            ;  |    |    |    |    area
			      C     fst     zArea               ;  |    |    |    |    area
			      C 
			      C     ;; Pop temp things from the sw culling off the fp stack
			      C     fstp    st(0)   ; 4
			      C     fstp    st(0)   ; 3
			      C     fstp    st(0)   ; 2
			      C     fstp    st(0)   ; 1
			      C     fstp    st(0)   ; 0    
			      C 
			      C     mov     intArea, zArea        ; j = *(long *)&area
			      C     xor     eax, eax              ; Clear the return value (0 == culled)
			      C 
			      C     ; Zero Area Triangle Check
			      C     and     intArea, 7fffffffh    ; if ((j & 0x7FFFFFFF) == 0)
			      C     jz      __triDone
			      C 
			      C     ;; Triangle area check vs culling mode
			      C     mov     intArea, zArea              ; reload area just in case we're culling
			      C     xor     intArea, cull               ; if (j ^ (culltest << 31))
			      C     
			      C     jge     __triDone
			      C nocull: 
			      C ENDIF ; GLIDE_CULLING    
			      C 
			      C             align 4
			      C     ;; Check to make sure that we have enough room for
			      C     ;; the complete triangle packet.
 00000410  8B 46 4C	      C     mov     eax, [gc + curTriSize]
 00000413  8B 9E 00000DEC     C     mov     ebx, [gc + fifoRoom]
			      C 
 00000419  83 C0 04	      C     add     eax, 4
 0000041C  3B D8	      C     cmp     ebx, eax
			      C 
 0000041E  7D 20	      C     jge     __triBegin
			      C     
 00000420  68 00000338	      C     push    @Line
 00000425  6A 00	      C     push    0h
			      C     
 00000427  50		      C     push    eax
 00000428  E8 00000000 E      C     call    __grCommandTransportMakeRoom@12
			      C 
			      C     ;; Send triangle parameters
			      C     
 = ebx			      C dlp     TEXTEQU     <ebx>       ; points to dataList structure
 = ebp			      C fifo    TEXTEQU     <ebp>       ; points to next entry in fifo
 = edx			      C vertex  TEXTEQU     <edx>       ; the current vertex
 = ecx			      C vOffset TEXTEQU     <ecx>       ; Current vertex offset
			      C 
 = edi			      C packCol TEXTEQU     <edi>
 = edi			      C tempVal TEXTEQU     <edi>
			      C 
			      C GR_FIFO_WRITE   MACRO __addr, __offset, __data
			      C IFDEF HAL_CSIM
			      C     pushad
    pushfd
    
    push    __data
			      C     mov     eax, __addr
			      C     add     eax, __offset
			      C     push    eax
    call    halStore32@8
			      C 
			      C     popfd
    popad
ELSE
    mov    [__addr + __offset], __data
			      C ENDIF
ENDM ; GR_FIFO_WRITE
			      C 
			      C             align 32
			      C __triBegin:
			      C     mov     fifo, [gc + fifoPtr]        ; Fetch Fifo Ptr
			      C     mov     vOffset, 4                  ; Starting vertex
			      C 
			      C     mov     eax, [gc + triPacketHdr]    ; Packet 3 header
			      C     nop
			      C 
			      C     GR_FIFO_WRITE fifo, 0, eax          ; Write packet header to fifo    
 00000440		      C     add     fifo, 4                     ; Advance fifo for hdr & x/y coordinate
 00000440  8B AE 00000DE4     C 
 00000446  B9 00000004	      C             align 32   
			      C __vertexStart:
 0000044B  8B 86 00000DD8     C     mov     vertex, [esp + STKOFF + vOffset]    ; Current vertex
 00000451  90		      C     add     fifo, 8    
			      C 
			      C     nop                                         ; Avoid p5 agi w/ load of vertex ptr
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, 0
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000452  89 45 00	     1C     mov    [fifo + 0], eax
			     1C ENDIF
 00000455  83 C5 04	      C     nop
			      C     
			      C     mov     eax, DWORD PTR [vertex]             ; X
 00000460		      C     lea     dlp, [gc + tsuDataList]             ; Reset the dataList
 00000460  8B 54 0C 10	      C 
 00000464  83 C5 08	      C     GR_FIFO_WRITE fifo, -8, eax                 ; PCI write X
			      C     mov     eax, DWORD PTR [vertex + 4]         ; Y 
 00000467  90		      C 
 00000468  90		      C     xor     packCol, packCol                    ; Clear packed color
			      C     GR_FIFO_WRITE fifo, -4, eax                 ; PCI write Y
 00000469  8B 02	      C 
 0000046B  8D 9E 00000124     C __doParams:
			      C     mov     eax, DWORD PTR [dlp]                ; Get first offset from the data list
			      C     add     dlp, 4                              ; dlp++
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -8
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000471  89 45 F8	     1C     mov    [fifo + -8], eax
			     1C ENDIF
 00000474  8B 42 04	      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000477  33 FF	      C     je      __nextVertex
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    eax
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000479  89 45 FC	     1C     mov    [fifo + -4], eax
			     1C ENDIF
			      C     ;; Not using align directive here because it sometimes
 0000047C		      C     ;; introduces an agi for the eax use below.
 0000047C  8B 03	      C     nop
 0000047E  83 C3 04	      C     nop
			      C         
 00000481  83 F8 00	      C __paramLoop:
 00000484  74 16	      C     mov     tempVal, DWORD PTR [eax + vertex]   ; Get the parameter from teh vertex
			      C     add     fifo, 4                             ; fifoPtr += sizeof(FxU32)
			      C 
			      C     mov     eax, DWORD PTR [dlp]                ; offset = *(dlp + 1)
 00000486  90		      C     add     dlp, 4                              ; dlp++
 00000487  90		      C     
			      C     cmp     eax, 0                              ; Are we done?
 00000488		      C     GR_FIFO_WRITE fifo, -4, tempVal             ; *fifoPtr = data
 00000488  8B 3C 02	      C     
 0000048B  83 C5 04	      C     jne     SHORT __paramLoop
			      C 
 0000048E  8B 03	      C                 align 4        
 00000490  83 C3 04	      C __nextVertex:   
			      C     ;; On to the next vertex
 00000493  83 F8 00	      C     add     vOffset, 4
			      C 
			     1C IFDEF HAL_CSIM
			     1C     pushad
			     1C     pushfd
			     1C     
			     1C     push    tempVal
			     1C     mov     eax, fifo
			     1C     add     eax, -4
			     1C     push    eax
			     1C     call    halStore32@8
			     1C 
			     1C     popfd
			     1C     popad
			     1C ELSE
 00000496  89 7D FC	     1C     mov    [fifo + -4], tempVal
			     1C ENDIF
			      C     cmp     vOffset, 16                         ; Offset of one past last vertex?
 00000499  75 ED	      C     jne     __vertexStart
			      C 
			      C     ;; Update gc->fifoPtr and gc->fifoRoom
 0000049C		      C     mov     eax, fifo
			      C     mov     ebx, [gc + fifoPtr]
 0000049C  83 C1 04	      C     
			      C     mov     [gc + fifoPtr], fifo
 0000049F  83 F9 10	      C     sub     eax, ebx
 000004A2  75 BC	      C 
			      C     mov     ebx, [gc + trisDrawn]               ; _GlideRoot.stats.trisDrawn++;    
			      C     sub     [gc + fifoRoom], eax
 000004A4  8B C5	      C 
 000004A6  8B 9E 00000DE4     C     add     ebx, 1
			      C     mov     [gc + trisDrawn], ebx
 000004AC  89 AE 00000DE4     C 
 000004B2  2B C3	      C     ;; return 1 (triangle drawn)    
			      C     mov     eax, 1h
 000004B4  8B 5E 10	      C 
 000004B7  29 86 00000DEC     C __triDone:    
			      C     ;; Restore trashed registers
 000004BD  83 C3 01	      C     mov     ecx, [gc + trisProcessed]
 000004C0  89 5E 10	      C     pop     ebp
			      C         
			      C     add     ecx, 1    ; _GlideRoot.stats.trisProcessed++;    
 000004C3  B8 00000001	      C     pop     ebx
			      C     
 000004C8		      C     pop     edi
			      C     mov     [gc + trisProcessed], ecx
 000004C8  8B 4E 0C	      C         
 000004CB  5D		      C     pop     esi
			      C     ret     12
 000004CC  83 C1 01	      C ENDIF ; !GLIDE_CLIP_COOR
 000004CF  5B		      C ENDIF ; !GL_AMD3D
			      C 
 000004D0  5F		      C 
 000004D1  89 4E 0C	      C 
			      C 
 000004D4  5E		      C 
 000004D5  C2 000C	      C 
			      C 
			      C 
			      C 
 = 0				GLIDE_PACK_RGB       textequ <0>    
 = 0				GLIDE_CULLING        textequ <0>
 = 0				GLIDE_CLIP_COORDS    textequ <0>
 = 0				GLIDE_VALIDATE_STATE textequ <0>
 = 0				
 = 0				PROC_TYPE(win_nocull_valid) ENDP
				
			     1	    IFDEF GL_AMD3D
			     1	        EXITM <__trisetup_3DNow_win_nocull_valid@12>
			     1	    ELSE
			     1	        EXITM <__trisetup_Default_win_nocull_valid@12>
 000004D8			IFDEF       GL_AMD3D    
				            ALIGN   32
				            PUBLIC  __trisetup_clip_coor_thunk@12
				__trisetup_clip_coor_thunk@12 PROC NEAR
				
				procPtr TEXTEQU <eax>    
				vPtr    TEXTEQU <ecx>
				gc      TEXTEQU <edx>           ; Current graphics context passed implicitly through edx
				    
				    ;; Call through to the gc->curArchProcs.drawTrianglesProc w/o
				    ;; adding extra stuff to the stack. I wish we could actually
				    ;; do a direct return here w/o too much work.
				    lea     vPtr, [esp + _va$ - STKOFF]         ; Get vertex pointer address
				    mov     procPtr, [gc + drawTrianglesProc]   ; Prefetch drawTriangles proc addr
				    
				    push    vPtr                ; vertex array address
				    push    3                   ; 3 vertices
				
				    ;; If debugging make sure that we're in clip coordinates
				IFDEF GLIDE_DEBUG
				    mov     eax, [gc + CoordinateSpace]
				    test    eax, 1
				    jnz     __clipSpace
				    xor     eax, eax
				    mov     [eax], eax
				__clipSpace:    
				ENDIF ; GLIDE_DEBUG
				
				    push    1                   ; mode = grDrawVertexArray
				    call    procPtr             ; (*gc->curArchProcs.drawTrianglesProc)(grDrawVertexArray, 3, vPtr)
				
				    ret     12                  ; pop 3 dwords (vertex addrs) and return    
				__trisetup_clip_coor_thunk@12 ENDP
				
				ENDIF ; GL_AMD3D    
				
				_TEXT   ENDS
				        END
 04D8
Microsoft (R) Macro Assembler Version 6.14.8444		    06/20/00 17:18:57
xdraw2.asm						     Symbols 2 - 1




Macros:

                N a m e                 Type

GR_FIFO_WRITE  . . . . . . . . .	Proc
PROC_TYPE  . . . . . . . . . . .	Func


Segments and Groups:

                N a m e                 Size     Length   Align   Combine Class

CONST  . . . . . . . . . . . . .	32 Bit	 000C	  Para	  Private 
FLAT . . . . . . . . . . . . . .	GROUP
_DATA  . . . . . . . . . . . . .	32 Bit	 0008	  Para	  Private 
_TEXT  . . . . . . . . . . . . .	32 Bit	 04D8	  Page	  Public  'CODE'	


Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

__trisetup_Default_clip_cull_invalid@12  P Near	  0000	   _TEXT	Length= 0000 Public
__trisetup_Default_clip_cull_valid@12 	P Near	 0000	  _TEXT	Length= 0000 Public
__trisetup_Default_clip_nocull_invalid@12  P Near   0000     _TEXT	Length= 0000 Public
__trisetup_Default_clip_nocull_valid@12  P Near	  0000	   _TEXT	Length= 0000 Public
__trisetup_Default_win_cull_invalid@12 . P Near	  0100	   _TEXT	Length= 0178 Public
  pastContextTest  . . . . . . .	L Near	 0130	  _TEXT	
  no_validatioin . . . . . . . .	L Near	 013F	  _TEXT	
  Area_Computation . . . . . . .	L Near	 0159	  _TEXT	
  nocull . . . . . . . . . . . .	L Near	 01A9	  _TEXT	
  __triBegin . . . . . . . . . .	L Near	 01E0	  _TEXT	
  __vertexStart  . . . . . . . .	L Near	 0200	  _TEXT	
  __doParams . . . . . . . . . .	L Near	 021C	  _TEXT	
  __paramLoop  . . . . . . . . .	L Near	 0228	  _TEXT	
  __nextVertex . . . . . . . . .	L Near	 023C	  _TEXT	
  __triDone  . . . . . . . . . .	L Near	 0268	  _TEXT	
__trisetup_Default_win_cull_valid@12 .	P Near	 0280	  _TEXT	Length= 0158 Public
  pastContextTest  . . . . . . .	L Near	 02B0	  _TEXT	
  Area_Computation . . . . . . .	L Near	 02C9	  _TEXT	
  nocull . . . . . . . . . . . .	L Near	 0319	  _TEXT	
  __triBegin . . . . . . . . . .	L Near	 0340	  _TEXT	
  __vertexStart  . . . . . . . .	L Near	 0360	  _TEXT	
  __doParams . . . . . . . . . .	L Near	 037C	  _TEXT	
  __paramLoop  . . . . . . . . .	L Near	 0388	  _TEXT	
  __nextVertex . . . . . . . . .	L Near	 039C	  _TEXT	
  __triDone  . . . . . . . . . .	L Near	 03C8	  _TEXT	
__trisetup_Default_win_nocull_invalid@12 . P Near   0000     _TEXT	Length= 00F8 Public
  pastContextTest  . . . . . . .	L Near	 0030	  _TEXT	
  no_validatioin . . . . . . . .	L Near	 003F	  _TEXT	
  __triBegin . . . . . . . . . .	L Near	 0060	  _TEXT	
  __vertexStart  . . . . . . . .	L Near	 0080	  _TEXT	
  __doParams . . . . . . . . . .	L Near	 009C	  _TEXT	
  __paramLoop  . . . . . . . . .	L Near	 00A8	  _TEXT	
  __nextVertex . . . . . . . . .	L Near	 00BC	  _TEXT	
  __triDone  . . . . . . . . . .	L Near	 00E8	  _TEXT	
__trisetup_Default_win_nocull_valid@12 . P Near	  03E0	   _TEXT	Length= 00F8 Public
  pastContextTest  . . . . . . .	L Near	 0410	  _TEXT	
  __triBegin . . . . . . . . . .	L Near	 0440	  _TEXT	
  __vertexStart  . . . . . . . .	L Near	 0460	  _TEXT	
  __doParams . . . . . . . . . .	L Near	 047C	  _TEXT	
  __paramLoop  . . . . . . . . .	L Near	 0488	  _TEXT	
  __nextVertex . . . . . . . . .	L Near	 049C	  _TEXT	
  __triDone  . . . . . . . . . .	L Near	 04C8	  _TEXT	


Symbols:

                N a m e                 Type     Value    Attr

$T2003 . . . . . . . . . . . . .	DWord	 0000	  CONST	
$T2005 . . . . . . . . . . . . .	DWord	 0004	  CONST	
$T2006 . . . . . . . . . . . . .	DWord	 0008	  CONST	
Area . . . . . . . . . . . . . .	DWord	 0004	  _DATA	
CPUType  . . . . . . . . . . . .	Number	 0010h	 
CoordinateSpace  . . . . . . . .	Number	 0D98h	 
GLIDE_ALT_TAB  . . . . . . . . .	Text   	 
GLIDE_CLIP_COORDS  . . . . . . .	Text   	 0
GLIDE_CULLING  . . . . . . . . .	Text   	 0
GLIDE_GENERIC_SETUP  . . . . . .	Text   	 0
GLIDE_INIT_HWC . . . . . . . . .	Text   	 
GLIDE_PACKED_RGB . . . . . . . .	Text   	 0
GLIDE_PACK_ALPHA . . . . . . . .	Text   	 0
GLIDE_PACK_RGB . . . . . . . . .	Text   	 0
GLIDE_TRI_CULLING  . . . . . . .	Text   	 1
GLIDE_VALIDATE_STATE . . . . . .	Text   	 0
MM0  . . . . . . . . . . . . . .	Text   	 MM(0)
MM1  . . . . . . . . . . . . . .	Text   	 MM(1)
MM2  . . . . . . . . . . . . . .	Text   	 MM(2)
MM3  . . . . . . . . . . . . . .	Text   	 MM(3)
MM4  . . . . . . . . . . . . . .	Text   	 MM(4)
MM5  . . . . . . . . . . . . . .	Text   	 MM(5)
MM6  . . . . . . . . . . . . . .	Text   	 MM(6)
MM7  . . . . . . . . . . . . . .	Text   	 MM(7)
Mm0  . . . . . . . . . . . . . .	Text   	 MM(0)
Mm1  . . . . . . . . . . . . . .	Text   	 MM(1)
Mm2  . . . . . . . . . . . . . .	Text   	 MM(2)
Mm3  . . . . . . . . . . . . . .	Text   	 MM(3)
Mm4  . . . . . . . . . . . . . .	Text   	 MM(4)
Mm5  . . . . . . . . . . . . . .	Text   	 MM(5)
Mm6  . . . . . . . . . . . . . .	Text   	 MM(6)
Mm7  . . . . . . . . . . . . . .	Text   	 MM(7)
One  . . . . . . . . . . . . . .	DWord	 0000	  _DATA	
SIZEOF_GC  . . . . . . . . . . .	Number	 9714h	 
SIZEOF_GlideRoot . . . . . . . .	Number	 000BCFC4h   
SIZEOF_GrState . . . . . . . . .	Number	 0BBCh	 
STATS  . . . . . . . . . . . . .	Number	 0001h	 
STKOFF . . . . . . . . . . . . .	Number	 0010h	 
X  . . . . . . . . . . . . . . .	Number	 0000h	 
Y  . . . . . . . . . . . . . . .	Number	 0004h	 
__GlideRoot  . . . . . . . . . .	DWord	 0000	  External
__grCommandTransportMakeRoom@12 	L Near	 0000	  External
__grValidateState  . . . . . . .	L Near	 0000	  External
_hwcQueryContext . . . . . . . .	L Near	 0000	  External
_va$ . . . . . . . . . . . . . .	Number	 0014h	 
_vb$ . . . . . . . . . . . . . .	Number	 0018h	 
_vc$ . . . . . . . . . . . . . .	Number	 001Ch	 
bInfo  . . . . . . . . . . . . .	Number	 011Ch	 
base_ptr . . . . . . . . . . . .	Number	 0074h	 
colorType  . . . . . . . . . . .	Number	 0B74h	 
cullStripHdr . . . . . . . . . .	Number	 0DDCh	 
cull_mode  . . . . . . . . . . .	Number	 01E0h	 
cull . . . . . . . . . . . . . .	Text   	 edx
curTriSize . . . . . . . . . . .	Number	 004Ch	 
current_sst  . . . . . . . . . .	Number	 000Ch	 
depth_range  . . . . . . . . . .	Number	 0A44h	 
dlp  . . . . . . . . . . . . . .	Text   	 ebx
drawTrianglesProc  . . . . . . .	Number	 0DC8h	 
drawVertexList . . . . . . . . .	Number	 0DC4h	 
fa . . . . . . . . . . . . . . .	Text   	 eax
fbi_fbzMode  . . . . . . . . . .	Number	 0210h	 
fb . . . . . . . . . . . . . . .	Text   	 ebx
fc . . . . . . . . . . . . . . .	Text   	 ecx
fifoEnd  . . . . . . . . . . . .	Number	 0E08h	 
fifoJmpHdr . . . . . . . . . . .	Number	 0E14h	 
fifoOffset . . . . . . . . . . .	Number	 0E0Ch	 
fifoPtr  . . . . . . . . . . . .	Number	 0DE4h	 
fifoRead . . . . . . . . . . . .	Number	 0DE8h	 
fifoRoom . . . . . . . . . . . .	Number	 0DECh	 
fifoSize . . . . . . . . . . . .	Number	 0E10h	 
fifoStart  . . . . . . . . . . .	Number	 0E04h	 
fifo . . . . . . . . . . . . . .	Text   	 ebp
flds . . . . . . . . . . . . . .	Text   	 fld  DWORD PTR
fmuls  . . . . . . . . . . . . .	Text   	 fmul DWORD PTR
fogInfo_mode . . . . . . . . . .	Number	 0B2Ch	 
fogInfo_offset . . . . . . . . .	Number	 0B30h	 
fsubs  . . . . . . . . . . . . .	Text   	 fsub DWORD PTR
gc . . . . . . . . . . . . . . .	Text   	 esi
intArea  . . . . . . . . . . . .	Text   	 ebp
invalid  . . . . . . . . . . . .	Number	 0B78h	 
lfbLockCount . . . . . . . . . .	Number	 0E24h	 
lfb_ptr  . . . . . . . . . . . .	Number	 0080h	 
lostContext  . . . . . . . . . .	Number	 96BCh	 
mM0  . . . . . . . . . . . . . .	Text   	 MM(0)
mM1  . . . . . . . . . . . . . .	Text   	 MM(1)
mM2  . . . . . . . . . . . . . .	Text   	 MM(2)
mM3  . . . . . . . . . . . . . .	Text   	 MM(3)
mM4  . . . . . . . . . . . . . .	Text   	 MM(4)
mM5  . . . . . . . . . . . . . .	Text   	 MM(5)
mM6  . . . . . . . . . . . . . .	Text   	 MM(6)
mM7  . . . . . . . . . . . . . .	Text   	 MM(7)
mm0  . . . . . . . . . . . . . .	Text   	 MM(0)
mm1  . . . . . . . . . . . . . .	Text   	 MM(1)
mm2  . . . . . . . . . . . . . .	Text   	 MM(2)
mm3  . . . . . . . . . . . . . .	Text   	 MM(3)
mm4  . . . . . . . . . . . . . .	Text   	 MM(4)
mm5  . . . . . . . . . . . . . .	Text   	 MM(5)
mm6  . . . . . . . . . . . . . .	Text   	 MM(6)
mm7  . . . . . . . . . . . . . .	Text   	 MM(7)
p6Fencer . . . . . . . . . . . .	Number	 0000h	 
packCol  . . . . . . . . . . . .	Text   	 edi
paramIndex . . . . . . . . . . .	Number	 01E4h	 
paramMask  . . . . . . . . . . .	Number	 0DE0h	 
pool_f1  . . . . . . . . . . . .	Number	 0028h	 
pool_f255  . . . . . . . . . . .	Number	 002Ch	 
q0Info_mode  . . . . . . . . . .	Number	 0B5Ch	 
q0Info_offset  . . . . . . . . .	Number	 0B60h	 
q1Info_mode  . . . . . . . . . .	Number	 0B64h	 
q1Info_offset  . . . . . . . . .	Number	 0B68h	 
qInfo_mode . . . . . . . . . . .	Number	 0B54h	 
qInfo_offset . . . . . . . . . .	Number	 0B58h	 
reg_ptr  . . . . . . . . . . . .	Number	 0078h	 
roomToEnd  . . . . . . . . . . .	Number	 0E20h	 
roomToReadPtr  . . . . . . . . .	Number	 0E1Ch	 
tempVal  . . . . . . . . . . . .	Text   	 edi
tlsOffset  . . . . . . . . . . .	Number	 0008h	 
tmu0_s_scale . . . . . . . . . .	Number	 0A0Ch	 
tmu0_t_scale . . . . . . . . . .	Number	 0A10h	 
tmu1_s_scale . . . . . . . . . .	Number	 0A28h	 
tmu1_t_scale . . . . . . . . . .	Number	 0A2Ch	 
triPacketHdr . . . . . . . . . .	Number	 0DD8h	 
triSetupProc . . . . . . . . . .	Number	 0DC4h	 
trisDrawn  . . . . . . . . . . .	Number	 0010h	 
trisProcessed  . . . . . . . . .	Number	 000Ch	 
tsuDataList  . . . . . . . . . .	Number	 0124h	 
vOffset  . . . . . . . . . . . .	Text   	 ecx
vertexSize . . . . . . . . . . .	Number	 0B70h	 
vertexStride . . . . . . . . . .	Number	 0B6Ch	 
vertex . . . . . . . . . . . . .	Text   	 edx
vp_hdepth  . . . . . . . . . . .	Number	 0B08h	 
vp_hheight . . . . . . . . . . .	Number	 0B04h	 
vp_hwidth  . . . . . . . . . . .	Number	 0B00h	 
vp_ox  . . . . . . . . . . . . .	Number	 0AF4h	 
vp_oy  . . . . . . . . . . . . .	Number	 0AF8h	 
vp_oz  . . . . . . . . . . . . .	Number	 0AFCh	 
wInfo_offset . . . . . . . . . .	Number	 0B20h	 
windowed . . . . . . . . . . . .	Number	 96C4h	 
zArea  . . . . . . . . . . . . .	Text   	 One+04h
zculltest  . . . . . . . . . . .	Text   	 One+18h
zdxAB  . . . . . . . . . . . . .	Text   	 One+08h
zdxBC  . . . . . . . . . . . . .	Text   	 One+0ch
zdyAB  . . . . . . . . . . . . .	Text   	 One+10h
zdyBC  . . . . . . . . . . . . .	Text   	 One+14h

	   0 Warnings
	   0 Errors
