/*  gd_src.c
 *
 *  The purpose of this library is to provide easy access from
 *  a Fortran 77 program to the GD library.
 *
 *  Specifically, I was interested in providing support for PNG and
 *  JPEG images for generating web viewable graphics directly from
 *  Dataplot.  We previously had supported this by generating
 *  Postscript and then using various image conversion software.
 *  Although workable, the GD library allows us to build the support
 *  for web viewable graphics directly into Dataplot.  Dataplot
 *  is a Fortran 77 program that uses a vector graphics model (as
 *  oppossed to a bit-map model) to generate graphics.  The GD
 *  library provides a vector based interface to these formats
 *  with a C library.
 *
 *  Given my problem, I have not supported the full GD library.
 *  Instead, I have supported a basic set of calls to support a
 *  device driver for PNG or JPEG.  This set of routines provides
 *  a wrapper layer between Fortran and the C based GD libraries.
 *  That is, these routines use only integer and real arguments with
 *  no C specific structures.  This makes the calling sequence from
 *  Fortran easy.
 * 
 *  Although I wrote this wrapper with a specific application in
 *  mind, I believe it may well be useful for other Fortran
 *  codes.  This code may be used and modified by anyone without
 *  restriction.  
 *
 *  This code assumes that the following libraries are installed on
 *  your system:
 *
 *       libgd
 *       libpng
 *       jpeg-6b
 *       zlib
 *
 *  These libraries are all freely available and they are downloadable
 *  from the web.  A dummy version of this library is maintained for
 *  those systems that do not support gd or that do not allow C
 *  routines to be called from Fortran.  Since the dummy library is
 *  coded in Fortran, routine names will be limited to six characters.
 *
 *  Note that calling C from Fortran is not standard.  I have
 *  provided the following compiler defintions to enhance portability.
 *
 *  1) The default is to assume that the Fortran compiler appends an
 *         underscore to the routine name.  Use -DNOUNDERSCORE if your
 *         compiler does not append the underscore.
 *  2) The default is to assume that the Fortran compiler converts
 *        routine names to lower case.  Use -DUPPERCASE if your
 *        Fortran compiler does not do this (e.g., the Cray).
 *  3) Many Unix compilers support a "-r8", or something similar,
 *        to make single precision 64-bit.  Use -DDOUBLE if you
 *        compile your Fortran with this option.
 *  4) Character strings are the most troublesome issue for
 *        portability.  Passing character strings from Fortran to C
 *        is very compiler dependent.  I have addressed this issue
 *        by passing character strings as arrays of ASCII Decimal
 *        Equivalents (ADE's).  That is, the Fortran converts a
 *        character string to an array of the integer values where
 *        the integer is the ASCII collating sequence (i.e., A = 65,
 *        B = 66, etc.).  The end of the string is denoted by setting
 *        the value to 0.  This is easily accomplished on the Fortran
 *        side by using the ICHAR function.  The C code here then
 *        calls an internal routine to covnert the integer array to
 *        a C string.   Although a bit convoluted, this avoids a lot
 *        of messy portability issues.
 *
 *
 *  The following routines are included:
 *
 *  gdinit      - initialize gd library
 *  gdend       - close gd library
 *  gderas      - start a new graph (close currently open one as well)
 *  gddraw      - draw a polyline
 *  gdseco      - set foreground color
 *  gdsepa      - set line pattern
 *  gdpoin      - draw a point (i.e., a pixel)
 *  gdcirc      - draw a circle
 *  gdrgfl      - solid fill of a region
 *  gdtxth      - draw a horizontal character string
 *  gdtxtv      - draw a vertical character string
 *  i_to_s_2    - utility routine to convert array of ADE's to string
 *                array
 *
 */

/*  Site dependent definitions (see comments above) */
/*  Default is an underscore and lower case.  The compiler specified
 *  definitions -DNOUNDERSCORE and -DUPPERCASE can be specified to
 *  override these defaults. */

