/*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 = COLOR.C
 *
 * DESCRIPTIVE NAME = PLOTTER DRIVER SOURCE CODE
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION File contains OS/2 Plotter driver color/pen and pattern
 *             support functions.
 *
 *
 * FUNCTIONS  check_color_sorting          Determine the nearest pen color
 *            check_saved_color_tables()   recursively checks any saved DDCs
 *            color_distance()             return the distance between two
 *            constrain_hls                Constrain an HLS color
 *            convert_color()              accepts a color in the
 *                                         current device
 *
 *            get_closest_color()          get closest color
 *            get_closest_pen              returns the stall number of the pen
 *            get_color_group()            get color group
 *            rgb_to_hls()                 convert an RGB color value
 *                                         to HLS format
 *            locate_pen()                 finds the closest available pen
 *            locate_HPGL2pen()            finds the closest available HPGL2 pen
 *            select_user_defined_pen()    select a user defined pen
 *            select_HPGL2pen()            select a dynamic hpgl2 pen
 *            check_area_color()           check area color
 *            check_char_color()           check character color
 *            check_line_color()           check line color
 *            check_marker_color()         check marker color
 *            create_default_color_table() generates the default color
 *                                         table used by PLOTTERS
 *            start_color_sorting()        sets up PLOTTERS to begin
 *                                         color sorting.
 *            stop_color_sorting()         stop color sorting
 *            select_line_color()          select line color
 *            select_fill_pen()            select fill pen
 *            select_fill_type()           select fill type
 *            select_text_pen()            select text pen
 *            CreateLogColorTable()        create logical color table
 *            QueryColorData()             Query current color data
 *            QueryColorIndex()            Query color index
 *            QueryLogColorTable()         Query logical color table
 *            QueryNearestColor()          Query nearest color
 *            QueryRealColors()            QueryRealColors
 *            QueryRGBColor()              Query RGB color
 *            RealizeColorTable()          Realize color table
 *            UnrealizeColorTable()        Unrealize color table
 *            set_transparency_mode()      Sets the white TR mode
 *
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#define  INCL_32
#define  INCL_GPIBITMAP
#define  INCL_GPILOGCOLORTABLE
#define  INCL_GRE_JOURNALING

#include "plotters.h"
#include "color.h"
#include "attribs.h"
#include "dialog.h"
#include "dosio.h"
#include "error.h"
#include "output.h"
#include "utils.h"
#include "dispatch.h"

#define  HLS           0
#define  JOURNAL_OPTS  ( JNL_TEMP_FILE )
#define  COM_SAVE      0x10000000L     /* MarkV                             */

#define  FT_SOLID_BIDIRECTIONAL  1
#define  FT_SOLID_UNIDIRECTIONAL 2
#define  FT_HATCHED              3     /* parallel                          */
#define  FT_CROSS_HATCH          4
#define  FT_SHADING             10     /* HPGL2 only                        */
#define  FT_USER_DEFINED        11     /* HPGL2 only                        */


LONG ColorList[MAX_COLORS] =
{
  { COLOR_YELLOW } ,
  { COLOR_ORANGE } ,
  { COLOR_RED } ,
  { COLOR_GREEN } ,
  { COLOR_PINK } ,                    /* RED_VIOLET */
  { COLOR_CYAN } ,                    /* AQUA       */
  { COLOR_VIOLET } ,
  { COLOR_BLUE } ,
  { COLOR_BROWN } ,
  { COLOR_BLACK } ,
  { COLOR_WHITE } ,
  { COLOR_PALEGRAY } ,
  { COLOR_DARKBLUE } ,
  { COLOR_DARKRED } ,
  { COLOR_DARKPINK } ,
  { COLOR_DARKGREEN } ,
  { COLOR_DARKCYAN } ,
  { COLOR_DARKGRAY } ,
  { COLOR_LIGHTGRAY } ,
  { COLOR_REDGRAY } ,
  { COLOR_GREENGRAY } ,
  { COLOR_BLUEGRAY } ,
  { COLOR_BLUSH } ,
  { COLOR_LIGHTRED } ,
  { COLOR_CRIMSON } ,
  { COLOR_BRICKRED } ,
  { COLOR_BRICKGRAY } ,
  { COLOR_SAND } ,
  { COLOR_SALMON } ,
  { COLOR_PUMPKIN } ,
  { COLOR_CHESTNUT } ,
  { COLOR_SIENNABROWN } ,
  { COLOR_TAN } ,
  { COLOR_DARKTAN } ,
  { COLOR_BUFF } ,
  { COLOR_LIGHTPEACH } ,
  { COLOR_DARKPEACH } ,
  { COLOR_LIGHTBROWN } ,
  { COLOR_DARKBROWN } ,
  { COLOR_IVORY } ,
  { COLOR_DARKIVORY } ,
  { COLOR_PARCHMENT } ,
  { COLOR_PALEYELLOW } ,
  { COLOR_GOLD } ,
  { COLOR_DARKGOLD } ,
  { COLOR_UMBER } ,
  { COLOR_STRAW } ,
  { COLOR_DARKSTRAW } ,
  { COLOR_PALEGREEN } ,
  { COLOR_LIGHTGREEN } ,
  { COLOR_LEAFGREEN } ,
  { COLOR_DEEPGREEN } ,
  { COLOR_MOSS } ,
  { COLOR_DARKMOSS } ,
  { COLOR_MINTGREEN } ,
  { COLOR_SEAGREEN } ,
  { COLOR_LIGHTEMERALD } ,
  { COLOR_EMERALD } ,
  { COLOR_DARKEMERALD } ,
  { COLOR_EVERGREEN } ,
  { COLOR_DARKGREENGRAY } ,
  { COLOR_SEAFOAM } ,
  { COLOR_LIGHTAQUA } ,
  { COLOR_AQUA } ,
  { COLOR_TURQUOISE } ,
  { COLOR_SPRUCE } ,
  { COLOR_SEAGRAY } ,
  { COLOR_SPRUCEGRAY } ,
  { COLOR_PASTELBLUE } ,
  { COLOR_BABYBLUE } ,
  { COLOR_SKYBLUE } ,
  { COLOR_CERULEAN } ,
  { COLOR_TRUEBLUE } ,
  { COLOR_SLATEBLUE } ,
  { COLOR_COOLGRAY } ,
  { COLOR_COLDGRAY } ,
  { COLOR_ICEBLUE } ,
  { COLOR_CORNFLOWER } ,
  { COLOR_DUSTYBLUE } ,
  { COLOR_ROYALBLUE } ,
  { COLOR_FLAGBLUE } ,
  { COLOR_MIDNIGHTBLUE } ,
  { COLOR_DARKBLUEGRAY } ,
  { COLOR_LAVENDAR } ,
  { COLOR_DARKLAVENDAR } ,
  { COLOR_LILAC } ,
  { COLOR_DARKVIOLET } ,
  { COLOR_INDIGO } ,
  { COLOR_LILACGRAY } ,
  { COLOR_VIOLETGRAY } ,
  { COLOR_PURPLEWASH } ,
  { COLOR_PALEPURPLE } ,
  { COLOR_LIGHTPURPLE } ,
  { COLOR_PURPLE } ,
  { COLOR_GRAPE } ,
  { COLOR_DARKGRAPE } ,
  { COLOR_LIGHTPURPLEGRAY } ,
  { COLOR_PURPLEGRAY } ,
  { COLOR_PALEPINK } ,
  { COLOR_HOTPINK } ,
  { COLOR_LIGHTMAGENTA } ,
  { COLOR_MAGENTA } ,
  { COLOR_DARKMAGENTA } ,
  { COLOR_PLUM } ,
  { COLOR_LIGHTPLUMGRAY } ,
  { COLOR_PLUMGRAY } ,
  { COLOR_PALEROSE } ,
  { COLOR_LIGHTROSE } ,
  { COLOR_ROSE } ,
  { COLOR_DARKROSE } ,
  { COLOR_BURGUNDY } ,
  { COLOR_DARKBURGUNDY } ,
  { COLOR_SANDSTONE } ,
  { COLOR_DARKSANDSTONE } ,
  { COLOR_D3PCTGRAY } ,
  { COLOR_D6PCTGRAY } ,
  { COLOR_D13PCTGRAY } ,
  { COLOR_D19PCTGRAY } ,
  { COLOR_D31PCTGRAY } ,
  { COLOR_D38PCTGRAY } ,
  { COLOR_D44PCTGRAY } ,
  { COLOR_D56PCTGRAY } ,
  { COLOR_D63PCTGRAY } ,
  { COLOR_D69PCTGRAY } ,
  { COLOR_D75PCTGRAY } ,
  { COLOR_D81PCTGRAY }
} ;


/*
** The follow palettes were taken from the engine.
** We will use the 256 hardware palette as a default.
*/
ULONG ulDefaultPalette256[256] =
      {
         /**************************************************************/
         /* start off with the first half of the colors                */
         /**************************************************************/
         0x80000000, 0x80000055, 0x800000AA, 0x800000FF,
         0x80002400, 0x80002455, 0x800024AA, 0x800024FF,
         0x80004900, 0x80004955, 0x800049AA, 0x800049FF,
         0x80006D00, 0x80006D55, 0x80006DAA, 0x80006DFF,
         0x80009200, 0x80009255, 0x800092AA, 0x800092FF,
         0x8000B600, 0x8000B655, 0x8000B6AA, 0x8000B6FF,
         0x8000DB00, 0x8000DB55, 0x8000DBAA, 0x8000DBFF,
         0x8000FF00, 0x8000FF55, 0x8000FFAA, 0x8000FFFF,

         0x802B0000, 0x802B0055, 0x802B00AA, 0x802B00FF,
         0x802B2400, 0x802B2455, 0x802B24AA, 0x802B24FF,
         0x802B4900, 0x802B4955, 0x802B49AA, 0x802B49FF,
         0x802B6D00, 0x802B6D55, 0x802B6DAA, 0x802B6DFF,
         0x802B9200, 0x802B9255, 0x802B92AA, 0x802B92FF,
         0x802BB600, 0x802BB655, 0x802BB6AA, 0x802BB6FF,
         0x802BDB00, 0x802BDB55, 0x802BDBAA, 0x802BDBFF,
         0x802BFF00, 0x802BFF55, 0x802BFFAA, 0x802BFFFF,

         0x80550000, 0x80550055, 0x805500AA, 0x805500FF,
         0x80552400, 0x80552455, 0x805524AA, 0x805524FF,
         0x80554900, 0x80554955, 0x805549AA, 0x805549FF,
         0x80556D00, 0x80556D55, 0x80556DAA, 0x80556DFF,
         0x80559200, 0x80559255, 0x805592AA, 0x805592FF,
         0x8055B600, 0x8055B655, 0x8055B6AA, 0x8055B6FF,
         0x8055DB00, 0x8055DB55, 0x8055DBAA, 0x8055DBFF,
         0x8055FF00, 0x8055FF55, 0x8055FFAA, 0x8055FFFF,

         0x80800000, 0x80800055, 0x808000AA, 0x808000FF,
         0x80802400, 0x80802455, 0x808024AA, 0x808024FF,
         0x80804900, 0x80804955, 0x808049AA, 0x808049FF,
         0x80806D00, 0x80806D55, 0x80806DAA, 0x80806DFF,

         /**************************************************************/
         /* now come the group of 32 greys                             */
         /**************************************************************/
         0x80080808, 0x800F0F0F, 0x80171717, 0x801F1F1F,
         0x80272727, 0x802E2E2E, 0x80363636, 0x803E3E3E,
         0x80464646, 0x804D4D4D, 0x80555555, 0x805D5D5D,
         0x80646464, 0x806C6C6C, 0x80747474, 0x807C7C7C,
         0x80838383, 0x808B8B8B, 0x80939393, 0x809B9B9B,
         0x80A2A2A2, 0x80AAAAAA, 0x80B2B2B2, 0x80B9B9B9,
         0x80C1C1C1, 0x80C9C9C9, 0x80D1D1D1, 0x80D8D8D8,
         0x80E0E0E0, 0x80E8E8E8, 0x80F0F0F0, 0x80F7F7F7,

         /**************************************************************/
         /* now back to the colours again                              */
         /**************************************************************/
         0x80809200, 0x80809255, 0x808092AA, 0x808092FF,
         0x8080B600, 0x8080B655, 0x8080B6AA, 0x8080B6FF,
         0x8080DB00, 0x8080DB55, 0x8080DBAA, 0x8080DBFF,
         0x8080FF00, 0x8080FF55, 0x8080FFAA, 0x8080FFFF,

         0x80AA0000, 0x80AA0055, 0x80AA00AA, 0x80AA00FF,
         0x80AA2400, 0x80AA2455, 0x80AA24AA, 0x80AA24FF,
         0x80AA4900, 0x80AA4955, 0x80AA49AA, 0x80AA49FF,
         0x80AA6D00, 0x80AA6D55, 0x80AA6DAA, 0x80AA6DFF,
         0x80AA9200, 0x80AA9255, 0x80AA92AA, 0x80AA92FF,
         0x80AAB600, 0x80AAB655, 0x80AAB6AA, 0x80AAB6FF,
         0x80AADB00, 0x80AADB55, 0x80AADBAA, 0x80AADBFF,
         0x80AAFF00, 0x80AAFF55, 0x80AAFFAA, 0x80AAFFFF,

         0x80D50000, 0x80D50055, 0x80D500AA, 0x80D500FF,
         0x80D52400, 0x80D52455, 0x80D524AA, 0x80D524FF,
         0x80D54900, 0x80D54955, 0x80D549AA, 0x80D549FF,
         0x80D56D00, 0x80D56D55, 0x80D56DAA, 0x80D56DFF,
         0x80D59200, 0x80D59255, 0x80D592AA, 0x80D592FF,
         0x80D5B600, 0x80D5B655, 0x80D5B6AA, 0x80D5B6FF,
         0x80D5DB00, 0x80D5DB55, 0x80D5DBAA, 0x80D5DBFF,
         0x80D5FF00, 0x80D5FF55, 0x80D5FFAA, 0x80D5FFFF,

         0x80FF0000, 0x80FF0055, 0x80FF00AA, 0x80FF00FF,
         0x80FF2400, 0x80FF2455, 0x80FF24AA, 0x80FF24FF,
         0x80FF4900, 0x80FF4955, 0x80FF49AA, 0x80FF49FF,
         0x80FF6D00, 0x80FF6D55, 0x80FF6DAA, 0x80FF6DFF,
         0x80FF9200, 0x80FF9255, 0x80FF92AA, 0x80FF92FF,
         0x80FFB600, 0x80FFB655, 0x80FFB6AA, 0x80FFB6FF,
         0x80FFDB00, 0x80FFDB55, 0x80FFDBAA, 0x80FFDBFF,
         0x80FFFF00, 0x80FFFF55, 0x80FFFFAA, 0x80FFFFFF

      };
