;*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 = MARKER.ASM
;*
;* DESCRIPTIVE NAME = 
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/27/87
;*
;* DESCRIPTION  Code for the PolyMarker routine
;*              
;* FUNCTIONS    PolyMarker
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/27/87                     Hock Lee [hockl] Wrote it.
;*   06/20/87                     Charles Whitmer [chuckwh] Updated the inner loop
;*                                to use the new SetCurrentPosition conventions.
;*   07/18/87                     Hock Lee [hockl] Modified for new DDI.
;*   10/07/87                     Hock Lee [hockl] Added correlation.
;*   11/07/87                     Hock Lee [hockl] Updated CharStringPos call.
;*   11/30/87                     Hock Lee [hockl] Added bounds.
;*****************************************************************************/
        .286p
        .xlist
        include cmacros.inc
INCL_GRE_MARKERS        equ                      1
INCL_GRE_LINES          equ                      1
INCL_GRE_STRINGS        equ                      1
INCL_FONTFILEFORMAT     equ                      1
INCL_DDIMISC            equ                      1
INCL_DEV                equ                      1
INCL_DDIBUNDLES         equ                      1
INCL_DDICOMFLAGS        equ                      1
        include pmgre.inc
        include driver.inc
        include display.inc
        include fontseg.inc
        include assert.mac
        include njmp.mac
        .list

        errcode <INV_IN_AREA,INV_IN_PATH,BITMAP_NOT_SELECTED>
        errcode <INV_LENGTH_OR_COUNT>

;/*
;**  Define the codepoint for the blank symbol.  The blank marker,
;**  MARKSYM_BLANK is 64, but we avoid lots of wasted font space by
;**  mapping it to codepoint 11, which should be the last codepoint in
;**  the font.  This mapping is entirely internal to the driver, so if
;**  the marker font is ever enlarged, the value of MARKSYM_ALLBACKGROUND
;**  can be changed to follow the end of the font.  Note that the user
;**  can only get this symbol by selecting codepoint MARKSYM_BLANK  --
;**  directly selecting MARKSYM_ALLBACKGROUND will cause display of the
;**  default symbol, MARKER_DEFAULT.
;*/

MARKSYM_ALLBACKGROUND   equ                      11
        .errnz  MARKSYM_ALLBACKGROUND - MARKSYM_SMALLCIRCLE - 1

        externFP DosGetResource
        externFP CharMarkerPos

sBegin  Data
        externD pfnDefPolyMarker
sEnd    Data            

sBegin  Code
        externNP        convert_screen_world
        externNP        convert_world_screen
        externNP        enter_driver
        externNP        leave_driver
sEnd

sBegin  BlueMoon
        assumes cs,BlueMoon

        externW         BlueMoonData
page

;/***************************************************************************
;*
;* FUNCTION NAME = PolyMarker
;*
;* DESCRIPTION   = Outputs a marker starting at the current position, using the 
;*                 array of x,y coordinate pairs passed.
;*                                                                                    
;*                 Upon completion, the current x,y position is the last point in
;*                 the array of x,y coordinates.
;*                                                                                    
;*                 If COM_CORRELATE is set in the command dword, then correlation     
;*                 will be performed.                                                 
;*
;* INPUT         = lpPolyXY    Points to an array of x,y coordinates.                  
;*                         An extra x,y pair will be passed at the start of the xy     
;*                         array (and not included in the count), as work space.       
;*                         The whole array may, if need be, be overwritten by the      
;*                         transformed coordinates.                                    
;*                 PolyN        Specifies the number of x,y pairs.                     
;*                                                                                     
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 1 
;* RETURN-ERROR  = AX = 0 (ERROR_BAD_INTEGER) 
;*
;*                   Pseudo-Code
;*
;* INT FAR PASCAL PolyMarker(lpPolyXY,PolyN,hdc,FunN)
;* {
;*   save current ddc_char_bundle;
;*   save last marker position;
;*   for (each marker)
;*   {
;*        set screen position;
;*       GreCharString(ddc_ma.ma_chymbol);
;*   }
;*   set screen position last marker position;
;*   return 1;
;* }
;*
;***************************************************************************/

BATCH_POINTS    equ     5

        check   PolyMarker,<hdc,pptl,cptl,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   PolyMarker,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   lpPolyXY
        parmD   PolyN
        parmD   hddc
        parmD   FunN
        localW  marker_code_point
        localW  font_half_width
        localW  font_half_height
        localW  return_code                       ; Return code incase correlation
        localW  cPoints
        localV  aptl,%(BATCH_POINTS * SIZE POINTL)
