;*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     55,132
        TITLE    Get/Set Pixel
        SUBTITLE Header

;/*****************************************************************************
;*
;* SOURCE FILE NAME = PIXEL.ASM
;*
;* DESCRIPTIVE NAME = Set/Get Pixel routine.
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/25/91
;*
;* DESCRIPTION  Pixel is used to either set a pixel to a given color with  
;*              the current binary raster operation, or to return the color
;*              of the the pixel at the given location.                    
;*
;* FUNCTIONS    Pixel
;*              
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/25/91                     KEZ  Original
;*
;*****************************************************************************/

        .386P
        .MODEL FLAT,SYSCALL

;/*
;** Included files
;*/

INCL_NOBASEAPI     EQU 1
INCL_GPIPRIMITIVES EQU 1
INCL_SAADEFS       EQU 1
OS2_NOPMAPI        EQU 1
        INCLUDE PMGRE.INC

DINCL_BITMAP       EQU 1
DINCL_ENABLE       EQU 1
        INCLUDE DRIVER.INC
        INCLUDE EXTERN.INC
        INCLUDE PROTOS.INC
        INCLUDE DISPLAY.INC
        INCLUDE EGAFAM.INC
if SCAN_CNT EQ 768
        include oem_macs.inc
endif

;/*
;** Equates
;*/

;/*
;** Define the type flags used to determine which type of scan needs to be
;** performed (color or mono).
;*/

if    BITS_PEL eq 4                     ; 16 color driver  ;IBMJ
COLOR_OP EQU 00000001b
MONO_OP  EQU MONO_BIT
END_OP   EQU MONO_BIT shl 1 + (1 shl (BITS_PEL))
        .ERRNZ  BITS_PEL - 4
else ;BITS_PEL eq 8                     ; 256 color driver  ;IBMJ
COLOR_OP equ 00000001b
MONO_OP  equ High MONO_BIT shl 7
END_OP   equ High MONO_BIT
        .errnz  BITS_PEL - 8
endif;BITS_PEL eq 8       ;IBMJ

;/*
;** Macros
;*/

;/*
;** MakeROP - Make a ROP For Pixel
;**
;** MakeROP makes a raster operation for the pixel routine.  The raster
;** operation generated is based on the following table which shows the ROP
;** broken down into the boolean result for each plane based on what the pen
;** color is for the plane.
;**
;**       Color     Result                        Color     Result
;**
;** DDx     0         0                   DPa       0         0
;**         1         0                             1        dest
;**
;** DPon    0       ~dest                 DPxn      0       ~dest
;**         1         0                             1        dest
;**
;** DPna    0        dest                 D         0        dest
;**         1         0                             1        dest
;**
;** Pn      0         1                   DPno      0         1
;**         1         0                             1        dest
;**
;** PDna    0         0                   P         0         0
;**         1       ~dest                           1         1
;**
;** Dn      0       ~dest                 PDno      0       ~dest
;**         1       ~dest                           1         1
;**
;** DPx     0        dest                 DPo       0        dest
;**         1       ~dest                           1         1
;**
;** DPan    0         1                   DDxn      0         1
;**         1       ~dest                           1         1
;*/

MakeROP MACRO   l,ops

IRP x,<ops>
IFIDN   <x>,<0>
        BYTE    Pixel_is_0-Pixel_base_address

ENDIF

IFIDN   <x>,<1>
        BYTE    Pixel_is_1-Pixel_base_address

ENDIF

IFIDN   <x>,<~dest>
        BYTE    Pixel_is_inverted-Pixel_base_address

ENDIF

IFIDN   <x>,<dest>
        BYTE    Pixel_is_dest-Pixel_base_address

ENDIF

ENDM

ENDM ; MakeROP

;/*
;** Data
;*/

        .DATA
        ALIGN   4
BitmapROPIndexes LABEL BYTE
        MakeROP DDx,<0,0>
        MakeROP DPon,<~dest,0>
        MakeROP DPna,<dest,0>
        MakeROP Pn,<1,0>
        MakeROP PDna,<0,~dest>
        MakeROP Dn,<~dest,~dest>
        MakeROP DPx,<dest,~dest>
        MakeROP DPan,<1,~dest>
        MakeROP DPa,<0,dest>
        MakeROP DPxn,<~dest,dest>
        MakeROP D,<dest,dest>
        MakeROP DPno,<1,dest>
        MakeROP P,<0,1>
        MakeROP PDno,<~dest,1>
        MakeROP DPo,<dest,1>
        MakeROP DDxn,<1,1>

        ALIGN   4
