/*
 *      Shading.c
 *
 *      The AthenaTools Plotter Widget Set - Version 6.0
 *
 *      klin, Tue Jul  7 13:59:47 1992
 *      klin, Fri Aug  7 10:22:41 1992, Minor changes to keep
 *                                      ANSI C compilers quiet.
 *      klin, Sat Aug 15 10:31:50 1992, patchlevel 4
 *                                      Changed <At/..> to <X11/At/..>.
 */
static char SCCSid[] = "@(#) Plotter V6.0  92/08/15  Shading.c";

/*

Copyright 1991 by Burdett, Buckeridge & Young Ltd.

All rights reserved.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the firms, institutes
or employers of the authors not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.

THE AUTHORS AND THEIR FIRMS, INSTITUTES OR EMPLOYERS DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND THEIR FIRMS,
INSTITUTES OR EMPLOYERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

*/

/*
 * Routines to access and specify shading in a manner compatable with
 * X and PostScript
 */

#include <X11/At/Shading.h>

#include <ctype.h>

typedef struct _shading {
     struct _shading *next;
     Screen     *screen;
     AtShading  shading;
     Pixel      fg, bg;
     Pixmap     pixmap;
     Cardinal   refcnt;
} ShadingCacheEntry;

typedef struct _bitmaps {
     unsigned char       *data;
     unsigned   width, height;
     char       *setgray;       /* Arg to postscript SetGray */
} BitMapEntry;


/* These bitmaps taken from the originam AtBitmaps.h file */

#define gray0_width 16
#define gray0_height 16
static unsigned char gray0_bits[] = {
   0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
   0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00,
   0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00};

#define gray1_width 16
#define gray1_height 16
static unsigned char gray1_bits[] = {
   0x99, 0x99, 0x66, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99, 0x99, 0x66, 0x66,
   0x66, 0x66, 0x99, 0x99, 0x99, 0x99, 0x66, 0x66, 0x66, 0x66, 0x99, 0x99,
   0x99, 0x99, 0x66, 0x66, 0x66, 0x66, 0x99, 0x99};

#define gray2_width 16
#define gray2_height 16
static unsigned char gray2_bits[] = {
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};

#define gray3_width 16
#define gray3_height 16
static unsigned char gray3_bits[] = {
   0xee, 0xee, 0x55, 0x55, 0xbb, 0xbb, 0x55, 0x55, 0xee, 0xee, 0x55, 0x55,
   0xbb, 0xbb, 0x55, 0x55, 0xee, 0xee, 0x55, 0x55, 0xbb, 0xbb, 0x55, 0x55,
   0xee, 0xee, 0x55, 0x55, 0xbb, 0xbb, 0x55, 0xd5};

#define gray4_width 16
#define gray4_height 16
static unsigned char gray4_bits[] = {
   0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55,
   0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55,
   0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55};

#define gray5_width 16
#define gray5_height 16
static unsigned char gray5_bits[] = {
   0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0x77, 0x77, 0xff, 0xff, 0xdd, 0xdd,
   0xff, 0xff, 0x77, 0x77, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0x77, 0x77,
   0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0x77, 0x77};

static BitMapEntry Bitmaps[] = {
     gray0_bits, gray0_width, gray0_height, "1.0",
     gray1_bits, gray1_width, gray1_height, "0.9",
     gray2_bits, gray2_width, gray2_height, "0.8",
     gray3_bits, gray3_width, gray3_height, "0.7",
     gray4_bits, gray4_width, gray4_height, "0.6",
     gray5_bits, gray5_width, gray5_height, "0.5",
     gray1_bits, gray1_width, gray1_height, "0.4",
     gray2_bits, gray2_width, gray2_height, "0.3",
     gray3_bits, gray3_width, gray3_height, "0.2",
     gray4_bits, gray4_width, gray4_height, "0.1",
     gray5_bits, gray5_width, gray5_height, "0.0"
     };

static ShadingCacheEntry *ShadingCache;