#ifdef NOUNDERSCORE
#define APPEND_UNDERSCORE 0
#else
#define APPEND_UNDERSCORE 1
#endif
#ifdef UPPERCASE
#define SUBROUTINE_CASE 0
#else
#define SUBROUTINE_CASE 1
#endif
#ifdef DOUBLE
#define PRECISION 1
#else
#define PRECISION 0
#endif

/*  include files */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <strings.h>
#include <gd.h>

/* global definitions */

#define MAX_COLORS       89
#define MAX_GRAY        100
#define BORDER_WIDTH      3
#define DEFAULT_X_SIZE  600
#define DEFAULT_Y_SIZE  465
#define MIN_X_SIZE      100
#define MIN_Y_SIZE      100

/* GD declarations */
gdImagePtr    im;                 /* Declare Image */
FILE          *jpegout;           /* File ID for Image */
char          file_string[80];    /* Name of current file */

/* common parameters */
unsigned int  width, height;      /* last known window size */
unsigned long black, white;       /* values for black and white */
int    color_flag;         /* 0 - monochrome, 1 - color */
int    max_colors;         /* maximum colors actually allocated */
int    CURRENT_COLOR;      /* Define current color */
int    CURRENT_LINE_STYLE[12];   /* Define current line style */
int    NPTS_STYLE;               /* Number of points in style */
int    color_table[MAX_COLORS];  /* color table */
int red[MAX_COLORS] = {
    /*  0 -  7 */ 255,   0, 255,   0,   0, 255, 255,   0,
    /*  8 - 15 */ 255, 154,   0, 173, 138, 208,  47, 211,
    /* 16 - 23 */ 127, 165,  95, 255, 100,  85, 153,  72,
    /* 24 - 31 */   0, 178,  34, 255, 218, 192, 205, 240,
    /* 32 - 39 */ 105, 176,  50, 176, 102,   0, 107, 250,
    /* 40 - 47 */ 186,  60, 123,   0,  72, 199,  25,   0,
    /* 48 - 55 */ 255, 218, 152, 255, 221, 160, 250,  46,
    /* 56 - 63 */ 160, 125, 106,   0,  70, 210, 216,  64,
    /* 64 - 71 */ 238, 245, 173, 224,   0,   0,   0,   0,
    /* 72 - 79 */   0,   0,   0,   0,   0, 238, 205, 139,
    /* 80 - 87 */ 238, 205, 139, 238, 205, 139, 238, 205,
    /* 88 - 88 */ 139
};
int green[MAX_COLORS] = {
    /*  0 -  7 */ 255,   0,   0,   0, 255,   0, 165, 255,
    /*  8 - 15 */ 255, 205, 100, 216,  43,  32,  79, 211,
    /* 16 - 23 */ 255,  42, 158, 127, 149, 107,  50,  61,
    /* 24 - 31 */ 206,  34, 139, 215, 165, 192,  92, 230,
    /* 32 - 39 */ 105, 196, 205,  48, 205,   0, 142, 250,
    /* 40 - 47 */  85, 179, 104, 250, 209,  21,  25,   0,
    /* 48 - 55 */  69, 112, 251, 192, 160,  32, 128, 139,
    /* 56 - 63 */  82, 206,  90, 255, 130, 180, 191, 224,
    /* 64 - 71 */ 130, 222, 255, 255,   0,   0,   0, 238,
    /* 72 - 79 */ 205, 139, 238, 205, 139, 238, 205, 139,
    /* 80 - 87 */ 154, 133,  90,   0,   0,   0,   0,   0,
    /* 88 - 88 */   0
};
int blue[MAX_COLORS] = {
    /*  0 -  7 */ 255,   0,   0, 255,   0, 255,   0, 255,
    /*  8 - 15 */   0,  50,   0, 230, 226, 144,  79, 211,
    /* 16 - 23 */ 212,  42, 160,  80, 237,  47, 204, 139,
    /* 24 - 31 */ 209,  34,  34,   0,  32, 192,  92, 140,
    /* 32 - 39 */ 105, 222,  50,  96, 170, 205,  35, 210,
    /* 40 - 47 */  85, 179, 104, 250, 209,  21,  25,   0,
    /* 48 - 55 */   0, 214, 152, 203, 221, 240, 114,  87,
    /* 56 - 63 */  45, 235, 205, 127, 180, 140, 216, 208,
    /* 64 - 71 */ 238, 179,  47, 255, 238, 205, 139, 238,
    /* 72 - 79 */ 205, 139,   0,   0,   0,   0,   0,   0,
    /* 80 - 87 */   0,   0,   0,   0,   0,   0, 238, 205,
    /* 88 - 88 */ 139
};

