;*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 = PELSUP.ASM
;*
;* DESCRIPTIVE NAME = Pel Functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/09/87
;*
;* DESCRIPTION  Routines relating to Pel Support
;*
;* FUNCTIONS    convert_screen_world 
;*              convert_page_device 
;*              convert_screen_screen 
;*              convert_device_screen 
;*              convert_world_screen 
;*              convert_space_screen 
;*              convert_space_space 
;*              GetPel 
;*              SetPel  
;*              local_pt_visible        
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   --------  ----------  -----  --------------------------------------
;*   02/11/87                     Walt Moore [waltm] DR1/I0.
;*   05/22/87                     Walt Moore [waltm]
;*                                Wrote convert_space_screen
;*                                Wrote local_pt_visible
;*   06/09/87                     Written by Walt Moore
;*   07/27/87                     Hock Lee [hockl] Modified for new DDI.
;*                                Hock Lee [hockl] Modified for new DDI.
;*   07/30/87                     Hock Lee [hockl] Optimized it.
;*                                Wrote convert_screen_world
;*   09/23/87                     Hock Lee [hockl]
;*                                Returned color index rather than RGB value.
;*   10/05/87                     Hock Lee [hockl] Wrote to include other spaces
;*                                to screen.
;*   02/14/88                     Charles Whitmer [chuckwh] Made it not hit a
;*                                FIREWALL if the transfrm overflows in the Engine.
;*                                Made it add negative DC origins correctly.  Added
;*                                the checks that the SCREEN coordinates fit in 16
;*                                bits.  Added the SCREEN to SCREEN conversion
;*                                entry point so that people without COM_TRANSFORM
;*                                set can still get their coordinates checked.
;*                                Changed over to the convention that the ERROR
;*                                code is logged here, rather than by the caller.
;*                                Started calling this part directly with AL set,
;*                                rather than always falling through from above.
;*   03/01/88                      Walt Moore [waltm] Added device to screen to
;*                                add in the dc origin and check 16 bit numbers.
;*   05/26/88                     Bob Grudem [bobgru]
;*                                Now returns error if clipped or info DC.
;*   06/05/88                     Walt Moore [waltm] Changed to call
;*                                InnerAccumulate bounds.  Was doing correlation on
;*                                unclipped primitives.
;*                                Same stuff done to SetPel.
;*
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GRE_BITMAPS        equ                      1
INCL_GRE_CLIP           equ                      1
INCL_GRE_XFORMS         equ                      1
INCL_GRE_DEVSUPPORT     equ                      1
INCL_GRE_DEVMISC3       equ                      1
INCL_DEV                equ                      1
INCL_DDICOMFLAGS        equ                      1
INCL_GPITRANSFORMS      equ                      1
        include pmgre.inc
        include driver.inc
        include display.inc
        include njmp.mac
        .list

        errcode <COORDINATE_OVERFLOW,BITMAP_NOT_SELECTED>
        errcode <INV_IN_AREA,INV_IN_PATH,PEL_IS_CLIPPED>
        errcode <PEL_NOT_AVAILABLE>

        externFP Pixel                            ;OEM dependent set/get a pel

sBegin Data
        externB ddcInit
        externD pfnDefPtVisible
        externD pfnDefConvert
sEnd   Data

        externFP far_correlate_for_point_si
        externFP far_enter_driver
        externFP far_leave_driver
        externFP far_ipc_to_index
        externFP far_PropagateSysClrChange
        externFP far_MakeColorsValid
        externFP far_InnerAccumulateBounds


sBegin  Code
        assumes cs,Code
page

;/***************************************************************************
;*
;* FUNCTION NAME = convert_screen_world 
;*
;* DESCRIPTION   = this function sets up a call to the Engine for transforming  
;*                 coordinates from screen coordinates to world coordinates and 
;*                 then invokes the transform code.                             
;*
;*                 Registers Preserved:      
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:      
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       pfnDefConvert
;*
;* INPUT         = CX:DX  = long pointer to the points
;*                 BX     = count of points           
;*                 SI     = ddc                       
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX     = 1 (return code from Convert routine)
;* RETURN-ERROR  = DX:AX     = 0 (return code from Convert routine)
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   convert_screen_world,<PUBLIC,NEAR,NODATA,NONWIN>,<di>
        parmD   lpPoints
        parmW   wCount
cBegin
        fw_zero <es>
        ddc?    si

        les     di,lpPoints
        assumes es,nothing

        mov     cx,wCount
        jcxz    device_to_world                   ; to be sure we have right return code

;/*
;**  convert from screen to device coordinates first
;*/

        push    si                                ; save SI
        CPUMode 386
        lgs     bx,[si].ddc_prddc
        assumes gs,nothing
        rddc?   gs,bx
        movsx   eax,gs:[bx].rddc_ptsOrg.pts_x
        movsx   edx,gs:[bx].rddc_ptsOrg.pts_y
