;*DDK*************************************************************************/
;
; 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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = RECT.ASM
;*
;* DESCRIPTIVE NAME = Rectangle routines
;*
;*
;* VERSION      V2.0
;*
;* DATE         8/4/92
;*
;* DESCRIPTION  Utility functions for rectangles.
;*
;* FUNCTIONS    convert_rectl 
;*              truncate_rectl
;*              validate_rectl
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/02/88                     Written by Hock Lee
;*   10/23/89                     Viroon Touranachun [viroont]
;*                                   Convert 16-bit to 32-bit operations.
;*   05/27/88                     Hock Lee [hockl] - convert_rectl  
;*   05/02/88                     Hock Lee [hockl] - truncate_rectl 
;*   03/31/88                     Hock Lee [hockl] - validate_rectl 
;*
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GPITRANSFORMS      equ                      1
INCL_GRE_DEVMISC        equ                      1
INCL_GRE_XFORMS         equ                      1
INCL_DDICOMFLAGS        equ                      1
INCL_DDIMISC            equ                      1
INCL_DDIBUNDLES         equ                      1
        include pmgre.inc
        include driver.inc
        include njmp.mac
        include assert.mac
        .list

        CPUMode 386

        errcode <INV_RECT,COORDINATE_OVERFLOW>

CVTC_SCREEN     equ     6                         
MAXINT          equ     07fffh                    
MININT          equ     08000h                    

makemin macro   dest,src
        local   have_min
        cmp     dest,src
        jle     have_min
        mov     dest,src
have_min:
        endm

makemax macro   dest,src
        local   have_max
        cmp     dest,src
        jge     have_max
        mov     dest,src
have_max:
        endm

;/***************************************************************************
;*
;* FUNCTION NAME = truncate_long (MACRO)
;*
;* DESCRIPTION   = Truncate a LONG integer pointed to by ES:DI
;*                 The pointers DI is also advanced.          
;*                                                            
;*                 The new range is 0xffff8000..0x7fff.       
;*
;*                 Registers Preserved:       
;*                        CX,ES,DS
;*                 Registers Destroyed:       
;*                        AX,BX,DX,DI,SI
;*
;* INPUT         = ES:DI -> long integer to be truncated
;*                 CX = MAXINT                      
;* OUTPUT        = EDI -> truncated integer
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

truncate_long   macro
        local   have_it

        assert  cx,E,MAXINT                      ;; CX = maximum positive signed number supported

        .errnz  MAXINT-07fffh
        .errnz  MININT-08000h
        mov     ax,es:[di]
        cwd                                      ;; DX = sign word
        xor     dx,es:[di][2]
        jz      have_it                          ;; Yes, done
        mov     ax,cx                            ;; Assume MAXINT
        test    es:[di][2],8000h
        jz      have_it
        not     ax
have_it:
        stosw
        cwd
        xchg    ax,dx
        stosw
endm


sBegin Data
        externD  pfnDefConvert
sEnd   Data

sBegin  Code
        assumes cs,Code
        externW         CodeData

CodeSegRETF     db      0CBh                      ; RETF instruction

;/***************************************************************************
;*
;* FUNCTION NAME = convert_rectl
;*
;* DESCRIPTION   = Converts a RECTL from one coordinate space to another.  If 
;*                 the transform includes a rotation, a bounding rectangle of 
;*                 the rotated one will be returned.  The returned rectangle is
;*                 always well ordered. The given rectangle is converted in place.
;*                 A rectangle in DEVICE/SCREEN coordinates is taken as exclusive 
;*                 on right/top. However, all rectangles in other coordinate 
;*                 spaces are taken as inclusive on all edges.  A correct 
;*                 rectangle in the right representation (inclusive/exclusive) 
;*                 will be returned.
;*                 The inclusiveness of rectangles in coordinate spaces other 
;*                 than device/screen space makes it impossible to represent 
;*                 null rectangles in those spaces.
;*                
;*                 Registers Destroyed:   
;*                        AX,BX,CX,DX
;*
;* INPUT         = AH    = source coordinates
;*                 AL    = dest coordinates
;*                 DS:SI = ddc
;*                 ES:DI = rectl
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = CF = 0, DX:AX = 1
;* RETURN-ERROR  = CF = 1, DX:AX = 0
;*
;**************************************************************************/

ptl0    equ     0
ptl1    equ     1 * (SIZE POINTL)
ptl2    equ     2 * (SIZE POINTL)
ptl3    equ     3 * (SIZE POINTL)