/* flags for current attribute settings */
static int    OPEN_FLAG = 0;          /* 0 - GD closed, 1 - GD open */
int           DEVICE_TYPE = 0;        /* define device */
                                      /* 1 - jpeg */
                                      /* 2 - png */
                                      /* 3 - windows bmp */
char          FONT_NAME_CURRENT[80];  /* name of current font */
char          FONT_NULL[80];          /* null font */
char          FONT_NAME_DEFAULT[80];  /* name of default font */
int           FONT_HEIGHT_CURRENT;    /* pixel ascent of current font */
int           FONT_DESCENT_CURRENT;   /* descent of current font */
int           FONT_GAP_CURRENT;       /* vertical gap of current font */

#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void  gdend_(), gddraw_(), gdpoin_(), gdcirc_(), gdrgfl_();
void  gdinit_(), gderas_(), gdtxth_(), gdtxtv_();
void  gdseco_(), gdsepa_();
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void  GDEND_(), GDINIT_(), GDDRAW_(), GDPOIN_(), GDCIRC_(), GDRGFL_();
void  GDINIT_(), GDERAS_(), GDTXTH_(), GDTXTV_();
void  GDSECO_(), GDSEPA_();
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void  gdend(), gddraw(), gdpoin(), gdcirc(), gdrgfl();
void  gdinit(), gderas(), gdtxth(), gdtxtv(),gdtatt();
void  gdseco(), gdsepa();
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void  GDEND(), GDDRAW(), GDPOIN(), GDCIRC(), GDRGFL();
void  GDINIT(),  GDERAS(), GDTXTH(), GDTXTV();
void  GDSECO(), GDSEPA();
#endif
void  i_to_s_2();

/* GDINIT  - routine to initialize GD.
 *           For GD device, simply set flag saying this routine
 *           has been called, initialize a few variables.
 *
 *           DEVICE_TYPE = 1 -- jpeg
 *           DEVICE_TYPE = 2 -- png
 *           DEVICE_TYPE = 3 -- wbmp
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdinit_(itype)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDINIT_(itype)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdinit(itype)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDINIT(itype)
#endif
#if PRECISION == 0
int  *itype;
#else
int  itype[2];
#endif
{

   int   itype_temp;

#if PRECISION == 0
   itype_temp = *itype;
#else
   itype_temp = itype[0];
#endif
    DEVICE_TYPE = itype_temp;
    OPEN_FLAG = 0;

}

/* GDERAS  - routine to clear the screen.  Since PNG and JPEG devices
 *           treat each plot as a separate file, initialization
 *           functions occur here rather than GDINIT.  Do the
 *           following:
 *           1) Check if a plot is currently open.  If yes, write
 *              it to a file and destroy the current image.
 *           2) Create a new image with the specified size specified
 *              in pixels.  Note that orientation (landscape, portrait,
 *              is implicit in the pixel dimensions).  Note that
 *              this routine does not modify the values.
 *           3) Set all colors to be undefined and then set
 *              background and foreground colors.
 *
 *  xpixels   - width (in pixels) for graphics window
 *  ypixels   - height (in pixels) for graphics window
 *  back_col  - background color
 *  file name - file name (in integer ascii decimal equivalents)
 *
 */

