;*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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = PIXEL.ASM
;*
;* DESCRIPTIVE NAME = Set/Get Pixel routine.
;*
;*
;* VERSION      V2.0
;*
;* DATE         02/22/87
;*
;* 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
;*   03/03/87                     Kent Settle [kentse] Moved a mov
;*                                instruction in EGA ROP handling code.
;*   07/02/87                     Walt Moore [waltm] Changed to new rop
;*                                ordering (rops 6,7,9)
;*   02/14/88                     Charles Whitmer [chuckwh] Changed the
;*                                GetPixel part to return the IPC.
;*****************************************************************************/


        .xlist
        include cmacros.inc
        include pmgre.inc
        include driver.inc
        include display.inc
        include 8514.inc
        include 8514mem.inc
        .list


        ??_out  Pixel


        externFP    far_unexclude
        externFP    far_exclude
        externA     DOSHUGEINCR

sBegin  PtrData
        externB screen_busy                       ; cursor exclusion flag
sEnd    PtrData


sBegin  Data
        externW ipc_index_mask                    ; mask to just bpp
        externW hwFlags                           ; hw flags
sEnd    Data


sBegin  Code
        assumes cs,Code

        externB aipcLookup                        ; turns index into IPC
        externW CodeData
        externW MyPtrCodeData                     ; for access to pointer data segment
        externB hwMixes                           ; hw mix mode xlat table

        public  rot_bit_tbl
rot_bit_tbl     label   byte
                db      10000000b
                db      01000000b
                db      00100000b
                db      00010000b
                db      00001000b
                db      00000100b
                db      00000010b
                db      00000001b

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 
;*                 Calls:
;*                       exclude
;*                       unexclude
;*
;* INPUT         = SI = handle to DDC
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 0:IPC    if GetPixel
;*                 DX:AX = positive if SetPixel
;* RETURN-ERROR  = DX:AX = 080000000H if error occured
;*
;**************************************************************************/

        assumes ds,nothing
        assumes es,nothing

cProc   Pixel,<FAR,PUBLIC,NODATA>,<si,di>
        parmW   x                                 ;X coordinate of pixel
        parmW   y                                 ;Y coordinate of pixel
        parmW   p_color                           ;Physical color to set pixel to
        parmW   mix_mode                          ;Drawing mode to use, or -1 if Get
cBegin
        fw_zero <ds,es>
        ddc?    si,<SURFACE>

        mov     ds,CodeData
        assumes ds,Data
        mov     si,[si].ddc_npsd                  ;get surface definition from DDC

        test    [si].sd_fb,SD_DEVICE
        jnz     @F                                ; target bitmap is the device...
        jmp     memory_bitmap
@@:

;/*
;** This is the device.  The cursor must be excluded from the pixel
;** that will be processed.
;*/

        mov     cx,x                              ;Set left
        mov     dx,y                              ;    top
        mov     si,cx                             ;    right
        mov     di,dx                             ;    bottom
        call    far_exclude                           ;Exclude the area

        GrabScreen  pixel                         ; don't let cursor isr interfere

;/*
;** Set up the 8514/A hardware.
;*/

        WaitQ   8
        outwQ   XMIN,(XMIN_2DECODE+0)             ; max clip rect is fine
        outwQ   XMAX,(XMAX_2DECODE+1023)
        outwQ   YMIN,(YMIN_2DECODE+0)
        outwQ   YMAX,(YMAX_2DECODE+1023)
        mov     ax,x                              ; x coordinate
        outwQ   X0,ax
        outwQ   X1,ax
        mov     ax,y                              ; y coordinate
        outwQ   Y0,ax
        outwQ   Y1,ax

        WaitQ   7
        sub     ax,ax                             ; width,height are 1 (0-based)
        outwQ   LX,ax
        outwQ   LY,ax
        .errnz  LY_2DECODE

        mov     bx,mix_mode                       ; are we setting or getting a pixel ?
        or      bx,bx
        js      @F                                ; getting the pixel...