#if 0
/**********************************************************************/
/* The 128 entry palette has the following structure:                 */
/*                                                                    */
/* The middle 8 entries form an increasing grey scale.                */
/* The colours are the entries 0-59 and 68-127.                       */
/* The order of the colour entries is:                                */
/*     for each Red value in the group       00,40,80,C0,FF           */
/*       for each Green value in the group   00,33,66,99,CC,FF        */
/*         for each Blue value in the group  00,55,AA,FF              */
/*           RGB is Red,Green,Blue                                    */
/*         endfor                                                     */
/*       endfor                                                       */
/*     endfor                                                         */
/*                                                                    */
/**********************************************************************/
ULONG ulDefaultPalette128[128] =
      {
         /**************************************************************/
         /* start off with the first half of the colors                */
         /**************************************************************/
         0x80000000, 0x80000055, 0x800000AA, 0x800000FF,
         0x80003300, 0x80003355, 0x800033AA, 0x800033FF,
         0x80006600, 0x80006655, 0x800066AA, 0x800066FF,
         0x80009900, 0x80009955, 0x800099AA, 0x800099FF,
         0x8000CC00, 0x8000CC55, 0x8000CCAA, 0x8000CCFF,
         0x8000FF00, 0x8000FF55, 0x8000FFAA, 0x8000FFFF,

         0x80400000, 0x80400055, 0x804000AA, 0x804000FF,
         0x80403300, 0x80403355, 0x804033AA, 0x804033FF,
         0x80406600, 0x80406655, 0x804066AA, 0x804066FF,
         0x80409900, 0x80409955, 0x804099AA, 0x804099FF,
         0x8040CC00, 0x8040CC55, 0x8040CCAA, 0x8040CCFF,
         0x8040FF00, 0x8040FF55, 0x8040FFAA, 0x8040FFFF,

         0x80800000, 0x80800055, 0x808000AA, 0x808000FF,
         0x80803300, 0x80803355, 0x808033AA, 0x808033FF,
         0x80806600, 0x80806655, 0x808066AA, 0x808066FF,

         /**************************************************************/
         /* now the 8 gray scales                                      */
         /**************************************************************/
         0x801C1C1C, 0x80383838, 0x80545454, 0x80707070,
         0x808C8C8C, 0x80A8A8A8, 0x80C4C4C4, 0x80E0E0E0,

         /**************************************************************/
         /* now the last half of the colors                            */
         /**************************************************************/
         0x80809900, 0x80809955, 0x808099AA, 0x808099FF,
         0x8080CC00, 0x8080CC55, 0x8080CCAA, 0x8080CCFF,
         0x8080FF00, 0x8080FF55, 0x8080FFAA, 0x8080FFFF,

         0x80C00000, 0x80C00055, 0x80C000AA, 0x80C000FF,
         0x80C03300, 0x80C03355, 0x80C033AA, 0x80C033FF,
         0x80C06600, 0x80C06655, 0x80C066AA, 0x80C066FF,
         0x80C09900, 0x80C09955, 0x80C099AA, 0x80C099FF,
         0x80C0CC00, 0x80C0CC55, 0x80C0CCAA, 0x80C0CCFF,
         0x80C0FF00, 0x80C0FF55, 0x80C0FFAA, 0x80C0FFFF,

         0x80FF0000, 0x80FF0055, 0x80FF00AA, 0x80FF00FF,
         0x80FF3300, 0x80FF3355, 0x80FF33AA, 0x80FF33FF,
         0x80FF6600, 0x80FF6655, 0x80FF66AA, 0x80FF66FF,
         0x80FF9900, 0x80FF9955, 0x80FF99AA, 0x80FF99FF,
         0x80FFCC00, 0x80FFCC55, 0x80FFCCAA, 0x80FFCCFF,
         0x80FFFF00, 0x80FFFF55, 0x80FFFFAA, 0x80FFFFFF
    };

/**********************************************************************/
/* The 64 entry palette has the following structure:                  */
/*                                                                    */
/* The middle 4 entries form an increasing grey scale.                */
/* The colours are the entries 0-29 and 34-63.                        */
/* The order of the colour entries is:                                */
/*     for each Red value in the group       00,55,AA,FF              */
/*       for each Green value in the group   00,40,80,C0,FF           */
/*         for each Blue value in the group  00,80,FF                 */
/*           RGB is Red,Green,Blue                                    */
/*         endfor                                                     */
/*       endfor                                                       */
/*     endfor                                                         */
/*                                                                    */
/**********************************************************************/
ULONG ulDefaultPalette64[64] =
      {
         /**************************************************************/
         /* start off with the first half of the colors                */
         /**************************************************************/
         0x80000000, 0x80000080, 0x800000FF,
         0x80004000, 0x80004080, 0x800040FF,
         0x80008000, 0x80008080, 0x800080FF,
         0x8000C000, 0x8000C080, 0x8000C0FF,
         0x8000FF00, 0x8000FF80, 0x8000FFFF,

         0x80550000, 0x80550080, 0x805500FF,
         0x80554000, 0x80554080, 0x805540FF,
         0x80558000, 0x80558080, 0x805580FF,
         0x8055C000, 0x8055C080, 0x8055C0FF,
         0x8055FF00, 0x8055FF80, 0x8055FFFF,

         /**************************************************************/
         /* now the 4 gray scales (these are the same as 4 of the      */
         /* grays in the 32 entry palette).                            */
         /**************************************************************/
         0x80555555, 0x80808080, 0x80A6A6A6, 0x80CCCCCC,

         /**************************************************************/
         /* now the last half of the colors                            */
         /**************************************************************/
         0x80AA0000, 0x80AA0080, 0x80AA00FF,
         0x80AA4000, 0x80AA4080, 0x80AA40FF,
         0x80AA8000, 0x80AA8080, 0x80AA80FF,
         0x80AAC000, 0x80AAC080, 0x80AAC0FF,
         0x80AAFF00, 0x80AAFF80, 0x80AAFFFF,

         0x80FF0000, 0x80FF0080, 0x80FF00FF,
         0x80FF4000, 0x80FF4080, 0x80FF40FF,
         0x80FF8000, 0x80FF8080, 0x80FF80FF,
         0x80FFC000, 0x80FFC080, 0x80FFC0FF,
         0x80FFFF00, 0x80FFFF80, 0x80FFFFFF
    };

/**********************************************************************/
/* The 32 entry palette is the is similar to the default VGA palette  */
/* in terms of its structure in that it is based around RxGxBxLevel.  */
/* The default VGA palette (16 entries) is 2x2x2x2. Here we will use  */
/* a 2x2x2x4 structure. Because the all the entires of the 16 entry   */
/* palette are incorporated into this palette then the change from    */
/* one to the other should be less horrible! The greys chosen here    */
/* are designed to fit in with the ones in the 16 entry palette (and  */
/* are the same ones also used in the 64 entry palette).              */
/**********************************************************************/
ULONG ulDefaultPalette32[32] =
      {
         0x80000000,     /* black           0 */
         0x80000040,     /* very dark blue  1 */
         0x80004000,     /* very dark green   */
         0x80004040,     /* very dark cyan    */
         0x80400000,     /* very dark red     */
         0x80400040,     /* very dark magenta */
         0x80404000,     /* very dark yellow  */

         0x80000080,     /* dark blue       7 */
         0x80008000,     /* dark green        */
         0x80008080,     /* dark cyan         */
         0x80800000,     /* dark red          */
         0x80800080,     /* dark magenta      */
         0x80808000,     /* dark yellow       */

         0x802B2B2B,     /* very dark gray 13 */
         0x80555555,     /* dark gray         */
         0x80808080,     /* gray              */
         0x80A6A6A6,     /* quite light gray  */
         0x80CCCCCC,     /* light gray        */
         0x80E0E0E0,     /* very light gray   */

         0x800000C0,     /* light blue     19 */
         0x8000C000,     /* light green       */
         0x8000C0C0,     /* light cyan        */
         0x80C00000,     /* light red         */
         0x80C000C0,     /* light magenta     */
         0x80C0C000,     /* light yellow      */

         0x800000FF,     /* blue           25 */
         0x8000FF00,     /* green             */
         0x8000FFFF,     /* cyan              */
         0x80FF0000,     /* red               */
         0x80FF00FF,     /* magenta           */
         0x80FFFF00,     /* yellow            */
         0x80FFFFFF,     /* white          31 */
    };
#endif
LOCAL COLORTABLE DefaultColorTable[MAX_COLOR_INDEX] =
{
  {
    CLR_BACKGROUND, 0x00FFFFFF
  } ,
  {
    CLR_BLUE,       0x000000FF
  } ,
  {
    CLR_RED,        0x00FF0000
  } ,
  {
    CLR_PINK,       0x00FF00FF
  } ,
  {
    CLR_GREEN,      0x0000FF00
  } ,
  {
    CLR_CYAN,       0x0000FFFF
  } ,
  {
    CLR_YELLOW,     0x00FFFF00
  } ,
  {
    CLR_NEUTRAL,    0x00000000
  } ,
  {
    CLR_DARKGRAY,   0x00808080
  } ,
  {
    CLR_DARKBLUE,   0x00000080
  } ,
  {
    CLR_DARKRED,    0x00800000
  } ,
  {
    CLR_DARKPINK,   0x00800080
  } ,
  {
    CLR_DARKGREEN,  0x00008000
  } ,
  {
    CLR_DARKCYAN,   0x00008080
  } ,
  {
    CLR_BROWN,      0x00808000
  } ,
  {
    CLR_PALEGRAY,   0x00CCCCCC
  }
} ;

LOCAL short PenPixelThickness[MAX_PEN_TYPES] =
{
  1,                                   // P3
  2,                                   // P7
  1,                                   // T3
  2,                                   // T6
  1,                                   // V25
  1,                                   // V35
  2,                                   // V50
  2,                                   // V70
  1,                                   // R3
  1,                                   // .18
  1,                                   // .25
  1,                                   // .35
  2,                                   // .50
  2,                                   // .70
  3                                    // 1.00
} ;

LOCAL NPSZ PenThicknessStrings[MAX_PEN_TYPES] =
{
  ".3",                                // P3
  ".7",                                // P7
  ".3",                                // T3
  ".6",                                // T6
  ".25",                               // V25
  ".35",                               // V35
  ".50",                               // V50
  ".70",                               // V70
  ".3",                                // R3
  ".18",                               // .18
  ".25",                               // .25
  ".35",                               // .35
  ".50",                               // .50
  ".70",                               // .70
  "1.00"                               // 1.00
} ;

  /*
  ** LOCAL FUNCTION PROTOTYPES þþþ
  */

LOCAL BOOL   check_color_sorting(PDDC,LONG,USHORT);
LOCAL ULONG  color_distance(LONG,LONG);
LOCAL VOID   constrain_hls(PHLSBLOCK);
LOCAL LONG   convert_color(PDDC,LONG);
LOCAL LONG   get_closest_color(PDDC,LONG);
LOCAL SHORT  get_closest_pen(PDDC,LONG);
LOCAL SHORT  get_color_group(SHORT);
LOCAL VOID   rgb_to_hls(LONG,PHLSBLOCK);
LOCAL USHORT locate_pen(PDDC,LONG,USHORT);
LOCAL USHORT locate_HPGL2pen(PDDC,LONG,USHORT);
LOCAL BOOL   select_user_defined_pen(PDDC,SHORT,LONG,ULONG,SHORT);
LOCAL BOOL   select_HPGL2pen(PDDC,USHORT,LONG,ULONG,USHORT);
LOCAL BOOL   set_pen_width(PDDC,PPDEVICE,PSZ,SHORT);

/*
**   EXTERN FUNCTIONS
*/
//extern ULONG InnerGre32Entry3();
//extern ULONG InnerGre32Entry4();


/***************************************************************************
 *
 * FUNCTION NAME = check_color_sorting
 *
 * DESCRIPTION   = Determine the nearest pen color
 *                 available to the requested color.  Then
 *                 use this pen in direct mode.  If
 *                 playing back the journal file, we may
 *                 only record the information.
 *
 * INPUT         = PDDC pDDC;
 *                 LONG lRealPenColor;
 *                 USHORT usPenUsage;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL BOOL check_color_sorting(PDDC pDDC, LONG lRealPenColor, USHORT usPenUsage)
{

  /*
  **      Checks to see if we can output the requested color based
  **  on the pen usage.  All functions must call down to here to find out
  **  if they can go ahead with the draw.  So the first thing we do is
  **  reject COLOR_WHITE if we are not on a HPGL2 device.
  **  After that, if color sorting is enabled, we find
  **  out if the Color matches our current selected pen based the usage.
  **  If so, then we give the green light (TRUE) to the calling function.
  */
  PPDEVICE pPDevice = pDDC->pPDevice;
  BOOL bResult = FALSE;

  /*
  ** If we have already selected the pen we do not have any work.
  */
  if (  pPDevice->bPenIsSelected &&          /* A Pen has been selected    */
        pPDevice->CurrentRealColor == lRealPenColor && /* Curr Pen color    */
        pPDevice->CurrentPenUsage  == usPenUsage)      /* Curr Pen Usage    */
  {
    bResult = TRUE;
  }
  else
  {
    ULONG  Distance;
    ULONG  MinDistance = (ULONG)~0L;
    SHORT  Carousel;
    SHORT  ColorIndex;
    SHORT  Pen;
    USHORT Usage;
    SHORT  SaveCarousel = 0;
    SHORT  SavePen = 0;
    USHORT SaveUsage = 0;
    LONG   ConvertedPenColor;

    /*
    ** scan all pens in all carousels to determine the nearest
    ** color.  if white is requested, there is no need to look
    ** further since no drawing will be performed.
    ** DO NOT compare the requested color to white, since this
    ** will cause the lightest colors to be set to white.
    */
    ConvertedPenColor = convert_color(pDDC, lRealPenColor);

    if ((PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2) ||
        (ConvertedPenColor != COLOR_WHITE))
    {
      /*
      ** scan all carousels for the available color
      */
      for (Carousel = 0; Carousel < MAX_CAROUSELS; Carousel++)
      {
        if (!pPDevice->pSetup->bActiveCarousel[Carousel])
          /*
          ** carousel not available
          */
          continue;

        for (Pen = 0; Pen < MAX_PENS; Pen++)
        /*
        ** check all pens in this carousel.
        */
        {
          PPENINFO pPenInfo;

          pPenInfo = &pPDevice->pSetup->Carousel[Carousel].Pen[Pen];

          if ((ColorIndex = (short)pPenInfo->Color) &&
             (Distance = color_distance(ColorList[ColorIndex-1],
                            ConvertedPenColor)) <= MinDistance)
          {
            Usage = (USHORT)pPenInfo->Usage;

            if (Distance < MinDistance ||
                (SaveUsage != usPenUsage &&
                (Usage == usPenUsage ||
                (!Usage && SaveUsage))))
            {
              /*
              ** A closer match - remember it
              */
              MinDistance = Distance;
              SaveCarousel = Carousel;
              SavePen = Pen+1;
              SaveUsage = Usage;
            }
          }
        }
      }
    }

    if (SavePen)
    {
      /*
      **      Found a match that is not white.  Decide what to answer.
      **  If not colorsorting,  then return TRUE.  If colorsorting, action
      **  depends upon activity.  First pass through is to record which
      **  pens are used - this always returns FALSE,  as drawing should
      **  not take place at this time.  On the second pass (drawing is
      **  in effect) return TRUE if the desired pen is the current pen;
      **  else FALSE (which will stop drawing).
      */
      if (!pPDevice->bColorSorting)
        bResult = TRUE;
      else
      {
        if (!pPDevice->bCarouselPensUsedBuilt)
        {
          /*
          ** Determining pens used:  so remember this one!
          */
          pPDevice->fbCarPenUsed[SaveCarousel] |= 1 << (SavePen-1);
        }
        else
        {
          /*
          ** Journal file playback - TRUE if want the current pen
          */
          if (pPDevice->CurrentPen == SavePen &&
              pPDevice->CurrentCarousel == SaveCarousel)
          {
            /*
            ** if this pen is ok
            ** set global vars to avoid checking the pen again for the
            ** same usage and color
            */
            pPDevice->CurrentPenUsage  = usPenUsage;  /* Current Pen Usage     */
            pPDevice->CurrentRealColor = lRealPenColor;  /* Curr real Pen color*/
            bResult = TRUE;
          }
        }
      }
    }
  }

  return  bResult;
}

