;*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 = drawline.asm
;*
;* DESCRIPTIVE NAME = Polyline drawing device driver.
;*
;*
;* VERSION      V2.0
;*
;* DATE         10/19/87
;*
;* DESCRIPTION  Takes the line(s) path from structure and draws lines.
;*
;* FUNCTIONS    Public:  DrawLinesInPath
;*                       DrawLinesCorrelate
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   10/19/87                     Kent Settle (kentse) - Created
;*   05/10/88                     Charles Whitmer [chuckwh]
;*                                  Wrote DrawLinesCorrelate
;*   05/17/88                     Charles Whitmer [chuckwh]
;*                                  Wrote DrawLinesInPath
;*   06/20/88                     Bob Grudem [bobgru]
;*                                  Implemented the "max" metric for
;*                                  line styling.
;*
;* ***************************************************************************/

        .xlist
        include cmacros.inc
INCL_DDIPATHS           equ        1
INCL_GRE_LINES          equ        1
INCL_DDICOMFLAGS        equ        1
INCL_GPICORRELATION     equ        1
INCL_GPIPRIMITIVES      equ        1
        include pmgre.inc
DINCL_ROPS              equ        1
        include driver.inc
        include polyline.inc                     ; polyline equates file
        include njmp.mac
        .list

        ??_out  drawline

        errcode <INV_LENGTH_OR_COUNT,BITMAP_NOT_SELECTED>

        externFP        FSRSemCheck

        externA         SCREEN_CY

sBegin  Data
        externB         ddcInit
        externB         semDriver
sEnd    Data

        externFP        far_recalc_correlate_rect   ; MAJOR0B.ASM
        externFP        far_clip_line               ; CLIP.ASM

sBegin  PtrCode
        externFP        far_exclude                 ; CURSORS.ASM
        externFP        far_unexclude               ; CURSORS.ASM
sEnd        PtrCode

sBegin  Code
        externNP        MakeColorsValid
        externNP        PropagateSysClrChange
sEnd    Code


sBegin  Code
        assumes cs,Code

        externW         CodeData

        externNP        polyline_workhorse_routine  ; POLYLINE.ASM
        externNP        polyline_init               ; POLYLINE.ASM
        externNP        polyline_background_init    ; POLYLINE.ASM

;/***************************************************************************
;*
;* FUNCTION NAME = DrawLinesInPath
;*
;* DESCRIPTION   = Draws a given number of lines from a given path
;*                 structure.
;*
;*                 Registers Destroyed:
;*                        AX,BX,CX,DX,flags.
;*                 Registers Preserved:
;*                        DI,SI,DS,BP
;*                 Calls:
;*                         exclude
;*                         unexclude
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1         if no correlation hit
;*                 AX = 2         if correlation hit
;* RETURN-ERROR  = AX = 0         if polylines not drawn
;*
;**************************************************************************/

        check        DrawLinesInPath,<hdc,pph,pcvFirst,ccv,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc        DrawLinesInPath,<PUBLIC,FAR,NODATA>,<di,si>
        parmD        hdc
        parmD        lpph                    ; pointer to a path
        parmD        lpcvFirst               ; pointer to a curve in the path
        parmD        icvCount                ; count of curves
        parmD        hddc
        parmD        FunN
        include plylocal.inc
cBegin
        mov     Flags,0
        mov     returnvalue,1                ; assume all OK
        mov     ds,CodeData
        assumes ds,Data

;/*
;** This call only makes sense with the device locked, check it out!
;*/
ifdef FIREWALLS
        cCall   FSRSemCheck,<DataOFFSET semDriver>
        or      ax,dx
        jz      @F
        rip     text,<DrawLinesInPath called without LockDevice>
@@:
endif

;/*
;** Make sure the system colors and IPC are up to date.  If the system
;** colors did change, the IPC will have to also be realized.
;*/

        mov     si,hddc.lo                ; DS:SI --> DDC
        mov     ax,ddcInit.ddc_iSysClr
        cmp     ax,[si].ddc_iSysClr
        jne     dlip_need_sys_colors
        test    [si].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        jz      dlip_have_valid_ipc
        jmp     short dlip_get_new_ipc
dlip_need_sys_colors:
        cCall   PropagateSysClrChange
dlip_get_new_ipc:
        lea     bx,[si].ddc_la.la_ba
        call    MakeColorsValid
        jns     dlip_have_valid_ipc
        jmp     short dlip_error_exit        ;Error logged by MakeBrushValid

;/*
;** Some error handlers in here
;*/

