;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = MATH.ASM
;*
;* DESCRIPTIVE NAME = Contains FIXED point math routines.
;*
;*
;* VERSION      V2.0
;*
;* DATE         08/30/87
;*
;* DESCRIPTION  MATH ROUTINES FOR PRINTER DRIVER
;*
;*
;* FUNCTIONS
;*
;*                 ulNormalize
;*                 frVectLength
;*                 quad_square_root
;*                 frsqrt
;*                 frmul
;*                 frmultiply
;*                 frdiv
;*                 iqdiv
;*                 BigMulDiv
;*                 LongMulFixed
;*                 CopyAndNormalize
;*                 copy_and_normalize
;*                 compute_accelerator_flags
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Complete re-write and copyied functions from 32math.asm (GRE).
;*
;*
;*****************************************************************************/

        .386p
        .xlist
INCL_GPIPRIMITIVES      equ     1
INCL_DDIBUNDLES         equ     1
INCL_DDIMISC            equ     1

; Condition/Error flags returned by certain functions in math.asm:
GRE_NUM_IS_ZERO          equ           1
GRE_NUM_IS_NEGATIVE      equ           2
GRE_OVERFLOW             equ           4

        include inc\32cmacro.inc
?PLM = CC_SYSCALL
ifndef PSCRIPT
        include pmgre.inc
        include engine.mac        ;;CONSTANT.INC IS REMOVED
endif   ; no PSCRIPT
        include os2def.inc
        include pmgpi.inc
        include pmddi.inc
        include inc\dcstruc.inc
        include inc\xform.inc
        include profile.inc
        .list


LONG    struc
lo      dw      ?
hi      dw      ?
LONG    ends


UQUAD   struc
uq0     dw      ?
uq1     dw      ?
uq2     dw      ?
uq3     dw      ?
UQUAD   ends


QUAD      struc
q0               dw      ?       ;*; lowest-order word
q1               dw      ?       ;*; low DWord
q2               dw      ?
q3               dw      ?
QUAD      ends

QUAD_0_12_3      struc
q12q0            dw      ?       ;*; low DWord
q12              dd      ?
q12q3            dw      ?
QUAD_0_12_3      ends

QUAD_01_23      struc
q01              dd      ?       ;*; low DWord
q23              dd      ?
QUAD_01_23      ends


ifdef PSCRIPT

assert  macro
        endm

;FIREWALLS     equ     0
MININT        equ     8000h

endif   ; PSCRIPT

FLATSEGDEF

.DATA


staticD SRootConst,< 00000135h > ;  0
                  DD 000001b5h   ;  1
                  DD 0000026ah   ;  2
                  DD 0000036ah   ;  3
                  DD 000004d4h   ;  4
                  DD 000006d4h   ;  5
                  DD 00000f50h   ;  6
                  DD 00000da8h   ;  7
                  DD 00001350h   ;  8
                  DD 00001b50h   ;  9
                  DD 000026a0h   ; 10
                  DD 000036a0h   ; 11
                  DD 00004d41h   ; 12
                  DD 00006d41h   ; 13
                  DD 00009a82h   ; 14
                  DD 0000da82h   ; 15
                  DD 00000135h   ; 16
                  DD 000001b5h   ; 17
                  DD 0000026ah   ; 18
                  DD 0000036ah   ; 19
                  DD 000004d4h   ; 20
                  DD 000006d4h   ; 21
                  DD 000009a8h   ; 22
                  DD 00000da8h   ; 23
                  DD 00001350h   ; 24
                  DD 00001b60h   ; 25
                  DD 000026a0h   ; 26
                  DD 000036a0h   ; 27
                  DD 00004d41h   ; 28
                  DD 00006d41h   ; 29
                  DD 00009a82h   ; 30
                  DD 0000da82h   ; 31


SEGM47     SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT

;/*
;** Public-Routine
;*/

;/***************************************************************************
;*
;* FUNCTION NAME = ulNormalize
;*
;* DESCRIPTION   = Return the number of shifts needed to shift the
;*                 the passed ULONG number so that the highest order bit is 1
;*
;* NOTE          : If the number is zero then zero will be returned.
;*
;* INPUT         = ulNum
;*
;* RETURN-NORMAL = EAX   number of shifts
;*
;* RETURN-ERROR  = NONE
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Wrote it.
;*
;**************************************************************************/
cProc   ulNormalize,<PUBLIC>,<ECX>
        parmD   ulNum