/***************************************************************************
 *
 * FUNCTION NAME = color_distance()
 *
 * DESCRIPTION   = return the distance between two
 *                 colors
 *
 *                 return the distance between two
 *                 colors based on HLS or RGB squaring
 *                 system
 *
 * INPUT         = lRGBColor1,lRGBColor2;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = color
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL ULONG color_distance(LONG lRGBColor1,LONG lRGBColor2)
{

#if      HLS
  HLSBLOCK HLSColor1,HLSColor2;

  rgb_to_hls(lRGBColor1, &HLSColor1);
  constrain_hls(&HLSColor1);
  rgb_to_hls(lRGBColor2, &HLSColor2);
  constrain_hls(&HLSColor2);

  return (ULONG)(ABS((LONG)HLSColor1.Hue-(LONG)HLSColor2.Hue)|((ABS((LONG)
     HLSColor1.Lightness-(LONG)HLSColor2.Lightness)/500L) << 13));

#else
  ULONG Red   = ABS((lRGBColor1 >> 16) & 0xff)-((lRGBColor2 >> 16) & 0xff);
  ULONG Green = ABS((lRGBColor1 >> 8) & 0xff)-((lRGBColor2 >> 8) & 0xff);
  ULONG Blue  = ABS((lRGBColor1) & 0xff) - ((lRGBColor2) & 0xff);

  return ((Red * Red)+(Green * Green)+(Blue * Blue));
#endif
}

#if      HLS

/***************************************************************************
 *
 * FUNCTION NAME =  constrain_hls
 *
 * DESCRIPTION   =  Constrain an HLS color
 *                  Constrain an HLS color to certain
 *                  regions of the color wheel.  If
 *                  the color is grey, we force it to
 *                  white or black.  If not, we force
 *                  it out to the rim of the wheel.
 *
 * INPUT         =  pHLS
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID constrain_hls(PHLSBLOCK pHLS)
{

  if ((pHLS->Saturation) < 500)
  {
    /*
    ** it is grey
    */
    if ((pHLS->Lightness) < 500)
      (pHLS->Lightness) = 0;
    else
      (pHLS->Lightness) = 1000;

    (pHLS->Saturation) = 0;
    (pHLS->Hue) = 0;
  }
  else
  {
    /*
    ** force it out to the rim
    */
    (pHLS->Lightness)  = 500;
    (pHLS->Saturation) = 1000;
  }
}

#endif

/***************************************************************************
 *
 * FUNCTION NAME = convert_color()
 *
 * DESCRIPTION     accepts a color in the current device
 *                 accepts a color in the current
 *                 device format and returns the
 *                 RGB color
 *
 * INPUT         = pDDC
 *                 lColor
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL LONG convert_color(PDDC pDDC,LONG lColor)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  BOOL bFound = FALSE;
  LONG lCnvColor = COLOR_WHITE;

  /*
  ** fairly straight forward, handle SYS_COLOR (NEGATIVE) values
  */
  if (lColor < 0L)
  {
    switch ((SHORT)lColor)
    {
      case  CLR_WHITE :
      case  CLR_TRUE :
        lCnvColor = COLOR_WHITE;
        break;

      /*
      ** all others should be black
      ** case  CLR_BLACK :
      ** case  CLR_DEFAULT :
      ** case  CLR_FALSE :
      */
      default  :
        lCnvColor = COLOR_BLACK;
        break;
    }
  }
  else
  {
    /*
    ** If we are running on the new GRE
    ** we let the gre hook all color functions.
    ** Therefore, We must ask the GRE for the
    ** color
    */
    if (pDDC->lEngineVersion >= RASTER_ENGINE_22)
    {
      if ((lCnvColor = GreQueryRGBColor(pDDC->hdc, LCOLOPT_REALIZED,
                                              lColor)) == GPI_ALTERROR)
      {
         GplErrSetError(PMERR_INV_COLOR_INDEX);
         lCnvColor = COLOR_BLACK ;
      }
    }
    else
    {
      if (pDDC->DCState.usColorFormat != LCOLF_RGB)
      {
          if (lColor <= MAX_COLOR_INDEX)
            lCnvColor = pDDC->DCState.pColorTable[lColor].PhysRGB;
      }
      else
      {
        /*
        ** easy enough, PLOTTERS is currently in RGB format.
        */
        lCnvColor = lColor;
      }
    }
  }

  return  lCnvColor;
}

/***************************************************************************
 *
 * FUNCTION NAME = get_closest_color()
 *
 * DESCRIPTION   = get closest color
 *                 returns the currently available,
 *                 closest match to the RGB value
 *                 passed in.
 * INPUT         =
 *
 * OUTPUT        = pDDC
 *                 RGBIn
 *
 * RETURN-NORMAL = SelColor
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL LONG get_closest_color(PDDC pDDC,LONG RGBIn)
{
  short ColorIndex,Loop;
  LONG SelColor = COLOR_WHITE;

  ULONG Distance,MinDistance = (ULONG)-1L;

  if ((PlotterClass[pDDC->pPDevice->Plotter].usHPGLCaps & HPGL2) ||
      (RGBIn != COLOR_WHITE))
  {
    /*
    ** if the color passed in is not white, check all the
    ** pens in the currently selected carousel
    */
    for (Loop = 0; Loop < MAX_PENS; Loop++)
    {
      if (ColorIndex = pDDC->pPDevice->pSetup->Carousel
         [pDDC->pPDevice->CurrentCarousel].Pen[Loop].Color)
      {
        if ((Distance = color_distance(ColorList[ColorIndex-1],
                                       RGBIn)) < MinDistance)
        {
          MinDistance = Distance;
          SelColor = ColorList[ColorIndex-1];
        }
      }
    }
  }

  return  SelColor;
}

/***************************************************************************
 *
 * FUNCTION NAME = get_closest_pen
 *
 * DESCRIPTION   = returns the stall number of the pen
 *                 returns the stall number of the pen
 *                 that most closely matches the
 *                 specified color.  If RGBIn == WHITE,
 *                 then returns 0
 *
 * INPUT         = pDDC
 *                 RGBIn
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = SelColor
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL short get_closest_pen(PDDC pDDC,LONG RGBIn)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  PPROFILEINFO pSetup = pPDevice->pSetup;
  SHORT ColorIndex,
        Loop,
        SelColor = 0,
        SelCarousel = pPDevice->CurrentCarousel;
  SHORT Carousel,MaxCarousels;
  ULONG Distance,MinDistance = (ULONG)-1L;
  BOOL  bHPGL2Device = PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2;


  if ((bHPGL2Device) || (RGBIn != COLOR_WHITE))
  {
    /*
    ** Loop through the current carousel if NOT HPGL2
    ** Loop through all the active carousels if HPGL2
    */
    MaxCarousels = (bHPGL2Device?(SHORT)MAX_CAROUSELS:
       (pPDevice->CurrentCarousel+1));
    Carousel = (bHPGL2Device?0:pPDevice->CurrentCarousel);

    for (; Carousel < MaxCarousels; Carousel++)
    {
      if (pSetup->bActiveCarousel[Carousel])
      {
        for (Loop = 0; Loop < MAX_PENS; Loop++)
        {
          /*
          ** straight forward, just check the available pen colors
          */
          if (ColorIndex = pSetup->Carousel[Carousel].Pen[Loop].Color)
          {
            if ((Distance = color_distance(ColorList[ColorIndex-1],
                                           RGBIn)) < MinDistance)
            {
              MinDistance = Distance;
              SelColor = Loop+1;
              SelCarousel = Carousel;
            }
          }
        }
      }
    }
  }

   /*
   ** set current carousel for pen.
   ** Note CurrentCarousel only changes for HPGL2 devices
   */
   pPDevice->CurrentCarousel = SelCarousel;

   return  SelColor;
}

/***************************************************************************
 *
 * FUNCTION NAME = get_color_group()
 *
 * DESCRIPTION   = get color group
 *                 returns whether a pen is paper,
 *                 transparency, ect.
 *
 * INPUT         = Type
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = Result
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL short get_color_group(short Type)
{
  short Result;

  Type += P3;

  if (WITHIN(Type, P3, P7))
  {
    Result = PAPER;
  }
  else
  {
    if (WITHIN(Type, T3, T6))
    {
      Result = TRANSPARENCY;
    }
    else
    {
      if (Type == R3)
      {
        Result = ROLLERBALL;
      }
      else
      {
        if (WITHIN(Type, V25, V70))
        {
          Result = DISPOSABLE;
        }
        else
        {
          Result = REFILLABLE;
        }
      }
    }
  }

  return (Result);
}

#if      HLS

/***************************************************************************
 *
 * FUNCTION NAME = rgb_to_hls()
 *
 * DESCRIPTION   = convert an RGB color value to HLS format
 *
 * INPUT         = LONG Color
 *                 PHLSBLOCK pHLSResult
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL VOID rgb_to_hls(LONG Color,
                      PHLSBLOCK pHLSResult)
{

  int Maximum,Minimum,Difference,Sum,Red,Green,Blue,red,green,blue;
  Blue  = (USHORT)((Color & 0x000000FF) * 1000 / 255);
  Green = (USHORT)(((Color >> 8) & 0x000000FF) * 1000 / 255);
  Red   = (USHORT)(((Color >> 16) & 0x000000FF) * 1000 / 255);

  if (Red > Green)
  {
    if (Red > Blue)
    {
      Maximum = Red;
    }
    else
    {
      Maximum = Blue;
    }

    if (Green < Blue)
    {
      Minimum = Green;
    }
    else
    {
      Minimum = Blue;
    }
  }
  else
  {
    if (Red < Blue)
    {
      Minimum = Red;
    }
    else
    {
      Minimum = Blue;
    }

    if (Green > Blue)
    {
      Maximum = Green;
    }
    else
    {
      Maximum = Blue;
    }
  }

  if (Difference = (Maximum-Minimum))
  {
    red   = (INT)(1000L * (LONG)(Maximum - Red)   / (LONG)Difference);
    green = (INT)(1000L * (LONG)(Maximum - Green) / (LONG)Difference);
    blue  = (INT)(1000L * (LONG)(Maximum - Blue)  / (LONG)Difference);
  }
  Sum = (Maximum+Minimum);
  (pHLSResult->Lightness) = Sum / 2;

  if (!Difference)
  {
    (pHLSResult->Saturation) = 0;
  }
  else
  {
    if ((pHLSResult->Lightness) <= 500)
    {
      (pHLSResult->Saturation) = (USHORT)(1000L*(LONG)Difference/(LONG)Sum);
    }
    else
    {
      (pHLSResult->Saturation) = (USHORT)(1000L * (LONG)Difference /
                                             (LONG)(2000 - Sum));
    }
  }

  if (!(pHLSResult->Saturation))
  {
    (pHLSResult->Hue) = 0;
  }
  else
  {
    if (Red == Maximum)
    {
      (pHLSResult->Hue) = 2000+blue-green;
    }
    else
    {
      if (Green == Maximum)
      {
        (pHLSResult->Hue) = 4000+red-blue;
      }
      else
      {
        (pHLSResult->Hue) = 6000+green-red;
      }
    }
  }
  (pHLSResult->Hue) = (USHORT)(((LONG)(pHLSResult->Hue)*6L)/100L);

  while ((pHLSResult->Hue) < 0)
  {
    (pHLSResult->Hue) += 360;
  }

  while ((pHLSResult->Hue) >= 360)
  {
    (pHLSResult->Hue) -= 360;
  }
}
#endif

/***************************************************************************
 *
 * FUNCTION NAME = locate_pen()
 *
 * DESCRIPTION   = finds the closest available pen
 *                 color to color finds the closest
 *                 available pen color to color, with
 *                 prioriry given to usage.
 *
 *                      1.  Lines
 *                      2.  Fills
 *                      3.  Text
 *                      4.  RFPEN : Do not select the pen. If the asked pen
 *                                  color is not in the defined palette, then
 *                                  first define it and return the pen number.
 *                                  This pen number will be sent with
 *                                  RF instruction in fill_pattern_use_device
 *                                  to difine the user define pattern. This pen
 *                                  can be redefined once we usedup the pattern.
 *                                  We still have to implement this.
 *
 * INPUT         = PDDC   pDDC;
 *                 LONG   lRealPenColor;
 *                 USHORT usPenUsage;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Pen
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL USHORT locate_pen(PDDC pDDC, LONG lRealPenColor, USHORT usPenUsage)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  USHORT Pen;

  /*
  ** if we are not mapping colors to pen colors
  ** just call HPGL2 to create a a pen
  */
  if (pPDevice->pSetup->usFlags & FL_USEAPPCOLORS)
    return(locate_HPGL2pen(pDDC, lRealPenColor, usPenUsage));

  Pen = pPDevice->CurrentPen;        /* default to current pen            */

  if (!pPDevice->bPenIsSelected ||   /* A Pen has NOT been selected       */
     (!pPDevice->bColorSorting &&    /* not color sorting and             */
      !pDDC->DCState.bClearingArea && /* NOT Clearing the area            */
      (pPDevice->CurrentRealColor != lRealPenColor || /* Not Curr Pen clor */
       pPDevice->CurrentPenUsage != usPenUsage)))/* Not Curr Pen Usage     */
  {
    USHORT i;
    UCHAR SaveColor,SaveUsage,TempUsage;
    SHORT Carousel = pPDevice->CurrentCarousel;
    ULONG ulRGBColor = convert_color(pDDC, lRealPenColor);

    Pen = get_closest_pen(pDDC, ulRGBColor);

    if (Pen)
    {
      SaveColor = pPDevice->pSetup->Carousel[pPDevice->CurrentCarousel].Pen
         [Pen-1].Color;
      SaveUsage = pPDevice->pSetup->Carousel[pPDevice->CurrentCarousel].Pen
         [Pen-1].Usage;

      /*
      ** see if we have a pen that matches our usage
      */
      if (SaveUsage != (UCHAR)usPenUsage)
      {
        PPROFILEINFO pSetup = pPDevice->pSetup;
        USHORT CarouselNum;
        BOOL   fFound = FALSE;

        for (CarouselNum = 0; (CarouselNum < MAX_CAROUSELS) && !fFound;
             CarouselNum++)
        {
          if (!pSetup->bActiveCarousel[CarouselNum])
            for (i = 0; i < MAX_PENS; i++)
            {
              if (pSetup->Carousel[CarouselNum].Pen[i].Color == SaveColor &&
                 ((TempUsage =
                   pSetup->Carousel[CarouselNum].Pen[i].Usage)!=SaveUsage) &&
                 ((TempUsage == (UCHAR)usPenUsage) || !TempUsage))
              {
                pPDevice->CurrentCarousel = CarouselNum;
                fFound = TRUE;
                Pen = i+1;
                break;
              }
            }
        }
      }

      if (!pPDevice->bPenIsSelected || /* Pen NOT selected                */
         (!pPDevice->bColorSorting &&  /* not color sorting               */
         (pPDevice->CurrentPen != (SHORT)Pen || /* pen changed or         */
         Carousel != pPDevice->CurrentCarousel)))/* Carousel changed      */
      {
        select_user_defined_pen(pDDC, Pen, lRealPenColor,
                                ulRGBColor, usPenUsage);
      }
      else
      {
        /*
        ** set vars to avoid searching for the pens for the same color
        ** and usage.
        */
        pPDevice->CurrentRealColor = lRealPenColor; /* Curr real color   */
        pPDevice->CurrentPenUsage  = usPenUsage;/* Current Pen Usage     */
      }
    }
  }

  return (Pen);
}