;/*
;** Specific initialization for SetPixel.
;*/

        mov     al,hwMixes[bx]                    ; fetch hw mix mode
        or      al,FUNC_2OP_COL1                  ; fixed data is in COLOR_1
        outbQ   FUNCTION_1,al
        outbQ   COLOR_1,p_color.ipc_bClr          ; fg color
        outbQ   WRITE_ENABLE,0ffh                 ; write to all planes
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES)
        outwQ   CMD_FLAGS,(CMD_C_FRECT+CMD_WORD+CMD_FV_FIX+CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW_W)
        WaitQ   -5                                ; still room for 5 words if getting
                                                  ; a pixel

        ReleaseScreen  pixel1                     ; allow cursor to interfere
        call    far_unexclude                     ; bring back any excluded cursor
        xor     ax,ax                             ; return DX:AX == 0 for success
        cwd
        jmp     pixel_300                         ; common exit code...


; Specific initialization for GetPixel.

@@:     outbQ   READ_ENABLE,0ffh                 ; read from all planes
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_AF_R_THRU)
        outwQ   CMD_FLAGS,(CMD_C_FRECT+CMD_WORD+CMD_FV_VAR+CMD_MA_ACCESS+CMD_PA_ONE+CMD_RW_R)

        WaitQIN                                   ; wait for available queued data
        mov     dx,COLOR_1                        ; input queue port #
        in      ax,dx                             ; pixel retrieved to al

        ReleaseScreen  pixel2                     ; allow cursor to interfere
        call    far_unexclude                     ; bring back any excluded cursor
        jmp     pixel_290                         ; to common exit code...


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

memory_bitmap:

        test    [si].sd_fb,SD_COLOR              ; is memory bitmap color ?
        jnz     color_memory_bitmap              ; yes...

;/*
;** We need to do a set or get to/from a monochrome memory bitmap.
;*/

        mov     cx,((0 shl 8) + 3)                ; 8 pixels / byte
        call    pixel_xyaddr                      ; fetch byte -> of pixel to ES:DI
        mov     si,x
        and     si,7                              ; bit position within byte

        mov     bx,mix_mode                       ; fetch mix_mode
        or      bx,bx                             ; getting or setting the pixel ?
        jns     set_mono_bitmap                   ; setting...


;/*
;** Fetch a monochrome pixel.
;*/

        mov     al,es:[di]                        ; fetch byte containing pixel
        inc     si                                ; left shift count to get pixel to C
        mov     cx,si
        shl     al,cl                             ; get pixel to carry
        sbb     al,al                             ; (pixel == 1) ? all 1s : all 0s
        jmp     pixel_290                         ; common code below...

;/*
;** Set a pixel in a monochrome bitmap.
;*/

set_mono_bitmap:

        mov     al,rot_bit_tbl[si]                ; get bitmask for bit within byte
        mov     ah,al
        not     ah                                ; create not mask

        add     bx,bx                             ;Set rop_indexes table address
        lea     si,rop_indexes[bx]                ;  for the given rop
        mov     bl,p_color.ipc_bClr               ;Get color for the pixel

        and     bl,al                             ;Mask color for current plane
        cmp     bl,1                              ;'C' if pen is a 0 for this plane
        sbb     bx,bx                             ;BX = -1 if black, 0 if white
        inc     bx                                ;BX = 0  if black, 1 if white
        mov     bl,byte ptr cs:[si][bx]           ;Get delta to the drawing function
        add     bx,CodeOFFSET pixel_base_address
        jmp     bx                                ;Invoke the function

pixel_base_address:                               ;Deltas are computed from here
pixel_is_0:
        and     es:[di],ah                        ;Set pixel to a 0
        jmp     short pixel_is_dest

pixel_is_inverted:
        xor     es:[di],al                        ;Invert destination
        jmp     short pixel_is_dest

pixel_is_1:
        or      es:[di],al                        ;Set pixel to a 1

pixel_is_dest:
        xor     ax,ax                             ;Set dx:ax = 0:0
        cwd
        jmp     pixel_300                         ;Return 0:0 to show success


;/*
;** Set or get a pixel to/from a color memory bitmap.
;*/

color_memory_bitmap:

        mov     bx,mix_mode                       ; fetch mix_mode
        or      bx,bx                             ; getting or setting the pixel ?
        jns     set_color_bitmap                  ; setting...

;/*
;** Get a pixel in a color memory bitmap.
;*/