cBegin
        mov     EAX,ulNum

        sub     ECX, ECX

        or      EAX, EAX
        jz      ulNormalize_exit

        bsr     ECX, EAX                 ; scan for the first 1 bit
        neg     ECX
        add     ECX,31

ulNormalize_exit:
        mov     EAX, ECX
                                         ; return number of shifts in EAX
cEnd



;***************************************************************************
;*
;* FUNCTION NAME = frVectLength
;*
;*
;* DESCRIPTION   =
;*
;* Compute the length of a vector given the X and Y components as fixed
;* point numbers. Return the square root as a fixed point value.
;*
;* Entry:
;*       per parameters.
;*
;*
;*
;* OUTPUT        = NONE
;*
;*
;* RETURN-NORMAL = EAX    the square root as a fixed point value.
;* RETURN-ERROR  = NONE
;*
;*
;* REGISTERS DESTROYED = AX,BX,CX,DX
;*
;*
;* REGISTERS PRESERVED = NONE
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Modified.
;*
;*
;**************************************************************************

cProc  frVectLength,<PUBLIC,NODATA,NONWIN>
        parmD   fx1    ;* The horizontal component of the vector
        parmD   fx2    ;* The vertical component of the vector
        LocalQ  qtmp
cBegin
;* Square the horizontal component
        mov     eax,fx1
        imul    eax

;* Store the quad-product in local variable q1

        mov     dword ptr qtmp.uq0, eax
        mov     dword ptr qtmp.uq2, edx

;* Square the vertical component
        mov     eax, fx2
        imul    eax
;*
;* Sum the square of the two components and take the square root to
;* get the length of the vector (hypotenuse).
;*
        add    eax, dword ptr qtmp.uq0
        adc    edx, dword ptr qtmp.uq2
        cCall  quad_square_root
cEnd


SEGM47     ENDS


SEGM18     SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT

;-------------------------------Public-Routine---------------------------;
; quad_square_root        FIXED quad_square_root(UQUAD *puQuad);
;
;   Approximates the square root of an unsigned QUAD
;
; Entry:
;     EDX:EAX = unsigned QUAD
; Returns:
;     EAX = square root
; Error Returns:
;     none
; Calls:
;     square_root
;
; Fri-11-Jun-1993 -by-  Ravisankar
; Modified
;
;------------------------------------------------------------------------;
cProc quad_square_root,<PUBLIC,NODATA,NONWIN>
        localV  tempq,%(size UQUAD)
cBegin
           mov     dword ptr tempq.uq0, eax
           mov     dword ptr tempq.uq2, edx

        ;; if the quad has no significant bits in the high word
        ;; of EDX then convert to a 16.16 fixed

        cmp     edx, 00007FFFh  ; handle numbers upto 7FFF which will
        jle     SHORT convert_1616    ;  remain +ve after converting to 16.16
        cmp     edx, 0000FFFFh  ; handle numbers 8000->FFFF which could
        jle     SHORT convert_1616_ng ;  be -ve after converting to 16.16

        ;; the integer portion of the quad is greater than 65536.
        ;; this makes the fractional portion inconsequential, so
        ;; only use the integer

        mov     eax, edx
        jmp     SHORT call_sqrt

convert_1616_ng:
        ;; use 16.16 representation of number, but since it will
        ;; appear to be -ve, divide by 4 to make it +ve. Then multiply
        ;; sqrt by 2 later. The data lost will be inconsequential

        mov     eax, dword ptr tempq.uq0
        shr     eax,2
        jmp     SHORT call_sqrt

convert_1616:
        ;; use 16.16 representation of number
        mov     eax, dword ptr tempq.uq1
call_sqrt:
        push edx
        cCall   frsqrt,<eax>
        pop     edx

        ;; Check to see if we are using High DWord in the Quad
        ;; if we are then we need to adjust to a 16:16 fixed

        cmp     edx, 0000FFFFh
        jle     SHORT skip_shift
        shl     eax, 8
        jmp     SHORT fin

