;*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 = 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 egafam.inc
        include egamemf.inc
        .list


        ??_out  Pixel


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

COLOR_OP        equ     00000001b
MONO_OP         equ     MONO_BIT
END_OP          equ     MONO_BIT shl 1 + (1 shl (BITS_PEL))
        .errnz  BITS_PEL - 4


;/*
;** Link time constants describing the size and color format
;** that the EGA will be running in.
;*/

        externA DOSHUGEINCR
        externA SCREEN_CBSCAN                         ;Screen width in bytes

        externFP far_exclude                          ;Exclude area from screen
        externFP far_unexclude                        ;Clear excluded area


sBegin  Bitmap
        assumes cs,Bitmap

        externW BitmapData
        externW aipcLookup                              ; turns index into IPC

        externB Bitmap_rop_flags                        ; Special EGA drawing mode flags
        externB Bitmap_rop_data_r                       ; EGA Data Rotate Register value
        externB Bitmap_rop_pen_and                      ; Special EGA Drawing mode pen AND mask
        externB Bitmap_rop_pen_xor                      ; Special EGA Drawing mode pen XOR mask

        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
;*                 EGA registers in default state
;*
;* 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,BitmapData
        assumes ds,nothing
        mov     si,[si].ddc_npsd                  ;get surface definition from DDC

        test    [si].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    si                                ;save surface pointer
        mov     cx,x                              ;Set left
        mov     dx,y                              ;    top
        mov     si,cx                             ;    right
        mov     di,dx                             ;    bottom
        call    far_exclude                       ;Exclude the area
        mov     ds,BitmapData
        assumes ds,nothing
        pop     si                                ;restore surface pointer

        lds     si,[si].sd_pBits                  ;--> the bits
        assumes ds,nothing

        mov     ax,SCREEN_CBSCAN                  ;Compute starting address of scan
        mul     y                                 ;Better on 286 than explicit shifts
        xchg    ax,si                             ;SI is offset of the scan

        mov     cl,COLOR_OP                       ;Show color incase this is GetPixel
        mov     di,1                              ;Next scan index = 1 indicates display
        jmp     short pixel_70                    ;  (odd width is illegal)



;/*
;** The device is a memory bitmap.                  If it is a huge bitmap,
;** special processing must be performed to compute the Y address.
;*/


memory_bitmap:
        mov     ax,y                              ;Need Y coordinate a few times
        xor     dx,dx                             ;Set segment bias to 0
        test    [si].sd_fb,SD_HUGE
        jz      small_bitmap

;/*
;** This is a huge bitmap. Compute which segment the Y coordinate
;** is in.        Assuming that no huge bitmap will be bigger than two
;** or three segments, iteratively computing the value would be
;** faster than a divide, especially if Y is in the first segment
;** (which would always be the case for a huge color bitmap that
;** didn't have planes >64K).
;*/

        mov     cx,DOSHUGEINCR
        mov     bx,[si].sd_cySeg                  ;Get # scans per segment

pixel_30:
        add     dx,cx                             ;Show in next segment
        sub     ax,bx                             ;See if in this segment
        jnc     pixel_30                          ;Not in current segment, try next
        add     ax,bx                             ;Restore correct Y
        sub     dx,cx                             ;Show correct segment

;/*
;** This is a memory DC.  If this is a monochrome memory DC, set up
;** the inner loop so that it will terminate after one time through
;** and set the color to be equal to the mono bit in the physical
;** color.        If it is color, set up the inner loop for all planes,
;** same as for the display.
;**
;** Also handle modifying Y for huge bitmaps is necessary.
;**
;**
;** Currently:
;**       AX     =  Y coordinate
;**       DX     =  Segment bias for huge bitmaps
;**       DS:SI --> PDevice
;**       CH     =  Huge bitmap flag
;**                 (0 = small bitmap)
;*/

small_bitmap:
        mov     di,[si].sd_cbScan                 ;Get index to next plane
        mov     cl,MONO_OP                        ;Assume mono loop
        test    [si].sd_fb,SD_COLOR
        jz      pixel_60
        mov     cl,COLOR_OP                       ;Show color loop
pixel_60:
        add     dx,[si].sd_pBits.sel              ;Compute segment of the bits
        mov     bx,[si].sd_dScan                  ;Get index to next scan
        mov     si,[si].sd_pBits.off              ;Get offset of the bits
        mov     ds,dx                             ;Set DS:SI --> to the bits
        assumes ds,nothing
        mul     bx                                ;Compute start of scan
        add     si,ax                             ;DS:SI --> start of scanline byte is in



;/*
;** Currently:
;**       DS:SI --> the bitmap, start of the correct scan
;**       DI = Index to next plane of the scan
;**            1 if the display (odd with illegal)
;**       CL = looping flag
;*/

pixel_70:                                         ;Display code enters here
        mov     ax,x                              ;Get X coordinate
        mov     bx,ax
        shr     ax,3                              ;Compute byte offset from start of scan
        add     si,ax                             ;ds:si --> byte of pixel

        and     bx,00000111B                      ;Get bit mask for bit
        mov     ch,rot_bit_tbl[bx]
        mov     dx,di                             ;Need index to next plane here
        mov     bx,mix_mode                       ;Get pel if -1
        or      bx,bx
        jns     pixel_100                         ;Given, operation is set pixel
        jmp     get_the_pixel                     ;Not given, return pixel color