#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gderas_(xpixels, ypixels, back_col, file_name)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDERAS_(xpixels, ypixels, back_col, file_name)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gderas(xpixels, ypixels, back_col, file_name)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDERAS(xpixels, ypixels, back_col, file_name)
#endif
#if PRECISION == 0
int  *xpixels, *ypixels, *back_col;
int file_name[];
#else
int  xpixels[2], ypixels[2], back_col[2];
int file_name[];
#endif
{

   int   back_col_temp, temp_color, temp_color_2;
   int   xpixels_temp, ypixels_temp;
   int   len;
   int   itemp, quality;
   int   i;

#if PRECISION == 0
   back_col_temp = *back_col;
   xpixels_temp = *xpixels;
   ypixels_temp = *ypixels;
#else
   back_col_temp = back_col[0];
   xpixels_temp = xpixels[0];
   ypixels_temp = ypixels[0];
#endif

   /* First, check if a graph is currently open, if so write it
      to the current file name. */
   if (OPEN_FLAG == 1) {
      /* interlaced images load faster on web, but leave for now */
      /* gdImageInterlace(im,1); */
      jpegout = fopen(file_string,"wb");
      if (DEVICE_TYPE == 1) {
         quality = -1;
         gdImageJpeg(im,jpegout,quality);
      }
      else if (DEVICE_TYPE == 2) {
         gdImagePng(im,jpegout);
      }
      else if (DEVICE_TYPE == 3) {
         itemp=1;
         /* gdImageWBMP(im,itemp,jpegout); */
      }
      else {
         quality = -1;
         gdImageJpeg(im,jpegout,quality);
      }
      fclose(jpegout);
      gdImageDestroy(im);
   }

   /* Now, start new image */
#if PRECISION == 0
     i_to_s_2(file_name, file_string, 80, &len);
#else
     i_to_s_2(file_name, file_string, 160, &len);
#endif
   im = gdImageCreate(xpixels_temp, ypixels_temp);   /* Open Image */
   /* Set colors */
   gdImageColorAllocate(im,
     red[back_col_temp],green[back_col_temp],blue[back_col_temp-1]);
   for (i=0; i < MAX_COLORS; i++) {
      color_table[i] = gdImageColorAllocate(im,red[i],green[i],blue[i]);
   }
   OPEN_FLAG = 1;

}

/* GDEND   - routine to end GD.  Close the display.
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdend_()
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDEND_()
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdend()
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDEND()
#endif

{
   int     quality;
   int     itemp;

   if (OPEN_FLAG == 1) {
      /* interlaced images load faster on web, but leave for now */
      /* gdImageInterlace(im,1); */
      jpegout = fopen(file_string,"wb");
      if (DEVICE_TYPE == 1) {
         quality = -1;
         gdImageJpeg(im,jpegout,quality);
      }
      else if (DEVICE_TYPE == 2) {
         gdImagePng(im,jpegout);
      }
      else if (DEVICE_TYPE == 3) {
         itemp=1;
         /* gdImageWBMP(im,itemp,jpegout); */
      }
      else {
         gdImageJpeg(im,jpegout,quality);
      }
      fclose(jpegout);
      gdImageDestroy(im);
   }
   OPEN_FLAG = 0;

}

/* GDDRAW  - draw a polyline.  The color and line style have
 *           been set in GDSECO and GDSEPA (line thickness is
 *           generated in software)
 *
 * xpts   - contains the x coordinates
 * ypts   - contains the y coordinates
 * npts   - the number of points to plot
 *
 */
#define MAX_LINE_POINTS  500
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gddraw_(ix1,iy1,ix2,iy2)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDDRAW_(ix1,iy1,ix2,iy2)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gddraw(ix1,iy1,ix2,iy2)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDDRAW(ix1,iy1,ix2,iy2)
#endif
#if PRECISION == 0
int   *ix1, *iy1, *ix2, *iy2;
#else
int   ix1[2], iy1[2], ix2[2], iy2[2];
#endif
{
   int     ix1_temp;
   int     iy1_temp;
   int     ix2_temp;
   int     iy2_temp;

#if PRECISION == 0
   ix1_temp = *ix1;
   iy1_temp = *iy1;
   ix2_temp = *ix2;
   iy2_temp = *iy2;
#else
   ix1_temp = ix1[0];
   iy1_temp = iy1[0];
   ix2_temp = ix2[0];
   iy2_temp = iy2[0];
#endif

   if (CURRENT_LINE_STYLE[0] <= 0) {            /* Solid Line */
      gdImageLine(im, ix1_temp, iy1_temp, ix2_temp, iy2_temp,
                  color_table[CURRENT_COLOR]);
   }
   else {      /* Dashed or Dotted Line */
      gdImageSetStyle(im, CURRENT_LINE_STYLE, NPTS_STYLE);
      gdImageLine(im,ix1_temp,iy1_temp,ix2_temp,iy2_temp,CURRENT_LINE_STYLE);
   }

}