dlip_no_surface:
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        jmp     short dlip_log_error

dlip_bad_count:
        mov     ax,PMERR_INV_LENGTH_OR_COUNT

dlip_log_error:
        save_error_code

dlip_error_exit:
        xor     ax,ax                        ; indicate error
        jmp     drawline_exit

dlip_good_exit_relay:
        jmp     drawline_good_exit


;/*
;** Make sure we have a surface and valid counts
;*/

dlip_have_valid_ipc:
        test    [si].ddc_fb,DDC_PRESENT
        jz      dlip_no_surface
        cmp     icvCount.hi,0
        jne     dlip_bad_count
        mov     cx,icvCount.lo
        jcxz    dlip_good_exit_relay

;/*
;** accumulate bounds
;*/

        mov     es,lpph.sel                 ; ES => path
        assumes es,nothing
        mov     di,FunN.hi                  ; DI = Command
ifdef FIREWALLS
        test    di,COM_BOUND+COM_ALT_BOUND
        jz      @F
        rip     text,<Bounds should not be set>
@@:
endif


;/*
;** compute correlation
;*/

        test    di,COM_CORRELATE
        jz      correlate_done
        mov     di,lpcvFirst.lo         ; ES:DI = curves
        cCall   <far ptr DrawLinesCorrelate>,<cx>
        mov     returnvalue,ax
correlate_done:


;/*
;** draw the lines
;*/

        mov     cl,[si].ddc_fb
        and     cl,DDC_VISIBLE
        .errnz  DDC_VISIBLE - COM_DRAW
        test    byte ptr FunN.hi,cl
        njz     drawing_all_done

;/*
;** exclude the pointer if the device
;*/

        test    [si].ddc_fb,DDC_DEVICE
        jz      exclusion_done
        mov     bx,lpph.off

        mov     bx,es:[bx].ph_npspFirst

        mov     cx,es:[bx].sp_rcsBounding.rcs_xLeft       ; CX = left (inclusive)
        mov     di,es:[bx].sp_rcsBounding.rcs_yBottom     ; DI = bottom (inclusive)
        mov     si,es:[bx].sp_rcsBounding.rcs_xRight      ; SI = right (inclusive)
        mov     dx,es:[bx].sp_rcsBounding.rcs_yTop        ; DX = top (inclusive)
        sub     dx,SCREEN_CY-1                ; flip the vertical
        neg     dx
        sub     di,SCREEN_CY-1
        neg     di
        call    far_exclude                ; (destroys ES)
        mov     es,lpph.sel                ; ES => path
        assumes es,nothing
exclusion_done:

;/*
;** initialize according to the physical device type
;*/

        mov     di,hddc.lo
        call    polyline_init

        assumes ds,nothing                ; DS => surface

setup_drawlines:

        mov     ax,icvCount.lo
        mov     Count,ax
        mov     ax,lpcvFirst.off
        mov     Points,ax

;/*
;** loop through all curves
;*/

ifdef FIREWALLS
        push    cx
        mov     cx,es
        cmp     cx,lpcvFirst.sel
        jz      @F
        rip     text,<Inconsistent path and curve>
@@:     pop  cx
endif

drawlines_loop:
        mov     di,Points
        mov     ax,es:[di].ln_npcvNext
        mov     Points.off,ax
ifdef FIREWALLS
        cmp     es:[di].ln_bIdent,CURVE_IDENTIFIER
        jz      @F
        rip     text,<Curve identifier invalid>
@@:
endif


;/*
;** make sure it's a line...
;*/
        cmp     es:[di].ln_bType,LINE_IDENTIFIER
        njnz    drawlines_next

;/*
;** normalize the line
;*/

        xor     si,si                                ; SI = flags
        mov     ax,es:[di].ln_ptsA.pts_x        ; (AX,BX) = point 1
        mov     bx,es:[di].ln_ptsA.pts_y
        mov     cx,es:[di].ln_ptsC.pts_x        ; (CX,DX) = point 2
        mov     dx,es:[di].ln_ptsC.pts_y

;/*
;** make sure we go left to right
;*/

        cmp     ax,cx
        jle     is_left_to_right
        xchg    ax,cx
        xchg    bx,dx
        or      si,LF_LEFT_XCHG
is_left_to_right:

;/*
;** record the start position (so we can calculate the surface address)
;*/

        mov     lsg.lsg_xStart,ax
        mov     lsg.lsg_yStart,bx

;/*
;** normalize coordinates relative to xStart and yStart
;*/
        sub     cx,ax
        sub     dx,bx
        jge     y_be_unsigned
        neg     dx
        or      si,LF_Y_FLIP + LF_VERTICAL_FLIP
