;*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.
;*   11/04/91                     Cliff Levesque [cliffl] Cleanup and convert to
;*                                386 and above flat model, protected mode
;*                                32 bit operation.
;*
;*****************************************************************************/
        .386

        .xlist

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
INCL_GPIERRORS          equ        1
DINCL_ENABLE            equ        1
DINCL_BITMAP            equ        1

        OPTION  OLDSTRUCTS

        include pmgre.inc
        include driver.inc
        include fontmap.inc
        include assert.mac
        include extern.inc
        include protos.inc

        .list

        .MODEL FLAT
    
        ASSUME  CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT

        .DATA

        .CODE

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

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 = EAX = 1 
;* RETURN-ERROR  = EAX = 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

ALIGN 4
PolyMarker      PROC SYSCALL USES EBX edi esi, hdc:DWORD, lpPolyXY:DWORD,
                                           PolyN:DWORD, hddc:DWORD,
                                           FunN:DWORD
                LOCAL   marker_code_point:DWORD,
                        font_half_width:DWORD,
                        font_half_height:DWORD,
                        return_code:DWORD,
                        cPoints:DWORD,
                        aptl[BATCH_POINTS]:POINTL

        DebugMsg <PolyMarker, DISPATCH, marker, CLIFFL>

        cld
        mov        esi,hddc                ; ESI --> ddc
        mov        edx,esi
        ENTER_DRIVER2
        jc         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?       esi

        ASSUME  esi:PTR DDC

        mov        eax,PMERR_BITMAP_NOT_SELECTED
        test       [esi].ddc_fb,DDC_PRESENT
        jz         PolyMarker_bad_exit
        mov        eax,PMERR_INV_LENGTH_OR_COUNT
        cmp        PolyN,0
        jz         PolyMarker_good_exit

        test       FunN,COM_DEVICE
        jnz        normal                        ; we are forced to go through with it.
        test       [esi].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
        pop        esi
        pop        edi
        pop        ebx
        leave
        jmp        pfnDefPolyMarker        ;Pass it back to the engine
ALIGN 4

normal:

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

ifdef FIREWALLS

        test       [esi].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,[esi].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       [esi].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        have_marker_symbol
ALIGN 4

use_default_marker:

        mov        bl,MARKSYM_DEFAULT

have_marker_symbol:

        movzx      ebx,bl
        mov        marker_code_point,ebx
        test       [esi].ddc_ma.ma_fs,CA_MUST_MAP
        jz         no_code_page_map

        mov        edi,[esi].ddc_ma.ma_paus         ; get the code page vector
        or         edi,edi
        jz         no_code_page_map

        add        ebx,ebx                        ; shift this left
        mov        ebx,[edi][ebx]                ; get the real glyph point

no_code_page_map:

        mov        edi,[esi].ddc_ma.ma_pFont

;/*
;** "half_height is a misnomer here: what we want is
;** ((1/2)*(MaxAscender + MaxDescender)) - MaxDescender
;*/

        ASSUME  edi:PTR FOCAFONT

        movsx      eax,[edi].ff_fmMetrics.foca_yMaxAscender
        movsx      ecx,[edi].ff_fmMetrics.foca_yMaxDescender
        add        eax,ecx
        shr        eax,1

        assert     eax,GE,ecx

        sub        eax,ecx
        mov        font_half_height,eax

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

        mov        eax,ebx
        movsx      ecx,[edi].ff_fmMetrics.foca_usFirstChar
        cmp        eax,ecx
        jb         get_the_default
        cmp        ax,[edi].ff_fmMetrics.foca_usLastChar
        jbe        less_then_last

get_the_default:

        movsx      ebx,[edi].ff_fmMetrics.foca_usDefaultChar

less_then_last:

        sub        ebx,ecx                        ; zero base the symbol
        movsx      ecx,[edi].ff_fdDefinitions.fdh_usCellSize
        mov        eax,ecx
        mul        ebx
        xchg       ebx,eax

        ASSUME  edi:PTR FONTMAP

        movsx      eax,WORD PTR [edi].fsCharOffset[ebx][4]
        cmp        ecx,6
        jz         got_the_width
        mov        edx,eax          
        add        edx,edx          
        add        eax,edx          
        movsx      ecx,WORD PTR [edi].fsCharOffset[ebx][6] ; add the b and c space
        add        eax,ecx                                 ; add the b and c space
        add        eax,ecx                                 ; add the b and c space