skip_shift:
        ;; Multiply the sqrt by 2 if we divided by 4 originally
        cmp     edx, 00007FFFh
        jle     SHORT fin
        shl     eax,1

fin:
        ;; at this point EAX contains our result
        ;;
        ;; end of routine
cEnd



;---------------------------Public-Routine-----------------------------------;
;
;  ULONG frsqrt (ULONG ulVal)
;
;  Return the square root of the given positive fixed point 32-bit value.
;  The return value is in fixed point.
;
;
; Fri-11-Jun-1993 -by-  Ravisankar
; Copied from 32math.asm (GRE).
;
;----------------------------------------------------------------------------;
cProc frsqrt,<PUBLIC>,<EBX,ECX,ESI,EDI>
        parmD   ulVal
cBegin
        mov     EAX,ulVal
        mov     ESI,ulVal
        mov     EDI,ulVal

        or      EAX,EAX
        jnz     SHORT @F

        jmp     SHORT SRoot_finis   ; return 0

@@:
        bsr     EBX,EAX                ; search position starts at
                                       ;  index (operandsize - 1)
        mov     EBX,SRootConst[EBX*4]

        cmp     EAX,10000h
        mov     ECX,EAX
        jge     SHORT SR_GE_1_compute

        ; sqx         = ulVal = passed-in parameter
        ; sqx       <<= 16;
        ; sqrtx_small = SRootConst[]
        ; 
        ; sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        ; sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        ; sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        ; return((LONG)sqrtx_small);

        mov     ECX,EAX   ;  sqx
        shl     EAX,10h
        mov     ECX,EAX

        ;       sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        sub     EDX,EDX
        div     EBX       ;  sqrtx_small
        add     EAX,EBX   ;  sqrtx_small
        shr     EAX,01H
        mov     EBX,EAX   ;  sqrtx_small

        ;       sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        mov     EAX,ECX   ;  sqx
        sub     EDX,EDX
        div     EBX       ;  sqrtx_small
        add     EAX,EBX   ;  sqrtx_small
        shr     EAX,01H
        mov     EBX,EAX   ;  sqrtx_small

        ;       sqrtx_small = ((sqx / sqrtx_small) + sqrtx_small) >> 1;
        mov     EAX,ECX   ;  sqx
        sub     EDX,EDX
        div     EBX       ;  sqrtx_small
        add     EAX,EBX   ;  sqrtx_small
        shr     EAX,01H

        jmp     SHORT SRoot_finis


SR_GE_1_compute:

        ; sqx   = ulVal = passed-in parameter
        ; sqrtx = SRootConst[]
        ; 
        ; sqrtx = ((sqx / sqrtx) + sqrtx) >> 1;
        ; sqrtx = ((sqx / sqrtx) + sqrtx) >> 1;
        ; y = ulVal - (sqrtx * sqrtx);
        ; sqrtx = (sqrtx << 8) + (((y << 12) / sqrtx) >> 5);
        ; return(sqrtx);

        ;       sqrtx = ((sqx / sqrtx) + sqrtx) >> 1;

        cdq
        idiv    EBX     ;  sqrtx
        add     EAX,EBX ;  sqrtx
        sar     EAX,1
        mov     EBX,EAX ;  sqrtx

        ;       sqrtx = ((sqx / sqrtx) + sqrtx) >> 1;
        mov     EAX,ECX ;  sqx
        cdq
        idiv    EBX     ;  sqrtx
        add     EAX,EBX ;  sqrtx
        sar     EAX,1
        mov     EBX,EAX ;  sqrtx

        ;       y = ulVal - (sqrtx * sqrtx);
        imul    EAX,EBX ;  sqrtx
        sub     ECX,EAX
        mov     EAX,ECX ;  y

        ;       sqrtx = (sqrtx << 8) + (((y << 12) / sqrtx) >> 5);
        shl     EAX,12
        cdq
        idiv    EBX     ;    sqrtx

        sar     EAX,5
        shl     EBX,8
        add     EAX,EBX

SRoot_finis:
cEnd