y_be_unsigned:

;/*
;** get x-major
;*/
        cmp     dx,cx
        jbe     we_be_x_major
        xchg    dx,cx
        or      si,LF_XY_XCHG
we_be_x_major:

;/*
;** remember the normalized line
;*/
        mov     lsg.lsg_cdx,cx
        mov     lsg.lsg_cdy,dx

;/*
;** Compute the clip range from the POINTFXs.  Handle the y-major case.
;*/
        test    si,LF_XY_XCHG ; test for y-major
        jz      ptfx_x_major
        neg     bx                        ; get relative to the start y!
        mov     dx,bx
        mov     ax,es:[di].ln_ptfxA.ptfx_y.lo           ; BX:AX = y1
        add     bx,es:[di].ln_ptfxA.ptfx_y.hi
        mov     cx,es:[di].ln_ptfxC.ptfx_y.lo           ; DX:CX = y2
        add     dx,es:[di].ln_ptfxC.ptfx_y.hi

;/*
;** do Y flip
;*/
        test    si,LF_Y_FLIP
        jz      do_left_flips
        neg     ax
        adc     bx,0
        neg     bx
        neg     cx
        adc     dx,0
        neg     dx
        jmp     short do_left_flips

;/*
;** handle the x-major case
;*/
ptfx_x_major:
        neg     ax
        mov     bx,ax
        mov     dx,ax
        mov     ax,es:[di].ln_ptfxA.ptfx_x.lo           ; BX:AX = x1
        add     bx,es:[di].ln_ptfxA.ptfx_x.hi
        mov     cx,es:[di].ln_ptfxC.ptfx_x.lo           ; DX:CX = x2
        add     dx,es:[di].ln_ptfxC.ptfx_x.hi

;/*
;** do left flips
;*/
do_left_flips:
        test    si,LF_LEFT_XCHG
        jz      @F
        xchg    ax,cx
        xchg    bx,dx
@@:

;/*
;** take ceil(major1) and floor(major2)
;*/
        neg     ax
        adc     bx,0                        ; BX = ceil(x1), DX = floor(x2)
                                            ; we will render from BX to DX

;/*
;** clip off the first pel, if needed
;*/
        test    es:[di].ln_fs,CURVE_DO_FIRST_PEL
        jnz     all_clipping_done
        test    si,LF_LEFT_XCHG
        jnz     is_left_exchanged
        or      bx,bx
        jnz     all_clipping_done
        inc     bx
        jmp     short all_clipping_done
is_left_exchanged:
        mov     ax,lsg.lsg_cdx                ; AX = major extent
        cmp     dx,ax
        jb      all_clipping_done
        dec     ax
        mov     dx,ax
        inc     ax
        jnz     all_clipping_done        ; watch out for the zero length line!
        xor     dx,dx
        mov     bx,1
all_clipping_done:

;/*
;** remember the clip interval
;*/
        mov     lsg.lsg_xA,bx
        mov     lsg.lsg_xB,dx

;/*
;** do styling and half flip
;*/
        cmp     LineStyle,LINETYPE_SOLID - 1
        njz     ignore_styles

;----------start of max metric changes (bobgru)-----------------

        cmp     LineStyle,LINETYPE_ALTERNATE - 1
        jnz     determine_major_styling

        mov     ax,wStyleStepHorz
        mov     cx,ax                    ;wStyleStepVert = wStyleStepHorz
        mov     wStyleStepDiag,ax        ;wStyleStepDiag =        "
        jmp     short store_style_steps

;/*
;** Determine whether line is styled as x or y major.
;** If LF_XY_XCHG is true, then DI will be delta_y, but
;** we want it to be delta_x, so swap SI and DI.
;*/

determine_major_styling:
        mov     ax,wStyleStepHorz
        mov     bx,wStyleStepVert
        test    si,LF_XY_XCHG
        jz      @F
        xchg    ax,bx
@@:
        mov     wStyleStepHorzTmp,ax        ; really is major step
        mov     wStyleStepVertTmp,bx        ; really is minor step

        mul     lsg.lsg_cdx                ; DX:AX = major_step * delta_major
        xchg    ax,bx                        ; 
        mov     cx,dx                        ; save all 32 bits
        mul     lsg.lsg_cdy                ; DX:AX = minor step * delta_minor
        cmp     dx,cx
        jb      styled_as_expected
        ja      styled_as_opposite
        cmp     ax,bx
        ja      styled_as_opposite