/***************************************************************************
 *
 * FUNCTION NAME = locate_HPGL2pen()
 *
 * DESCRIPTION   = finds the HPGL2 Pen currently defined
 *                 If the Pen is not defined yet, we define
 *                 a new pen
 *
 *                 No priority is given to usage.
 *                 This function should only be called if
 *                 the user is using application colors.
 *                  ie. if (pSetup->usFlags & FL_USEAPPCOLORS) is set.
 *                 Note: Application colors should never be
 *                 set with color sorting on.
 *
 * INPUT         = PDDC pDDC;
 *                 LONG PenColor;
 *                 USHORT usPenUsage;
 *                      1.  Lines
 *                      2.  Fills
 *                      3.  Text
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = usPen
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL USHORT locate_HPGL2pen(PDDC pDDC, LONG lRealPenColor, USHORT usPenUsage)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  USHORT usPen;

  usPen = pPDevice->CurrentPen;        /* default to current pen         */

  if (!pPDevice->bPenIsSelected ||     /* A Pen has NOT been selected    */
      (!pDDC->DCState.bClearingArea && /* NOT Clearing the area          */
       pPDevice->CurrentRealColor != lRealPenColor)) /* Not Curr Pen color */
  {
    USHORT i;
    ULONG ulRGBColor;

    ulRGBColor =  convert_color(pDDC, lRealPenColor);

    if (pPDevice->usPensInPalette)
    {
      /*
      ** look through current defined pens for our color
      */
      for (i = 0;i < pPDevice->usPensInPalette; i++)
      {
        if (pPDevice->paPaletteEntry[i].fulPenFlags & PEN_DEFINED)
          if (pPDevice->paPaletteEntry[i].ulPenRGBColor == ulRGBColor)
            break;
      }
      /*
      ** If the index is beyond the array
      ** we did not find a pen with the same RGB color.
      ** So, define a new one.
      */
      if (i == pPDevice->usPensInPalette)
      {
        /*
        ** if we have not reached our max # of defined pens
        ** just make a new one
        */
        if ( i == PlotterClass[pPDevice->Plotter].usMaxHPGL2Pens)
        {
          /*
          ** Look for a pen that can be redefined starting with the
          ** least recently used
          */
          for (i = pPDevice->usLastPenDefined+1;i < pPDevice->usPensInPalette;i++)
          {
            if (!(pPDevice->paPaletteEntry[i].fulPenFlags & PEN_PERMANENT))
              break;
          }
          /*
          ** If the index is beyond the array
          ** we did not find and redefinable pen from the last position
          ** to the max in the array So, look at the beginning of the array.
          */
          if (i == pPDevice->usPensInPalette)
          {
            for (i = 1 ;i < pPDevice->usPensInPalette; i++)
            {
              if (!(pPDevice->paPaletteEntry[i].fulPenFlags & PEN_PERMANENT))
                break;
            }
          }
        }
        /*
        ** Make sure we do not go above the max number of
        ** HPGL2 pens allowed for this class of device.
        ** If we are at the max we will keep redefining
        ** the last pen with the current color.
        */
        i = MIN(i, (PlotterClass[pPDevice->Plotter].usMaxHPGL2Pens - 1));
        set_pen(pDDC, i, ulRGBColor, PEN_NOFLAGS);
      }
    }
    else
    { /* first pen will be 1 since we will set pen 0 when initializing
      ** the palette
      */
      i = 1;
      set_pen(pDDC, i, ulRGBColor, PEN_NOFLAGS);
    }
    usPen = i;

    select_HPGL2pen(pDDC, usPen, lRealPenColor, ulRGBColor, usPenUsage);
  }
  return (usPen);
}

