#ifdef SCCS
static char sccsid[]="@(#)init.c	1.1 Oki Electric Industry Co., Ltd. 93/05/11";
#endif
/*
 *			Copyright (c) 1992 by
 *			Oki Electric Industry Co., 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 Oki not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission. Oki
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 *************************************************************************
 *
 * init.c containes the initialization routines for pexdraw.
 *
 *************************************************************************/

#include <stdio.h>

#include <math.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#include <X11/PEX5/PEXlib.h>

#include "pexdraw.h"

/* for PEXUtFindVisual */
#include "util/pexutcmap.h"

extern renderProcs wksProcs, rdrProcs;

extern PEXLookupTable theLightLUT;

extern int theDBFlag;
extern int theHPFlag;

/*************************************************************************
 * M A I N
 */
main(argc,argv)
int	argc;
char	*argv[];
{   
    InitUserInterface(argc, argv);

    InitPEX();

    MainLoop();
}
/*************************************************************************
 * InitPEX
 *
 * Open PEX using popen_xphigs
 */
void
InitPEX()
{
  PEXExtensionInfo *info;
  PEXStructure struxid;
  PEXCoord p[6], *pp;
  PEXLookupTable		depthCueLUT, colorLUT, 
				colorApproxLUT;
  XWindowAttributes winAttrs;
  XVisualInfo betterVisualInfo, *visInfo;
  int i, j, count;

  int error;
  char charString[81];

  unsigned long setWinMask;
  XSetWindowAttributes setWinAttrs;

  if (error = PEXInitialize(theDisplay, &info, 80, charString)) {
    charString[80] = (char)0;
    (void) fprintf(stderr,"%s\n", charString);
    (void) fprintf(stderr,"PEX not initialized error = %d\n", error);
    exit(-1);
  }

  /*
   * O.K. We would like to used mixed mode if possible 
   *					(cause it will always work in 6.0)
   * but we have some constraints:
   *  - if we are 5.0 only, we need to use the workstation to get picking done.
   *  - if we are workstation subset
   * Otherwise, we can use the 5.1 Renderer picking, etc.  
   */
  if (info->major_version != 5) {printf("5.X NOT!!\n"); exit(-5);}
  if (info->minor_version == 0) {
    theRenderProcs = wksProcs;
    the51Flag = 0;
  } else {
    the51Flag = 1;
    if (info->subset_info == PEXWorkstationOnly ) {
      theRenderProcs = wksProcs;
    } else if (info->subset_info == PEXImmediateMode ) {
      printf("OT!!\n"); exit(-5);
    }	
    theRenderProcs = rdrProcs;

    /* for testing */
    if (theForceWKSFlag) theRenderProcs = wksProcs;
  }
  /* need this for fetches */
  theFF = PEXGetProtocolFloatFormat(theDisplay);

/*
 * Determine which visual to use
 *
 * did user specify a visual?
 *
 * First, check to see if the window we have is satisfactory.
 *  - might check to see if it is PEX worthy & DB worthy.
 *    if so, get std colormap.
 *
 * If not, if max Cmaps == 1, then use default
 *    Get STD_CMAP_ grab visual.
 *
 * else find best.
 *
 *
 */
  XGetWindowAttributes(theDisplay,theWindow,&winAttrs);
  theScreen = XScreenNumberOfScreen(winAttrs.screen);

  if ((winAttrs.depth < 24) &&
      (MaxCmapsOfScreen(winAttrs.screen) > 1) &&  /* prevent flashing */
      (FindBetterPEXVisual( theDisplay, theWindow, PEXWindowDrawable,
				    winAttrs.visual, &betterVisualInfo ))) {
    /* found one */
    theWimpyWindow = theWindow;
    theWindow = MakeBetterPEXWindow( theDisplay, theWindow,
				    &winAttrs, &betterVisualInfo );
    visInfo = &betterVisualInfo;
  } else { 
    /* not worth looking for anything better, or there is nothing. get
     * what we need to make do with what we have.
     */
    theWimpyWindow = 0;

    betterVisualInfo.visualid = XVisualIDFromVisual(winAttrs.visual);
    visInfo = XGetVisualInfo(theDisplay, VisualIDMask, &betterVisualInfo, &i);
  }
/*
 * O.K. We are all set, set up color approximation, hide this it is ugly
 */
  colorApproxLUT = MakeColorApprox( theDisplay, theWindow, visInfo );

  theWinHeight =  winAttrs.height;

/*
 *  Init Render Object
 *
 * Set up all of the LUTs we want (colorApprox, color, light & depthCue )
 * Then call the Render Proc to init ( see above )
 */
  colorLUT =    InitColorLUT( theDisplay,theWindow);
  theLightLUT = PEXCreateLookupTable( theDisplay,theWindow, PEXLUTLight);
  depthCueLUT = PEXCreateLookupTable( theDisplay,theWindow, PEXLUTDepthCue);
  theFontLUT = PEXCreateLookupTable( theDisplay, theWindow, PEXLUTTextFont);

  theRenderObj = theRenderProcs.Init( theDisplay, theWindow,
				     colorLUT, theLightLUT, theFontLUT,
				     depthCueLUT, 
				     colorApproxLUT);

/*
 * Just turn some lights on for the heck of it.
 */
  InitLights();

  struxid = PEXCreateStructure(theDisplay);

  PEXSetEditingMode(theDisplay, struxid, PEXStructureInsert);

  PEXSetViewIndex(theDisplay, struxid, PEXOCStore, 1);

  pp = (PEXCoord *)p;
  pp->x = 0.5; pp->y = 0.0; pp->z = 0.0; pp++;
  pp->x = 1.0; pp->y = 1.0; pp->z = 0.0; pp++;
  pp->x = 0.5; pp->y = 0.0; pp->z = 1.0; pp++;
  pp->x = 0.5; pp->y = 0.0; pp->z = -1.0; pp++;
  pp->x = 0.5; pp->y = 1.0; pp->z = -1.0; pp++;
  pp->x = 1.0; pp->y = 0.0; pp->z = 0.0;
  PEXPolyline(theDisplay, struxid, PEXOCStore, 6, p);

  theRenderProcs.Post( struxid );

  applyViewSet(1);

  theRenderProcs.ReDraw();

  theSpinList.count = 0;
  PEXRotate(PEXXAxis, 0.0, theMCMatrix.matrix ); /* init MC matrix */

  theDynGC = CreateDynGC(); /* for dynamics using X */
}