ifdef   4BPP_USED
        test    hwFlags,HW_8_BPP                  ; are we 8 bpp ?
        jnz     get_color_bitmap_8bpp             ; yes...

        mov     cx,1                              ; there are 2 4bpp pixels / byte
        call    pixel_xyaddr                      ; es:di is -> into bitmap
        mov     al,es:[di]                        ; fetch pixels at that address

        test    x,1                               ; odd addressed 4 bpp pixel ?
        jnz     @F                                ; yes, no need to shift...
        shr     al,4                              ; else get left pixel down to lo nibble
        jmp     short @F
endif;  4BPP_USED

get_color_bitmap_8bpp:

        sub     cx,cx                             ; 8 bpp bitmap
        call    pixel_xyaddr                      ; fetch byte -> of pixel to ES:DI
        mov     al,es:[di]                        ; fetch pixel at that address
@@:     jmp     pixel_290                         ; common code below...


;/*
;** Set a pixel in a color memory bitmap.
;*/

set_color_bitmap:

ifdef   4BPP_USED
        test    hwFlags,HW_8_BPP                  ; 8 bpp target ?
        jz      set_color_bitmap_4bpp             ; no...
endif;  4BPP_USED

        sub     cx,cx                             ; 8 bpp bitmap
        push    bx
        call    pixel_xyaddr                      ; fetch byte -> of pixel to ES:DI
        pop     bx

        mov     al,p_color.ipc_bClr               ; color to set pixel to
        mov     ah,0ffh                           ; all 1s mask

        mov     bl,cs:scb_8bpp_op_tbl[bx]         ; get 8 bit offset to mix mode op
        add     bx,CodeOFFSET scb_8bpp_ops
        jmp     bx                                ; go to specialist...

scb_8bpp_ops    label   near

scb_8bpp_DDx:
        not     ah                                ; mask to 0s

scb_8bpp_DDxn:
        mov     al,ah                             ; to register for storing
        stosb                                     ; store 1s or 0s to dest
        jmp     short scb_8bpp_D

scb_8bpp_DPon:
        or      al,es:[di]                        ; DPo
        not     al                                ; DPon
        stosb
        jmp     short scb_8bpp_D

scb_8bpp_DPna:
        not     al                                ; Pn

scb_8bpp_DPa:
        and     es:[di],al                        ; DPa
        jmp     short scb_8bpp_D

scb_8bpp_Pn:
        not     al                                ; Pn

scb_8bpp_P:
        stosb                                     ; P
        jmp     short scb_8bpp_D

scb_8bpp_PDna:
        xor     ah,es:[di]                        ; Dn
        and     al,ah                             ; PDna
        stosb
        jmp     short scb_8bpp_D

scb_8bpp_Dn:
        not     byte ptr es:[di]                  ; Dn
        jmp     short scb_8bpp_D

scb_8bpp_DPx:
        xor     es:[di],al                        ; DPx
        jmp     short scb_8bpp_D

scb_8bpp_DPan:
        and     al,es:[di]                        ; DPa
        not     al                                ; DPan
        stosb
        jmp     short scb_8bpp_D

scb_8bpp_DPxn:
        xor     al,es:[di]                        ; DPx
        not     al                                ; DPxn
        stosb

scb_8bpp_D:
        xor     ax,ax                             ; return DX:AX == 0 for success
        cwd
        jmp     pixel_300

scb_8bpp_DPno:
        not     al                                ; Pn

scb_8bpp_DPo:
        or      es:[di],al                        ; DPno
        jmp     short scb_8bpp_D

scb_8bpp_PDno:
        xor     ah,es:[di]                        ; Dn
        or      al,ah                             ; PDno
        stosb
        jmp     short scb_8bpp_D


scb_8bpp_op_tbl label   byte
        db      scb_8bpp_DDx - scb_8bpp_ops
        db      scb_8bpp_DPon - scb_8bpp_ops
        db      scb_8bpp_DPna - scb_8bpp_ops
        db      scb_8bpp_Pn - scb_8bpp_ops
        db      scb_8bpp_PDna - scb_8bpp_ops
        db      scb_8bpp_Dn - scb_8bpp_ops
        db      scb_8bpp_DPx - scb_8bpp_ops
        db      scb_8bpp_DPan - scb_8bpp_ops
        db      scb_8bpp_DPa - scb_8bpp_ops
        db      scb_8bpp_DPxn - scb_8bpp_ops
        db      scb_8bpp_D - scb_8bpp_ops
        db      scb_8bpp_DPno - scb_8bpp_ops
        db      scb_8bpp_P - scb_8bpp_ops
        db      scb_8bpp_PDno - scb_8bpp_ops
        db      scb_8bpp_DPo - scb_8bpp_ops
        db      scb_8bpp_DDxn - scb_8bpp_ops