convert_loop:
        sub     es:[di].ptl_x,eax
        sub     es:[di].ptl_y,edx
        add     di,size POINTL
        loop    convert_loop
        CPUMode 286
        pop     si                                ;Restore SI

device_to_world:
        mov     ax,1                                ; assume success
        test    [si].ddc_fb,DDC_UNIT_XFORM          ; unit transform?
        jnz     convert_done                        ;   yes
        dec     ax                                  ;A handy zero
        farPtr  myhdc,[si].ddc_hdc.hi,[si].ddc_hdc.lo
        farPtr  world,ax,CVTC_WORLD
        farPtr  device,ax,CVTC_DEVICE
        farPtr  count,ax,wCount
        farPtr  hddcNull,ax,ax
        check   Convert,<hdc,lSrc,lTarg,pptl,cptl,hddc,ulFunN>
        cCall   pfnDefConvert,<myhdc,device,world,lpPoints,count,hddcNull,GreConvert>

convert_done:
        cwd
        fw_zero <es>
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = convert_space_screen
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*                 
;*                 Registers Preserved:      
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:      
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = SI:DI = DDC
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   far_convert_space_screen,<PUBLIC,FAR,NODATA>
        parmD   pptl
        parmW   cptl
cBegin
        cCall   convert_space_screen,<pptl,cptl>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = convert_page_device
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*                 
;*                 Registers Preserved:      
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:      
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = SI:DI = DDC
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*
;**************************************************************************/

cProc   convert_page_device,<PUBLIC,NEAR,NODATA>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin
        mov     ax,CVTC_PAGE                      ; Page/Device Transform
        mov     bx,CVTC_DEVICE
        cCall   convert_space_space,<pptl, cptl>
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = convert_screen_screen
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*                 
;*                 Registers Preserved:      
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:      
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = SI:DI = DDC
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*
;**************************************************************************/

cProc   convert_screen_screen,<PUBLIC,NEAR>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin  <nogen>
        mov     al,CVTC_SCREEN                    ; Screen/Screen Transform
        jmpnext
cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = convert_device_screen
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*                 
;*                 Registers Preserved:      
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:      
;*                       AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = SI:DI = DDC
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*
;**************************************************************************/

cProc   convert_device_screen,<PUBLIC,NEAR>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin  <nogen>
        mov     al,CVTC_DEVICE                    ; Device/Screen Transform
        jmpnext
cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = convert_world_screen
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*                 
;*                 Registers Preserved:        
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:        
;*                       AX,BX,CX,DX,ES
;*                 
;* INPUT         = DS:SI = DDC 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*
;**************************************************************************/

cProc   convert_world_screen,<PUBLIC,NEAR>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin  <nogen>
        mov     al,CVTC_WORLD                     ; World/Screen Transform
        jmpnext stop
        cbw
        errn$   convert_space_screen
cEnd    <nogen>

;/***************************************************************************
;*
;* FUNCTION NAME = convert_space_screen
;*
;* DESCRIPTION   = Converts the given points from whatever space they are in to 
;*                 SCREEN coordinates.  Calls the Engine (if necessary) to convert
;*                 as far as DEVICE, adds in the DC origin, and then checks that
;*                 the results fit in 16 bits.
;*                 These guys really just set AL to the proper source coordinate and
;*                 fall through to InnerConvertSpaceSpace to do the work.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       BX,DX,ES
;*                 Calls:
;*                       pfnDefConvert
;*                 
;* INPUT         = DS:SI = DDC 
;*                 AX    = Source coordinate space
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;*                 CX = 1
;* RETURN-ERROR  = AX = 0 (Error code logged)  
;*                 CX = 0
;**************************************************************************/

cProc   convert_space_screen,<PUBLIC,NEAR>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin  <nogen>
        mov     bx,CVTC_SCREEN
        errn$   convert_space_space