;***************************************************************************
;*
;* FUNCTION NAME = frmul
;*
;*
;* DESCRIPTION   =
;* Computes the FIXED product of two FIXED values.  This routine
;* simply pulls the parameters from the stack and call fxmultiply.
;*
;* Entry:
;*       fx1  = FIXED value
;*       fx2  = FIXED value
;*
;* OUTPUT        = NONE
;*
;*
;* RETURN
;*               EAX = FIXED fx1*fx2
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Modified.
;*
;**************************************************************************

cProc   frmul,<PUBLIC,NODATA,NONWIN>
        parmD   fx1
        parmD   fx2
        localQ  qtmp
        localD  ulOFlag
cBegin
        ADR     qtmp
        ADR     ulOFlag

        cCall   fxmultiply,<@qtmp, fx1, fx2, @ulOFlag>
cEnd


SEGM18    ENDS


SEGM31     SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT


;**************************************************************************
; FIXED fxmultiply(QUAD *pQuad, LONG x, LONG y, LONG *plOFlag);
;
; Multiplies two 32 bit fixed point numbers.  FIXED is a signed 32 bit
; number with 16 bits of integer and 16 bits of fraction.
;
;     RETURNS:  fixed format integer in EAX, or NULL if
;               GRE_OVERFLOW occurred.  The QUAD value
;               will be unaffected
;
; Set *pulOFlag to GRE_OK if no overflow, else to GRE_OVERFLOW.
; Returns middle DWORD of QUAD result.
;
; Fri-11-Jun-1993 -by-  Ravisankar
; Copied from 32math.asm (GRE).
;
; ------------------------------------------------------------------------
;
EAX_SIGNED      equ     1h
EDX_SIGNED      equ     2h

cProc fxmultiply,<PUBLIC>,<EBX,ESI,EDI>
        parmDP  pQuad
        parmD   x
        parmD   y
        parmDP  pOFlag
cBegin
        mov     EAX,x
        imul    y

fxmul_done:

        ;;
        ;; The top 17 bits of EDX:EAX must be the same
        ;; for no overflow.
        ;; Move the result to the proper registers
        ;;
        mov     ebx,edx                 ; Result from EDX:EAX
                                        ;          to EBX.EAX
        mov     esi, pOFlag
        mov     dword ptr [esi], 0

        and     ebx, 0FFFF8000h
        jz      SHORT no_oflow
        cmp     ebx, 0FFFF8000h
        jz      SHORT no_oflow

        mov     dword ptr [esi], GRE_OVERFLOW

no_oflow:
        ;mov     edi,pQuad
        ;mov     [edi].q01,eax
        ;mov     [edi].q23,edx
        ;mov     eax,[edi].q12

        mov     EBX,pQuad
        mov     [EBX].q01,eax
        mov     [EBX].q23,edx
        mov     eax,[EBX].q12
cEnd




;***************************************************************************
;*
;* FUNCTION NAME = frdiv
;*
;*
;* DESCRIPTION   =
;*
;* Computes the FIXED quotient of two longs.  Works by noting that all
;* we want is 16 bits of fraction tacked onto the quotient.  To get this,
;* we multiply the numerator by 10000h, and let iqdiv do the rest.
;*
;* Entry:
;*       param1 = FIXED numerator      changed to param1 = fixed deno
;*       param2 = FIXED denominator               param2 = fixed nume
;*
;*
;*
;* OUTPUT        = NONE
;*
;*
;* RETURN-NORMAL EAX fixed quotient
;*
;* REGISTERS DESTROYED = BX, CX
;*
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Modified.
;*
;**************************************************************************

cProc   frdiv,<PUBLIC,NODATA,NONWIN>
        parmD   numerator
        parmD   denominator
        localQ  qtmp
        localD  lRemainder
        localD  ulOFlag

cBegin
        mov     eax, numerator
        cdq                            ; edx:eax = numerator * 10000h
        shld    edx,eax,16
        shl     eax, 16

        mov     dword ptr qtmp.uq0, eax
        mov     dword ptr qtmp.uq2, edx

        ADR     qtmp
        ADR     lRemainder
        ADR     ulOFlag

        cCall   iqdiv,<@qtmp,denominator,@lRemainder,@ulOFlag>
cEnd