got_the_width:

        shr        eax,1
        mov        font_half_width,eax

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

        mov        ebx,[esi].ddc_prddc        ; EBX = RDDC

        rddc?      ebx

        ASSUME  ebx:PTR RDDC

        mov        eax,[ebx].rddc_ptsCurPos.ptl_y
        sub        eax,font_half_height
        push       eax
        mov        eax,[ebx].rddc_ptsCurPos.ptl_x
        sub        eax,font_half_width
        push       eax
        mov        ecx,esp                        ; SS:CX -> marker position
        xor        eax,eax
        mov        edx,FunN        ; FunN - MSW is commands
        and        edx,NOT COM_TRANSFORM        ; already in screen coordinate
        mov        dx,NGreCharStringPos

        INVOKE  CharMarkerPos, hdc, ecx, 0, CHS_LEAVEPOS + CHS_START_XY,
                        1, ADDR marker_code_point, 0, 0, hddc, edx
 
        add        esp,size POINTL                ; free marker position

;/*
;** check correlation hit
;*/
        cmp        eax,1                        ; no need to check command flags
        je         no_correlation_hit
        mov        return_code,eax
        jb         PolyMarker_exit

no_correlation_hit:

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

        dec        PolyN                        ; we already did one
        jz         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        edx,hddc
        call       enter_driver
        jc         pm_exit_no_lock                ; DX:AX = 0 on error

        mov        ecx,PolyN                ; CX = count>0, SI = random
        cmp        ecx,BATCH_POINTS
        jb         count_is_small
        mov        ecx,BATCH_POINTS

count_is_small:

        sub        PolyN,ecx                ; decrement count remaining
        mov        cPoints,ecx

        .errnz     SIZE POINTL - 8

        shl        ecx,1                        ; CX = word count
        mov        esi,lpPolyXY
        lea        edi,aptl
        cld
        rep        movsd
        mov        lpPolyXY,esi                ; advance pointer
        sub        edi,SIZE POINTL                ; DI = last point
        mov        esi,hddc                ; SI = DDC

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

        mov        ebx,[esi].ddc_prddc

        rddc?      ebx
        
        ASSUME  edi:PTR POINTL, ebx:PTR RDDC

        mov        eax,[edi].ptl_x
        mov        [ebx].rddc_ptlWorldPos.ptl_x,eax
        mov        eax,[edi].ptl_y
        mov        [ebx].rddc_ptlWorldPos.ptl_y,eax

; transform points if asked to

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

; transform new position to WORLD coordinates

        rddc?      ebx

        lea        ebx,[ebx].rddc_ptlWorldPos.ptl_x

        .errnz     RDDC.rddc_ptlWorldPos.ptl_y-RDDC.rddc_ptlWorldPos.ptl_x-(SIZE POINTL / 2)

        INVOKE     convert_screen_world, ebx, 1                 ; ds:si = ddc

        or         eax,eax
        jz         jmp_PolyMarker_exit         
        jmp        points_converted_to_screen
ALIGN 4

;/*
;** transform all the points
;*/

points_are_world_coords:

        INVOKE     convert_world_screen, ADDR aptl, cPoints ; DS:SI = ddc
        or         eax,eax
        jnz        points_converted_to_screen

jmp_PolyMarker_exit:

        jmp        PolyMarker_exit         
ALIGN 4

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

points_converted_to_screen:

        mov        ebx,[esi].ddc_prddc

        rddc?      ebx

        mov        eax,[edi].ptl_x
        mov        [ebx].rddc_ptsCurPos.ptl_x,eax
        mov        eax,[edi].ptl_y
        mov        [ebx].rddc_ptsCurPos.ptl_y,eax

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

        lea        edi,aptl                 ; SS:DI = points array
        mov        eax,font_half_width
        mov        ebx,font_half_height
        xor        edx,edx
        mov        ecx,cPoints

center_loop:

        sub        [edi].ptl_x,eax
        sbb        [edi].ptl_x,edx
        sub        [edi].ptl_y,ebx
        sbb        [edi].ptl_y,edx
        add        edi,SIZE POINTL
        loop       center_loop

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

        lea        edi,aptl                 ; SS:DI = points array

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

output_marker_loop:

        xor        eax,eax
        lea        ebx,[esi].ddc_ma.ma_ch       ; DS:BX -> marker symbol
        mov        edx,FunN                     ; FunN - MSW is commands
        and        edx,NOT COM_TRANSFORM        ; already in screen coordinate

        INVOKE  CharMarkerPos, hdc, edi, 0, CHS_LEAVEPOS + CHS_START_XY,
                                1, ebx, 0, 0, hddc, edx
                         
;/*
;** check correlation hit
;*/

        cmp        eax,1                        ; no need to check command flags
        je         no_corr_hit
        jb         PolyMarker_exit         
        mov        return_code,eax

no_corr_hit:

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

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

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

        cmp        PolyN,0
        jnz        batchin_loop

PolyMarker_good_exit:

        mov        eax,return_code
        jmp        PolyMarker_exit
ALIGN 4

PolyMarker_bad_exit:

        save_error_code
        xor        eax,eax

PolyMarker_exit:

        call       leave_driver

pm_exit_no_lock:

        mov        ecx,eax

                RET

PolyMarker      ENDP

        end
