/*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.                                */
/*                                                                           */
/*****************************************************************************/
#pragma  pagesize(55)

/**************************************************************************
 *
 * SOURCE FILE NAME = MARKER.C
 *
 * DESCRIPTIVE NAME = Draw Marker Support
 *
 *
 * VERSION = V2.0
 *
 * DATE      09/18/88
 *
 * DESCRIPTION
 *             Contains functions to draw the supported marker types.
 *             Only PolyMarker is exported to the world.
 *
 * FUNCTIONS
 *             draw_polymarker_cross
 *             draw_polymarker_plus
 *             draw_polymarker_diamond
 *             draw_polymarker_square
 *             draw_polymarker_sixpointstar
 *             draw_polymarker_eightpointstar
 *             draw_polymarker_soliddiamond
 *             draw_polymarker_solidsquare
 *             draw_polymarker_dot
 *             draw_polymarker_circle
 *             PolyMarker
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "plotters.h"
#include "bounds.h"
#include "color.h"
#include "dispatch.h"
#include "error.h"
#include "marker.h"
#include "output.h"
#include "paths.h"
#include "utils.h"
#include "xforms.h"
#include "lockddc.h"

/*
** Local Function Declarations
*/

LOCAL VOID  draw_polymarker_cross(HDC,PPOINTL,PPOINTL);