cBegin
        cld
        mov     ds,BlueMoonData
        assumes ds,Data
        mov     si,hddc.lo                        ; DS:SI --> ddc
        mov     dx,si
        call    enter_driver
        njc     pm_exit_no_lock                   ; DX:AX = 0 on error

;/*
;** Illegal to draw markers in area bracket
;*/

        no_path_area    PolyMarker_bad_exit,area,error

        mov     return_code,1                      ; Return code for success
        ddc?    si
        mov     ax,PMERR_BITMAP_NOT_SELECTED
        test    [si].ddc_fb,DDC_PRESENT
        njz     PolyMarker_bad_exit
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        cmp     PolyN.hi,0
        njnz    PolyMarker_bad_exit
        cmp     PolyN.lo,0
        njz     PolyMarker_good_exit

        test    FunN.hi,COM_DEVICE
        jnz     normal                            ; we are forced to go through with it.
        test    [si].ddc_ma.ma_fs,CA_VECTOR+CA_STRIKEOUT+CA_UNDERSCORE+CA_ITALIC+CA_BOLD
        jz      normal                  ; we can handle it

goto_engine:
        call    leave_driver
        mov     ax,ds
        mov     es,ax
        assumes es,Data
        cleanframe
        assumes ds,nothing
        jmp     pfnDefPolyMarker                 ;Pass it back to the engine

        assumes ds,Data
        assumes es,nothing

normal:

;/*
;**  illegal to draw RASTER markers in path bracket
;*/

ifdef FIREWALLS
        test    [si].ddc_ma.ma_fs,CA_VECTOR
        assert  Z
endif
        no_path_area    PolyMarker_bad_exit,path,error

;/*
;**  Get the marker codepoint.  If it's MARKSYM_ALLBACKGROUND (i.e. a privately
;**  valid codepoint not available to the caller), then map it to the default
;**  marker.  If it's MARKSYM_BLANK, then map it to MARKSYM_ALLBACKGROUND.
;**  This mapping saves us from having to store 64 symbols in our font,
;**  getting away with 11 instead.
;*/

        mov     bl,[si].ddc_ma.ma_ch

;/*
;**  if this is the not the default marker set then there's no need to worry about
;**    the space out at 64 and all that jazz
;*/

        test    [si].ddc_ma.ma_fs,CA_USER_FONT
        jnz     have_marker_symbol

        cmp     bl,MARKSYM_SMALLCIRCLE
        jbe     have_marker_symbol
        cmp     bl,MARKSYM_BLANK
        jne     use_default_marker
        mov     bl,MARKSYM_ALLBACKGROUND
        .errnz  MARKSYM_ALLBACKGROUND-MARKSYM_SMALLCIRCLE-1
        .errnz  MARKSYM_ALLBACKGROUND-11
        jmp     short have_marker_symbol
use_default_marker:
        mov     bl,MARKSYM_DEFAULT

public have_marker_symbol
have_marker_symbol:
        xor     bh,bh
        mov     marker_code_point,bx
        test    [si].ddc_ma.ma_fs,CA_MUST_MAP
        jz      no_code_page_map

        les     di,[si].ma_paus                  ; get the code page vector
        assumes es,nothing
        mov     cx,es
        or      cx,di
        jz      no_code_page_map

        add     bx,bx                             ; shift this left
        mov     bx,es:[di][bx]                    ; get the real glyph point

no_code_page_map:
        les     di,[si].ddc_ma.ca_pFont
        assumes es,nothing
;/*
;**  "half_height is a misnomer here: what we want is
;**  ((1/2)*(MaxAscender + MaxDescender)) - MaxDescender
;*/

        mov     ax,es:[di].ff_fmMetrics.foca_yMaxAscender
        mov     cx,es:[di].ff_fmMetrics.foca_yMaxDescender
        add     ax,cx
        shr     ax,1
        assert  ax,GE,cx
        sub     ax,cx
        mov     font_half_height,ax

;/*
;**  ok we got the real scan code now so lets map it to the default
;**    if necessary
;*/


        mov     ax,bx
        mov     cx,es:[di].ff_fmMetrics.foca_usFirstChar
        cmp     ax,cx
        jb      get_the_default
        cmp     ax,es:[di].ff_fmMetrics.foca_usLastChar
        jbe     less_then_last
get_the_default:
        mov     bx,es:[di].ff_fmMetrics.foca_usDefaultChar