/***************************************************************************
 *
 * FUNCTION NAME = select_HPGL2pen()
 *
 * DESCRIPTION   = Selects pen using the HPGL2 Pens in the Dynamic
 *                 Pen Palette. Not the Carousel pens.
 *                 This function is Called when
 *                 (pSetup->usFlags & FL_USEAPPCOLORS) is set.
 *                 Generates the HPGL command to
 *                 select a specified pen from the palette
 *
 * INPUT         = PDDC pDDC
 *                 short Pen
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL BOOL select_HPGL2pen(PDDC pDDC,
                      USHORT usPen,
                      LONG   lRealPenColor,
                      ULONG  ulRGBColor,
                      USHORT usPenUsage)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  CHAR  szPenThicknessString[4];
  SHORT iPenThicknessInPixels;

  /*
  ** set selected pen status
  */
  pPDevice->bPenIsSelected = TRUE;     /* A Pen has been selected         */
  pPDevice->CurrentRealColor = lRealPenColor;/* Curr real color of sel Pen*/
  pPDevice->CurrentPenUsage  = (SHORT)usPenUsage;/* Current Pen Usage     */
  pPDevice->CurrentPen = (SHORT)usPen;           /* current pen selected  */
  /*
  ** Turn off line in construction
  */
  check_line_construction(pDDC);
  /*
  ** "SP" Select Pen
  */
  output_bytes(pDDC, "SP");
  /*
  ** use the physical pen number
  */
  output_number(pDDC, (LONG)usPen);

  /*
  ** Set the transparency mode for the color
  ** White only works if transparency is off.
  */
  if (ulRGBColor == COLOR_WHITE)
  {
     /* if white turn transparency off */
     set_transparency_mode(pDDC, 0);
  }
  else
  {
     /* else turn transparency on */
     set_transparency_mode(pDDC, 1);
  }

  /*
  ** if bWideLines is set we are doing a StrokePath.
  ** Therefore, use the geometric line width
  */
  if (pDDC->DCState.bWideLines)
  {
    strcpy (szPenThicknessString,"");
    iPenThicknessInPixels = pDDC->DCState.lbnd.lGeomWidth;
  }
  /*
  ** else use 1 or 2 pel lines depending on the
  ** LineWidth multiplier attribute
  ** NOTE: To fully implement LINEWIDTH_THICK we must
  ** allow the setting of the attribute and handle CAPS_LINEWIDTH_THICK
  */
  else
  {
    if (pDDC->DCState.bDrawingText)
    {
      /*
      ** produce the thinest line possible for text
      ** Note "0" should be 1 pel
      */
      strcpy (szPenThicknessString,"0");
      iPenThicknessInPixels = 1;
    }
    else
    {
      if (pDDC->DCState.lbnd.fxWidth == LINEWIDTH_THICK &&
           usPenUsage == USAGE_LINES)
      { /* note:if you change the .25 you must changes CAPS_CAPS_LINEWIDTH_THICK*/
        strcpy (szPenThicknessString,".25");
        iPenThicknessInPixels = 2;
      }
      else
      {
        strcpy (szPenThicknessString,".18");
        iPenThicknessInPixels = 1;
      }
    }
  }
  set_pen_width(pDDC, pPDevice, (PSZ)szPenThicknessString,
                iPenThicknessInPixels);
  return(TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = select_user_defined_pen()
 *
 * DESCRIPTION   = select pen
 *                 generates the HPGL command to
 *                 select a specified pen
 *
 * INPUT         = PDDC pDDC
 *                 short Pen
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL BOOL select_user_defined_pen(PDDC pDDC,
                      short iPen,
                      LONG  lRealPenColor,
                      ULONG ulRGBColor,
                      SHORT PenUsage)
{
  PPDEVICE pPDevice = pDDC->pPDevice;

  short iValue,
        iCarousel = pPDevice->CurrentCarousel,
        iType = pPDevice->pSetup->Carousel[iCarousel].Pen[iPen-1].Type,
        Group = get_color_group(iType);

  /*
  ** set selected pen status
  */
  pPDevice->bPenIsSelected = TRUE;     /* A Pen has been selected         */
  pPDevice->CurrentRealColor = lRealPenColor;/* Curr real color of sel Pen*/
  pPDevice->CurrentPenUsage = PenUsage;/* Current Pen Usage               */
  pPDevice->CurrentPen = iPen;         /* current pen selected            */
  check_line_construction(pDDC);
  output_bytes(pDDC, "SP");

  if (PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)
  {
    /*
    ** use the pen palette pen number
    */
    output_number(pDDC, (LONG)pPDevice->iHPGL2PenNumber[iCarousel][iPen-1]);
  }
  else
  {
    /*
    ** use the physical pen number
    */
    output_number(pDDC, (LONG)iPen);
  }

  /*
  ** Set the transparency mode for the color
  ** White only works if transparency is off.
  */
  if (ulRGBColor == COLOR_WHITE)
  {
     /* if white turn transparency off */
     set_transparency_mode(pDDC, 0);
  }
  else
  {
     /* else turn transparency on */
     set_transparency_mode(pDDC, 1);
  }

  if ((iValue = pPDevice->pSetup->Carousel[iCarousel].Pen[iPen-1].Speed) ==
     0)
  {
    iValue = PlotterClass[pPDevice->Plotter].PenOptions.Speed[Group];
  }

  if (pPDevice->CurrentSpeed != iValue)
  {
    pPDevice->CurrentSpeed = iValue;
    output_bytes(pDDC, "VS");

    if (iValue != (short)PlotterClass[pPDevice->Plotter].PenOptions.Speed
       [Group] || (iValue == (short)PlotterClass[pPDevice->Plotter].
       PenOptions.Speed[Group] && PlotterClass[pPDevice->Plotter].
       DeviceInfo.PenOptionsSupport[2]))
    {
      output_number(pDDC, (LONG)iValue);
    }
  }

  if (PlotterClass[pPDevice->Plotter].DeviceInfo.PenOptionsSupport[1])
  {
    if ((iValue=pPDevice->pSetup->Carousel[iCarousel].Pen[iPen-1].Force) == 0)
    {
      iValue = PlotterClass[pPDevice->Plotter].PenOptions.Force[Group];
    }

    if (pPDevice->CurrentForce != iValue)
    {
      pPDevice->CurrentForce = iValue;
      output_bytes(pDDC, "FS");
      output_number(pDDC, (LONG)iValue);
    }
  }

  if (PlotterClass[pPDevice->Plotter].DeviceInfo.PenOptionsSupport[2])
  {

    if ((iValue = pPDevice->pSetup->Carousel[iCarousel].Pen[iPen-1].
       Acceleration) == 0)
    {
      iValue = PlotterClass[pPDevice->Plotter].PenOptions.Acceleration[Group];
    }

    if (pPDevice->CurrentAcceleration != iValue)
    {
      pPDevice->CurrentAcceleration = iValue;
      output_bytes(pDDC, "AS");
      output_number(pDDC, (LONG)iValue);
    }
  }
  set_pen_width(pDDC, pPDevice, (PSZ)PenThicknessStrings[iType],
                 (pDDC->DCState.bWideLines ? pDDC->DCState.lbnd.lGeomWidth:
                                             PenPixelThickness[iType]));

  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME  = set_pen_witdth()
 *
 * DESCRIPTION    = generates the HPGL1 or HPGL2 command to set
 *                  the pen width(HPGL2) thickness(HPGL1).
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL set_pen_width(PDDC pDDC,
                   PPDEVICE pPDevice,
                   PSZ   pszPenThicknessString,
                   SHORT iPenThicknessInPixels)
{
  pPDevice->CurrentPenThickness = iPenThicknessInPixels;

  /*
  **   if HPGL2 device
  */
  if (PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)
  {
    output_bytes(pDDC, "PW");

    if (pDDC->DCState.bWideLines)
    {
      LONG lPenWidthX100;
      LONG lPelsPerMMX100;
      SHORT Plotter = pPDevice->Plotter;

      iPenThicknessInPixels = MAX(iPenThicknessInPixels, 1);

      /*
      ** Set the pen width to the geometric line width in millimeters.
      ** bWideLines should only be set when drawing lines from
      ** StrokePath.
      */
      lPelsPerMMX100 = ( (1000 * pPDevice->lRes_YPelsPerInch) /
                           MMPER10INCH);
      lPenWidthX100 = (iPenThicknessInPixels * 10000L) / lPelsPerMMX100;
      output_number(pDDC, (lPenWidthX100 / 100L) );
      output_bytes(pDDC, ".");
      output_number(pDDC, lPenWidthX100 - ((lPenWidthX100 / 100L) * 100L));
    }
    else
    {
      {
        /*
        ** Set width of pen according to the pen thickness
        ** string table.
        */
        output_bytes(pDDC, pszPenThicknessString);
      }
    }
  }
  /*
  **   else HPGL1 device
  */
  else
  {
    if (PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL_PENTHICK)
    {
      output_bytes(pDDC, "PT");
      output_bytes(pDDC, pszPenThicknessString);
    }
  }

  /*
  ** Make sure we do not continue building lines after pen width commands
  */
  pDDC->pPDevice->bLineInConstruction = FALSE;

  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME  = check_area_color()
 *
 * DESCRIPTION    = check area color
 *                  validates the capability of the
 *                  plotter to output the current
 *                  area fill color
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_area_color(PDDC pDDC)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  BOOL bResult;


  if (pDDC->DCState.abnd.usMixMode == FM_LEAVEALONE)
  {
    bResult = FALSE;
  }
  else
  {
    /*
    ** if the plotter is not HPGL2 it can not do white lines.
    ** so don't try
    */
          // line removed to make ptt gpisetbackcolorexh work
    if (  //(!(PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)) &&
       (pDDC->DCState.abnd.usSymbol == PATSYM_BLANK ||
       pDDC->DCState.abnd.usSymbol == PATSYM_NOSHADE))
    {
      bResult = FALSE;
    }
    else
    {
      bResult = check_color_sorting(pDDC, pDDC->DCState.abnd.lColor,
                                    USAGE_FILLS);
    }
  }

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME  = check_area_background_color()
 *
 * DESCRIPTION    = check area background color
 *                  validates the capability of the
 *                  plotter to output the current
 *                  area fill color
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_area_background_color(PDDC pDDC)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  USHORT usSymbol  = pDDC->DCState.abnd.usSymbol;
  ULONG  lColorWhite;
  BOOL bResult;

  /*
  ** Get correct color white format for testing for color
  ** white on non HPGL2 plotters
  */
  if (pDDC->DCState.usColorFormat != LCOLF_RGB)
    lColorWhite = CLR_WHITE;
  else
    lColorWhite = COLOR_WHITE;

  /*
  ** if the plotter is not HPGL2 it can not do white lines.
  ** so don't try
  */
  if ((!(PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)) &&
      (lColorWhite == pDDC->DCState.abnd.lBackColor) )
  {
    bResult = FALSE;
  }
  else
  {
    /*
    ** If the BackGround mix  mode is overpaint and
    ** the foreground pattern is not solid we must
    ** Paint the background. So check color Sorting.
    */
    if (pDDC->DCState.abnd.usBackMixMode == BM_OVERPAINT &&
        usSymbol !=  PATSYM_SOLID   &&
        usSymbol !=  PATSYM_DEFAULT)
    {
      bResult = check_color_sorting(pDDC, pDDC->DCState.abnd.lBackColor,
                                    USAGE_FILLS);
    }
    else
    {
      bResult = FALSE;
    }
  }

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME = check_char_color()
 *
 * DESCRIPTION   = check character color
 *                 validates the capability of
 *                 the plotter to output the
 *                 current character color.
 *
 * INPUT         = pDDC
 *                 Color
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_char_color(PDDC pDDC,
                      LONG Color)
{
  BOOL bResult;


  if (pDDC->DCState.dcbnd.cbnd.usMixMode == FM_LEAVEALONE)
    bResult = FALSE;
  else
    bResult = check_color_sorting(pDDC, Color, USAGE_TEXT);

  return (bResult);
}
/***************************************************************************
 *
 * FUNCTION NAME  = check_char_background_color()
 *
 *
 * DESCRIPTION    = check char background color
 *                  validates the capability of the
 *                  plotter to output the current
 *                  char background fill color
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_char_background_color(PDDC pDDC, LONG lBackColor,
                                 USHORT usBackMixMode)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  ULONG  lColorWhite;
  BOOL bResult;

  /*
  ** Get correct color white format for testing for color
  ** white on non HPGL2 plotters
  */
  if (pDDC->DCState.usColorFormat != LCOLF_RGB)
    lColorWhite = CLR_WHITE;
  else
    lColorWhite = COLOR_WHITE;

  /*
  ** if the plotter is not HPGL2 it can not do white lines.
  ** so don't try
  */
  if ((!(PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)) &&
      (lColorWhite == lBackColor) )
  {
    bResult = FALSE;
  }
  else
  {
    /*
    ** If the BackGround mix  mode is not leavalone
    ** check color Sorting.
    */
    if (usBackMixMode != BM_DEFAULT &&
        usBackMixMode != BM_LEAVEALONE)
    {
      bResult = check_color_sorting(pDDC, lBackColor, USAGE_FILLS);
    }
    else
    {
      bResult = FALSE;
    }
  }

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME = check_line_color()
 *
 * DESCRIPTION   = check line color
 *                 validates the capability of
 *                 the plotter to output the
 *                 current line color.
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_line_color(PDDC pDDC)
{
  BOOL bResult;


  if (pDDC->DCState.lbnd.usType == LINETYPE_INVISIBLE ||
     pDDC->DCState.lbnd.usMixMode == FM_LEAVEALONE)
  {
    bResult = FALSE;
  }
  else
  {
    bResult = check_color_sorting(pDDC, pDDC->DCState.lbnd.lColor,
                                  USAGE_LINES);
  }

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME = check_marker_color()
 *
 * DESCRIPTION   = check marker color
 *                 validates the capability
 *                 of the plotter to output
 *                 the current marker
 *                 color/marker
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL check_marker_color(PDDC pDDC)
{
  BOOL bResult;


  if (pDDC->DCState.mbnd.usMixMode == FM_LEAVEALONE)
  {
    bResult = FALSE;
  }
  else
  {

    switch (pDDC->DCState.mbnd.usSymbol)
    {
      case  MARKSYM_CROSS :
      case  MARKSYM_PLUS :
      case  MARKSYM_DIAMOND :
      case  MARKSYM_SQUARE :
      case  MARKSYM_SIXPOINTSTAR :
      case  MARKSYM_EIGHTPOINTSTAR :
      case  MARKSYM_SMALLCIRCLE :
      case  MARKSYM_DEFAULT :
      default  :
        bResult = check_color_sorting(pDDC, pDDC->DCState.mbnd.lColor,
                                      USAGE_LINES);
        break;
      case  MARKSYM_SOLIDDIAMOND :
      case  MARKSYM_SOLIDSQUARE :
      case  MARKSYM_DOT :
        bResult = check_color_sorting(pDDC, pDDC->DCState.mbnd.lColor,
                                      USAGE_FILLS);
        break;
    }
  }

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME = create_default_color_table()
 *
 * DESCRIPTION   = generates the default color table used by PLOTTERS
 *
 *                 This function is called at enable_dc
 *                 time to create the default color table
 *                 information.  It may be called at
 *                 reset_dc time to reinitialize the
 *                 color table to it's default state.
 *
 * INPUT         = pDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL create_default_color_table(PDDC pDDC)
{
  BOOL bResult = FALSE;
  LONG Index;


  if (!pDDC->DCState.pColorTable)
  {
    pDDC->DCState.pColorTable =
            (PCOLORTABLE)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
                               MAX_COLOR_INDEX *sizeof(COLORTABLE));
  }

  pDDC->DCState.usColorFormat = LCOLF_DEFAULT;
  pDDC->DCState.lColorLoIndex = 0L;
  pDDC->DCState.lColorHiIndex = MAX_DEFAULT_INDEX;

  for (Index = 0; Index < MAX_COLOR_INDEX; Index++)
  {
    pDDC->DCState.pColorTable[Index] = DefaultColorTable[Index];
  }

  bResult = TRUE;

  return (bResult);
}

/***************************************************************************
 *
 * FUNCTION NAME = start_color_sorting()
 *
 * DESCRIPTION   =   sets up PLOTTERS to begin color sorting.
 *
 *                   sets up PLOTTERS to begin color sorting.
 *                   Ensures correct mode (not first pass
 *                   from spooler queue processor,) and that
 *                   the user has selected color_sorting from
 *                   dialog box This function is called to
 *                   enable journaling for color sorting.  It
 *                   is called at enable time, and at each
 *                   new page.
 *
 * INPUT         = PDDC pDDC
 *                 HDC hDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID start_color_sorting(PDDC pDDC, HDC hDC)
{
  PPDEVICE pPDevice = pDDC->pPDevice;


  if (pDDC->usDCType == OD_DIRECT && pPDevice->DataType == PM_Q_STD &&
     pPDevice->bColorSorting)
  {
    pDDC->lSavedDCid = InnerGre32Entry3(hDC, pDDC,
                                     MAKEULONG(NGreSaveDC,HIUSHORT(COM_SAVE)));
    pPDevice->hJournal = (LHANDLE)GreCreateJournalFile(NULL,
                                                       JOURNAL_OPTS, 0L);
    GreStartJournalFile(hDC, pPDevice->hJournal);
    pPDevice->bCarouselPensUsedBuilt = FALSE;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = stop_color_sorting()
 *
 * DESCRIPTION   = stop color sorting
 *                 Called at end of page/end of frame.
 *                 Basic operation is to replay the
 *                 journal file and only perform those
 *                 operations requiring the current
 *                 pen.  Thus, ALL drawing operations
 *                 are completed for each pen in one
 *                 operation, thus reducing the number
 *                 of (slow) pen change operations.
 *
 * INPUT         = PDDC pDDC
 *                 HDC hDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID stop_color_sorting(PDDC pDDC,
                        HDC hDC)
{

  /*
  **   This function processes the color sorting stuff.  It is called at
  **  the end of a page.  This function will stop journaling, then
  **  play the journal file for each pen used in the carousel.  It will
  **  set the current pen based on lightness to darkness for a given
  **  carousel.
  **  In the event an ABORTDOC signal is received, the bEnableOutput flag
  **  will be cleared.  Further output will cease -- output_bytes will stop
  **  sending -- and we will skip the rest of the journal file replay.
  */

  PPDEVICE pPDevice = pDDC->pPDevice;
  BOOL     bMessageDisplayed = FALSE;
  USHORT   Carousel;
  USHORT   Color;
  USHORT   Pen;
  USHORT   usNumPlaysOfJournal;
  ULONG    ulRGBColor;

  /*
  **    First step:  stop journalling,  then play the file back to record
  **  which pens in which carousels are used.  When the file is played
  **  back for drawing,  we then select only pens and/or carousels that
  **  are required.
  */
  GreStopJournalFile(hDC, pPDevice->hJournal);

  /*
  ** Make sure our DC is in the Initial state for the page
  */
  if (pDDC->lSavedDCid > 0)
  {
    /*
    ** if DC was save restore it to the original
    ** start of recording-markv
    */
    InnerGre32Entry4(hDC, pDDC->lSavedDCid, pDDC,
                  MAKEULONG(NGreRestoreDC,HIUSHORT(COM_SAVE)));

    /*
    ** resave the inital state
    */
    pDDC->lSavedDCid = InnerGre32Entry3(hDC, pDDC,
                                  MAKEULONG(NGreSaveDC,HIUSHORT(COM_SAVE)));
  }   /* endif  */

  pPDevice->bCarouselPensUsedBuilt = FALSE;
  pDDC->bJournalPlayed = FALSE;
  GrePlayJournalFile(hDC, pPDevice->hJournal);
  pDDC->bJournalPlayed = TRUE;

  /*
  ** Lift the pen to avoid putting the new pen down
  ** on a position painted with the previous pen color.
  ** markv part of b724595
  */

  if (pPDevice->bPageStarted)
  {
    lift_pen(pDDC);
    GplThreadFlushBuffer(pPDevice->hThread, FALSE);
  }  /* endif                             */

  /*
  ** calculate the number of times we will replay the journal file
  ** We need this info for determining the number of times we need
  ** to save the DC
  */

  usNumPlaysOfJournal = 0;

  for (Carousel = 0; Carousel < MAX_CAROUSELS; Carousel++)
  {
    if (pPDevice->pSetup->bActiveCarousel[Carousel])
    {
      for (Pen = 0; Pen < MAX_PENS; Pen++)
      {
        if (pPDevice->fbCarPenUsed[Carousel]&(1 << Pen))
        {
          usNumPlaysOfJournal++;
        }
      }
    }
  }

  /*
  ** Special case: We saved the DC and we don't have to replay the journal
  ** file because no pens were used.= BLANK PAGE(but some attrs may be set)
  **
  ** We must through away the DC we saved before saving any more.
  ** Since this is a blank page it is faster to restore the DC and
  ** replay the journal file causing the next page to correctly inherit
  ** the ending state of the of this page.
  */

  if (!usNumPlaysOfJournal && pDDC->lSavedDCid > 0)
  {
    InnerGre32Entry4(hDC, pDDC->lSavedDCid, pDDC,
                              MAKEULONG(NGreRestoreDC,HIUSHORT(COM_SAVE)));
    pDDC->lSavedDCid = 0;
    GrePlayJournalFile(hDC, pPDevice->hJournal);
  }  /* endif                             */

  pPDevice->bCarouselPensUsedBuilt = TRUE;

  /*
  **    Now for the real work - cycle through each carousel and each pen
  ** within each carousel.  If the pen is used,  the play back the file
  ** to draw what is relevant for that pen.  A dialog box will be
  ** displayed when it is time to change carousels.
  */
  for (Carousel = 0; Carousel < MAX_CAROUSELS; Carousel++)
  {
    if (!(pPDevice->bEnableOutput))
    {
      goto DoneLoops;                // aborted? leave!
    }

    if (pPDevice->pSetup->bActiveCarousel[Carousel])
    {
      pPDevice->CurrentCarousel = Carousel;

      for (Color = 0; Color < MAX_COLORS; Color++)
      {
        for (Pen = 0; Pen < MAX_PENS; Pen++)
        {
          if (!(pPDevice->bEnableOutput))
          {
            goto DoneLoops;          // aborted? leave!
          }

          if ((pPDevice->fbCarPenUsed[Carousel]&(1 << Pen)) &&
             (pPDevice->pSetup->Carousel[Carousel].Pen[Pen].Color == (UCHAR)
             (Color+1)))
          {

            /*
            ** Make sure our DC is in the Initial state for the page
            */
            if (pDDC->lSavedDCid > 0)
            {
              /*
              ** if DC was saved restore it to the original state
              ** before playing the journal-markv
              */
              InnerGre32Entry4(hDC, pDDC->lSavedDCid, pDDC,
                            MAKEULONG(NGreRestoreDC,HIUSHORT(COM_SAVE)));
              usNumPlaysOfJournal--;
              pDDC->lSavedDCid = 0;

                    /*
                    ** resave the inital state if we are going to need it
                    */

              if (usNumPlaysOfJournal)
              {

                pDDC->lSavedDCid = InnerGre32Entry3(hDC, pDDC,
                      MAKEULONG(NGreSaveDC,HIUSHORT(COM_SAVE)));
              }
            }                        /* endif                             */
            pPDevice->CurrentPen = Pen+1;

            if (pPDevice->bMultiCarousel && bMessageDisplayed != Carousel+1
               && !(PlotterClass[pPDevice->Plotter].usHPGLCaps&HPGL2))
            {
              output_bytes(pDDC, "SP;");
              GplThreadFlushBuffer(pPDevice->hThread, FALSE);
              bMessageDisplayed = Carousel+1;
              prompt_for_carousel(pDDC, Carousel+1);
            }

            ulRGBColor = ColorList[pPDevice->pSetup->Carousel[Carousel].Pen
                          [Pen].Color-1];
            select_user_defined_pen(pDDC, Pen+1, ulRGBColor, ulRGBColor,
                       pPDevice->pSetup->Carousel[Carousel].Pen[Pen].Usage);
            GrePlayJournalFile(hDC, pPDevice->hJournal);

            /*
            ** Lift the pen to avoid putting the new pen down
            ** on a position painted with the previous pen color.
            ** markv part of b724595
            */
            if (pPDevice->bPageStarted)
            {
              lift_pen(pDDC);
              GplThreadFlushBuffer(pPDevice->hThread, FALSE);
            } /* endif                             */

            if (!pPDevice->bEnableOutput)
            {
              goto DoneLoops;
            }
          }
        }
      }
    }
  }
DoneLoops:


  if (GPI_OK == GreDeleteJournalFile(pPDevice->hJournal))
  {
    pPDevice->hJournal = 0;          /* b732221                           */
  }

  for (Carousel = 0; Carousel < MAX_CAROUSELS; Carousel++)
  {
    pPDevice->fbCarPenUsed[Carousel] = 0;
  }
  pPDevice->bCarouselPensUsedBuilt = FALSE;
  return ;
}

/***************************************************************************
 *
 * FUNCTION NAME = select_line_pen()
 *
 * DESCRIPTION   = select line pen
 *                 returns the stall number of
 *                 the pen that most closely
 *                 matches the Color
 *                 parameter.
 *
 * INPUT         =  PDDC pDDC
 *                  LONG lColor
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = pen value
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

  USHORT select_line_pen(PDDC pDDC,
                         LONG lColor)
  {
    return (locate_pen(pDDC, lColor, USAGE_LINES));
  }

/***************************************************************************
 *
 * FUNCTION NAME =  select_fill_pen()
 *
 * DESCRIPTION   =  select fill pen
 *
 * INPUT         = PDDC pDDC;
 *                 LONG lColor;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = returns the stall number of the
 *                 pen that most closely matches
 *                 the Color parameter.
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

USHORT select_fill_pen(PDDC pDDC, LONG lColor)
{
  return (locate_pen(pDDC, lColor, USAGE_FILLS));
}

/***************************************************************************
 *
 * FUNCTION NAME =  select_text_pen()
 *
 *
 * DESCRIPTION   =  select text pen
 *
 *
 *
 * INPUT         = PDDC pDDC;
 *                 LONG lColor;
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns the stall number of the
 *                 pen that most closely matches
 *                 the current text foreground color.
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

  USHORT select_text_pen(PDDC pDDC, LONG lColor)
  {
    return (locate_pen(pDDC, lColor, USAGE_TEXT));
  }

/***************************************************************************
 *
 * FUNCTION NAME =  return_RF_fill_pen()
 *
 * DESCRIPTION   =  Returns pen number for RF instruction
 *
 * INPUT         = PDDC pDDC;
 *                 LONG lColor;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = returns the pen number
 *                 that most closely matches
 *                 the lColor color.
 *
 * RETURN-ERROR  = NONE
 **************************************************************************/

  USHORT return_RF_fill_pen(PDDC pDDC, LONG lColor)
  {
    return (locate_pen(pDDC, lColor, USAGE_RFPEN));
  }

#if      FILLOPTBOX

/***************************************************************************
 *
 * FUNCTION NAME = select_fill_type()
 *
 *
 * DESCRIPTION   = Selects the HPGL fill type that most closely matches
 *                 the OS/2 pattern.
 *                 Sets the direction of fill lines
 *                 if supported on the particular
 *                 plotter.  Whether or not to fill
 *                 depends on the shape of the area
 *                 being filled and the orientation
 *                 of the paper.  The fill type is a
 *                 function of the direction to fill,
 *                 the spacing between lines
 *                 (currently 0 to default to pen
 *                 thickness), and the type of line
 *                 to draw (bidirectional).  The
 *                 bidirectional lines are not as
 *                 precise as unidirectional, but
 *                 much faster when the pen does not
 *                 have to be lifted.
 *
 *      Note: HP DraftMaster SX SXplus RX RXplus MX MXplus
 *            HP7550plus do not support user-defined fill type
 *
 * INPUT         = PDDC pDDC,PPOINTL pP,PPOINTL pQ
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID select_fill_type(PDDC pDDC,USHORT usPatSym, PPOINTL pP, PPOINTL pQ)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  BOOL     bLandscape;
  BOOL     bWide;
  USHORT   usFillType = 0;
  USHORT   usFillOpt1 = 0;
  USHORT   usFillOpt2 = 0;

  /*
  **  Check if it is a user defined pattern.  Kran
  */
  if (usPatSym == PATSYM_USERDEFINED)
  {

    output_bytes(pDDC,"FT11,");   // select fill type with our raster index
    output_number(pDDC,pPDevice->RFindex);
    /*
    ** save the device state.
    ** carefull with PATSYM_USERDEFINED. If a PATSYM_XXXXX is defined with
    ** the same value as PATSYM_USERDEFINED in pmgpi.h then change the define
    ** for PATSYM_USERDEFINED in color.h   Kran
    */
    pPDevice->usCurrentFillPattern = PATSYM_USERDEFINED;

    /*
    ** We must turn of bLineInConstruction because
    ** continuing comma separated points directly
    ** after setting the fill type will not work.
    */
    pDDC->pPDevice->bLineInConstruction = FALSE;
    return;
  }
  /*
  ** HP say's all plotters support FT
  **if (PlotterClass[pPDevice->Plotter].fsOdd & OD_FILLTYPE)
  */
  {
    bLandscape = !(pPDevice->fsTransform & DXF_PORTRAIT);
    bWide = pQ->x-pP->x >= pQ->y-pP->y;

    /*
    ** Fill Type        description             Option1              Option2
    ** ------------   -------------------       -------              -------
    **     1          FT_SOLID_BIDIRECTIONAL    ignored              ignored
    **     2          FT_SOLID_UNIDIRECTIONAL   ignored              ignored
    **     3          FT_HATCHED (parallel)     spacing              angle
    **     4          FT_CROSS_HATCH            spacing              angle
    **    10  HPGL2   FT_SHADING                level                ignored
    **    11  HPGL2   FT_USER_DEFINED           raster-fill index    pen
    */

    switch (usPatSym)
    {

      /*
      ** Since we still fill complex areas with lines when
      ** they do not fit into the polygon buffer we must use
      ** cross-hatch lines for density
      ** When we can fit everything into the polygon buffer or
      ** fill everything with fill rectangle commands we can
      ** use the correct shading commands.
      */
      case  PATSYM_DENSE1:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 4;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE2:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 5;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE3:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 6;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE4:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 7;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE5:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 8;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE6:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 10;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE7:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 13;
        usFillOpt2 = 0;
        break;
      case  PATSYM_DENSE8:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 16;
        usFillOpt2 = 0;
        break;
      case  PATSYM_HORIZ:
        usFillType = FT_HATCHED;
        usFillOpt1 = 10;
        usFillOpt2 = 180;
        break;
      case  PATSYM_VERT:
        usFillType = FT_HATCHED;
        usFillOpt1 = 10;
        usFillOpt2 = 90;             /* 90 degrees for vertical lines     */
        break;
      case  PATSYM_DIAG1:
        usFillType = FT_HATCHED;
        usFillOpt1 = 13;
        usFillOpt2 = 45;             /* 45 degrees for diagonal lines
                                        left to top right                 */
        break;
      case  PATSYM_DIAG2:
        usFillType = FT_HATCHED;
        usFillOpt1 = 12;
        usFillOpt2 = 32;             /* 32 degrees for diagonal lines
                                        left to top right                 */
        break;
      case  PATSYM_DIAG3:
        usFillType = FT_HATCHED;
        usFillOpt1 = 13;
        usFillOpt2 = 135;            /* -45 degrees for diagonal lines
                                        left to bottom right              */
        break;
      case  PATSYM_DIAG4:
        usFillType = FT_HATCHED;
        usFillOpt1 = 12;
        usFillOpt2 = 148;            /* -32 degrees for diagonal lines
                                        left to bottom right              */
        break;
      case  PATSYM_HALFTONE:
        usFillType = FT_CROSS_HATCH;
        usFillOpt1 = 6;
        usFillOpt2 = 45;             /* 45 degrees CROSS_HATCH diag lines */
        break;
      case  PATSYM_DEFAULT:
      case  PATSYM_SOLID :
        usFillType = FT_SOLID_BIDIRECTIONAL;
        usFillOpt1 = 0;

        if (PlotterClass[pPDevice->Plotter].usHPGLCaps & HPGL2)
        {
          /*
          ** don't set fill direction for HPGL2 devices since the Pen
          ** does not physically move
          */
          usFillOpt2 = 0;
        }
        else
        {
          /*
          ** set fill direction for pen plotters based on size and
          ** landscape mode to optimize pen motion
          */
          usFillOpt2 = ((bLandscape^bWide)?90:0);
        }
        break;
      case  PATSYM_NOSHADE :
      case  PATSYM_BLANK :
      default  :
        usFillType = FT_SOLID_BIDIRECTIONAL;
        usFillOpt1 = 0;
        usFillOpt2 = 0;
        break;
    }                                /* endswitch                         */

    /*
    ** If the device is not currently in the correct fill mode
    ** set it.
    */
    if (pPDevice->usCurrentFillPattern != usPatSym ||
        pPDevice->usCurrentFillAngle   != usFillOpt2)
    {
      output_bytes(pDDC, "FT");
      output_number(pDDC, (LONG)usFillType);

      if (usFillOpt1 || usFillOpt2)
      {
        output_comma(pDDC);
        output_number(pDDC,
                  (LONG)(usFillOpt1 * pDDC->pPDevice->CurrentPenThickness));

        if (usFillOpt2)
        {
          output_comma(pDDC);
          output_number(pDDC, (pPDevice->fsTransform & DXF_PORTRAIT ?
                               (LONG)usFillOpt2+90L : /* rotate pattern */
                               (LONG)usFillOpt2));
        }
      }

      /*
      ** save the device state
      */
      pPDevice->usCurrentFillPattern = usPatSym;
      pPDevice->usCurrentFillAngle = usFillOpt2;

      /*
      ** We must turn of bLineInConstruction because
      ** continuing comma separated points directly
      ** after setting the fill type will not work.
      */
      pDDC->pPDevice->bLineInConstruction = FALSE;
    }
  }
}
#endif
/***************************************************************************
 *
 * FUNCTION NAME =  set_mix_mode()
 *
 * DESCRIPTION   =  Set the Merge Control (ROP) in the device.
 *                  NOTE: FM_DEFAULT = FM_OVERPAINT
 *                        BM_DEFAULT = BM_LEAVALONE
 *                        Unless changed with GpiSetDefAttrs.
 *
 * INPUT         = PDDC   pDDC;
 *                 USHORT usMixMode;
 *                 USHORT usBackMixMode;
 *                 USHORT usMCROP;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/
BOOL set_mix_mode( PDDC pDDC, USHORT usMixMode, USHORT usBackMixMode,
                            USHORT usMCROP)
{
  SHORT usMCOpcode;
  /*
  ** MC Merge control command is only on HPGL2 devices
  */
  if (pDDC->pPDevice->usHPGLType & HPGL2)
  {
    /*
    ** if a ROP was passed, the call is from bitblt or sdBitBlt-Just
    ** use the ROP. It maps directly to the HP ROPs
    */
    if (usMCROP)
    {
      usMCOpcode = usMCROP;
    }
    else
    {
      switch (usMixMode)
      {
        case FM_OR:
            usMCOpcode = 254; //DTSoo
            break;
        case FM_XOR:
            usMCOpcode = 90;  //DTx
            break;
        case FM_AND:
            usMCOpcode = 160; //DTa
            break;
        case FM_SUBTRACT:
            usMCOpcode = 10;  //DTna
            break;
        case FM_MASKSRCNOT:
            usMCOpcode = 80;  //TDna
            break;
        case FM_ZERO:
            usMCOpcode = 0;   //0
            break;
        case FM_NOTMERGESRC:
            usMCOpcode = 5;   //DTon
            break;
        case FM_NOTXORSRC:
            usMCOpcode = 165;  //TDxn
            break;
        case FM_INVERT:
            usMCOpcode = 85;   //Dn
            break;
        case FM_MERGESRCNOT:
            usMCOpcode = 245;  //TDno
            break;
        case FM_NOTCOPYSRC:
            usMCOpcode = 15;   //Tn
            break;
        case FM_MERGENOTSRC:
            usMCOpcode = 175;  //DTno
            break;
        case FM_NOTMASKSRC:
            usMCOpcode = 95;   //DTan
            break;
        case FM_ONE:
            usMCOpcode = 255;  //1
            break;
        case FM_LEAVEALONE:
            usMCOpcode = 170;  //D
            break;
        case FM_OVERPAINT:
        default:
            usMCOpcode = 240;  //T
            break;
      }
      if (usMCOpcode != pDDC->pPDevice->usCurrentMCROP)
      {
        output_bytes(pDDC, "MC1,");
        output_number(pDDC, (LONG)usMCOpcode);
        pDDC->pPDevice->usCurrentMCROP = usMCOpcode;

      } /* endif */
    }
  }
  return TRUE;
}

 /*
 ** þ GRE FUNCTIONS þþþþþ
 */
/***************************************************************************
 *
 * FUNCTION NAME = CreateLogColorTable()
 *
 * DESCRIPTION   = create logical color table
 *                 Creates a Logical color table
 *                 for the current device context
 *
 * INPUT         = hDC,
 *                 Options
 *                 Format
 *                 Start
 *                 Count
 *                 pArray
 *                 pDDC
 *                 FunN
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 1L & 0L
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LONG CreateLogColorTable(HDC hDC,
                         ULONG Options,
                         ULONG Format,
                         LONG Start,
                         LONG Count,
                         PULONG pArray,
                         PDDC pDDC,
                         ULONG FunN)
{
  PCOLORTABLE pNewTable = pDDC->DCState.pColorTable;
  SHORT Index;
  SHORT Loop;
  ULONG ulRet;
  BOOL  bReset = FALSE;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);
  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreCreateLogColorTable (pDDC->hdcMemory, Options,
                                         Format, Start, Count,
                                         pArray, FunN );
    LeaveDriver( pDDC );
    return( ulRet );
  }

  /*
  ** The application is requesting a logical color table
  ** be created in RGB format.  This effectively means that
  ** there is no logical color table.
  */
  if (Format == LCOLF_RGB)
  {
    if (pDDC->DCState.usColorFormat != LCOLF_RGB)
    {
      PDCSTATE  pDCState = &pDDC->DCState;
      /*
      **  we are going to RGB mode and our default colors
      **  are in indexed mode - convert them to RGB mode
      */
      if (pDDC->DCState.pColorTable)
      {
        pDCState->lbnd.lColor = convert_color(pDDC,pDCState->lbnd.lColor);
        pDCState->mbnd.lColor = convert_color(pDDC,pDCState->mbnd.lColor);
        pDCState->abnd.lColor = convert_color(pDDC,pDCState->abnd.lColor);
        pDCState->ibnd.lColor = convert_color(pDDC,pDCState->ibnd.lColor);
        pDCState->dcbnd.cbnd.lColor =
                                convert_color(pDDC,pDCState->dcbnd.cbnd.lColor);

        pDCState->mbnd.lBackColor = convert_color(pDDC,pDCState->mbnd.lBackColor);
        pDCState->abnd.lBackColor = convert_color(pDDC,pDCState->abnd.lBackColor);
        pDCState->ibnd.lBackColor = convert_color(pDDC,pDCState->ibnd.lBackColor);
        pDCState->dcbnd.cbnd.lBackColor =
                            convert_color(pDDC,pDCState->dcbnd.cbnd.lBackColor);
      }
      /*
      ** PLOTTERS is not currently in RGB mode,
      ** so maybe free the current logical color table,
      */
      if (pDDC->DCState.pColorTable)
      {                              /* if we have a one - free it        */
        if (GplMemoryFree ((PVOID)(pDDC->DCState.pColorTable)))
           pDDC->DCState.pColorTable = (PCOLORTABLE)NULL;
      }  /* end if                            */
    }

    /*
    ** do a little house cleaning
    */
    pDDC->DCState.pColorTable   = NULL;
    pDDC->DCState.usColorFormat = LCOLF_RGB;
    pDDC->DCState.lColorHiIndex = 0;
    LeaveDriver(pDDC);
    return 1L;
  }

  if (Format == LCOLF_INDRGB)
  {
    /*
    ** The format of an indexed logical color table is
    **    INDEX, RGB VALUE
    ** for each entry, so divide the count by two
    */
    Count /= 2;
  }

  if (Start < 0L || Start >= MAX_COLOR_INDEX)
  {
    GplErrSetError(PMERR_INV_COLOR_START_INDEX);
    LeaveDriver(pDDC);
    return 0L;
  }

  if (Count < 0L || (Count+Start) > MAX_COLOR_INDEX)
  {
    GplErrSetError(PMERR_INV_LENGTH_OR_COUNT);
    LeaveDriver(pDDC);
    return 0L;
  }

  if (Format != LCOLF_INDRGB && Format != LCOLF_CONSECRGB)
  {
    GplErrSetError(PMERR_INV_COLOR_FORMAT);
    LeaveDriver(pDDC);
    return 0L;
  }

  /*
  ** allocate a new table
  */

  pNewTable = (PCOLORTABLE)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
                                           MAX_COLOR_INDEX *sizeof
                                              (COLORTABLE));


  if (!pNewTable)
  {
    /*
    ** not enough memory in the heap
    */
    GplErrSetError(PMERR_INSUFFICIENT_MEMORY);
    LeaveDriver(pDDC);
    return 0L;
  }

  if (pDDC->DCState.usColorFormat == LCOLF_RGB || (Options&LCOL_RESET))
  {
    /*
    ** setup the new color table, as specified by the
    ** application, as the default color table
    */
    pDDC->DCState.usColorFormat = LCOLF_DEFAULT;

    for (Index = 0; Index < MAX_COLOR_INDEX; Index++)
    {
      pNewTable[Index] = DefaultColorTable[Index];
    }
  }
  else
  {
    /*
    ** copy the current color table to the new table
    **
    */
    for (Index = 0; Index < MAX_COLOR_INDEX; Index++)
    {
      pNewTable[Index] = pDDC->DCState.pColorTable[Index];
    }
  }

  if (Count)
  {
    if (Format == LCOLF_CONSECRGB)
    {
      for (Loop = 0; Loop < (SHORT)Count; Loop++)
      {
        pNewTable[Loop+(SHORT)Start].PhysRGB = pArray[Loop];
      }
      /*
      ** Was the Color table lengthened?
      */
      if ((LONG)(Start+Count) > pDDC->DCState.lColorHiIndex)
      {
        pDDC->DCState.lColorHiIndex = (SHORT)Start+(SHORT)Count;
      }      /* endif                             */
    }
    else
    {
      Index = 0;

      for (Loop = 0; Loop < (SHORT)Count; ++Loop)
      {
        if ((pArray[Index] < MAX_COLOR_INDEX))
        {
          pNewTable[pArray[Index]].PhysRGB = pArray[Index+1];

          if (pDDC->DCState.lColorHiIndex < (LONG)pArray[Index])
          {
            pDDC->DCState.lColorHiIndex = (LONG)pArray[Index];
          }                          /* endif                             */
          Index += 2;
        }
        else
        {
          GplErrSetError(PMERR_INV_COLOR_INDEX);
          if (GplMemoryFree ((PVOID)(pNewTable)))
             pNewTable = (PCOLORTABLE)NULL;
          LeaveDriver(pDDC);
          return  GPI_ERROR;
        }
      }
    }

    pDDC->DCState.usColorFormat = LCOLF_INDRGB;
    /*
    ** reset color attributes to the default values
    */
    bReset = TRUE;
  }

  if (pDDC->DCState.pColorTable)     /* maybe should free old color table */
  {
    if (GplMemoryFree ((PVOID)(pDDC->DCState.pColorTable)))
       pDDC->DCState.pColorTable = (PCOLORTABLE)NULL;
  }

  pDDC->DCState.pColorTable = pNewTable;

  /*
  ** if the attributes need to be reset to the default values
  */
  if (bReset)
  {
    /*
    ** reset color attributes to the default values
    */
    GreDeviceSetGlobalAttribute(hDC, ATYPE_COLOR, NULL, GATTR_DEFAULT);
    GreDeviceSetGlobalAttribute(hDC, ATYPE_BACK_COLOR, NULL, GATTR_DEFAULT);
  }

  if (Options&LCOL_REALIZABLE)
  {
    GplErrSetWarning(PMERR_REALIZE_NOT_SUPPORTED);
  }

  if (pDDC->lEngineVersion >= RASTER_ENGINE_22)
  { // tell the GRE the colortable is changing
    (*daCreateLogColorTable)(hDC,Options,Format,Start,Count,pArray,pDDC,FunN);
  }
  LeaveDriver(pDDC);
  return 1L;
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryColorData()
 *
 *
 * DESCRIPTION   = Query current color data
 *
 *                 returns information regarding
 *                 the currently selected color
 *                 support for the driver
 *
 *
 *
 * INPUT         = HDC hDC
 *                 LONG Count
 *                 PLONG pArray
 *                 PDDC pDDC
 *                 ULONG FunN
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = 1L
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryColorData(HDC hDC, LONG Count, PLONG pArray,
                      PDDC pDDC, ULONG FunN)
{

  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreQueryColorData (pDDC->hdcMemory, Count,
                                     pArray, FunN );
    LeaveDriver( pDDC );
    return( ulRet );
  }

  while (Count > 3L)
  {
     pArray[--Count] = 0L;
  }

  if (Count >= 3)
  {
     pArray[QCD_LCT_HIINDEX] = pDDC->DCState.lColorHiIndex;
  }

  if (Count >= 2)
  {
     pArray[QCD_LCT_LOINDEX] = pDDC->DCState.lColorLoIndex;
  }

  if (Count >= 1)
  {
     pArray[QCD_LCT_FORMAT] = (LONG)pDDC->DCState.usColorFormat;
  }
  LeaveDriver(pDDC);
  return (1L);
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryColorIndex()
 *
 *
 * DESCRIPTION   = Query color index
 *
 *                 returns the index of the RGB
 *                 color value which most closely
 *                 matches the RGBColor parameter
 *
 *
 * INPUT         = HDC hDC
 *                 ULONG Options
 *                 LONG RGBColor
 *                 PDDC pDDC
 *                 ULONG FunN
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = Result
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryColorIndex(HDC hDC, ULONG Options, LONG RGBColor,
                       PDDC pDDC, ULONG FunN)
{
  LONG Result = GPI_ALTERROR;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    Result = InnerGreQueryColorIndex (pDDC->hdcMemory, Options,
                                      RGBColor, FunN );
    LeaveDriver( pDDC );
    return( Result );
  }

  if (pDDC->DCState.usColorFormat == LCOLF_RGB)
  {
    if (RGBColor <= 0xffffffL)
    {
      Result = RGBColor;
    }
    else
    {
      GplErrSetError(PMERR_INV_RGBCOLOR);
    }
  }
  else
  {
    SHORT Loop;
    ULONG Distance,MinDistance = (ULONG)-1L;


    for (Loop = 0; Loop < MAX_COLOR_INDEX; Loop++)
    {
      if (RGBColor == COLOR_WHITE)
      {
        if (pDDC->DCState.pColorTable[Loop].PhysRGB == COLOR_WHITE)
        {
          Result = (LONG)Loop;
          break;
        }
      }
      else
      {
        if ((Distance = color_distance(pDDC->DCState.pColorTable[Loop].
           PhysRGB,
                                       RGBColor)) < MinDistance)
        {
          MinDistance = Distance;
          Result = (LONG)Loop;
        }
      }
    }
  }
  LeaveDriver(pDDC);
  return  Result;
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryLogColorTable()
 *
 *
 * DESCRIPTION   = Query logical color table
 *
 *
 *
 *
 * INPUT         = HDC hDC
 *                 ULONG Options
 *                 LONG Start
 *                 LONG Count
 *                 PLONG pArray
 *                 PDDC pDDC
 *                 ULONG FunN
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns the contents of the
 *                 current logical color table Result
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryLogColorTable(HDC hDC, ULONG Options, LONG Start,
                        LONG Count, PLONG pArray, PDDC pDDC,
                        ULONG FunN)
{

    LONG Index,MaxCount = Count,NumVals = 0,Result = QLCT_ERROR;
    PCOLORTABLE pCT = pDDC->DCState.pColorTable;
    ULONG ulRet;

    if (!EnterDriver(pDDC))
       return(GPI_ERROR);

   /*
   **          In case of MEMORYDC Dispatch to Graphics Engine
   */
   if (pDDC->usDCType == OD_MEMORY)
   {
     ulRet = InnerGreQueryLogColorTable( pDDC->hdcMemory, Options,
                                         Start,Count, pArray, FunN );
     LeaveDriver( pDDC );
     return( ulRet );
   }

    if (Start < 0L || Start >= MAX_COLOR_INDEX)
    {
      GplErrSetError(PMERR_INV_COLOR_START_INDEX);
    }
    else
    {
      if (Count < 0L)
      {
        GplErrSetError(PMERR_INV_LENGTH_OR_COUNT);
      }
      else
      {
        if (pDDC->DCState.usColorFormat == LCOLF_RGB)
        {
          Result = QLCT_RGB;
        }
        else
        {
          if (Options&LCOLOPT_INDEX)
          {
            MaxCount &= ~1L;
          }

          for (Index = Start; NumVals < MaxCount && Index < MAX_COLOR_INDEX;
             Index++)
          {
            if (pCT[Index].LogRGB != 0xFFFFFFFFL)
            {
              if (Options&LCOLOPT_INDEX)
              {
                pArray[NumVals++] = Index;
              }
              pArray[NumVals] = pCT[Index].PhysRGB;
              ++NumVals;
            }
            else
            {
              if (!(Options&LCOLOPT_INDEX))
              {
                pArray[NumVals++] = 0xFFFFFFFFL;
              }
            }
          }
          Result = NumVals;
        }
      }
    }
    LeaveDriver(pDDC);
    return (Result);
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryNearestColor()
 *
 *
 * DESCRIPTION   = This function returns the available color nearest to
 *                 the specified color on the currently associated device
 *                 even if it is not available in the logical color table.
 *
 *
 * INPUT         = HDC hDC
 *                 ULONG Options
 *                 LONG RGBIn
 *                 PDDC pDDC
 *                 ULONG FunN
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns the RGB value of one of
 *                 the currently available colors
 *                 that most closely matches the
 *                 RGBIn parameter value
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryNearestColor(HDC hDC, ULONG ulOptions, LONG lRGBIn,
                       PDDC pDDC,
                       ULONG FunN)
{
  SHORT Index;
  ULONG Distance;
  ULONG MinDistance = ~0L;
  LONG  lClosestColor = COLOR_WHITE;
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreQueryNearestColor( pDDC->hdcMemory, ulOptions,
                                     lRGBIn, FunN );
    LeaveDriver( pDDC );
    return( ulRet );
  }

  if ((ULONG)lRGBIn > 0xffffffUL)
  {
    GplErrSetError(PMERR_INV_RGBCOLOR);
  }
  else
  {
    /*
    ** if we are sending application RGB colors
    ** to the device to define a HPGL2 pen palette
    ** simply return the RGB value passed in as the
    ** closest color
    */
    if (pDDC->pPDevice->pSetup->usFlags & FL_USEAPPCOLORS)
    {
      //lClosestColor = convert_color(pDDC, lRGBIn);
      lClosestColor = lRGBIn;
    }
    /*
    ** Find the closest user defined pen
    */
    else
    {
      if (lRGBIn != COLOR_WHITE)
      {
        for (Index = 0; Index < MAX_COLORS; Index++)
        {
          if (pDDC->pPDevice->ColorAvailable[Index] &&
              (Distance =
               color_distance(ColorList[Index], lRGBIn)) < MinDistance)
          {
            MinDistance = Distance;
            lClosestColor = ColorList[Index];
          }
        }
      }
    }
  }
  LeaveDriver(pDDC);
  return  lClosestColor;
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryRealColors()
 *
 *
 * DESCRIPTION   = This function returns an array of the distinct colors
 *                 available on the device.
 *
 *
 *
 * INPUT         = HDC hDC
 *                 ULONG ulOptions
 *                 LONG Start
 *                 LONG Count
 *                 PLONG pArray
 *                 PDDC pDDC
 *                 ULONG FunN
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns the currently available color set as RGB values
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryRealColors(HDC hDC, ULONG ulOptions, LONG Start,
                     LONG Count, PLONG pArray, PDDC pDDC,
                     ULONG FunN)
{
  LONG   i;
  LONG   NumColors;
  USHORT j;
  LONG Result = -1L;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    Result = InnerGreQueryRealColors (pDDC->hdcMemory, ulOptions,
                                    Start, Count, pArray, FunN );
    LeaveDriver( pDDC );
    return( Result );
  }

  CLRDBGMSG("\n\rPLOTTERS:  enter QueryRealColors\n\r");

  if (Start < 0L || Start >= MAX_COLORS)
  {
    GplErrSetError(PMERR_INV_COLOR_START_INDEX);
    LeaveDriver( pDDC );
    return -1L;
  }                                  /* endif                             */

  if (Count < 0L)
  {
    GplErrSetError(PMERR_INV_LENGTH_OR_COUNT);
    LeaveDriver( pDDC );
    return -1L;
  }                                  /* endif                             */

  NumColors = 0;

  if (ulOptions & LCOLOPT_INDEX)
  {
    Count &= ~1L;                    /* Values come in pairs (truncate
                                        down)                             */
  }                                  /* endif                             */

  for (i = Start; i < MAX_COLORS && NumColors < Count; i++)
  {
    if (pDDC->pPDevice->ColorAvailable[i])
    {
      /*
      **    Color is available,  so look for it
      */
      if (ulOptions & LCOLOPT_INDEX)
      {
        /*
        **    Find this plotter color in logical color table
        */
        pArray[NumColors] = CLR_NOINDEX;/* Not there                      */

        for (j = 0; j < MAX_COLOR_INDEX; j++)
        {
          /*
          **    Scan the logical color table
          */
          if (pDDC->DCState.pColorTable[j].PhysRGB == ColorList[i])
          {
            /*
            **    The color is in the color table,  so return
            **    the index into the color table, UNLESS we are
            **    in RGB mode,  in which case we return the RGB
            **    value twice,  since there is no index.
            */
            if (pDDC->DCState.usColorFormat == LCOLF_RGB)
            {
              pArray[NumColors] = ColorList[i];
            }
            else
            {
              pArray[NumColors] = j;
            }                        /* endif                             */
            break;
          }                          /* endif                             */
        }                            /* endfor                            */
        ++NumColors;
      }                              /* endif                             */
      pArray[NumColors++] = ColorList[i];
    }                                /* endif                             */
  }                                  /* endfor                            */

  /*
  ** LT999 - GpiQueryRealColors now returns the number of pens + white
  ** (the background as specifed in the DevQueryCaps[CAPS_COLORS] writeup)
  **
  ** ptr GDDM --- 1 Jul 1991
  **   added -254L assignment to force even return value.
  **   According to Everton in Hursley, the problem in GDDM
  **   is being caused by an an odd return value.
  **
  ** PTR B724996 -- 23 July 1991          
  **      ADDED IF...THEN...ELSE
  **           
  */

  if (ulOptions & LCOLOPT_INDEX)
  {
    pArray[NumColors] = CLR_NOINDEX; /* Not there                         */

    for (j = 0; j < MAX_COLOR_INDEX; j++)
    {
      /*
      **    Scan the logical color table
      */
      if (pDDC->DCState.pColorTable[j].PhysRGB == COLOR_WHITE)
      {
        /*
        **    The color is in the color table,  so return
        **    the index into the color table, UNLESS we are
        **    in RGB mode,  in which case we return the RGB
        **    value twice,  since there is no index.
        */
        if (pDDC->DCState.usColorFormat == LCOLF_RGB)
        {
          pArray[NumColors] = COLOR_WHITE;
        }
        else
        {
          pArray[NumColors] = j;
        }                            /* endif                             */
        break;
      }                              /* endif                             */
    }                                /* endfor                            */
    ++NumColors;
  }                                  /* endif                             */
  pArray[NumColors++] = COLOR_WHITE;
  CLRDBGMSG("PLOTTERS:  leave QueryRealColors\n\r");

  LeaveDriver( pDDC );
  return  NumColors;
}