/* GDSECO  - set the color
 *
 * jcol   - index for desired color
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdseco_(jcol)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDSECO_(jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdseco(jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDSECO(jcol)
#endif
#if PRECISION == 0
int   *jcol;
#else
int   jcol[2];
#endif
{
   int     jcol_temp;

#if PRECISION == 0
   jcol_temp = *jcol;
#else
   jcol_temp = jcol[0];
#endif

   jcol_temp = jcol_temp - 1;
   CURRENT_COLOR = jcol_temp;

}

/* GDSEPA  - set pattern for lines
 *
 * jpatt  - the line pattern
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdsepa_(jpatt)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDSEPA_(jpatt)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdsepa(jpatt)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDSEPA(jpatt)
#endif
#if PRECISION == 0
int   *jpatt;
#else
int   jpatt[2];
#endif
{
   int     jpatt_temp;

#if PRECISION == 0
   jpatt_temp = *jpatt;
#else
   jpatt_temp = jpatt[0];
#endif

   if (jpatt_temp == 1) {            /* Solid Line */
      CURRENT_LINE_STYLE[0] = 0;
      NPTS_STYLE = 0;
   }
   else if (jpatt_temp == 2) {      /* Dashed Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[2] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[3] = gdTransparent;
      CURRENT_LINE_STYLE[4] = gdTransparent;
      CURRENT_LINE_STYLE[5] = gdTransparent;
      NPTS_STYLE = 6;
   }
   else if (jpatt_temp == 3) {      /* Dotted Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = gdTransparent;
      NPTS_STYLE = 2;
   }
   else if (jpatt_temp == 4) {      /* DA2 Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[2] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[3] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[4] = gdTransparent;
      CURRENT_LINE_STYLE[5] = gdTransparent;
      NPTS_STYLE = 6;
   }
   else if (jpatt_temp == 5) {      /* DA3 Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[2] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[3] = gdTransparent;
      CURRENT_LINE_STYLE[4] = gdTransparent;
      CURRENT_LINE_STYLE[5] = gdTransparent;
      CURRENT_LINE_STYLE[6] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[7] = gdTransparent;
      NPTS_STYLE = 8;
   }
   else if (jpatt_temp == 6) {      /* DA4 Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[2] = gdTransparent;
      CURRENT_LINE_STYLE[3] = gdTransparent;
      NPTS_STYLE = 4;
   }
   else if (jpatt_temp == 7) {      /* DA5 Line */
      CURRENT_LINE_STYLE[0] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[1] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[2] = gdTransparent;
      CURRENT_LINE_STYLE[3] = color_table[CURRENT_COLOR];
      CURRENT_LINE_STYLE[4] = gdTransparent;
      NPTS_STYLE = 5;
   }

}