page

pixel_90:
        jmp     pixel_130                         ;Just a vector



;/*
;** The operation to be performed is SetPixel.  Currently:
;**
;**       CH    =   bit mask
;**       DS:SI --> byte bit is to be set in
;**       BX    =   mix mode
;**       CL    =   loop mask
;**       DX    =   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
page

;/*
;** 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 to
        mov     al,GRAF_BIT_MASK                 ;  be altered
        mov     ah,ch
        out16   dx,ax

        mov     cl,p_color.ipc_bClr              ;Need color here
        mov     ah,MM_ALL                        ;Plane enable / color mask
        test    Bitmap_rop_flags[bx],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
        out16   dx,ax

        and     cl,Bitmap_rop_pen_and[bx]        ;Set correct color for the ROP
        xor     cl,Bitmap_rop_pen_xor[bx]
        and     ah,cl                            ;Only leave bits of interest
        mov     al,GRAF_SET_RESET
        out16   dx,ax

        mov     al,GRAF_DATA_ROT                 ;Set Data Rotate reg value
        mov     ah,Bitmap_rop_data_r[bx]
        out16   dx,ax

        xchg    cl,[si]                          ;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 set/reset
        out16   dx,ax
        jmp     short pixel_restore_ega_more


;/*
;** 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[bx]         ;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[bx]         ;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,[si]

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
        out16   dx,ax

        xchg    ch,[si]                           ;Invert bit if needed
        errnz   MM_C0-C0_BIT                      ;This assumption has been made
        errnz   MM_C1-C1_BIT                      ;  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 writting
        mov     dl,SEQ_DATA
        out     dx,al

pixel_restore_ega_more:
        mov     dl,GRAF_ADDR                      ;Set DR_SET mode
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        out16   dx,ax

        mov     ax,0FF00h+GRAF_BIT_MASK           ;Enable all bits for alteration
        out16   dx,ax
        jmp     short pixel_160                   ;All done
page

;/*
;** 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
;**     BX        Work
;**     CH        Pen Color
;**     CL        Loop mask
;**     DX        Index to next plane, or 1 if EGA
;**  DS:SI        destination pointer
;**     DI        ROP table address for the rop
;*/

pixel_130:
        add     bx,bx                             ;Set Bitmap_rop_indexes table address
        lea     di,Bitmap_rop_indexes[bx]         ;  for the given rop
        mov     ax,cx                             ;Get mask for bit being altered
        mov     al,ah                             ;  and also create a mask for
        not     ah                                ;  ANDing
        mov     ch,p_color.ipc_bClr               ;Get color for the pixel

pixel_140:
        mov     bl,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     bx,bx                             ;BX = -1 if black, 0 if white
        inc     bx                                ;BX = 0  if black, 1 if white
        mov     bl,byte ptr cs:[di][bx]           ;Get delta to the drawing function
        add     bx,BitmapOFFSET pixel_base_address
        jmp     bx                                ;Invoke the function

pixel_base_address:                               ;Deltas are computed from here
pixel_is_0:
        and     [si],ah                           ;Set pixel to a 0
        jmpnext

pixel_is_inverted:
        xor     [si],al                           ;Invert destination
        jmpnext

pixel_is_1:
        or      [si],al                           ;Set pixel to a 1
        jmpnext stop

pixel_is_dest:
        add     si,dx                             ;--> byte in next plane
        rol     cl,1                              ;Select next plane
        test    cl,END_OP                         ;Done with all planes?
        jz      pixel_140                         ;  Not yet

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

;/*
;** 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
;**       DX    =   index to next plane
;**                 1 if physical device
;**       DS:SI --> 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     dx,dx
        mov     ax,BLACK
        test    [si],ch                           ; Is pixel black?
        jz      pixel_300                         ;  It is, return color in AX:DX
        mov     ax,WHITE
        jmp     short pixel_300

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

pixel_210:
        xor     bx,bx                             ; Accumulate the color into BL
        cmp     dx,2                              ; If EGA, counter the
        adc     si,bx                             ;   first dec SI

pixel_220:
        test    dl,00000001b                      ; Is this the physical device?
        jz      pixel_240                         ;   No, don't play with EGA registers

        dec     si                                ; Adjust for adding in phoney width
        mov     dx,EGA_BASE + GRAF_ADDR           ; --> EGA graphics addr register
        mov     al,GRAF_READ_MAP                  ; --> 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

        out16   dx,ax
        mov     dx,1                              ;Show device

pixel_240:
        mov     al,[si]                           ;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     si,dx                             ;--> next plane
        rol     cl,1                              ;Select next plane
        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

;/*
;** return the IPC
;*/

        mov     ax,aipcLookup[bx]
        xor     dx,dx
pixel_300:
        call    far_unexclude                     ;Clear any exclude rectangle

        fw_zero <cx,ds,es>
cEnd


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


Bitmap_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    Bitmap
end