cEnd    <nogen>

        assumes ds,Data
        assumes es,nothing

cProc   convert_space_space,<PUBLIC,NEAR>,<di,si>
        parmD   pptl
        parmW   cptl
cBegin
        fw_zero <es>
        ddc?    si
        cwd                                       ; DX:AX = Source space
        mov     di,bx                             ; DX:BX = Target space (screen/device)
        mov     cx,cptl
        njcxz   transform_done_ok

;/*
;**  if we're told to do SCREEN to SCREEN, then just check the coordinates
;*/

        cmp     ax,CVTC_DEVICE
        ja      just_check_16_bits                ;Must be screen to screen
        je      we_got_device                     ;Device to screen, do DC origin

;/*
;**  call the Engine to convert to DEVICE coordinates, if it's non-trivial
;/*

        cmp     ax,CVTC_WORLD                     ; no short cut if source is not world
        jnz     call_convert
        test    [si].ddc_fb,DDC_UNIT_XFORM
        jnz     we_got_device
call_convert:
        farPtr  myhdc,[si].ddc_hdc.hi,[si].ddc_hdc.lo
        farPtr  space,dx,ax
        farPtr  device,dx,CVTC_DEVICE
        farPtr  count,dx,cx
        farPtr  hddcNull,dx,dx
        check   Convert,<hdc,lSrc,lTarg,pptl,cptl,hddc,ulFunN>
        cCall   pfnDefConvert,<myhdc,space,device,pptl,count,hddcNull,GreConvert>
        or      ax,ax
        jz      convert_space_space_exit
we_got_device:

;/*
;**  add in the DC origin
;*/

        cmp     di,CVTC_DEVICE
        jz      just_check_16_bits               ; target space is device
        les     di,pptl
        assumes es,nothing
        mov     cx,cptl

        CPUMode 386
        lgs     bx,[si].ddc_prddc
        assumes gs,nothing
        rddc?   gs,bx

        movsx   eax,gs:[bx].rddc_ptsOrg.pts_x
        movsx   edx,gs:[bx].rddc_ptsOrg.pts_y
dc_origin_loop:
        add     es:[di].ptl_x,eax
        add     es:[di].ptl_y,edx
        add     di,SIZE POINTL
        loop    dc_origin_loop
        CPUMode 286
        jmp     short check_16_bits

;/*
;**  check the results to see if they fit in 16 bits
;*/

just_check_16_bits:
        mov     es,pptl.sel
        assumes es,nothing
check_16_bits:
        mov     di,pptl.off
        mov     cx,cptl
        add     cx,cx                             ; CX = count of DWORDS
check_16_loop:
        mov     ax,es:[di].lo
        cwd
        cmp     dx,es:[di].hi
        jnz     convert_space_error
        add     di,4
        loop    check_16_loop
transform_done_ok:
        mov     ax,1                              ; indicate success
        jmp     short convert_space_space_exit

;/*
;**  handle errors
;*/

convert_space_error:
        mov     ax,PMERR_COORDINATE_OVERFLOW
        save_error_code
        xor     ax,ax

convert_space_space_exit:
        cwd
        fw_zero <es>
        mov     cx,ax
cEnd

sEnd    Code

sBegin  Bitmap
        assumes cs,Bitmap

        externW BitmapData
page

;/***************************************************************************
;*
;* FUNCTION NAME = GetPel 
;*
;* DESCRIPTION   = This function returns the color index (or RGB triplet) of the 
;*                 given pel.  The pel's coordinate must be clipped against the 
;*                 bounds of the device to avoid an addressing exception (this 
;*                 can be accomplished by checking if the point is visible).
;*                 This function only recognizes the COM_TRANSFORM bit of the 
;*                 command. dword.  Any other bit will be ignored.
;*
;*                 Registers Preserved:         
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:         
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       enter_driver
;*                       PropagateSysClrChange
;*                       convert_space_screen
;*                       local_pt_visible
;*                       Pixel
;*                       ipc_to_index
;*                       leave_driver
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = pel color 
;* RETURN-ERROR  = DX:AX = -1
;*
;**************************************************************************/
 
        check   GetPel,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   GetPel,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   lpParm
        parmD   hddc
        parmD   FunN
        localV  a_point,%(size POINTL)