RotBitTbl LABEL BYTE
        BYTE    10000000b
        BYTE    01000000b
        BYTE    00100000b
        BYTE    00010000b
        BYTE    00001000b
        BYTE    00000100b
        BYTE    00000010b
        BYTE    00000001b

;/*
;** Public functions
;*/

        .CODE

        SUBTITLE Pixel
        PAGE +

;/***************************************************************************
;*
;* FUNCTION NAME = Pixel  
;*
;* DESCRIPTION   = Set or Get a Given Pixel.  The given pixel is set to the  
;*                 given color or the given pixel's physical color is        
;*                 returned.  The physical device may be the screen, a       
;*                 monochrome bitmap, or a bitmap in our color format.  There
;*                 will be no error checking to see if the bitmap is in our  
;*                 color format.  If it isn't, then we'll treat the bitmap as
;*                 if it was monochrome.  If mix_mode is -1, then the        
;*                 physical color of the pixel is returned.  If mix_mode     
;*                 isn't -1, then the pixel will be set to the physical color
;*                 passed in, combined with the pixel already at that        
;*                 location according to the raster-op in mix_mode.  Pixel   
;*                 doesn't pay attention to the background mode.  No clipping
;*                 of the input value is required.  GDI clips the coordinate 
;*                 before it is passed in, for both Set and Get.             
;*
;*                 Registers Preserved:       
;*                       SI,DI,DS,BP          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = C Prototype:                                                             
;*                   LONG _syscall Pixel (LONG lX, LONG lY, LONG lPhysColor, 
;*                                        LONG lMixMode);
;*                                                                                          
;*                    where:                                                                
;*                       ESI = Handle to DDC                                                
;*                       EGA registers in default state                                     
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = IPC if GetPixel            
;*                 Positive if SetPixel
;* RETURN-ERROR  = 080000000H if error occured
;*
;**************************************************************************/

ALIGN 4
Pixel PROC SYSCALL PUBLIC USES edi esi,
                lX        :LONG,        ; X coordinate of pixel
                lY        :LONG,        ; Y coordinate of pixel
                lPhysColor2:DWORD,      ; Physical color to set pixel to
                lMixMode  :LONG         ; Drawing mode to use, or -1 if Get

          LOCAL lPhysColor:IPC,
                lpDDC     :DWORD

        mov     eax,lPhysColor2
        mov     lPhysColor,ax
        DebugMsg <Entering PIXEL.Pixel,Public,KEZ>

        ddc?    ESI,<SURFACE>
        mov     lpDDC,esi
        MOV     ESI,[ESI].DDC.ddc_npsd  ; Get surface definition from DDC
        TEST    [ESI].SURFACE.sd_fb,SD_DEVICE
        JZ      Memory_bitmap


;/*
;** This is the device.  The cursor must be excluded from the pixel that will be
;** processed.  The innerloop mask for the device will be set for color.  The
;** width of a plane will be set to 1 to flag to the loop code that this is the
;** EGA (odd widths are illegal).
;*/


        PUSH    ESI                             ; Save surface pointer
        MOV     ECX,lX                          ; Set left
        MOV     EDX,lY                          ;    top
        MOV     ESI,ECX                         ;    right
        MOV     EDI,EDX                         ;    bottom
        CALL    far_exclude                     ; Exclude the area
if SCAN_CNT EQ 768

;/*
;** START BANKS
;*/

        mov     eax,lY
        mov     edx,0
        test    eax,0200h
        jz      @f
        sub     eax,200h
        mov     lY,eax
        mov     edx,1
@@:
        SetBankRW

;/*
;** END BANKS
;*/

endif
        POP     ESI                             ; Restore surface pointer
        MOV     ESI,[ESI].SURFACE.sd_pBits      ; ESI --> the bits
        MOV     EAX,SCREEN_CBSCAN               ; Compute starting address of
                                                ; scan
        MUL     lY                              ; Better on 286 than explicit
                                                ; shifts
        ADD     ESI,EAX                         ; ESI is offset of the scan
        MOV     CL,COLOR_OP                     ; Show color in case this is
                                                ; GetPixel
        MOV     EDI,1                           ; Next scan index = 1
                                                ; indicates display
        JMP     Pixel_70                        ; (odd width is illegal)

ALIGN   4
;/*
;** The device is a memory bitmap.
;*/

Memory_bitmap:
        MOV     EAX,lY                          ; Need Y coord a few times
        MOV     EDI,[ESI].SURFACE.sd_cbScan     ; Get index to next plane
        MOV     CL,MONO_OP                      ; Assume mono loop
        TEST    [ESI].SURFACE.sd_fb,SD_COLOR
        JZ      Pixel_60
        MOV     CL,COLOR_OP                     ; Show color loop