LOCAL VOID  draw_polymarker_plus(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_diamond(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_square(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_sixpointstar(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_eightpointstar(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_soliddiamond(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_solidsquare(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_dot(HDC,PPOINTL,PPOINTL);
LOCAL VOID  draw_polymarker_circle(HDC,PPOINTL,PPOINTL);

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_cross
 *
 * DESCRIPTION   = Function to draw a crosshaired PolyMarker
 *
 *                                \ /
 *                                 X
 *                                /  *
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_cross(HDC hDC,PPOINTL pptlCenter,
                                             PPOINTL pptlSize)
{
  POINTL From,To;

  From.x = pptlCenter->x+((pptlSize->x *(707L/3L))/1000L);
  From.y = pptlCenter->y+((pptlSize->y *(707L/3L))/1000L);
  To.x = pptlCenter->x-((pptlSize->x *(707L/3L))/1000L);
  To.y = pptlCenter->y-((pptlSize->y *(707L/3L))/1000L);
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
  From.x = pptlCenter->x+((pptlSize->x *(707L/3L))/1000L);
  From.y = pptlCenter->y-((pptlSize->y *(707L/3L))/1000L);
  To.x = pptlCenter->x-((pptlSize->x *(707L/3L))/1000L);
  To.y = pptlCenter->y+((pptlSize->y *(707L/3L))/1000L);
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_plus
 *
 * DESCRIPTION   = Function to draw a plus-sign PolyMarker
 *
 *                                 ³
 *                               ÄÄÅÄÄ
 *                                 ³
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_plus(HDC hDC,PPOINTL pptlCenter,
                                            PPOINTL pptlSize)
{
  POINTL From,To;

  /*
  ** Draw Horizontal line
  */
  From.x = pptlCenter->x-pptlSize->x/3;
  From.y = pptlCenter->y;
  To.x = pptlCenter->x+pptlSize->x/3;
  To.y = pptlCenter->y;
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
  /*
  ** Draw Vertical line
  */
  From.x = pptlCenter->x;
  From.y = pptlCenter->y-pptlSize->y/3;
  To.x = pptlCenter->x;
  To.y = pptlCenter->y+pptlSize->y/3;
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_diamond
 *
 * DESCRIPTION   = Function to draw a diamond PolyMarker
 *
 *                                /  *                                \ /
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_diamond(HDC hDC,PPOINTL pptlCenter,
                                               PPOINTL pptlSize)
{
  POINTL To[4];

  To[3].x = pptlCenter->x - pptlSize->x/3;
  To[3].y = pptlCenter->y;
  To[0].x = pptlCenter->x;
  To[0].y = pptlCenter->y + pptlSize->y/3;
  To[1].x = pptlCenter->x + pptlSize->x/3;
  To[1].y = pptlCenter->y;
  To[2].x = pptlCenter->x;
  To[2].y = pptlCenter->y - pptlSize->y/3;
  GreSetCurrentPosition(hDC, &To[3]);
  GrePolyLine(hDC, To, 4L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_square
 *
 * DESCRIPTION   = Function to draw a square PolyMarker
 *
 *                               ÚÄÄÄ¿
 *                               ³   ³
 *                               ÀÄÄÄÙ
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_square(HDC hDC,PPOINTL pptlCenter,
                                              PPOINTL pptlSize)
{

  POINTL From,To[2];
  From.x = pptlCenter->x - pptlSize->x/3;
  From.y = pptlCenter->y - pptlSize->y/3;
  To[0].x = pptlCenter->x + pptlSize->x/3;
  To[0].y = pptlCenter->y + pptlSize->y/3;
  To[1].x = To[1].y = 0L;
  GreSetCurrentPosition(hDC, &From);
  GreBoxBoundary(hDC, To);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_sixpointstar
 *
 * DESCRIPTION   = Function to draw a six-pointed PolyMarker
 *
 *                               \³/
 *                                ³
 *                               /³ *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_sixpointstar(HDC hDC,PPOINTL pptlCenter,
                                                     PPOINTL pptlSize)
{
  POINTL From,To;

  From.x = pptlCenter->x;
  From.y = pptlCenter->y - pptlSize->y / 2;
  To.x   = pptlCenter->x;
  To.y   = pptlCenter->y + pptlSize->y / 2;
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
  From.x = pptlCenter->x + ((pptlSize->x * (866L/2L)) / 1000L);
  From.y = pptlCenter->y + ((pptlSize->y * (500L/2L)) / 1000L);
  To.x   = pptlCenter->x - ((pptlSize->x * (866L/2L)) / 1000L);
  To.y   = pptlCenter->y - ((pptlSize->y * (500L/2L)) / 1000L);
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
  From.x = pptlCenter->x - ((pptlSize->x * (866L/2L)) / 1000L);
  From.y = pptlCenter->y + ((pptlSize->y * (500L/2L)) / 1000L);
  To.x   = pptlCenter->x + ((pptlSize->x * (866L/2L)) / 1000L);
  To.y   = pptlCenter->y - ((pptlSize->y * (500L/2L)) / 1000L);
  GreSetCurrentPosition(hDC, &From);
  GrePolyLine(hDC, &To, 1L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_eightpointstar
 *
 * DESCRIPTION   = Function to draw an eight-pointed PolyMarker
 *
 *                               \³/
 *                              ÄÄÅÄÄ
 *                               /³ *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_eightpointstar(HDC hDC,PPOINTL pptlCenter,
                                                       PPOINTL pptlSize)
{
  draw_polymarker_cross(hDC, pptlCenter, pptlSize);
  draw_polymarker_plus(hDC, pptlCenter, pptlSize);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_soliddiamond
 *
 * DESCRIPTION   = Function to draw a filled diamond marker
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_soliddiamond(HDC hDC,PPOINTL pptlCenter,
                                                     PPOINTL pptlSize)
{
  POINTL To[4];

  To[3].x = pptlCenter->x - pptlSize->x / 3;
  To[3].y = pptlCenter->y;
  To[0].x = pptlCenter->x;
  To[0].y = pptlCenter->y + pptlSize->y / 3;
  To[1].x = pptlCenter->x + pptlSize->x / 3;
  To[1].y = pptlCenter->y;
  To[2].x = pptlCenter->x;
  To[2].y = pptlCenter->y - pptlSize->y / 3;
  GreBeginPath(hDC, 1L);
  GreSetCurrentPosition(hDC, &To[3]);
  GrePolyLine(hDC, To, 3L);
  GreEndPath(hDC, 0L);
  GreFillPath(hDC, 1L, 0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_solidsquare
 *
 * DESCRIPTION   = Function to draw a filled square marker
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_solidsquare(HDC hDC,PPOINTL pptlCenter,
                                                    PPOINTL pptlSize)
{
  POINTL To[4];

  To[3].x = pptlCenter->x - pptlSize->x / 3;
  To[3].y = pptlCenter->y - pptlSize->y / 3;
  To[0].x = pptlCenter->x + pptlSize->x / 3;
  To[0].y = pptlCenter->y - pptlSize->y / 3;
  To[1].x = pptlCenter->x + pptlSize->x / 3;
  To[1].y = pptlCenter->y + pptlSize->y / 3;
  To[2].x = pptlCenter->x - pptlSize->x / 3;
  To[2].y = pptlCenter->y + pptlSize->y / 3;
  GreBeginPath(hDC, 1L);
  GreSetCurrentPosition(hDC, &To[3]);
  GrePolyLine(hDC, To, 3L);
  GreEndPath(hDC, 0L);
  GreFillPath(hDC, 1L, 0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_dot
 *
 * DESCRIPTION   = Function to draw a small filled circle marker
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_dot(HDC hDC,PPOINTL pptlCenter,
                                           PPOINTL pptlSize)
{
  ARCPARAMS ArcParams;

  GreSetCurrentPosition(hDC, pptlCenter);
  ArcParams.lP = ArcParams.lQ = 1L;
  ArcParams.lR = ArcParams.lS = 0L;
  GreSetArcParameters(hDC, &ArcParams);
  GreBeginPath(hDC, 1L);
  GreFullArcBoundary(hDC, pptlSize->x / 3 * 65536);
  GreEndPath(hDC, 0L);
  GreFillPath(hDC, 1L, 0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = draw_polymarker_circle
 *
 * DESCRIPTION   = Function to draw a small filled circle marker
 *
 * INPUT         = hDC     - device context handle
 *                 pptlCenter - center of the Marker
 *                 pptlSize   - size of the Marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID  draw_polymarker_circle(HDC hDC,PPOINTL pptlCenter,
                                              PPOINTL pptlSize)
{
  ARCPARAMS ArcParams;

  GreSetCurrentPosition(hDC, pptlCenter);
  ArcParams.lP = ArcParams.lQ = 1L;
  ArcParams.lR = ArcParams.lS = 0L;
  GreSetArcParameters(hDC, &ArcParams);
  GreBeginPath(hDC, 1L);
  GreFullArcBoundary(hDC, pptlSize->x / 5 * 65536);
  GreEndPath(hDC, 0L);
  GreOutlinePath(hDC, 1L, 0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = PolyMarker (Exported)
 *
 * DESCRIPTION   = Draws a series of Markers at the specified locations.
 *
 *
 * INPUT         = hDC      - device context handle
 *                 pWrldPts - array of locations to place markers
 *                 nMarkers - Number of Markers
 *                 pDDC     - pointer to device driver cookie
 *                 FunN     - type of marker
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = GPI_OK    - Everything completed OK (always returned by us)
 * RETURN-ERROR  = GPI_ERROR - Failure. (May come from engine)
 *
 **************************************************************************/

LONG  PolyMarker(HDC hDC,PPOINTL pWrldPts,LONG nMarkers,PDDC pDDC,
                            ULONG ulFunN)
{
  ULONG ulRet;
  if(!(EnterDriver(pDDC)))
    return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGrePolyMarker( pDDC->hdcMemory, pWrldPts, nMarkers, ulFunN );
    LeaveDriver( pDDC );
    return( ulRet );
  }

  /*
  **    Place the markers at the locations indicated.  First one is
  **  placed at the current position,  following ones are placed at
  **  the locations specified in pWrldPts.  Finally  set the current
  **  position to the last point.
  */

  if (pDDC->DCState.mbnd.usSet != 0)
  {
    /*
    ** An engine job,  so forget about it.
    */
    LeaveDriver(pDDC);
    return (LONG)(*daPolyMarker)(hDC, pWrldPts, nMarkers, pDDC, ulFunN);
  }

  if (nMarkers > 0)
  {
    PPDEVICE pPDevice = pDDC->pPDevice;
    ULONG hSavedDC;
    POINTL ptlMarkSize;

    ptlMarkSize.x = (pDDC->DCState.mbnd.sizfxCell.cx + 32768L) / 65536L;
    ptlMarkSize.y = (pDDC->DCState.mbnd.sizfxCell.cy + 32768L) / 65536L;

    if (ulFunN & COM_BOUND)
    {
      SHORT Index = 0;
      SHORT Loop = (SHORT)nMarkers-1;
      RECTL Bounds;
      POINTL BndMarkOrig;
      POINTL ptlBndMarkSize;

      ptlBndMarkSize = ptlMarkSize;

      if (ulFunN & COM_TRANSFORM)
        convert_world_to_device(hDC, &ptlBndMarkSize, 1L, pDDC);
      BndMarkOrig = pDDC->DCState.LogPosition;

      do
      {
        Bounds.xLeft   = BndMarkOrig.x - (ptlBndMarkSize.x / 2L);
        Bounds.xRight  = BndMarkOrig.x + (ptlBndMarkSize.x / 2L);
        Bounds.yBottom = BndMarkOrig.y - (ptlBndMarkSize.y / 2L);
        Bounds.yTop    = BndMarkOrig.y + (ptlBndMarkSize.y / 2L);
        AccumulateBounds(hDC, &Bounds, pDDC, ulFunN);

        if (Loop)
        {
          BndMarkOrig = pWrldPts[Index++];

          if (ulFunN & COM_TRANSFORM)
            convert_world_to_device(hDC, &BndMarkOrig, 1L, pDDC);
        }
      }

      while (Loop--);
    }

    if (!check_marker_color(pDDC) || !(ulFunN & COM_DRAW))
    {
      if (nMarkers > 1L)
        GreSetCurrentPosition(hDC, &pWrldPts[nMarkers-2]);
    }
    else
      if ((hSavedDC = GreSaveDC(hDC)) != 0L)
      {
        SHORT Index = 0;
        SHORT Loop = (SHORT)nMarkers-1;
        POINTL ptlCenter;

        GreGetCurrentPosition(hDC, &ptlCenter);


        /*
        **  We set the area and line attributes to defaults as they
        **  may have been set to funky values (eg patterned fill) and
        **  we use area fill to fill-in the marker shape of solid
        **  markers.  The area fill is achieved by doing a
        **  begin:endarea around the polyline calls (look at the solid
        **  marker sub-functions).  After settting everything to
        **  defaults we set the global color and mix mode attributes
        **  to the those specified in the marker bundle and go draw
        **  them.  Finally the RestoreDC down at the end will undo all
        **  the fiddling around we are performing.
        */

        GreSetAttributes(hDC, PRIM_AREA, -1L, -1L, 0L);
        GreSetAttributes(hDC, PRIM_LINE, -1L, -1L, 0L);
        GreSetGlobalAttribute(hDC, ATYPE_COLOR,
                              pDDC->DCState.mbnd.lColor, 0L);
        GreSetGlobalAttribute(hDC, ATYPE_MIX_MODE,
                              pDDC->DCState.mbnd.usMixMode,
                              0L);

        if (!ptlMarkSize.x || !ptlMarkSize.y)
        {
          do
          {
            POINTL Temp;

            if (ptlMarkSize.x)          /* draw horizontal line              */
            {
              Temp.x = ptlCenter.x - (ptlMarkSize.x / 2);
              Temp.y = ptlCenter.y;
              GreSetCurrentPosition(hDC, &Temp);
              Temp.x =  ptlCenter.x + (ptlMarkSize.x / 2);
              Temp.y =  ptlCenter.y;
              GrePolyLine(hDC, &Temp, 1L);
            }
            else
              if (ptlMarkSize.y)        /* draw vertical line                */
              {
                Temp.x = ptlCenter.x;
                Temp.y = ptlCenter.y - (ptlMarkSize.y / 2);
                GreSetCurrentPosition(hDC, &Temp);
                Temp.x = ptlCenter.x;
                Temp.y = ptlCenter.y + (ptlMarkSize.y / 2);
                GrePolyLine(hDC, &Temp, 1L);
              }
              else                     /* collapse to point                 */
                draw_point(pDDC, &pDDC->DCState.LogPosition);

            if (Loop)
            {
              /*
              ** Move to next Marker
              */
              GreSetCurrentPosition(hDC, &pWrldPts[Index]);
              ptlCenter = pWrldPts[Index++];
            }
          } while (Loop--);

        }
        else
        {
          do
          {
            switch (pDDC->DCState.mbnd.usSymbol)
            {
              default  :
              case  MARKSYM_DEFAULT :
              case  MARKSYM_CROSS :
                draw_polymarker_cross(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_PLUS :
                draw_polymarker_plus(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_DIAMOND :
                draw_polymarker_diamond(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_SQUARE :
                draw_polymarker_square(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_SIXPOINTSTAR :
                draw_polymarker_sixpointstar(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_EIGHTPOINTSTAR :
                draw_polymarker_eightpointstar(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_SOLIDDIAMOND :
                draw_polymarker_soliddiamond(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_SOLIDSQUARE :
                draw_polymarker_solidsquare(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_DOT :
                draw_polymarker_dot(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_SMALLCIRCLE :
                draw_polymarker_circle(hDC, &ptlCenter, &ptlMarkSize);
                break;
              case  MARKSYM_BLANK :
                break;
            }

            if (Loop)
            {
              /*
              ** Move to next Marker
              */
              GreSetCurrentPosition(hDC, &pWrldPts[Index]);
              ptlCenter = pWrldPts[Index++];
            }
          } while (Loop--);

        }
        GreRestoreDC(hDC, hSavedDC);

        /*
        ** set current position which was destroyed by RestoreDC
        */
        GreSetCurrentPosition(hDC, &ptlCenter);
      }
  }

  LeaveDriver(pDDC);
  return  GPI_OK;
}