/***************************************************************************
 *
 * FUNCTION NAME = QueryRGBColor()
 *
 *
 * DESCRIPTION   = This function returnes the actual RBG color that results
 *                 from the specified index. If the color index is RGB mode
 *                 the nearest RGB color is returned.
 *
 * INPUT         = HDC hDC;
 *                 ULONG ulOptions;
 *                 LONG Color;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns the RGB color value that
 *                 corresponds to the index value
 *                 contained in the Color
 *                 parameter.
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG QueryRGBColor(HDC hDC, ULONG ulOptions, LONG lColor,
                   PDDC pDDC, ULONG FunN)
{
  LONG lResult = -1L;
  LONG lRGBColor;

  CLRDBGMSG("\n\rPLOTTERS:  enter QueryRGBColor\n\r");

  if (!EnterDriver(pDDC))
     return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    lResult = InnerGreQueryRGBColor (pDDC->hdcMemory, ulOptions,
                                  lColor, FunN );
    LeaveDriver( pDDC );
    return( lResult );
  }

  if (pDDC->DCState.usColorFormat != LCOLF_RGB)
  {
    /*
    ** Index was passed in.
    ** Validate index entry.
    */
    if (lColor > MAX_COLOR_INDEX)
    {
      CLRDBGMSG("    INV_COLOR_INDEX passed to QueryRGBColor\n\r");
      GplErrSetError(PMERR_INV_COLOR_INDEX);
      LeaveDriver( pDDC );
      return (lResult);
    }

    /*
    ** Convert to RGB
    ** convert_color handles indexes < 0
    */
    lRGBColor = convert_color(pDDC, lColor);
  }
  else
  {
    /*
    ** Special fix for new GRE
    ** when we call the GRE back in DeviceSetAttributes() the
    ** application may be asking for default colors.  In this
    ** case the GRE will call us with negative SYS_ colors even
    ** if we are in RGB mode.
    */
    if (lColor < 0)
    {
      switch ((SHORT)lColor)
      {
        case  CLR_WHITE :
        case  CLR_TRUE :
          lRGBColor = COLOR_WHITE;
          break;

        /*
        ** all others should be black
        ** case  CLR_BLACK :
        ** case  CLR_DEFAULT :
        ** case  CLR_FALSE :
        */
        default  :
          lRGBColor = COLOR_BLACK;
          break;
      }
    }
    else
    {
      /*
      ** else RBG passed in.
      ** Validate the RGB entry
      */
      if ((ULONG)lColor > 0xffffffUL)
      {
        CLRDBGMSG("    INV_COLOR_INDEX passed to QueryRGBColor\n\r");
        GplErrSetError(PMERR_INV_COLOR_INDEX);
        LeaveDriver( pDDC );
        return (lResult);
      }

      /*
      ** use the RGB passed in.
      */
      lRGBColor = lColor;
    }
  }

  if (!(ulOptions & LCOLOPT_INDEX))
  {
    /*
    ** When NOT set the nearest RGB color for this index
    ** must be returned.
    */
    CLRDBGMSG("    Calling QueryNearestColor\n\r");
    lResult = QueryNearestColor(hDC, ulOptions, lRGBColor, pDDC, FunN);
  }
  else
  {
    /*
    ** When set the actual RGB color originally specified
    ** for this index must be returned.
    */
    lResult = lRGBColor;
  }
  CLRDBGMSG("PLOTTERS:  Leave QueryRGBColor\n\r\n\r");

  LeaveDriver( pDDC );
  return  lResult;
}