styled_as_expected:
        mov     wStyleStepVertTmp,0        ; set minor step to 0
        jmp     short set_diag_style_step
styled_as_opposite:
        mov     wStyleStepHorzTmp,0        ; set major step to 0
set_diag_style_step:
        mov     ax,wStyleStepHorzTmp        ; take major step
        mov     cx,ax                        ; side step = major step +
        add     cx,wStyleStepVertTmp        ;              minor step

;/*
;** Determine major and side style steps.
;*/
store_style_steps:
        mov     wStyleStepRun,ax
        mov     wStyleStepDiag,ax
        mov     wStyleStepSide,cx

;/*
;**----------end of max metric changes (bobgru)-----------------
;** compute the change in style
;*/

        mov     bx,lsg.lsg_cdx                ; change = RunStep * (major - minor)
        sub     bx,lsg.lsg_cdy                ;         + SideStep * minor
        mul     bx
        xchg    ax,cx
        mul     lsg.lsg_cdy
        add     ax,cx                         ; AX = style change
        mov     bx,es:[di].ln_usStyle         ; BX = style at start
        add     ax,bx                         ; AX = style at finish


;/*
;** reverse the style if we've exchanged left for right
;*/
        mov     dx,wStyleMask
        test    si,LF_LEFT_XCHG
        jz      @F
        mov     bx,ax
        not     bx                        ; BX = style count to use
        mov     dl,dh                        ; DL = style mask to use
@@:     mov     bActiveStyleCounter,bl
        mov     cl,bh
        and     cl,7
        rol     dl,cl
        mov     bActiveStyleMask,dl

;/*
;** do the styling version of a half-flip
;*/
        mov     cx,lsg.lsg_cdx
        mov     dx,lsg.lsg_cdy
        mov     ax,dx
        add     ax,ax
        jc      flip_it_style                ; 2dy > dx -- half flip needed
        cmp     ax,cx
        jbe     @F                          ; 2dy <= dx -- no half flip needed
flip_it_style:
        sub     dx,cx
        neg     dx
        xor     si,LF_HALF_FLIP + LF_VERTICAL_FLIP

;/*
;** exchange the style steps
;*/
        mov     ax,wStyleStepRun
        xchg    ax,wStyleStepSide
        mov     wStyleStepRun,ax
        mov     wStyleStepDiag,ax
@@:
        jmp     short half_flips_done

;/*
;** do half flip for the non-styled case
;*/
ignore_styles:
        mov     cx,lsg.lsg_cdx
        mov     dx,lsg.lsg_cdy
        mov     ax,dx
        add     ax,ax
        jc      flip_it                  ; 2dy > dx -- half flip needed
        cmp     ax,cx
        jbe     half_flips_done         ; 2dy <= dx -- no half flip needed
flip_it:
        sub     dx,cx
        neg     dx
        xor     si,LF_HALF_FLIP + LF_VERTICAL_FLIP
half_flips_done:
        mov     lsg.lsg_cdx,cx
        mov     lsg.lsg_cdy,dx

;/*
;** save the flags
;*/
        mov     lsg.lsg_fsLineFlags,si

;/*
;** call the workhorse to compute the rendering
;*/
        mov     di,lsg.lsg_cdx
        mov     si,lsg.lsg_cdy
        mov     ax,lsg.lsg_xA                ; get rid of clipped lines
        cmp     ax,lsg.lsg_xB
        ja      drawlines_next
        call    polyline_workhorse_routine
drawlines_next:
        dec     Count
        njnz    drawlines_loop

;/*
;** restore any hardware defaults
;*/
        call    npfnUnSetup
        call    far_unexclude                ; I own the semaphore...

;/*
;** If the line is not solid and the background mix mode is not
;** transparent, then go back and draw the background line, unless we
;** have already.
;*/

        test    Flags,PF_DOING_BACKGROUND
        jnz     done_background
        cmp     LineStyle,LINETYPE_SOLID - 1
        jz      done_background
        mov     ds,CodeData
        assumes ds,Data
        mov     di,hddc.lo
        cmp     [di].ddc_la.la_ba.ba_bkmix,ROP_D    ; Leave alone
        je      done_background
        call    polyline_background_init
        assumes ds,nothing
        or      Flags,PF_DOING_BACKGROUND
        mov     es,lpph.sel                ; ES => path
        assumes es,nothing
        jmp     setup_drawlines

done_background:

        mov     ds,CodeData
        assumes ds,Data

drawing_all_done:

drawline_good_exit:
        mov     ax,returnvalue
drawline_exit:
        cwd
        fw_zero <es,cx>