ifdef   4BPP_USED
set_color_bitmap_4bpp:

        mov     cl,1                              ; there are two 4 bpp pixels / byte
        push    bx
        call    pixel_xyaddr                      ; fetch byte -> of pixel to ES:DI
        pop     bx

        mov     al,p_color.ipc_bClr               ; color to set pixel to
        mov     ah,0fh                            ; all 1s mask
        and     al,ah                             ; mask pixel to just bpp

        test    x,1                               ; leftmost pixel in byte ?
        jnz     @F                                ; no, no need to shift up...
        shl     ax,4                              ; mask and pixel shifted up to left
@@:

        mov     bl,cs:scb_4bpp_op_tbl[bx]         ; get 8 bit offset to mix mode op
        add     bx,CodeOFFSET scb_4bpp_ops
        jmp     bx                                ; go to specialist...

scb_4bpp_ops    label   near

scb_4bpp_DDx:
        not     ah                                ; mask to 0s
        and     es:[di],ah                        ; 0s to pixel we touch
        jmp     short scb_4bpp_D

scb_4bpp_DDxn:
        or      es:[di],ah                        ; 1s to pixel we touch
        jmp     short scb_4bpp_D

scb_4bpp_DPon:
        or      al,es:[di]                        ; DPo
        xor     al,ah                             ; DPon
        stosb
        jmp     short scb_4bpp_D

scb_4bpp_DPna:
        not     al                                ; Pn

scb_4bpp_DPa:
        and     es:[di],al                        ; DPa
        jmp     short scb_4bpp_D

scb_4bpp_Pn:
        not     al                                ; Pn

scb_4bpp_P:
        not     ah                                ; not mask
        and     ah,es:[di]                        ; isolate pixel we don't touch
        or      al,ah                             ; combine with pixel we do touch
        stosb                                     ; P
        jmp     short scb_4bpp_D

scb_4bpp_PDna:
        not     ah                                ; not mask
        or      al,ah                             ; 1s to pixel we don't touch
        not     ah                                ; just mask
        xor     ah,es:[di]                        ; Dn
        and     al,ah                             ; PDna
        stosb
        jmp     short scb_4bpp_D

scb_4bpp_Dn:
        xor     byte ptr es:[di],ah               ; Dn
        jmp     short scb_4bpp_D

scb_4bpp_DPx:
        xor     es:[di],al                        ; DPx
        jmp     short scb_4bpp_D

scb_4bpp_DPan:
        not     ah                                ; not mask
        or      al,ah                             ; 1s to pixel we don't touch
        not     ah                                ; just mask
        and     al,es:[di]                        ; DPa
        xor     al,ah                             ; DPan
        stosb
        jmp     short scb_4bpp_D

scb_4bpp_DPxn:
        xor     al,es:[di]                        ; DPx
        xor     al,ah                             ; DPxn
        stosb

scb_4bpp_D:
        xor     ax,ax                             ; return DX:AX == 0 for success
        cwd
        jmp     pixel_300

scb_4bpp_DPno:
        xor     al,ah                             ; Pn

scb_4bpp_DPo:
        or      es:[di],al                        ; DPno
        jmp     short scb_4bpp_D

scb_4bpp_PDno:
        xor     ah,es:[di]                        ; Dn
        or      al,ah                             ; PDno
        stosb
        jmp     short scb_4bpp_D


scb_4bpp_op_tbl label   byte
        db      scb_4bpp_DDx - scb_4bpp_ops
        db      scb_4bpp_DPon - scb_4bpp_ops
        db      scb_4bpp_DPna - scb_4bpp_ops
        db      scb_4bpp_Pn - scb_4bpp_ops
        db      scb_4bpp_PDna - scb_4bpp_ops
        db      scb_4bpp_Dn - scb_4bpp_ops
        db      scb_4bpp_DPx - scb_4bpp_ops
        db      scb_4bpp_DPan - scb_4bpp_ops
        db      scb_4bpp_DPa - scb_4bpp_ops
        db      scb_4bpp_DPxn - scb_4bpp_ops
        db      scb_4bpp_D - scb_4bpp_ops
        db      scb_4bpp_DPno - scb_4bpp_ops
        db      scb_4bpp_P - scb_4bpp_ops
        db      scb_4bpp_PDno - scb_4bpp_ops
        db      scb_4bpp_DPo - scb_4bpp_ops
        db      scb_4bpp_DDxn - scb_4bpp_ops