/*************************************************************************
 * FindBestPEXVisual - just do it.
 *
 * type is for MatchRenderingTargets 
 */
int 
FindBetterPEXVisual(dpy, w, type, visIn, visBest )
     Display *dpy;
     Window w;
     int type;
     Visual *visIn;
     XVisualInfo *visBest;
{
  int i;
  PEXRenderingTarget *targets;
  unsigned long lcount;
  XVisualInfo visTemplate;  
  XVisualInfo visMatch;
  XVisualInfo *visInfo;
  XWindowAttributes winAttrs;
  int            screen;
  Window         winWin;
  int   notDone = 1, triedTrue = 0, triedDirect = 0;
        PEXUtVisualCriteria             criteria;
              XStandardColormap         cmap_info_return;
             PEXColorApproxEntry    capx_info_return;
      unsigned int                  unmet;
    Atom                            std_prop_atom_return;
                          int found;                                                   

  if (w) {
    screen = theScreen;
    winWin = w;
  } else {
    screen = DefaultScreen(dpy);
    winWin = RootWindow(dpy, screen);
  }
  
  criteria.visual_class = TrueColor;
  criteria.depth = 24;
  criteria.sharable_colormap = 1;
  criteria.double_buffering_capability = 1;
  
  criteria.hard_criteria_mask = PEXUtVisualClass;
  criteria.soft_criteria_mask = PEXUtDepth |  PEXUtSharableColormap;
  
  if (theDBFlag) {
    criteria.soft_criteria_mask |= PEXUtDoubleBufferingCapability;
    }

  found = PEXUtFindVisual( dpy, screen, &criteria, visBest,  &cmap_info_return, 
             &capx_info_return, &unmet, &std_prop_atom_return);

  if ((found == PEXUtQualifiedSuccess) || (found == PEXUtSuccess))
    return (1); 
  else {

    criteria.hard_criteria_mask = 0;
    
    found = PEXUtFindVisual( dpy, screen, &criteria, visBest,  &cmap_info_return, 
             &capx_info_return, &unmet, &std_prop_atom_return);

    if ((found == PEXUtQualifiedSuccess)||(found == PEXUtSuccess)) return (1); 
            
  }
  return (0);
}