less_then_last:
        sub     bx,cx                             ; zero base the symbol
        mov     cx,es:[di].ff_fdDefinitions.fdh_usCellSize
        mov     ax,cx
        mul     bx
        xchg    bx,ax

        mov     ax,word ptr es:[di].fsCharOffset[bx][4]
        cmp     cx,6
        jz      got_the_width
        mov     dx,ax                             ;!!! The abc code is off by the a space so we're adding
        add     dx,dx                             ;!!! in 2*aspace so when it gets divided by two, it includes
        add     ax,dx                             ;!!! (abcspace/2)+aspace.
        add     ax,word ptr es:[di].fsCharOffset[bx][6]     ; add the b and c space
        add     ax,word ptr es:[di].fsCharOffset[bx][8]

got_the_width:
        shr     ax,1
        mov     font_half_width,ax

;/*
;**  put out the first marker at the current position
;*/

        les     bx,[si].ddc_prddc                ; ES:BX = RDDC
        assumes es,nothing
        rddc?   es,bx

        mov     ax,es:[bx].rddc_ptsCurPos.pts_y
        sub     ax,font_half_height
        cwd
        push    dx                                ; marker Y position
        push    ax
        mov     ax,es:[bx].rddc_ptsCurPos.pts_x
        fw_zero <es>
        sub     ax,font_half_width
        push    dx                                ; marker X position (positive? !!!)
        push    ax
        mov     cx,sp                             ; SS:CX -> marker position

        xor     ax,ax

        lea     bx,marker_code_point
        mov     dx,seg_FunN                       ; FunN - MSW is commands
        and     dx,NOT COM_TRANSFORM              ; already in screen coordinate
        farPtr  MyXY,ss,cx
        farPtr  MyRect,ax,ax
        farPtr  MyOptions,ax,CHS_LEAVEPOS+CHS_START_XY ; don't destroy current position
        farPtr  MyN,ax,1
        farPtr  MyCh,ss,bx
        farPtr  MyDx,ax,ax
        farPtr  MyAttrs,ax,ax
        farPtr  FuncNum,dx,off_CharStringPos
        check   CharStringPos,<hdc,pptlStart,prclOpaque,flCmd,cch,pch,pdx,pcspAttrs,hddc,ulFunN>
        cCall   CharMarkerPos,<hdc,MyXY,MyRect,MyOptions,MyN,MyCh,MyDx,MyAttrs,hddc,FuncNum>
        add     sp,size POINTL                    ; free marker position

;/*
;**  check correlation hit
;*/

        cmp     ax,1                              ; no need to check command flags
        je      no_correlation_hit
        mov     return_code,ax
        njb     PolyMarker_exit
no_correlation_hit:

;/*
;**  see if there are more to do!
;*/

        dec     PolyN.lo                          ; we already did one
        njz     PolyMarker_good_exit

;/*
;**  batch them into the local space
;*/

batchin_loop:

;/*
;**  We give other processes waiting on display driver semaphore a break
;**  in each BATCH_POINTS loop by temporarily releasing the semaphore.
;**  This way the window manager will not be held up too long.
;*/

        call    leave_driver
        mov     dx,hddc.lo
        call    enter_driver
        njc     pm_exit_no_lock                   ; DX:AX = 0 on error

        mov     cx,PolyN.lo                       ; CX = count>0, SI = random
        cmp     cx,BATCH_POINTS
        jb      count_is_small
        mov     cx,BATCH_POINTS
count_is_small:
        sub     PolyN.lo,cx                       ; decrement count remaining
        mov     cPoints,cx
        .errnz  SIZE POINTL - 8
        shl     cx,2                              ; CX = word count
        lds     si,lpPolyXY
        assumes ds,nothing
        mov     ax,ss
        mov     es,ax                             ; ES = SS
        assumes es,nothing
        lea     di,aptl
        cld
        rep     movsw
        mov     lpPolyXY.lo,si                    ; advance pointer
        mov     ds,BlueMoonData
        assumes ds,Data
        sub     di,SIZE POINTL                    ; DI = last point
        mov     si,hddc.lo                        ; SI = DDC

;/*
;**  the last one will be the new position (WORLD coord)
;*/

        CPUMode 386
        les     bx,[si].ddc_prddc
        assumes es,nothing
        rddc?   es,bx
        mov     eax,ss:[di].ptl_x
        mov     es:[bx].rddc_ptlWorldPos.ptl_x,eax
        mov     eax,ss:[di].ptl_y
        mov     es:[bx].rddc_ptlWorldPos.ptl_y,eax
        CPUMode 286
    