cBegin
        fw_zero <ds,es>
        ddc?    hddc,<SURFACE>

        cld
        mov     ds,BitmapData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        call    far_enter_driver
        mov     ax,-1                             ; assume error
        cwd
        njc     gp_exit_no_lock

        mov     di,FunN.hi
        test    [si].ddc_fbAbove,DDC_INFO_DC
        jnz     get_pel_ic
        mov     al,[si].ddc_fb
        test    al,DDC_PRESENT
        jz      get_pel_bitmap_error
        test    al,DDC_VISIBLE                    ; This test will catch null clip
        jz      get_pel_clipped_error             ;   or an IC


;/*
;**  Make sure the system color info is up to date.  We do this just incase
;** the color of the returned pel maps to one of the system colors of a
;** logical color table.
;*/

        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        je      get_pel_sys_colors_good
        cCall   far_PropagateSysClrChange
        jmp     short get_pel_sys_colors_good

;/*
;** A few error handlers here in the middle of nowhere.  Sys colors should
;** not change much, so this should be a good place for them.
;*/

get_pel_ic:
        mov     ax,PMERR_PEL_NOT_AVAILABLE
        jmp     short get_pel_log_error

get_pel_clipped_error:
        mov     ax,PMERR_PEL_IS_CLIPPED
        jmp     short get_pel_log_error

get_pel_bitmap_error:
        mov     ax,PMERR_BITMAP_NOT_SELECTED

get_pel_log_error:
        save_error_code

get_pel_error_exit:
        mov     ax,-1
        jmp     short get_pel_exit

;/*
;** The colors and surface are valid.  Transform the coordinate if needed.
;** The convert function will be called even if the transform bit isn't
;** set because it will validate the coordinates for us.
;*/

get_pel_sys_colors_good:
        mov     bx,si
        les     si,lpParm                         ;In protected mode, it will be
        assumes es,nothing                        ;  faster to move by hand than
        lods    word ptr es:[si]                  ;  to pay the cost of the segment
        mov     a_point.ptl_x.lo,ax               ;  loads for a movsw
        lods    word ptr es:[si]
        mov     a_point.ptl_x.hi,ax
        lods    word ptr es:[si]
        mov     a_point.ptl_y.lo,ax
        lods    word ptr es:[si]
        mov     a_point.ptl_y.hi,ax
        mov     si,bx
        .errnz  ptl_x.lo
        .errnz  ptl_x.hi-ptl_x.lo-2
        .errnz  ptl_y.lo-ptl_x.hi-2
        .errnz  ptl_y.hi-ptl_y.lo-2

        mov     ax,CVTC_SCREEN
        test    di,COM_TRANSFORM
        jz      @F                                ;No transforming, just range check
        mov     ax,CVTC_WORLD
@@:
        lea     dx,a_point                        ;Transform one point
        farPtr  lp_point,ss,dx
        cCall   <far ptr far_convert_space_screen>,<lp_point,1>
        or      ax,ax
        jz      get_pel_error_exit

;/*
;** See if the point is visible.                   If so, then we can get it, else we
;** will returned the clipped error code.
;*/

        lea     bx,a_point                        ;SS:BX --> point
        call    local_pt_visible                  ;DS:SI --> hddc
        or      ax,ax
        jz      get_pel_clipped_error             ;Point isn't visible
        mov     bx,[si].ddc_npsd
        mov     cx,a_point.ptl_y.lo               ;Flip the coordinate system.
        sub     cx,[bx].sd_cy
        not     cx                                ;AX = garbage for the call
        cCall   Pixel,<(a_point.ptl_x.lo),cx,ax,-1> ;Expects SI = hddc

;/*
;** Convert the IPC to an index and return it
;*/
        mov     bx,si
        call    far_ipc_to_index                     ;Result may be RGB, so we must
        jmpcl                                        ;  skip over the CWD instruction
get_pel_exit:
        cwd
        jmpcl   stop
        call    far_leave_driver
gp_exit_no_lock:
        fw_zero <cx,es>
cEnd
page


;/***************************************************************************
;*
;* FUNCTION NAME = SetPel
;*
;* DESCRIPTION   = The pel at the given location is set using the current line 
;*                 attribute's color and mix.                                  
;*
;*                 Registers Preserved:        
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:        
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       enter_driver
;*                       PropagateSysClrChange
;*                       MakeColorsValid
;*                       convert_space_screen
;*                       InnerAccumulateBounds
;*                       local_pt_visible
;*                       Pixel
;*                       correlate_for_point_si
;*                       leave_driver
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0 
;*
;**************************************************************************/

        check   SetPel,<hdc,pptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   SetPel,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   lpParm
        parmD   hddc
        parmD   FunN
        localV  a_point,%(size POINTL)