infinite_rectl  equ     this dword
        dd      MIN_COORDINATE,MIN_COORDINATE,MAX_COORDINATE,MAX_COORDINATE
.errnz  ($ - infinite_rectl) - (SIZE RECTL)

        assumes ds,Data
        assumes es,nothing

cProc   convert_rectl,<PUBLIC,NEAR>,<si,di>
        localW  xform_requested
        localW  xform_type
        localW  hddc
        localD  prcl
        localV  aptl,%(4 * SIZE POINTL)
cBegin

;/*
;**  do assertion first
;*/

        ddc?    si

ifdef FIREWALLS

;/*
;**  actually we should firewall null rectangles in device coordinates too.
;*/

        pusha

        assert  ah,BE,CVTC_SCREEN
        assert  al,BE,CVTC_SCREEN
        call    validate_rectl                    ; make sure rectangle is good
        jnc     good_rect
        rip     text,<Engine Error: bad rectangle in convert_rectl>

good_rect:
        popa
endif

        mov     prcl.hi,es
        mov     prcl.lo,di
        mov     hddc,si
        mov     xform_requested,ax

;/*
;**  do not convert infinite rectangle!
;*/

        push    si
        push    di
        lea     si,infinite_rectl
        .errnz  (size RECTL) and 3
        mov     cx,(size RECTL)/4
        rep     cmps dword ptr cs:[si], dword ptr es:[di]
        pop     di
        pop     si                                ; don't touch zero flag!
        njz     convert_rectl_good_exit

;/*
;**  convert src rectangle from screen to device if it's in screen coordinates
;*/

        cmp     byte ptr xform_requested[1],CVTC_SCREEN
        jnz     src_not_screen
        lgs     bx,[si].ddc_prddc
        assumes gs,nothing
        movsx   eax,gs:[bx].rddc_ptsOrg.pts_x    ; EAX = DC origin X
        movsx   ebx,gs:[bx].rddc_ptsOrg.pts_y    ; EBX = DC origin Y

screen_to_device_loop:
        sub     es:[di].ptl_x,eax
        jo      convert_rectl_overflow_error
        sub     es:[di].ptl_y,ebx
        jo      convert_rectl_overflow_error
        sub     es:[di][size POINTL].ptl_x,eax
        jo      convert_rectl_overflow_error
        sub     es:[di][size POINTL].ptl_y,ebx
        jo      convert_rectl_overflow_error

src_not_screen:

;/*
;**  make source rectangle inclusive if it's in screen/device space
;*/

        cmp     byte ptr xform_requested[1],CVTC_DEVICE
        jb      scr_rect_inclusive
        .erre   CVTC_SCREEN GT CVTC_DEVICE
        sub     dword ptr es:[di].rcl_xRight,1
        jo      convert_rectl_overflow_error
        sub     dword ptr es:[di].rcl_yTop,1
        jo      convert_rectl_overflow_error
scr_rect_inclusive:

;/*
;**  wo do special cases for identity transform between WORLD and
;**  DEVICE/SCREEN coordinates only
;*/

        test    [si].ddc_fb,DDC_UNIT_XFORM
        jz      its_complex_xform                ; not a identity transform
        mov     ax,xform_requested
        mov     bx,CVTC_WORLD*100h + CVTC_SCREEN
        cmp     ax,bx                             ; world -> screen?
        jz      its_unit_xform
        xchg    bh,bl
        cmp     ax,bx                             ; screen -> world?
        jz      its_unit_xform
        dec     bh
        cmp     ax,bx                             ; device -> world?
        jz      its_unit_xform
        xchg    bh,bl
        cmp     ax,bx                             ; world -> device?
        jnz     its_complex_xform
        errnz   CVTC_SCREEN-CVTC_DEVICE-1

its_unit_xform:
        jmp     do_target_rectangle

convert_rectl_overflow_error:
        mov     ax,PMERR_COORDINATE_OVERFLOW
convert_rectl_error:
        push    es                                ; dont destroy register
        save_error_code
        pop     es
convert_rectl_bad_exit:
        xor     ax,ax
        stc
        jmp     convert_rectl_exit

;/*
;**  Complex Transform
;**  fill the four point rectangle
;*/