;/*
;**  transform points if asked to
;*/

        test    seg_FunN,COM_TRANSFORM            ; FunN - MSW is commands
        jnz     points_are_world_coords

;/*
;**  transform new position to WORLD coordinates
;*/

        rddc?   es,bx
        lea     bx,[bx].rddc_ptlWorldPos.ptl_x
        .errnz  rddc_ptlWorldPos.ptl_y-rddc_ptlWorldPos.ptl_x-(SIZE POINTL / 2)
        farPtr  lp_point,es,bx
        cCall   convert_screen_world,<lp_point,1> ; ds:si = ddc
        or      ax,ax
        jz      jmp_PolyMarker_exit              ; what about ddc attributes recovery?!!!
        jmp     short points_converted_to_screen

; transform all the points

points_are_world_coords:

        lea     dx,aptl
        farPtr  lp_point,ss,dx
        cCall   convert_world_screen,<lp_point,cPoints>      ; DS:SI = ddc
        or      ax,ax
        jnz     points_converted_to_screen
jmp_PolyMarker_exit:
        jmp     PolyMarker_exit                  ; what about ddc attributes recovery?!!!

;/*
;**  save the new current position in SCREEN coordinates
;*/

points_converted_to_screen:

        les     bx,[si].ddc_prddc
        assumes es,nothing
        rddc?   es,bx
        mov     ax,ss:[di].ptl_x.lo
        mov     es:[bx].rddc_ptsCurPos.pts_x,ax
        mov     ax,ss:[di].ptl_y.lo
        mov     es:[bx].rddc_ptsCurPos.pts_y,ax
        fw_zero <es>

;/*
;**  center the points in the character box
;*/

        lea     di,aptl                           ; SS:DI = points array
        mov     ax,font_half_width
        mov     bx,font_half_height
        xor     dx,dx
        mov     cx,cPoints
center_loop:
        sub     ss:[di].ptl_x.lo,ax
        sbb     ss:[di].ptl_x.hi,dx
        sub     ss:[di].ptl_y.lo,bx
        sbb     ss:[di].ptl_y.hi,dx
        add     di,SIZE POINTL
        loop    center_loop

;/*
;**  output one marker at a time
;**    DS:SI --> DDC
;*/

        lea     di,aptl                           ; SS:DI = points array

;/*
;**  make the CharStringPos call
;*/

output_marker_loop:
        xor     ax,ax
        lea     bx,[si].ddc_ma.ma_ch              ; DS:BX -> marker symbol
        mov     dx,seg_FunN                       ; FunN - MSW is commands
        and     dx,NOT COM_TRANSFORM              ; already in screen coordinate
        farPtr  MyXY,ss,di
        farPtr  MyRect,ax,ax
        farPtr  MyOptions,ax,CHS_LEAVEPOS+CHS_START_XY ; don't destroy current position
        farPtr  MyN,ax,1
        farPtr  MyCh,ds,bx
        farPtr  MyDx,ax,ax
        farPtr  MyAttrs,ax,ax
        farPtr  FuncNum,dx,off_CharStringPos
        check   CharStringPos,<hdc,pptlStart,prclOpaque,flCmd,cch,pch,pdx,pcspAttrs,hddc,ulFunN>
        cCall   CharMarkerPos,<hdc,MyXY,MyRect,MyOptions,MyN,MyCh,MyDx,MyAttrs,hddc,FuncNum>

;/*
;**  check correlation hit
;*/

        cmp     ax,1                              ; no need to check command flags
        je      no_corr_hit
        jb      PolyMarker_exit                   ; what about ddc attributes recovery?!!!
        mov     return_code,ax
no_corr_hit:

;/*
;**  finish inner loop
;*/

        add     di,SIZE POINTL                    ; advance to next point
        dec     cPoints
        jnz     output_marker_loop

;/*
;**  finish batch loop
;*/

        cmp     PolyN.lo,0
        njnz    batchin_loop

PolyMarker_good_exit:
        mov     ax,return_code
        jmp     short PolyMarker_exit

PolyMarker_bad_exit:
        save_error_code
        xor     ax,ax
        errn$   PolyMarker_exit

PolyMarker_exit:
        cwd
        call    leave_driver
pm_exit_no_lock:
        mov     cx,ax

cEnd

sEnd    BlueMoon

        end