;**************************************************************************
;
; iqdiv
;
; This routine just keeps track of the signs and calls idiv to do the
; real work.
;
; Entry:
;       EDX:EAX = QUAD Numerator
;       EBX     = LONG Denominator
; Returns:
;       EAX = quotient
;       EDX = remainder
;       OF flag
;
; Fri-11-Jun-1993 -by-  Ravisankar
; Copied from 32math.asm (GRE).
;
;**************************************************************************
IQDIV_RESULT_SIGN       equ     1
IQDIV_REM_SIGN          equ     2

cProc iqdiv,<PUBLIC>,<EBX,ECX,ESI>
        parmDP  pQuad
        parmD   ulDenominator
        parmDP  pRemainder
        parmDP  pOFlag
cBegin
        mov     EAX,pQuad
        mov     EDX,[EAX].q23
        mov     EAX,[EAX].q01
        mov     EBX,ulDenominator
        mov     ESI,pOFlag

        ; CX will store bits indicating if the quotient and remainder need to be
        ; negated.

        sub     ecx,ecx
        mov     DWORD PTR [ESI],ecx

        ; take the absolute value of the denominator

        or      ebx,ebx
        jns     SHORT denominator_is_cool
        xor     cl,IQDIV_RESULT_SIGN
        neg     ebx

        ; EBX is now unsigned so possible overflow is unimportant.

denominator_is_cool:

        ; take the absolute value of the numerator

        or      edx,edx
        jns     SHORT numerator_is_cool
        xor     cl,IQDIV_RESULT_SIGN + IQDIV_REM_SIGN
        not     edx
        neg     eax
        sbb     edx,-1

        ; EDX:EAX is now unsigned so possible overflow is unimportant.

numerator_is_cool:

        ; do the unsigned division

        cmp     ebx,edx
        jbe     SHORT iqdiv_overflow
        div     ebx

        ; check for overflow

        or      edx,edx
        jns     SHORT have_a_bit_to_spare

iqdiv_overflow:
        mov     DWORD PTR [ESI],1
        mov     ah,80h
        dec     ah
        jmp     SHORT iqdiv_exit

have_a_bit_to_spare:
        ; negate the result, if required

        test    cl,IQDIV_RESULT_SIGN
        jz      SHORT result_is_done
        neg     eax

result_is_done:
        ; negate the remainder, if required

        test    cl,IQDIV_REM_SIGN
        jz      SHORT remainder_is_done
        neg     edx

        ; Can't overflow because this number is closer to zero than the
        ; denominator.

remainder_is_done:
        mov     ESI,pRemainder
        mov     [ESI],EDX
        ;*; EAX already holds quotient
iqdiv_exit:
                               ;*; return answer (quotient) in EAX
cEnd

;***************************************************************************
;*
;* FUNCTION NAME = BigMulDiv
;*
;*
;* DESCRIPTION   =
;*
;* This is an extended precision multiply-divide routine.  The first
;* two long-word parameters are multiplied and the product is divided
;* by the third long-word parameter.
;*
;* Entry: NONE
;*
;*
;* OUTPUT        = NONE
;*
;*
;* RETURN-NORMAL = QUAD in lpQuad.
;*
;*
;* RETURN-ERROR  = NONE
;*
;*
;* REGISTERS DESTROYED = NONE
;*
;*
;* REGISTERS PRESERVED = NONE
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Modified.
;*
;**************************************************************************


cProc   BigMulDiv,<PUBLIC,NODATA,NONWIN>,<EBX>
        parmD   l1
        parmD   l2
        parmD   l3
        localQ  qtmp
        localD  lRemainder
        localD  ulOFlag

cBegin
        mov     eax, l1
        mov     ebx, l2
        imul    ebx
        mov     dword ptr qtmp.uq0, eax
        mov     dword ptr qtmp.uq2, edx

        ADR     qtmp
        ADR     lRemainder
        ADR     ulOFlag

        cCall   iqdiv,<@qtmp,l3,@lRemainder,@ulOFlag>
cEnd