endif;  4BPP_USED

;/*
;** Common exit point for getting a pixel from the bitmap.
;*/

pixel_290:

        and     ax,ipc_index_mask                ; mask pixel inquired to just bpp
        mov     bx,ax                            ; ipc color to bx for indexing
        mov     ah,aipcLookup[bx]                ; get ipc flags
        xor     dx,dx

;/*
;** Common exit point for setting a pixel from the bitmap.
;*/

pixel_300:
        fw_zero <cx,ds,es>
cEnd


        page
;/***************************************************************************
;*
;* FUNCTION NAME = pixel_xyaddr
;*
;* DESCRIPTION   = Calculate a far pointer into the bitmap located in local     
;*                 memory.                                                      
;*
;*                 Registers Destroyed:
;*                       AX,BX,CX,DI,ES,FLAGS
;*                 Registers Preserved:
;*                       DX,SI,BP,DS
;*                 
;* INPUT         = [Ds:Si] =       -> surface definition                               
;*                 [Cl]    =       shift right count to convert x origin to a          
;*                                 specified boundary                                  
;*                 [Ch]    =       shift left count to convert offset in quantities    
;*                                 calculated using [Cl], to byte offset               
;*                 The effect of [Cl] is to round the -> returned down to some         
;*                 boundary (ie: words,dwords, etc)                                    
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = [ES:DI] =       -> byte containing 1st pixel of interest 
;* RETURN-ERROR  = DX:AX = 080000000H if error occured
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

        public  pixel_xyaddr
pixel_xyaddr    proc    near

        mov     di,[si].sd_pBits.sel              ; bitmap selector
        mov     ax,y                              ; pixel y origin

;/*
;** Test for huge bitmap. If we have a huge bitmap then we need to compute
;** the starting segment, and then do the xyaddr into that segment.
;*/

        cmp     [si].sd_selIncr,0                 ; do we have a huge bitmap ?
        je      xyaddr_small_bitmap               ; no...
 
        mov     bx,[si].sd_cySeg                  ; # scans / segment

@@:     add     di,DOSHUGEINCR                    ; assume advance to next segment
        sub     ax,bx                             ; advance to next segment
        jae     @B                                ; not in segment yet

        sub     di,DOSHUGEINCR                    ; we overshot into next segment
        add     ax,bx                             ; get scan # in correct segment

xyaddr_small_bitmap:

        mul     [si].sd_cbScan                    ; offset to scan of interest

        mov     es,di
        assumes es,nothing
        mov     di,[si].sd_pBits.off              ; -> bits of source bitmap
        add     di,ax                             ; -> start of scan of interest

        mov     ax,x                              ; pixels into scanline
        shr     ax,cl
        xchg    ch,cl                             ; round to specified boundary
        shl     ax,cl                             ; now make byte offset
        add     di,ax                             ; -> byte containing pixel

        ret
pixel_xyaddr    endp

;/*
;**  make_rop - 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
;*/


make_rop macro  l,ops

irp x,<ops>
ifidn   <&&x>,<0>
        db      pixel_is_0-pixel_base_address
endif
ifidn   <&&x>,<1>
        db      pixel_is_1-pixel_base_address
endif
ifidn   <&&x>,<~dest>
        db      pixel_is_inverted-pixel_base_address
endif
ifidn   <&&x>,<dest>
        db      pixel_is_dest-pixel_base_address
endif
endm
endm


rop_indexes     label   byte
make_rop DDx,<0,0>
make_rop DPon,<~dest,0>
make_rop DPna,<dest,0>
make_rop Pn,<1,0>
make_rop PDna,<0,~dest>
make_rop Dn,<~dest,~dest>
make_rop DPx,<dest,~dest>
make_rop DPan,<1,~dest>
make_rop DPa,<0,dest>
make_rop DPxn,<~dest,dest>
make_rop D,<dest,dest>
make_rop DPno,<1,dest>
make_rop P,<0,1>
make_rop PDno,<~dest,1>
make_rop DPo,<dest,1>
make_rop DDxn,<1,1>


sEnd    Code
end