/*************************************************************************
 *  GetStandardColormap - 
int GetStandardColormap(Display *dpy, XVisualInfo *visInfo, 
			XStandardColormap *cmap )
 *
 */
int GetStandardColormap( dpy, visInfo, cmap )
     Display *dpy;
     XVisualInfo *visInfo;
     XStandardColormap *cmap;
{
  XStandardColormap  *scm, *s;
  Atom property;
  int i, count;

  switch (visInfo->class) {
  case TrueColor:
  case StaticColor:
    property = XA_RGB_BEST_MAP;
    break;

  default:
    property = XA_RGB_DEFAULT_MAP;
    break;
  }

  if ( XmuLookupStandardColormap( dpy, visInfo->screen, visInfo->visualid,
				 visInfo->depth, property, False, True )) {

    if (XGetRGBColormaps(theDisplay, RootWindow(theDisplay, visInfo->screen),
		       &scm, &count, property )) {
      for (i = 0, s = scm; i < count; i++, scm++ ) {
	if ( scm->visualid == visInfo->visualid ) {
	  *cmap = *scm;
	  XFree((char *)s);
	  return (1);
	}
      }
    }
  }
  return (0);
}

/*************************************************************************
 * InitColorLUT(dpy, win)
 */
PEXLookupTable
InitColorLUT(dpy, win)
     Display *dpy;
     Window win;
{
  PEXLookupTable clt;
  PEXColorEntry  entries[8];

  clt = PEXCreateLookupTable( dpy, win, PEXLUTColor);

  entries[0].type = PEXColorTypeRGB;
  entries[0].value.rgb.red   =  0.0;
  entries[0].value.rgb.green =  0.0;
  entries[0].value.rgb.blue  =  0.0;

  entries[1].type = PEXColorTypeRGB;
  entries[1].value.rgb.red   =  1.0;
  entries[1].value.rgb.green =  1.0;
  entries[1].value.rgb.blue  =  1.0;

  entries[2].type = PEXColorTypeRGB;
  entries[2].value.rgb.red   =  1.0;
  entries[2].value.rgb.green =  0.0;
  entries[2].value.rgb.blue  =  0.0;

  entries[3].type = PEXColorTypeRGB;
  entries[3].value.rgb.red   =  0.0;
  entries[3].value.rgb.green =  1.0;
  entries[3].value.rgb.blue  =  0.0;

  entries[4].type = PEXColorTypeRGB;
  entries[4].value.rgb.red   =  0.0;
  entries[4].value.rgb.green =  0.0;
  entries[4].value.rgb.blue  =  1.0;

  entries[5].type = PEXColorTypeRGB;
  entries[5].value.rgb.red   =  0.0;
  entries[5].value.rgb.green =  1.0;
  entries[5].value.rgb.blue  =  1.0;

  entries[6].type = PEXColorTypeRGB;
  entries[6].value.rgb.red   =  1.0;
  entries[6].value.rgb.green =  0.0;
  entries[6].value.rgb.blue  =  1.0;

  entries[7].type = PEXColorTypeRGB;
  entries[7].value.rgb.red   =  1.0;
  entries[7].value.rgb.green =  1.0;
  entries[7].value.rgb.blue  =  0.0;

  PEXSetTableEntries(theDisplay,clt,0,8,PEXLUTColor,(char *)&entries);

  return (clt);
}
/*************************************************************************
 * MakeBetterPEXWindow(dpy, w, winAttrs, visBest )
 */