Pixmap AtShadingGetPixmap(screen, shading, fg, bg)
Screen *screen;
AtShading shading;
Pixel fg, bg;
{
     ShadingCacheEntry *sce = ShadingCache;

     for (; sce; sce = sce->next) {
	  if (sce->screen == screen && sce->shading == shading &&
	      sce->fg == fg && sce->bg == bg) {
	       sce->refcnt++;
	       return sce->pixmap;
	  }
     }

     /*
      * Doesn't exist, need to add it
      */
     if ((sce = XtNew(ShadingCacheEntry)) == NULL)
	  return None;

     assert(shading >= AtGRAY0 && shading <= AtGRAY10);

     sce->screen = screen;
     sce->shading = shading;
     sce->refcnt = 1;
     sce->next = ShadingCache;
     sce->pixmap =
	  XCreatePixmapFromBitmapData(DisplayOfScreen(screen),
				      RootWindowOfScreen(screen),
				      (char *) Bitmaps[shading].data,
				      Bitmaps[shading].width,
				      Bitmaps[shading].height, fg, bg,
				      DefaultDepthOfScreen(screen));
     ShadingCache = sce;
     return sce->pixmap;
}

void AtShadingReleasePixmap(pixmap)
Pixmap pixmap;
{
     ShadingCacheEntry *sce = ShadingCache, *prev;

     for (prev = NULL; sce; prev = sce, sce = sce->next) {
	  if (pixmap == sce->pixmap) {
	       if (--sce->refcnt <= 0) {
		    /*
		     * Release this cache entry
		     */
		    XFreePixmap(DisplayOfScreen(sce->screen), pixmap);
		    if (prev) {
			 prev->next = sce->next;
		    } else {
			 ShadingCache = sce->next;
		    }
		    XtFree((char *)sce);
	       }
	       return;
	  }
     }
     /* Should never get here */
     assert(pixmap && 0);
     *SCCSid = *SCCSid;       /* Keep gcc quiet */
}


char *AtShadingPS(shading)
AtShading shading;
{
     static char buf[40];

     assert(shading >= AtGRAY0 && shading <= AtGRAY10);
     sprintf(buf, " %s SG ", Bitmaps[shading].setgray);
     return buf;
}

#if defined(linux) || defined(SYSV) || defined(SVR4)
#else
extern int strncasecmp P((const char *, const char *, int));
#endif

/* The internal conversion routine */
static Boolean AtCvtStringToShading (display, args, nargs, fromVal,
				  toVal, data)
Display  *display;
XrmValue *args;
Cardinal *nargs;
XrmValue *fromVal, *toVal;
XtPointer *data;
{
  static AtShading result;
  Boolean ok = False;
  char *from = (char *)fromVal->addr;

  if (*nargs != 0) {
       XtAppError(XtDisplayToApplicationContext(display),
		  "String to Shading converter needs no extra arguments");
  }

  if (strncasecmp(from, "gray", 4) == 0 ||
       /* braindead americans */
      strncasecmp(from, "grey", 4) == 0) {
       if (strcmp(from + 4, "10") == 0) {
	    ok = True;
	    result = AtGRAY10;
       } else if (isdigit(from[4]) && !from[5]){
	    ok = True;
	    result = AtGRAY0 + from[4] - '0';
       }
  }

  if (!ok) {
       XtDisplayStringConversionWarning(display, from, "Shading");
  } else {
       if (!toVal->addr) toVal->addr = (XtPointer) &result;
       else if (toVal->size < sizeof (AtShading)) ok = False;
       else *(AtShading *)toVal->addr = result;
       toVal->size = sizeof(AtShading);
  }
  return ok;
}


void AtRegisterShadingConverter()
{
  static Boolean registered = False;

  if (registered == False) {
    XtSetTypeConverter(XtRString, XtRShading,
		       (XtTypeConverter) AtCvtStringToShading,
		       NULL, 0, XtCacheNone, NULL);
    registered = True;
  }
}