Pixel_60:
        MOV     EBX,[ESI].SURFACE.sd_dScan      ; Get index to next scan
        MOV     ESI,[ESI].SURFACE.sd_pBits      ; Get offset of the bits
        MUL     EBX                             ; Compute start of scan
        ADD     ESI,EAX                         ; ESI --> Start of scanline
                                                ;         byte is in
;/*
;** Currently:
;**       ESI --> The bitmap, start of the correct scan
;**       EDI = Index to next plane of the scan
;**             1 if the display (odd with illegal)
;**       CL  = Looping flag
;*/

Pixel_70:                                       ; Display code enters here
        MOV     EAX,lX                          ; Get X coordinate
        MOV     EBX,EAX
        SHR     EAX,3                           ; Compute byte offset from
                                                ; start of scan
        ADD     ESI,EAX                         ; ESI --> Byte of pixel
        AND     EBX,00000111B                   ; Get bit mask for bit
        MOV     CH,RotBitTbl[EBX]
        MOV     EDX,EDI                         ; Need index to next plane
                                                ; here
        MOV     EBX,lMixMode                    ; Get pel if -1
        OR      EBX,EBX
        JNS     Pixel_100                       ; Given, operation is set
                                                ; pixel
        JMP     Get_the_pixel                   ; Not given, return pixel
ALIGN 4
                                                ; color
Pixel_90:
        JMP     Pixel_130                       ; Just a vector
ALIGN 4

;/*
;** The operation to be performed is SetPixel.  Currently:
;**
;**       CH   =  Bit mask
;**       ESI --> Byte bit is to be set in
;**       EBX  =  Mix mode
;**       CL   =  Loop mask
;**       EDX  =  Index to next plane
;**                 1 if the display
;*/

Pixel_100:
        TEST    DL,00000001b    ; Memory device?
        JZ      Pixel_90        ; Yes, can't use special drawing modes

;/*
;** This is the EGA.  Regardless of the raster operation being performed in one
;** or two operations, set up the following registers which will be the same:
;**
;** BitMask Register     - To the bit to alter
;*/

        MOV     DX,EGA_BASE+GRAF_ADDR           ; Set bitmask register to bit
        MOV     AL,GRAF_BIT_MASK                ; to  be altered
        MOV     AH,CH
        OUT     DX,AX
        MOV     CL,BYTE ptr lPhysColor.ipc_bClr ; Need color here
        MOV     AH,MM_ALL                       ; Plane enable / color mask
        TEST    Bitmap_rop_flags[EBX],SINGLE_OK ; Can the ROP occur in one
                                                ; operation?
        JZ      Pixel_110                       ; Must do two operations

;/*
;** A special drawing mode can be used to set the pixel in one pass.
;*/

        MOV     AL,GRAF_ENAB_SR                 ; Enable all planes for
                                                ; set/reset
        OUT     DX,AX
        AND     CL,Bitmap_rop_pen_and[EBX]      ; Set correct color for the
        XOR     CL,Bitmap_rop_pen_xor[EBX]      ; ROP
        AND     AH,CL                           ; Only leave bits of interest
        MOV     AL,GRAF_SET_RESET
        OUT     DX,AX
        MOV     AL,GRAF_DATA_ROT                ; Set Data Rotate reg value
        MOV     AH,Bitmap_rop_data_r[EBX]
        OUT     DX,AX
        XCHG    CL,[ESI]                        ; Load latches/write pen into
                                                ; memory
        .ERRNZ  MM_C0-C0_BIT
        .ERRNZ  MM_C1-C1_BIT
        .ERRNZ  MM_C2-C2_BIT
        .ERRNZ  MM_C3-C3_BIT

;/*
;** Restore the EGA back to the defaults.
;*/

        MOV     AX,GRAF_ENAB_SR                 ; Disable all planes for
        OUT     DX,AX                           ; set/reset
        JMP     Pixel_restore_ega_more
ALIGN 4