Window
MakeBetterPEXWindow(dpy, w, winAttrs, visBest )
     Display *dpy;
     Window w;
     XWindowAttributes *winAttrs;
     XVisualInfo *visBest;
{
  XStandardColormap  cmap;

  int i, j, count;

  int error;
  char charString[81];

  unsigned long setWinMask;
  XSetWindowAttributes setWinAttrs;
  Window newWin;



    setWinMask = CWBorderPixel|CWBackPixel;
    setWinAttrs.border_pixmap = None;
    setWinAttrs.background_pixmap = None;
    setWinAttrs.border_pixel = -1;
    setWinAttrs.background_pixel = 0;
    if (GetStandardColormap(theDisplay, visBest, &cmap )) {

      if (cmap.colormap == 0) {

        theHPFlag = 1;
           	cmap.colormap = XCreateColormap(theDisplay, w,
      				      visBest->visual, AllocNone );
	printf("special  HP colormap id = %x visid %x\n", cmap.colormap,
  		visBest->visual );
      }	
      setWinAttrs.border_pixel = 0;
      setWinAttrs.background_pixel = 0;
      setWinMask |= CWColormap;
      setWinAttrs.colormap = cmap.colormap;
    } else {
    	printf("could not get standard colormap\n");
    }
    newWin = XCreateWindow(theDisplay, w, 
			      0,0, winAttrs->width, winAttrs->height, 0,
			      visBest->depth, InputOutput,
			      visBest->visual,
			      setWinMask, &setWinAttrs);
    /*
     * do this so Window Manager knows to install this colormap, too.
     */			      
    if (winAttrs->colormap != cmap.colormap)
      XSetWMColormapWindows( theDisplay, theTopWindow, &newWin, 1);
			      
    XMapWindow(theDisplay,newWin);
    XGetWindowAttributes(theDisplay,newWin,winAttrs);
    
   return (newWin);
}

/*************************************************************************
 * MakeColorApprox( dpy, w, visInfo )
 */
PEXLookupTable
MakeColorApprox( dpy, w, visInfo )
     Display *dpy;
     Window w;
     XVisualInfo *visInfo;
{
  PEXLookupTable capx;
  PEXColorApproxEntry colorApprox;
  XStandardColormap  cmap;
      
  capx = PEXCreateLookupTable( dpy, w, PEXLUTColorApprox );
  if (theHPFlag == 0) {					

   if (GetStandardColormap(theDisplay, visInfo, &cmap )) {

    colorApprox.type = PEXColorSpace;
    colorApprox.model = PEXColorApproxRGB;
    colorApprox.max1 = cmap.red_max;
    colorApprox.max2 = cmap.green_max;
    colorApprox.max3 = cmap.blue_max;
    colorApprox.mult1 = cmap.red_mult;
    colorApprox.mult2 = cmap.green_mult;
    colorApprox.mult3 = cmap.blue_mult;
    colorApprox.base_pixel = cmap.base_pixel;

    if ((CheckImpDepInteger(PEXIDDitheringSupported)) && !(theNoDitherFlag))
      colorApprox.dither = 1;
    else colorApprox.dither = 0;

    PEXSetTableEntries(theDisplay,capx,0,1,PEXLUTColorApprox,
		       (char *)&colorApprox);
   } else {
    printf("no color approx???\n");
   }
  }
  return (capx);
}