/* GDPOIN - draw a point.
 *
 * ix     - contains the x coordinate
 * iy     - contains the y coordinate
 * jcol   - color to use in drawing the point
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdpoin_(ix, iy, jcol)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDPOIN_(ix, iy, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdpoin(ix, iy, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDPOIN(ix, iy, jcol)
#endif
#if PRECISION == 0
int   *ix, *iy, *jcol;
#else
int   ix[2], iy[2], jcol[2];
#endif
{
#if PRECISION == 0
   gdImageSetPixel(im, *ix, *iy, color_table[*jcol]);
#else
   gdImageSetPixel(im, ix[0], iy[0], color_table[jcol[0]]);
#endif

}

/* GDCIRC  - draw a circle.  Note that the circle may be either filled or 
 *          unfilled.  For a filled circle, do twice, (once for the 
 *          outline, once to fill the interior).
 *
 * ix     - contains the x coordinate for the center of the circle
 * iy     - contains the y coordinate for the center of the circle 
 * irad   - radius
 * ifill  - 0 for unfilled circle, 1 for filled circle
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdcirc_(ix, iy, irad, ifill, jcol)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDCIRC_(ix, iy, irad, ifill, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdcirc(ix, iy, irad, ifill, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDCIRC(ix, iy, irad, ifill, jcol)
#endif
#if PRECISION == 0
int   *ix, *iy, *irad, *ifill, *jcol;
#else
int   ix[2], iy[2], irad[2], ifill[2], jcol[2];
#endif
{

   int   xpos, ypos, iwidth, iheight, iang1, iang2, ir, jcol_t;

   iang1 = 0;
   iang2 = 360;
#if PRECISION == 0
   ir = *irad;
   jcol_t = *jcol;
   xpos = *ix - *irad;
   ypos = *iy - *irad;
#else
   ir = irad[0];
   jcol_t = jcol[0];
   xpos = ix[0] - irad[0];
   ypos = iy[0] - irad[0];
#endif
   iwidth = 2 * ir;
   iheight = 2 * ir;
   gdImageArc(im, xpos, ypos, iwidth, iheight, iang1, iang2, color_table[jcol_t]);

}

/* GDRGFL - fill a region.  Rectangular regions will be filled differently
 *          non-rectangular regions.  Dataplot only handles convex polygons,
 *          so set this (for faster performance).  This routine only does
 *          solid fills.  Hatch patterns must be drawn
 *          by the calling program (i.e., send the individual lines to
 *          the GDDRAW routine).
 *
 * xpts   - contains the x coordinates
 * ypts   - contains the y coordinates
 * npts   - the number of points in the polygon (if 2, assume a rectangle,
 *          otherwise, a convex polygon)
 *
 */