its_complex_xform:
        mov     eax,es:[di].rcl_xLeft
        mov     aptl[ptl0].ptl_x,eax
        mov     aptl[ptl1].ptl_x,eax

        mov     eax,es:[di].rcl_yBottom
        mov     aptl[ptl0].ptl_y,eax
        mov     aptl[ptl2].ptl_y,eax

        mov     eax,es:[di].rcl_xRight
        mov     aptl[ptl2].ptl_x,eax
        mov     aptl[ptl3].ptl_x,eax

        mov     eax,es:[di].rcl_yTop
        mov     aptl[ptl1].ptl_y,eax
        mov     aptl[ptl3].ptl_y,eax

;/*
;**  convert the points
;*/

transform_points:
        ddc?    si
        push    es                                ; save ES
        lea     di,aptl
        xor     ax,ax                             ; general purpose null parameter
        mov     dx,xform_requested                ; DL = target space
        mov     bl,dh                             ; BL = source space
        mov     dh,al                             ; DX = target space
        mov     bh,al                             ; BX = source space
        cmp     dx,CVTC_SCREEN
        cmc
        sbb     dx,ax                             ; convert screen to device
        cmp     bx,CVTC_SCREEN
        cmc
        sbb     bx,ax                             ; convert screen to device
        errnz   CVTC_SCREEN-CVTC_DEVICE-1
        farPtr  Myhdc,[si].ddc_hdc.hi,[si].ddc_hdc.lo
        farPtr  MySource,ax,bx
        farPtr  MyTarget,ax,dx
        farPtr  MyPolyN,ax,4                      ; 4 points to transform
        farPtr  Myhddc,ax,ax
        farPtr  MyPolyXY,ss,di
        check   Convert,<hdc,lSrc,lTarg,pptl,cptl,hddc,ulFunN>
        cCall   pfnDefConvert,<Myhdc,MySource,MyTarget,MyPolyXY,MyPolyN,Myhddc,GreConvert>
        pop     es
        assumes es,nothing
        or      ax,ax
        njz     convert_rectl_bad_exit           ; encountered an error in Convert

;/*
;**  get a good ordering rectange
;*/

;/*
;**  find the max and min X
;*/

        mov     eax,aptl[ptl0].ptl_x             ; EAX = min X
        mov     edx,eax                          ; EDX = max X
        mov     ebx,aptl[ptl3].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl1].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl2].ptl_x             ; EBX = test X
        makemin eax,ebx
        makemax edx,ebx
;/*
;**  EAX = min X
;**  EDX = max X
;*/

have_x_values:
        mov     di,prcl.lo
        mov     es:[di].rcl_xLeft,eax
        mov     es:[di].rcl_xRight,edx

;/*
;**  find the max and min Y
;*/

        mov     eax,aptl[ptl0].ptl_y             ; EAX = min Y
        mov     edx,eax                          ; EDX = max Y
        mov     ebx,aptl[ptl3].ptl_y             ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl1].ptl_y             ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx
        mov     ebx,aptl[ptl2].ptl_y             ; EBX = test Y
        makemin eax,ebx
        makemax edx,ebx

;/*
;**  EAX = min Y
;**  EDX = max Y
;**  make new Y's inclusive/exclusive
;*/

have_y_values:
        mov     di,prcl.lo
        mov     es:[di].rcl_yBottom,eax
        mov     es:[di].rcl_yTop,edx

do_target_rectangle:

;/*
;**  convert dest rectangle from device to screen if needed
;*/

        cmp     byte ptr xform_requested[0],CVTC_SCREEN
        jnz     dest_not_screen
        mov     si,hddc
        lgs     bx,[si].ddc_prddc
        movsx   eax,gs:[bx].rddc_ptsOrg.pts_x    ; EAX = DC origin X
        movsx   ebx,gs:[bx].rddc_ptsOrg.pts_y    ; EBX = DC origin Y
device_to_screen_loop:
        add     es:[di].ptl_x,eax
        jo      jmp_convert_rectl_overflow_error
        add     es:[di].ptl_y,ebx
        jo      jmp_convert_rectl_overflow_error
        add     es:[di][size POINTL].ptl_x,eax
        jo      jmp_convert_rectl_overflow_error
        add     es:[di][size POINTL].ptl_y,ebx
        jo      jmp_convert_rectl_overflow_error
dest_not_screen:

;/*
;**  Separate DEVICE and SCREEN for further processing:
;*/

        cmp     byte ptr xform_requested[0],CVTC_DEVICE
        jb      got_dst_rect
        .erre   CVTC_SCREEN GT CVTC_DEVICE
        .erre   CVTC_WORLD  LT CVTC_DEVICE
        .erre   CVTC_MODEL  LT CVTC_DEVICE
        .erre   CVTC_PAGE   LT CVTC_DEVICE
        .erre   CVTC_DEFAULTPAGE LT CVTC_DEVICE