;***************************************************************************
;*
;* FUNCTION NAME = LongMulFixed
;*
;*
;* DESCRIPTION   =
;*
;* This is an extended precision multiply routine, intended to emulate
;* 80386 mul instruction.
;*
;* Entry:
;*       LONG
;*       FIXED
;*
;* OUTPUT        = NONE
;*
;*
;* RETURN-NORMAL = AX = 1.
;*                 lpAnswer holds the LONG product
;*                 (ignores hi word and fractional part).
;*
;* RETURN-ERROR  = AX = 0.
;*
;*
;* REGISTERS DESTROYED = CX, DX
;*
;*
;* REGISTERS PRESERVED = NONE
;*
;* Fri-11-Jun-1993 -by-  Ravisankar
;* Modified.
;*
;**************************************************************************
cProc   LongMulFixed,<PUBLIC,NODATA,NONWIN>,<ESI,EBX>
        parmD   lX
        parmD   fxY
        parmD   lpAnswer
cBegin
        mov     eax,lx
        mov     ebx,fxy
        imul    ebx
        add     eax,8000h
        mov     ax,0
        adc     edx,0
        jc      lmf_overflow   ;* overflow.
        mov     esi,lpAnswer
        shr     eax,16
        mov     [esi].lo,ax
        mov     [esi].hi,dx
        mov     eax,1           ;* indicate success.
        jmp     lmf_exit
lmf_overflow:
        mov     eax,0           ;* indicate overflow.
lmf_exit:
cEnd

;/*
;** The various coordinate systems and the transforms between them are
;** as follows:
;**
;** 1)  World            |
;**     Coordinate    ---+---
;**     Space            |
;**
;**                      |
;**                   Model                <--- SetModelXform
;**                   Transform
;**                      |
;**                           *-clip--*
;**                           |Viewing|    <--- SetViewingLimits
;**                           |Limits |
;** 2)  Model            |    *-------*
;**     Space         ---+---
;**                      |
;**
;**                      |
;**                   Window/Viewport      <--- SetWindowViewportXform
;**                   Transform
;**                      |
;**
;** 3)  Default          |
;**     Page          ---+---
;**     Coordinate       |
;**     Space
;**                      |
;**                   Global Viewing       <--- SetGlobalViewingXform
;**                   Transform
;**                      |
;**                          *--clip--*
;**                          |Graphics|    <--- SetGraphicsField
;**                          | Field  |
;** 4)  Page             |   *--------*
;**     Coordinate    ---+---
;**     Space            |
;**
;**                      |
;**                   Device               <--- implicit transform defined by:
;**                   Transform                 SetPageWindow, SetPageViewport
;**                      |
;**
;** 5)  Device           |
;**     Coordinate    ---+---
;**     Space            |
;**
;**                      |
;**                   DC Origin            <--- SetDCOrigin
;**                   Offset
;**                      |
;**
;** 6)  Screen           |
;**     Coordinates   ---+---
;**                      |
;**
;*/

SEGM31     ENDS


SEGM47     SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT


;/*
;** Public-Routine
;*/

;/***************************************************************************
;*
;* FUNCTION NAME = CopyAndNormalize
;*
;* DESCRIPTION   = This routine is simply and interface between
;*                 copy_and_normalize and the PostScript code.
;*
;*                 Registers Destroyed:
;*                       none
;*
;* INPUT         = per parms.
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
cProc   CopyAndNormalize,<PUBLIC,NODATA>,<edi,esi,ds,ebx>

    ParmD   lpxformSource       ; source XFORM.
    ParmD   lpmatrixDest        ; dest MATRIX.

cBegin
    cwd
    mov     esi,lpxformSource
    mov     edi,lpmatrixDest
    call    copy_and_normalize
cEnd



;/*
;** Private-Routine
;*/

;/***************************************************************************
;*
;* FUNCTION NAME = copy_and_normalize
;*
;* DESCRIPTION   = Copies an XFORM into a MATRIX.  Zeroes the fractional parts
;*                 of the offsets and computes accelerator bits.
;*
;*                 Registers Destroyed:
;*                       AX,CX,DX,SI
;*
;*
;* INPUT         = DS:SI = source XFORM            *new esi source
;*                 ES:DI = destination MATRIX      *new edi destination
;*                 DF = 0                          *df = 0
;*
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   copy_and_normalize,<PUBLIC>
cBegin
        assert  ND

;/*
;** move the XFORM
;*/
         mov     edx,edi
        .errnz  mx_xform
         mov   cx,(SIZE XFORM)/2
         movzx  ecx,cx
        .errnz  (SIZE XFORM) and 1
        rep     movsw