cBegin

        fw_zero <ds,es>
        ddc?    hddc,<SURFACE>

        cld
        mov     ds,BitmapData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        call    far_enter_driver
        njc     sp_exit_no_lock                   ; DX:AX = 0 on error

;/*
;** This function is not valid in a path or area, and a bitmap must be
;** selected into the ddc.
;*/

        mov     di,FunN.hi
        test    di,COM_PATH OR COM_AREA
        jnz     set_pel_path_area_error
        test    [si].ddc_fb,DDC_PRESENT
        jz      set_pel_bitmap_error

;/*
;** Make sure the system color info and line colors are up to date.
;*/

        mov     ax,[si].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        jne     set_pel_need_sys_colors
        test    [si].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      set_pel_colors_ok
        jmp     short set_pel_need_colors
set_pel_need_sys_colors:
        cCall   far_PropagateSysClrChange
set_pel_need_colors:
        lea     bx,[si].ddc_la.la_ba
        call    far_MakeColorsValid
        jns     set_pel_colors_ok
        jmp     short set_pel_error_exit

;/*
;** A few error handlers here in the middle of nowhere.  Sys colors should
;** not change much, so this should be a good place for them.
;*/

set_pel_bitmap_error:
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        jmp     short set_pel_log_error

set_pel_path_area_error:
        mov     ax,PMERR_INV_IN_AREA
        test    di,COM_AREA
        jnz     set_pel_log_error
        mov     ax,PMERR_INV_IN_PATH

set_pel_log_error:
        save_error_code

set_pel_error_exit:
        xor     ax,ax
        jmp     set_pel_exit

;/*
;** The colors and surface are valid.  Transform the coordinate if needed.
;** The convert function will be called even if the transform bit isn't
;** set because it will validate the coordinates for us.
;*/

set_pel_colors_ok:
        mov     bx,si
        les     si,lpParm                         ;In protected mode, it will be
        assumes es,nothing                        ;  faster to move by hand than
        lods    word ptr es:[si]                  ;  to pay the cost of the segment
        mov     a_point.ptl_x.lo,ax               ;  loads for a movsw
        lods    word ptr es:[si]
        mov     a_point.ptl_x.hi,ax
        lods    word ptr es:[si]
        mov     a_point.ptl_y.lo,ax
        lods    word ptr es:[si]
        mov     a_point.ptl_y.hi,ax
        mov     si,bx
        .errnz  ptl_x.lo
        .errnz  ptl_x.hi-ptl_x.lo-2
        .errnz  ptl_y.lo-ptl_x.hi-2
        .errnz  ptl_y.hi-ptl_y.lo-2

        mov     ax,CVTC_SCREEN
        test    di,COM_TRANSFORM
        jz      @F                                ;No transforming, just range check
        mov     ax,CVTC_WORLD
@@:
        lea     dx,a_point                        ;Transform one point
        farPtr  lp_point,ss,dx
        cCall   <far ptr far_convert_space_screen>,<lp_point,1>
        or      ax,ax
        jz      set_pel_exit

;/*
;** Perform any bounds accumulation which needs to be performed. We call
;** our own InnerAccumulateBounds function for this.  It takes an inclusive
;** rectangle in screen coordinates
;*/
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      set_pel_bounds_done
        mov     ax,a_point.ptl_x.lo               ;(AX,BX) = left lower corner
        mov     bx,a_point.ptl_y.lo
        mov     cx,ax                             ;(CX:DX) = right upper corner
        mov     dx,bx
        call    far_InnerAccumulateBounds   ;DS:SI --> ddc, DI = Command flags
        or      ax,ax
        jz      set_pel_exit                      ;Some error occured
set_pel_bounds_done:

;/*
;** See if the point is visible.                   If so, then we'll have to possibly
;** draw it and perform correlation on it.
;*/

        lea     bx,a_point                        ;SS:BX --> point
        call    local_pt_visible                  ;DS:SI --> hddc
        or      ax,ax
        mov     ax,1
        jz      set_pel_exit                      ;Point isn't visible
        and     al,[si].ddc_fb
        and     ax,di
        .errnz  DDC_VISIBLE-COM_DRAW
        .errnz  DDC_VISIBLE-1
        jz      set_pel_drawn                     ;No draw bit, can't draw it
        mov     bx,[si].ddc_npsd
        mov     cx,a_point.ptl_y.lo               ;Flip the coordinate system.
        sub     cx,[bx].sd_cy
        not     cx
        mov     al,[si].ddc_la.la_ba.ba_ipc.ipc_bClr
        xor     ah,ah
        mov     bl,[si].ddc_la.la_ba.ba_bmix
        xor     bh,bh
        cCall   Pixel,<(a_point.ptl_x.lo),cx,ax,bx> ;Expects SI = hddc
set_pel_drawn:

;/*
;** The pel has been drawn.  If correlation is to be performed, then call
;** the correlation routine.
;*/

        mov     ax,1
        test    di,COM_CORRELATE
        jz      set_pel_exit                      ;No correlation needed
        mov     bx,a_point.ptl_x.lo
        mov     dx,a_point.ptl_y.lo
        call    far_correlate_for_point_si        ;Return code of 1 or 2

set_pel_exit:
        cwd
        call    far_leave_driver
sp_exit_no_lock:
        fw_zero <cx,es>
cEnd

page

;/***************************************************************************
;*
;* FUNCTION NAME = local_pt_visible 
;*
;* DESCRIPTION   = This function sets up for a call to the Engine for checking if      
;*                 the given point is visible.  The point has already been 
;*                 transformed into screen coordinates.
;*
;*                 Registers Preserved:        
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:        
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 Calls:
;*                       pfdDefPtVisible
;*
;* INPUT         = SI    = hddc.lo                   
;*                 SS:BX = long pointer to the point 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0  if not visible 
;*                     = 1  if visible     
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   local_pt_visible,<NEAR,PUBLIC>
cBegin
        ddc?    si

;/*
;** If there is just a single clipping rectangle, we will perform the
;** hit test ourselves.  If there are more, then we will let the default
;** handler do it.
;*/
        mov     ax,1
        cmp     [si].ddc_crcsClip,ax
        jl      local_pt_vis_exit                ;No clip rectangles, make ax = 0
        jg      engine_pt_visible                ;More than one, use engine

;/*
;** Perform our own point visible function.
;*/
        les     si,[si].ddc_prddc                ; ES:SI = RDDC
        assumes es,nothing
        mov     dx,ss:[bx].ptl_x.lo
        cmp     dx,es:[si].rddc_arcsClip.rcs_xLeft
        jl      local_pt_vis_exit                ;Left edge inclusive in screen coords
        cmp     dx,es:[si].rddc_arcsClip.rcs_xRight
        jge     local_pt_vis_exit                ;Right edge exclusive
        mov     dx,ss:[bx].ptl_y.lo
        cmp     dx,es:[si].rddc_arcsClip.rcs_yBottom
        jl      local_pt_vis_exit                ;Bottom edge inclusive
        cmp     dx,es:[si].rddc_arcsClip.rcs_yTop
        jge     local_pt_vis_exit                ;Top edge exclusive
        inc     ax                               ;Want to return 1 to show visible
        mov     si,es:[si].rddc_npddc            ; SI = DDC
        ddc?    si
        fw_zero <es>
        jmp     short local_pt_vis_exit

engine_pt_visible:
        dec     ax                                ;AX = 0 for making nulls
        check   PtVisible,<hdc,pptl,hddc,ulFunN>
        farPtr  myhdc,[si].ddc_hdc.hi,[si].ddc_hdc.lo
        farPtr  lp_xy,ss,bx
        farPtr  hddcNull,ax,ax
        cCall   pfnDefPtVisible,<myhdc,lp_xy,hddcNull,GrePtVisible>

local_pt_vis_exit:
        dec     ax

ifdef FIREWALLS
;/*
;** The only way an error could be returned is if we messed up or
;** somebody else messed up.  The coordinates are in screen coordinates,
;** so they cannot give me an error.  Anything else I can think of
;** would be a logic error which would need to be caught and fixed.
;*/
        jns     no_ptvisible_error
        rip     text,<Error returned by PtVisible>
no_ptvisible_error:
endif

cEnd
sEnd    Bitmap
end