/***************************************************************************
 *
 * FUNCTION NAME = RealizeColorTable()
 *
 *
 * DESCRIPTION   = Realize color table
 *
 * INPUT         = HDC hDC;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns with an error, PLOTTERS
 *                 does not support color table
 *                 realization  0L
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG RealizeColorTable(HDC hDC, PDDC pDDC, ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreRealizeColorTable (pDDC->hdcMemory, FunN);
    LeaveDriver( pDDC );
    return( ulRet );
  }
  GplErrSetWarning(PMERR_REALIZE_NOT_SUPPORTED);
  LeaveDriver(pDDC);
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = UnrealizeColorTable()
 *
 *
 * DESCRIPTION   = Unrealize color table
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = returns with an error, PLOTTERS
 *                 does not support color table
 *                 realization, therefore is does
 *                 not support the reverse process. 0L
 *
 *
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

LONG UnrealizeColorTable(HDC hDC, PDDC pDDC, ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreUnrealizeColorTable (pDDC->hdcMemory, FunN);
    LeaveDriver( pDDC );
    return( ulRet );
  }
  GplErrSetWarning(PMERR_REALIZE_NOT_SUPPORTED);
  LeaveDriver( pDDC );
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = set_pen()
 *
 *
 * DESCRIPTION   = set RGB of pen
 *
 *
 *
 * INPUT         = PDDC pDDC
 *                 SHORT iPenNumber
 *                 LONG  iPenRGB
 *                 ULONG fulPenFlags;
 *
 *
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = sets the RGB of pen using the
 *                 PC(pen(,(Red,Green,Blue);) command.
 *
 *
 * Asumptions = Pens are defined sequentially from 0 to Max pens
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

VOID set_pen(PDDC pDDC, SHORT iPenNumber, LONG lPenRGB, ULONG fulPenFlags )
{
  PPDEVICE pPDevice = pDDC->pPDevice;

  output_bytes(pDDC, "PC");
  output_number(pDDC, (LONG)iPenNumber);
  output_bytes(pDDC, ",");

  /*
  ** Red
  */
  output_number(pDDC, (LONG)((lPenRGB >> 16) & 0xff));
  output_bytes(pDDC, ",");

  /*
  ** Green
  */
  output_number(pDDC, (LONG)((lPenRGB >> 8) & 0xff));
  output_bytes(pDDC, ",");

  /*
  ** Blue
  */
  output_number(pDDC, (LONG)(lPenRGB & 0xff));
  output_bytes(pDDC, ";");

  /*
  ** Keep Track of the HPGL2 pen Palette
  ** # of pen colors in HPGL2 pen pal and
  ** HPGL2 pen Color for each pen
  */
  if (iPenNumber >= pPDevice->usPensInPalette)
  {
    pPDevice->usPensInPalette = iPenNumber + 1;
  }
  pPDevice->usLastPenDefined = iPenNumber;
  pPDevice->paPaletteEntry[iPenNumber].ulPenRGBColor= lPenRGB;
  pPDevice->paPaletteEntry[iPenNumber].fulPenFlags  = fulPenFlags | PEN_DEFINED;

}