;/*
;** The ROP cannot be performed in one pass using the EGA hardware.  It can be
;** performed in two seperate operations to the EGA.  This will be done in the
;** following manner:
;**
;**     The color will be used for the Write Plane Enable Mask after possibly
;**     being inverted to sync for the output mode being used (xor or set).
;**
;**     A write with 0's or 1's in drSet mode will occur.  This will set bits to
;**     either 1's or 0's as needed.
;**
;**     After this write occurs, the color will be inverted for use as the Write
;**     Plane Enable Mask for those planes which must be XORed to get ~dest.  An
;**     XOR will occur to toggle those bits which must be toggled.
;**
;**         Color Destination
;**
;**     DPon    0  ~dest   for color bits which are 0, xor with 1
;**           1      0     for color bits which are 1, set to   0
;**
;**     PDna    0    0     for color bits which are 0, set to   0
;**           1    ~dest   for color bits which are 1, xor with 1
;**
;**     DPan    0    1     for color bits which are 0, set to   1
;**           1    ~dest   for color bits which are 1, xor with 1
;**
;**     PDno    0  ~dest   for color bits which are 0, xor with 1
;**           1      1     for color bits which are 1, set to   1
;*/

Pixel_110:
        MOV     DL,SEQ_DATA                     ; Will be playing with the
                                                ; sequencer
        XOR     CL,Bitmap_rop_pen_xor[EBX]      ; Invert color if necessary
        AND     CL,AH
        MOV     AL,CL                           ; 3/3/87 kfs  used to be after
                                                ; jz.
        JZ      Pixel_120                       ; No bits to SET to 0's or 1's
        OUT     DX,AL                           ; Enable planes which need
                                                ; enabling

;/*
;** The Bitmap_rop_pen_and table is not set correctly for using DR_SET mode.  It
;** is a color instead of a BYTE consisting entirely of 0's or 1's, for use with
;** Write Mode 2 or the Set/Reset register.  This color will have to be mapped
;** for use with Bitmap_rop_SET mode.
;*/

        MOV     BL,Bitmap_rop_pen_and[EBX]      ; Set will use this color,but
        SHR     BL,1                            ; it must be mapped first
        SBB     BL,BL                           ; 00h if black,FFh if white
        XCHG    BL,[ESI]

Pixel_120:
        XOR     AL,AH                           ; Now write to the other
                                                ; planes
        JZ      Pixel_restore_ega               ; No bits to XOR
        OUT     DX,AL                           ; Enable these planes for
                                                ; write
        MOV     DL,GRAF_ADDR                    ; Set up for inversion
        MOV     AX,DR_XOR shl 8 + GRAF_DATA_ROT
        OUT     DX,AX
        XCHG    CH,[ESI]                        ; Invert bit if needed
        .ERRNZ  MM_C0-C0_BIT                    ; This assumption has been
        .ERRNZ  MM_C1-C1_BIT                    ; made a lot in this sequence
        .ERRNZ  MM_C2-C2_BIT
        .ERRNZ  MM_C3-C3_BIT

Pixel_restore_ega:
        MOV     AL,MM_ALL                       ; Enable all planes for
        MOV     DL,SEQ_DATA                     ; writing
        OUT     DX,AL

Pixel_restore_ega_more:
        MOV     DL,GRAF_ADDR                    ; Set DR_SET mode
        MOV     AX,DR_SET shl 8 + GRAF_DATA_ROT
        OUT     DX,AX
        MOV     AX,0FF00h+GRAF_BIT_MASK         ; Enable all bits for
        OUT     DX,AX                           ; alteration
        JMP     Pixel_160                       ; All done
ALIGN 4

;/*
;** The SetPixel operation is to be performed on a memory bitmap.
;**
;** The loop will use the following registers:
;**
;**     AH        Inverse of the bitmask
;**     AL        The bitmask
;**     EBX       Work
;**     CH        Pen Color
;**     CL        Loop mask
;**     EDX       Index to next plane, or 1 if EGA
;**     ESI       destination pointer
;**     EDI       ROP table address for the rop
;*/

Pixel_130:
        ADD     EBX,EBX                         ; Set BitmapROPIndexes table
        LEA     EDI,BitmapROPIndexes[EBX]       ; address for the given rop
        MOV     AX,CX                           ; Get mask for bit being
        MOV     AL,AH                           ; altered and also create a
        NOT     AH                              ; mask for ANDing
        MOV     CH,BYTE ptr lPhysColor.ipc_bClr ; Get color for the pixel

Pixel_140:
        MOVZX   EBX,CH                  ; Get pen color
        AND     BL,CL                   ; Mask color for current plane
        CMP     BL,1                    ; 'C' if pen is a 0 for this plane
        SBB     EBX,EBX                 ; EBX = -1 if black,0 if white
        INC     EBX                     ; EBX = 0  if black, 1 if white
        MOVZX   EBX,BYTE ptr [EDI][EBX] ; Get delta to the drawing function
        ADD     EBX,Pixel_base_address
        JMP     EBX                     ; Invoke the function