;/*
;** Set the fractions to 1/2.  This will let us avoid an extra roundoff
;** step when actually doing a transform.  On the other hand, we have
;** to be careful to remember these when doing invert_matrix and
;** combine_xform.
;*/


        .errnz  mx_xform + (SIZE XFORM) - mx_usfracM41
        .errnz  mx_usfracM41        + 2 - mx_usfracM42
        mov     ax,MATRIX_ROUNDOFF
        stosw
        stosw

;/*
;** clear the flags
;*/

        .errnz  mx_usfracM42        + 2 - mx_flags
        .errnz  mx_flags            + 2 - mx_unused
        xor     eax,eax
        stosw
        stosw
        mov     edi,edx

;/*
;** compute accelerators while we're here!
;*/


        call    compute_accelerator_flags
cEnd


SEGM47     ENDS


SEGM19     SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT


;/*
;** Private-Routine
;*/

;/***************************************************************************
;*
;* FUNCTION NAME = compute_accelerator_flags
;*
;* DESCRIPTION   = Computes the accelerator flags for a given matrix.
;*
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX
;*
;*
;* INPUT         = ES:DI = MATRIX     *NEW EDI
;*                 DF = 0
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = OF = 0
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


cProc   compute_accelerator_flags,<PUBLIC>,<edi,esi>
cBegin
        assert  ND
        mov     esi,edi                   ; SI = MATRIX
        xor     eax,eax
        mov     [esi].mx_flags,ax

;/*
;** check for a simple rotation
;*/

        .errnz  mx_xform.xform_fxM11
        scasw                           ; does M11 = 0?
        jnz     not_rotate
        scasw
        jnz     not_rotate
        lea     edi,[esi].mx_xform.xform_fxM22
        scasw                           ; does M22 = 0?
        jnz     not_rotate
        scasw
        jnz     not_rotate

;/*
;** set the simple and exchange bits
;*/

        or      [esi].mx_flags,MATRIX_SIMPLE + MATRIX_XY_EXCHANGE

;/*
;** pick up the X multiplier in DX:AX and the Y multiplier in CX:BX
;*/
          mov     eax, [esi].mx_xform.xform_fxM12
          mov     ebx, [esi].mx_xform.xform_fxM21
        jmp     short have_multipliers
not_rotate:

;/*
;** check for scaling case
;*/

        lea     edi,[esi].mx_xform.xform_fxM12
        .errnz  xform_fxM21 - (xform_fxM12 + 4)
        mov     cx,4
        movzx   ecx,cx
        repz    scasw
        jnz     have_mx_flags

;/*
;** set the simple bit
;*/

        or      [esi].mx_flags,MATRIX_SIMPLE

;/*
;** pick up the X multiplier in DX:AX and the Y multiplier in CX:BX
;*/

        mov     ebx,[esi].mx_xform.xform_fxM22
        mov     eax,[esi].mx_xform.xform_fxM11
have_multipliers:

;/*
;** see if it's all units
;*/

        or      ax,bx                   ; no fractions allowed!
        jnz     have_mx_flags
        mov     bl,MATRIX_UNITS
        or      eax,eax
        jns     x_multiplier_positive
        neg     eax
        or      bl,MATRIX_X_NEGATE
x_multiplier_positive:
        or      cx,cx
        jns     y_multiplier_positive
        neg     cx
        or      bl,MATRIX_Y_NEGATE
y_multiplier_positive:
        dec     cx
        jnz     have_mx_flags
        dec     eax
        jnz     have_mx_flags
        or      [esi].mx_flags,bx
have_mx_flags:

;/*
;** check for a translation
;*/

        xor     eax,eax
        .errnz  (mx_xform.xform_lM41 + 4) - (mx_xform.xform_lM42)
        mov     cx,4
        movzx   ecx,cx
        lea     edi,[esi].mx_xform.xform_lM41
        repz    scasw
        jz      have_translate_flags
        or      [esi].mx_flags,MATRIX_TRANSLATION
have_translate_flags:
        or      eax,eax                   ; clear the overflow flag
cEnd

SEGM19     ENDS

END

