static char RCSid[] = "$Id: Shading.c,v 1.0 91/08/22 15:33:45 gnb Exp $"; 
/*
 * $Source: /export/data/sources/x/At/Plotter/RCS/Shading.c,v $
 * 
 * $Log:	Shading.c,v $
 * Revision 1.0  91/08/22  15:33:45  gnb
 * Initial revision
 * 
 * 
 */

/*

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 Burdett, Buckeridge &
Young Ltd. (BBY) not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

BBY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
BBY 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 <stdio.h>
#include <assert.h>
#include <ctype.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#ifdef _AtDevelopment_
#include "Shading.h"
#else
#include <At/Shading.h>
#endif 

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

typedef struct _bitmaps {
     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 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 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 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 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 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 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),
				      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);
     *RCSid = *RCSid;		/* 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; 
}

extern int strncasecmp P((const char *, const char *, int));

/* 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, AtCvtStringToShading,
		       NULL, 0, XtCacheNone, NULL);
    registered = True;
  }
}