cEnd

sEnd    Code

sBegin  BlueMoon
        assumes cs,BlueMoon

;/***************************************************************************
;*
;* FUNCTION NAME = DrawLinesCorrelate (cCurves)
;*
;* DESCRIPTION   = Performs correlation on the lines in the given path.
;*                 Registers Preserved:
;*                        DI,SI,BP,DS,ES
;*                 Registers Destroyed:
;*                        BX,CX,DX,GS
;*                 Calls:
;*                        clip_line
;*
;* INPUT         = DS:SI = DDC
;*                 ES:DI = curve
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX = 1 if no correlation
;*                 AX = 2 if correlation
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   DrawLinesCorrelate,<FAR,PUBLIC>,<si,di>
        parmW   cCurves
        localW  npCurve
        localV  lsg,%(SIZE LINESEGMENT)
cBegin
        ddc?    si

;/*
;** make sure the correlation rectangle is valid in the DDC
;*/
        test    [si].ddc_fb,DDC_CORR_INV
        jz      corr_is_valid
        push    es
        call    far_recalc_correlate_rect
        pop     es
corr_is_valid:

;/*
;** get the correlation rectangle
;*/
        CPUMode 386
        lgs     bx,[si].ddc_prddc
        assumes gs,nothing
        rddc?   gs,bx
        mov     ax,gs:[bx].rddc_rcsCorr.rcs_xLeft
        mov     cx,gs:[bx].rddc_rcsCorr.rcs_xRight
        mov     dx,gs:[bx].rddc_rcsCorr.rcs_yTop
        mov     bx,gs:[bx].rddc_rcsCorr.rcs_yBottom
        CPUMode 286

;/*
;** send null intersections home
;*/
        cmp     ax,cx
        jge     no_correlation
        cmp     bx,dx
        jge     no_correlation

;/*
;** stuff the test RECTS into the LINESEGMENT structure
;*/
        mov     lsg.lsg_rcsClip.rcs_xLeft,ax
        mov     lsg.lsg_rcsClip.rcs_yBottom,bx
        mov     lsg.lsg_rcsClip.rcs_xRight,cx
        mov     lsg.lsg_rcsClip.rcs_yTop,dx

;/*
;** loop through all the lines
;*/
correlate_loop:
        mov     npCurve,di

;/*
;** make sure it's a curve
;*/
ifdef FIREWALLS
        cmp     es:[di].ln_bIdent,CURVE_IDENTIFIER
        jz      @F
        rip     text,<Curve identifier invalid>
@@:
endif

;/*
;** only do the check if it's really a line
;*/
        cmp     es:[di].ln_bType,LINE_IDENTIFIER
        jnz     correlate_next

;/*
;** load up the line info in the registers
;*/
        lea     dx,[di].ln_ptfxA         ; for POINTFX clipping
        mov     bx,es:[di].ln_ptsA.pts_x ; (BX,CX) = point 1
        mov     cx,es:[di].ln_ptsA.pts_y
        mov     si,es:[di].ln_ptsC.pts_y ; (DI,SI) = point 2
        mov     di,es:[di].ln_ptsC.pts_x

;/*
;** clip the line against the RECTS
;*/
        push    bp
        lea     bp,lsg                        ; point to LineSegMENT structure
        call    far_clip_line
        pop     bp
;/*
;** correct for the first pel
;*/
        mov     dx,lsg.lsg_xA                ; DX = xA
        mov     bx,lsg.lsg_xB                ; BX = xB
        mov     cx,di                        ; CX = major extent
        mov     di,npCurve
        test    es:[di].ln_fs,CURVE_DO_FIRST_PEL
        jnz     corrected_for_first_pel
        jcxz    correlate_next                ; watch out for the zero length line!
        test    lsg.lsg_fsLineFlags,LF_LEFT_XCHG
        jnz     we_are_left_exchanged
        cmp     dx,1
        adc     dx,0
        jmp     short corrected_for_first_pel
we_are_left_exchanged:
        dec     cx
        cmp     cx,bx
        sbb     bx,0
corrected_for_first_pel:

;/*
;** check for a hit
;*/
        mov     ax,2
        cmp     dx,bx
        jbe     DrawLinesCorrelate_done

;/*
;** go to the next line
;*/
correlate_next:
        mov     di,es:[di].ln_npcvNext
        dec     cCurves
        jnz     correlate_loop

;/*
;** return the result
;*/
no_correlation:
        mov     ax,1
DrawLinesCorrelate_done:
cEnd

sEnd    BlueMoon

        end