ALIGN 4

Pixel_base_address::                    ; Deltas are computed from here

Pixel_is_0::
        AND     [ESI],AH        ; Set pixel to a 0
        jmp     Pixel_is_dest
ALIGN 4

Pixel_is_inverted::
        XOR     [ESI],AL        ; Invert destination
        jmp     Pixel_is_dest
ALIGN 4

Pixel_is_1::
        OR      [ESI],AL        ; Set pixel to a 1

Pixel_is_dest::
        ADD     ESI,EDX         ; ESI --> Byte in next plane
        ROL     CL,1            ; Select next plane
if    BITS_PEL eq 4                     ;16 color driver  ;IBMJ
        TEST    CL,END_OP       ; Done with all planes?
        JZ      Pixel_140       ; Not yet
else ;BITS_PEL eq 8                     ;256 color driver  ;IBMJ
        JNC     Pixel_140       ; Not yet
endif;BITS_PEL eq 8       ;IBMJ

Pixel_160:
        XOR     EAX,EAX         ; Set EAX = 0
        JMP     Pixel_300       ; Return 0 to show success
ALIGN 4

;/*
;** The operation to be performed is get pixel.  The IPC of the pixel will be
;** returned.
;**
;** If this is a monochrome bitmap, then the IPC will simply be black or white.
;**
;** Currently:
;**
;**       CH   =   Bit mask
;**       CL   =   Loop mask
;**       EDX  =   Index to next plane
;**                1 if physical device
;**       ESI --> Byte bit is to be set in
;*/

WHITE EQU C0_BIT+C1_BIT+C2_BIT+C3_BIT+MONO_BIT+ONES_OR_ZEROS
BLACK EQU ONES_OR_ZEROS

Get_the_pixel:
        CMP     CL,MONO_OP      ; Is this for a mono bitmap?
        JNE     Pixel_210       ; No, it's for color
        XOR     EDX,EDX
        MOV     EAX,BLACK
        TEST    [ESI],CH        ; Is pixel black?
        JZ      Pixel_290       ; It is, return color in AX:DX
        MOV     EAX,WHITE
        JMP     Pixel_290
ALIGN 4

;/*
;** Counter the first DEC ESI which the EGA will throw in if this is for the
;** EGA.  EDX will be 1 if it is.  EDX cannot be 0 at this point.
;*/

Pixel_210:
        XOR     EBX,EBX                 ; Accumulate the color into BL
        CMP     EDX,2                   ; If EGA,counter the first dec ESI
        ADC     ESI,EBX

Pixel_220:
        TEST    DL,00000001b            ; Is this the physical device?
        JZ      Pixel_240               ; No, don't play with EGA registers
        DEC     ESI                     ; Adjust for adding in phoney width
        MOV     EDX,EGA_BASE + GRAF_ADDR        ; EDX --> EGA graphics addr
                                                ;         register
        MOV     AL,GRAF_READ_MAP        ; AL --> Read Map Select Register
        MOV     AH,CL                   ; Set read plane mask
        SHR     AH,1
        CMP     AH,100b                 ; Set 'C' if not C3
        ADC     AH,-1                   ; Sub -1 only if C3
        OUT     DX,AX
        MOV     DX,1                    ; Show device

Pixel_240:
        MOV     AL,[ESI]                ; Get the BYTE
        AND     AL,CH                   ; Mask bit of interest
        NEG     AL                      ; Set 'C' if bit is 1
        RCR     BL,1                    ; Propagate the color
        ADD     ESI,EDX                 ; ESI --> next plane
        ROL     CL,1                    ; Select next plane
if    BITS_PEL eq 4                     ;16 color driver  ;IBMJ
        TEST    CL,END_OP               ; Done with all planes?
        JZ      Pixel_220               ; Not yet

;/*
;** Make the color index into a WORD index.
;*/

        .ERRNZ  BITS_PEL GT 6
        .ERRNZ  C0_BIT-1                ; Must be this for alignment
        SHR     BL,8-BITS_PEL-1
else ;BITS_PEL eq 8                     ;256 color driver  ;IBMJ
        JNC     Pixel_240
endif;BITS_PEL eq 8       ;IBMJ

;/*
;** Return the IPC.
;*/

        MOVZX   EAX,aipcLookup[EBX]

Pixel_290:

        mov     ebx,lpDDC
        call    ipc_to_index        ;Result may be RGB, so we must

Pixel_300:
        CALL    far_unexclude   ; Clear any exclude rectangle

        RET

Pixel ENDP

        END