/*****************************************************************************
 *
 * FUNCTION NAME = set_HPGL2_color_palette
 *
 *
 * DESCRIPTION   = Called during send_header processing for HPGL2 devices
 *                 only. Sets number of pens with NPn; command where n is
 *                 the number of pens in the palette. If n is not a power
 *                 of 2, the plotter uses the next larger power of 2.
 *
 *
 *
 * INPUT         = PDDC pDDC
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 *
 *
 *
 * RETURN-NORMAL = Sets the RGB value of each pen using the
 *                 PC(pen(,(Red,Green,Blue);) command.
 *
 *
 *
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

VOID set_HPGL2_color_palette(PDDC pDDC)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  SHORT Plotter = pPDevice->Plotter;
  PPROFILEINFO pSetup = pPDevice->pSetup;
  SHORT Carousel,Color,Pen;

  /*
  ** if the user has selected to use the application colors
  ** Not the user defined pen colors set the number of colors available
  ** to the hpgl2 pen palette size, Define a white pen as pen 0
  ** and a Black pen as pen 1. The remainder of the colors used by
  ** the application will be dynamicly created as used.
  */
  if (pSetup->usFlags & FL_USEAPPCOLORS)
  {
    /*
    ** Set number of pens in palette
    */
    output_bytes(pDDC, "NP");
    output_number(pDDC, (LONG)(pPDevice->NumColorsAvailable));
    pPDevice->usPensInPalette = 0;
    pPDevice->usLastPenDefined = 0;
    /*
    ** Set RGB for Pens
    **
    ** Pens are created dynamicly as needed
    */
    /*
    **
    ** Set pen 0 to White for quick access to a white fill pen
    ** Fill code in box.c is dependent on pen 0 being white.
    */
    set_pen(pDDC, 0, COLOR_WHITE, PEN_PERMANENT);
  }
  else
  {
    /*
    ** Set number of pens in palette
    ** + 1 because we reserve pen 0 for clearing areas
    */

    output_bytes(pDDC, "NP");
    output_number(pDDC, (LONG)(pPDevice->NumColorsAvailable+1));

    /*
    ** Set RGB for Pens
    **
    ** Set pen 0 to White for quick access to a white fill pen
    ** Fill code in box.c is dependent on pen 0 being white.
    */

    set_pen(pDDC, 0, COLOR_WHITE, PEN_PERMANENT);

    for (Carousel = 0; Carousel < MAX_CAROUSELS; Carousel++)
    {
      if (pSetup->bActiveCarousel[Carousel])
      {
        for (Pen = 0; Pen < MAX_PENS; Pen++)
        {
          if ((Color = (SHORT)pSetup->Carousel[Carousel].Pen[Pen].Color))
          {
            /*
            ** Store pen # in palette for pen selection
            ** Set pen RGB
            */
            set_pen(pDDC,
                    pPDevice->iHPGL2PenNumber[Carousel][Pen], /*Pen#InPallette*/
                    ColorList[Color-1],                       /* RGB          */
                    PEN_NOFLAGS);                             /* no pen flags */
          }
        }
      }
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = set_transparency_mode()
 *
 *
 * DESCRIPTION   = Checks and sets the transparency mode.
 *                 TR Defines how the white areas of graphics images are
 *                 Plotted.  IN and DF instructions return TR to its default.
 *                 White is defined as the shite reference specified by
 *                 the CR instructions.
 *
 * INPUT         = pDDC
 *                 bMODE   FALSE = off overlaying white areas becomes opaque
 *                         TRUE  = on overlaying white areas are transparent.
 * OUTPUT        = NONE
 *
 *
 * RETURN-NORMAL = bResult
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

BOOL set_transparency_mode(PDDC pDDC, SHORT iMode)
{

  if (pDDC->pPDevice->usHPGLType & HPGL2)
  {
    if (pDDC->pPDevice->CurrentTRMode != iMode)
    {
      if (iMode)
        output_bytes(pDDC, "TR1");
      else
        output_bytes(pDDC, "TR0");

      pDDC->pPDevice->CurrentTRMode = iMode;
    }
  }

  return (TRUE);
}


/***************************************************************************
 * FUNCTION NAME = setup_raster_fill_index
 *
 * DESCRIPTION   =
 *
 * INPUT         =
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 **************************************************************************/

LOCAL BOOL setup_raster_fill_index(HDC  hDC, PDDC pDDC,
                                   PRGB2 prgb2PatColors, PBMAPINFO pPatBmapInfo)
{

  ULONG              Plotter    = pDDC->pPDevice->Plotter;
  ULONG              fulOddCaps = PlotterClass[Plotter].fsOdd; /* odd caps      */
  ULONG              ullcid;
  ULONG              ulRet      = FALSE;
  HBITMAP            hbm;
  BITMAPINFOHEADER   bmi;

  DBPRINTF (("Entered setup_raster_fill_index \n"));

  if (!(fulOddCaps & (OD_PCL | OD_HPRTL)))
  {
    DBPRINTF(("Device does not support userdefined patterns"));
    return (TRUE);
  }
  /*
  ** For user defined patterns we fill the background regardless of the
  ** BACKGROUND Mix Mode.
  ** So If Foreground mix mode is FM_LEAVEALONE then just fill the background
  ** and return.
  */
  if (pDDC->DCState.abnd.usMixMode == FM_LEAVEALONE)
  {
    USHORT  usSaveMixMode = pDDC->DCState.abnd.usBackMixMode;

    DBPRINTF(("usMixMode : FM_LEAVEALONE in setup_raster"));

    pDDC->DCState.abnd.usBackMixMode = BM_OVERPAINT;
    ulRet = check_area_background_color(pDDC);
    pDDC->DCState.abnd.usBackMixMode = usSaveMixMode;
    return(ulRet);
  }

  /*
  ** If we are running on Gre22 and the call is from sdbitblt then only
  ** we will have the pPatBmapInfo.
  */
  if (pPatBmapInfo)
  {
    ulRet = download_pattern(hDC,pDDC,prgb2PatColors,pPatBmapInfo);
    assert(ulRet);
    return(ulRet);
  }
  /*
  **  The user defined pattern is defined by a bitmap.
  **  The lcid get us the bitmap handle.
  */
  ullcid = pDDC->DCState.abnd.usSet;
  hbm = GreQueryBitmapHandle(hDC,ullcid);

  if(pDDC->lEngineVersion <= 0x220L) // This      is needed to workaround
  {                                // the defect in GreQueryBitmapHandle
    hbm &= 0x0FFFFFFF;
    if(hbm > 0x04FFFFFF)
    {
      DBPRINTF (("Definitely a font."));
      assert(FALSE);
      return(TRUE);
    }
  }
  if (!hbm)
  {
    DBPRINTF (("Oh Oh! It's a Bitmap Font they want \n"));
    /* this is still a grey area (bitmap font) */
    return(TRUE);
  }

  /*
  **  Get bitmap size and parameters
  */
  if (!(GreGetBitmapParameters(hbm,&bmi)))
  {
    DBPRINTF (("GETBITMAPPARAMS in Setup Raster failed \n"));
    assert(FALSE);
    return(FALSE);
  }

  set_transparency_mode(pDDC, 0);
  ulRet = fill_pattern_use_device(hDC,pDDC,&bmi,NULL,hbm,NULL,NULL);
  set_transparency_mode(pDDC, 1);

  assert (ulRet);

  return(ulRet);

}

//typedef struct _HWPALETTEINFO { /* hwpaletteinfo */
//   ULONG  ulLength;
//   ULONG  fFlags;               /* Get/Set palette                      */
//   ULONG  ulStartIndex;         /*                                      */
//   ULONG  ulNumEntries;         /*                                      */
//   PRGB2  pRGBs;                /*                                      */
//} HWPALETTEINFO;
//typedef HWPALETTEINFO *PHWPALETTEINFO;

LONG APIENTRY DevicePalette( HDC hdc, PHWPALETTEINFO pHWPaletteInfo,
                             PDDC pDDC, ULONG ulFunction )
{
  if (!EnterDriver(pDDC))
     return(GPI_ERROR);
  if (pHWPaletteInfo->fFlags && PALETTE_SET)
  {
  //ULONG ulBitCount = pDDC-pPDevice->pDS->DevCaps[ CAPS_COLOR_BITCOUNT ]
  ///*
  //**  Save hardware palette set by the application
  //*/
  //pDDC->DCState.PRGB2DevicePalette =
  //      (PRGB2)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
  //                   ulBitCount * sizeof(RGB2));
  //
  //if (pDDC->DCState.PRGB2DevicePalette)
  //{
  //  if () {
  //  } else {
  //  } /* endif */
  //  pDDC->DCState.PRGB2DevicePalette = pHWPaletteInfo->p;
  //}
  }

  LeaveDriver(pDDC);
  return TRUE;
}