#define MAX_REG_POINTS  1000
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdrgfl_(xpts, ypts, npts, jcol)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDRGFL_(xpts, ypts, npts, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdrgfl(xpts, ypts, npts, jcol)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDRGFL(xpts, ypts, npts, jcol)
#endif
int   xpts[], ypts[];
#if PRECISION == 0
int   *npts, *jcol;
#else
int   npts[2], jcol[2];
#endif
{
   int     points[MAX_REG_POINTS];
   int     npts_temp, jcol_temp, indx;

#if PRECISION == 0
   npts_temp = *npts;
   jcol_temp = *jcol;
#else
   npts_temp = npts[0];
   jcol_temp = jcol[0];
#endif
#if PRECISION == 0
    indx = 1;
#else
    indx = 2;
#endif

   if (npts_temp == 2) {      /* rectangle */
      int  x1, y1, x2, y2;
      if (xpts[0] <= xpts[indx]) {
        x1 = xpts[0];
        x2 = xpts[indx];
      }
      else {
        x1 = xpts[indx];
        x2 = xpts[0];
      }
      if (ypts[0] <= ypts[indx]) {
        y1 = ypts[0];
        y2 = ypts[indx];
      }
      else {
        y1 = ypts[indx];
        y2 = ypts[0];
      }
      gdImageFilledRectangle(im, x1, y1, x2, y2, color_table[jcol_temp-1]);
   }
   else if (npts_temp > 2) {     /* convex polygon */
/*
      int  i, temp;
      temp = npts_temp;
      if(npts_temp > MAX_REG_POINTS) temp = MAX_REG_POINTS;
      for (i = 0; i < temp; i++) {
#if PRECISION == 0
         points[i].x = xpts[i];
         points[i].y = ypts[i];
#else
         points[i].x = xpts[2*i];
         points[i].y = ypts[2*i];
#endif
      }
      gdImageFilledPolygon(im,points,temp,color_table[jcol_temp-1]);
 */
   }

}

/* GDTXTH - draw a horizontal text string.
 *
 *          NOTE: This is not implemented on our first
 *                pass for this driver.  Issue of how
 *                to access fonts, set sizes and 
 *                justifications need to be addressed.
 *
 *
 * string - text string to draw
 * ixpos  - x position
 * iypos  - y position
 * ijusth - justification (horizontal)
 *          0 - left justified
 *          1 - center justified
 *          2 - right justified
 * ijustv - justiciation (vertical)
 *          0 - center justified
 *          1 - bottom justified
 *          2 - top justified
 * jcol   - color
 * error  - error flag
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdtxth_(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDTXTH_(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdtxth(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDTXTH(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#endif
int    string[];
#if PRECISION == 0
int    *ixpos, *iypos, *ijusth, *ijustv, *jcol, *error;
#else
int    ixpos[2], iypos[2], ijusth[2], ijustv[2], jcol[2], error[2];
#endif
{

   int    itest, itempx, itempy;   /* temporary variables */
   int    len;                     /* number of characters in string */
   int    string_width;            /* width of string in pixels */
   char   string2[130];            /* converted string */
   int    i;
   int    ixpos_temp, iypos_temp, ijusth_temp, ijustv_temp;
   int    jcol_temp;

#if PRECISION == 0
   ixpos_temp = *ixpos;
   iypos_temp = *iypos;
   ijusth_temp = *ijusth;
   ijustv_temp = *ijustv;
   jcol_temp = *jcol;
#else
   ixpos_temp = ixpos[0];
   iypos_temp = iypos[0];
   ijusth_temp = ijusth[0];
   ijustv_temp = ijustv[0];
   jcol_temp = jcol[0];
#endif

#if PRECISION == 0
   i_to_s_2(string, string2, 130, &len);
#else
   i_to_s_2(string, string2, 260, &len);
#endif
   /* string_width = XTextWidth(font_struct, string2, len); */

   switch (ijusth_temp) {
      case 0:                       /* Left justified string */
          itempx = ixpos_temp;
          break;
      case 1:                       /* Center justified string */
          itempx = ixpos_temp - (string_width/2);
          break;
      case 2:                       /* Right justified string */
          itempx = ixpos_temp - string_width;
          break;
      default:
          itempx = ixpos_temp;
          break;
   }
   switch (ijustv_temp) {
      case 0:                       /* Center justified string */
          itempy = iypos_temp + (FONT_HEIGHT_CURRENT/2.0);
          break;
      case 1:                       /* Bottom justified string */
          itempy = iypos_temp;
          break;
      case 2:                       /* Top justified string */
          itempy = iypos_temp + FONT_HEIGHT_CURRENT;
          break;
      default:
          itempy = iypos_temp + (FONT_HEIGHT_CURRENT/2.0);
          break;
    }


}

/* GDTXTV - draw a horizontal text string.
 *
 *          NOTE: This is not implemented on our first
 *                pass for this driver.  Issue of how
 *                to access fonts, set sizes and 
 *                justifications need to be addressed.
 *
 *
 * string - text string to draw
 * ixpos  - x position
 * iypos  - y position
 * ijusth - justification (horizontal)
 *          0 - left justified
 *          1 - center justified
 *          2 - right justified
 * ijustv - justiciation (vertical)
 *          0 - center justified
 *          1 - bottom justified
 *          2 - top justified
 * jcol   - color
 * error  - error flag
 *
 */