;/*
;**  coordinates must fit in 16 bits
;*/

check_16_loop:
        movsx   eax,es:[di].rcl_xRight.lo
        cmp     eax,es:[di].rcl_xRight
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,es:[di].rcl_yTop.lo
        cmp     eax,es:[di].rcl_yTop
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,es:[di].rcl_yBottom.lo
        cmp     eax,es:[di].rcl_yBottom
        jnz     jmp_convert_rectl_overflow_error

        movsx   eax,es:[di].rcl_xLeft.lo
        cmp     eax,es:[di].rcl_xLeft
        jnz     jmp_convert_rectl_overflow_error

;/*
;**  make dest rectangle exclusive if needed
;*/

        mov     eax,1
        add     es:[di].rcl_xRight,eax
        jo      jmp_convert_rectl_overflow_error
        add     es:[di].rcl_yTop,eax
        jno     got_dst_rect
jmp_convert_rectl_overflow_error:
        jmp     convert_rectl_overflow_error
got_dst_rect:

convert_rectl_good_exit:
        mov     ax,1
        clc

convert_rectl_exit:
        cwd
ifdef FIREWALLS

;/*
;**  make sure rectangle is good
;**  actually we should firewall null rectangles in device coordinates too.
;*/

        jc      skip_validate_rectl
        pushf
        pusha
        mov     bx,es

        assert  bx,E,prcl.hi
        call    validate_rectl                    ; make sure rectangle is good
        jnc     good_rectangle
        rip     text,<Invalid rectangle passed to convert_rectl>

good_rectangle:
        popa
        popf
skip_validate_rectl:
endif
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = truncate_rectl() 
;*
;* DESCRIPTION   = Truncate a RectL to the 16 bit coordinate system.
;*                 Coodinates which are too large or too small are truncated.   
;*                                                                              
;*                 The minimum and maximum coordinates are 0xffff8000 and 0x7fff
;*                 
;*                 Registers Preserved:   
;*                        SI,DI,DS,ES
;*                 Registers Destroyed:   
;*                        AX,BX,CX,DX 
;*
;* INPUT         = ES:DI -> RectL to be truncated
;* OUTPUT        = ES:DI -> truncated Rectl
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

sEnd    Code

sBegin  FarCode
        assumes cs,FarCode

        assumes ds,nothing
        assumes es,nothing

cProc   truncate_rectl,<PUBLIC,NEAR>,<di>
cBegin

;/*
;**  ES:DI -> RectL
;*/

        mov     cx,MAXINT
        truncate_long                            ; left
        truncate_long                            ; bottom
        truncate_long                            ; right
        truncate_long                            ; top

        .errnz  rcl_xLeft
        .errnz  rcl_yBottom - rcl_xLeft - 4
        .errnz  rcl_xRight - rcl_yBottom - 4
        .errnz  rcl_yTop - rcl_xRight - 4
cEnd

sEnd    FarCode

sBegin  Code
        assumes cs,Code

;/***************************************************************************
;*
;* FUNCTION NAME = validate_rectl()
;*
;* DESCRIPTION   = Check if a RectL is a good rectangle (i.e. no cross edges).            
;*                 An empty rectangle in device coordinates is also valid.  Note 
;*                 also that there is no representation of null rectangles in other
;*                 coordinate spaces.
;*                 
;*                 Registers Preserved: 
;*                        SI,DI,DS,ES   
;*                 Registers Destroyed: 
;*                        AX,EBX
;*                 
;* INPUT         = ES:DI -> RectL 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = CF = 0      
;* RETURN-ERROR  = CF = 1                                  
;*                 AX = Engine error code (PMERR_INV_RECT)
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   validate_rectl,<PUBLIC,NEAR>
cBegin

        mov     ax,PMERR_INV_RECT
        mov     ebx,es:[di].rcl_xRight            ; verify the X ordering
        sub     ebx,es:[di].rcl_xLeft
        js      validate_bad_rect
        mov     ebx,es:[di].rcl_yTop              ; verify the Y ordering
        sub     ebx,es:[di].rcl_yBottom
        clc
        jns     validate_exit
validate_bad_rect:
        stc
validate_exit:
cEnd

sEnd    Code

        end