#if APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 1
void gdtxtv_(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 1 && SUBROUTINE_CASE == 0
void GDTXTV_(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 1
void gdtxtv(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#elif APPEND_UNDERSCORE == 0 && SUBROUTINE_CASE == 0
void GDTXTV(string, ixpos, iypos, ijusth, ijustv, jcol, error)
#endif
int    string[];
#if PRECISION == 0
int    *ixpos, *iypos, *ijusth, *ijustv, *jcol, *error;
#else
int    ixpos[2], iypos[2], ijusth[2], ijustv[2], jcol[2], error[2];
#endif
{

   int   itest, itempx, itempy;   /* temporary variables */
   int   len;                     /* number of characters in string */
   int   y_pix_len;               /* height of entire string */
   int   string_width;            /* width of string in pixels */
   char  string2[130];            /* converted string */
   int   i, ijunk;
#if PRECISION == 0
   int   string3[2];              /* one character at a time */
#else
   int   string3[4];              /* one character at a time */
#endif
   int   ixpos_temp, iypos_temp, ijusth_temp, ijustv_temp;
   int   jcol_temp;

#if PRECISION == 0
   ixpos_temp = *ixpos;
   iypos_temp = *iypos;
   ijusth_temp = *ijusth;
   ijustv_temp = *ijustv;
   jcol_temp = *jcol;
#else
   ixpos_temp = ixpos[0];
   iypos_temp = iypos[0];
   ijusth_temp = ijusth[0];
   ijustv_temp = ijustv[0];
   jcol_temp = ijustv[0];
#endif


#if PRECISION == 0
   i_to_s_2(string, string2, 130, &len);
#else
   i_to_s_2(string, string2, 260, &len);
#endif
   y_pix_len = len * (FONT_HEIGHT_CURRENT + FONT_GAP_CURRENT);

   switch (ijustv_temp) {
      case 0:                       /* Center justified string */
          itempy = -(y_pix_len/2) + FONT_HEIGHT_CURRENT;
          break;
      case 1:                       /* Bottom justified string */
          itempy = -y_pix_len + FONT_HEIGHT_CURRENT;
          break;
      case 2:                       /* Top justified string */
          itempy = FONT_HEIGHT_CURRENT;
          break;
      default:
          itempy = -(y_pix_len/2) + FONT_HEIGHT_CURRENT;
          break;
    }
    itempy = iypos_temp + itempy;

#if PRECISION == 0
   string3[1] = 0;
   for (i = 0; i < len; i++) {  /* plot each character one at a time */
      string3[0] = string[i];
      i_to_s_2(string3,string2, 2, &ijunk);
      /* string_width = XTextWidth(font_struct, string2, 1); */

     switch (ijusth_temp) {
        case 0:                       /* Left justified string */
            itempx = 0;
            break;
        case 1:                       /* Center justified string */
            itempx = (string_width/2);
            break;
        case 2:                       /* Right justified string */
            itempx = string_width;
            break;
        default:
            itempx = ixpos_temp;
            break;
     }

     itempx = ixpos_temp - itempx;


     itempy = itempy + (FONT_HEIGHT_CURRENT + FONT_GAP_CURRENT);

   }
#else
   string3[1] = 0;
   string3[2] = 0;
   string3[3] = 0;
   for (i = 0; i < len; i++) {  /* plot each character one at a time */
      string3[0] = string[2*i];
      i_to_s_2(string3,string2, 4, &ijunk);

     switch (ijusth_temp) {
        case 0:                       /* Left justified string */
            itempx = 0;
            break;
        case 1:                       /* Center justified string */
            itempx = (string_width/2);
            break;
        case 2:                       /* Right justified string */
            itempx = string_width;
            break;
        default:
            itempx = ixpos_temp;
            break;
     }

     itempx = ixpos_temp - itempx;

     itempy = itempy + (FONT_HEIGHT_CURRENT + FONT_GAP_CURRENT);

   }
#endif

}

/* i_to_s_2  - utitlity routine to convert an integer array containing
 *           Ascii Decimal Equivalents to a character string array.  The
 *           Fortran routines pass character type data as an array of
 *           ADE's, which this routine then converts to C's character
 *           type.  Note that the input array is assumed to be correct
 *           (i.e., a value between 0 and 127) and no error checking is
 *           done on it.
 *
 * string1 - input array containing ADE's.
 * string2 - output array in C character format.
 * maxlen  - maximum length for string2
 * ilen    - length of character string
 *
 */
void i_to_s_2(string1, string2, maxlen, ilen)
int   string1[], maxlen, *ilen;
char  string2[];

{
     int  i;
     int  itemp;
     i = 0;
#if PRECISION == 0
     while (string1[i] != 0 && i < (maxlen - 1) ) {
         itemp = string1[i];
         string2[i] = string1[i];
         i++;
     }
     *ilen = i;
     string2[i]='\0';
}
#else
     while (string1[2*i] != 0 && i < (maxlen - 1) ) {
         itemp = string1[2*i];
         string2[i] = string1[2*i];
         i++;
     }
     *ilen = i;
     string2[i]='\0';
}
#endif
