togl.c
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:94k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. /* $Id: togl.c,v 1.15 2002/09/26 16:56:04 kberg Exp $ */
  2. /*
  3.  * Togl - a Tk OpenGL widget
  4.  * Version 1.5
  5.  * Copyright (C) 1996-1997  Brian Paul and Ben Bederson
  6.  * See the LICENSE file for copyright details.
  7.  */
  8. /*
  9.  * $Log: togl.c,v $
  10.  * Revision 1.15  2002/09/26 16:56:04  kberg
  11.  * fixed a typo
  12.  *
  13.  * Revision 1.14  2002/09/21 02:00:42  kberg
  14.  * Added prgamas to turn off optimizations so windows version doesn't crash
  15.  * in optimized build
  16.  * ---------------------------------------------------------
  17.  *
  18.  * Revision 1.13  2001/10/09 22:26:13  smr
  19.  * Add #define for TK 8.3.3
  20.  *
  21.  * Revision 1.12  2001/07/24 22:12:22  kberg
  22.  * Update on the overlay plane work around. (kberg)
  23.  *
  24.  * Revision 1.11  2001/07/02 17:56:30  srm
  25.  * switched trunk over to branch non-lmeunier-rollfwd
  26.  *
  27.  * Revision 1.7.2.3  2001/06/14 15:06:45  srm
  28.  * roll fwd to 2000-12-16
  29.  *
  30.  * Revision 1.10  2000/11/22 08:55:40  srm
  31.  * Added yet another Tcl version to togl.
  32.  * Note 8.3.{1,2} point to the 8.3.2 header file
  33.  *
  34.  * Revision 1.9  2000/06/06 10:17:59  magi
  35.  * fix win32 compile
  36.  *
  37.  * Revision 1.8  2000/05/07 00:02:53  smr
  38.  * Linux portability fixes.
  39.  *
  40.  * Revision 1.7  1999/01/12 17:35:26  magi
  41.  * update win32 port
  42.  *
  43.  * Revision 1.6  1998/11/10 10:05:30  magi
  44.  * change order of operations in destroy handler, so client's destroy
  45.  * callback can still access widget fields like Togl->Ident
  46.  *
  47.  * Revision 1.5  1998/10/28 13:54:04  magi
  48.  * cache static images as bitmap for fast redraws -- only render when necessary
  49.  *
  50.  * Revision 1.4  1998/06/17 01:37:10  magi
  51.  * add per-togl support for timers
  52.  *
  53.  * Revision 1.3  1998/04/29 00:58:42  magi
  54.  * updated Togl code to version 1.5 beta 3 -- because 1.4 wasn't working
  55.  * under Tcl/Tk 8.0 -- note that I had to make one change to togl.c
  56.  * in ToglCmdDeletedProc, or it faults when trying to destroy the widget
  57.  * (only if there's an overlay buffer) because tkwin is NULL.
  58.  *
  59.  * Revision 1.43  1998/03/12 04:10:47  brianp
  60.  * added display list and OpenGL context sharing options
  61.  *
  62.  * Revision 1.42  1998/03/12 03:20:31  brianp
  63.  * fixed a few overlay update bugs (Yang Guo Liang)
  64.  *
  65.  * Revision 1.41  1998/01/20 01:05:10  brianp
  66.  * added more destroy/clean-up code
  67.  * added a few Tcl 7.4 / Tk 4.0 #if/#else/#endifs (David Laur)
  68.  *
  69.  * Revision 1.40  1997/12/13 02:27:46  brianp
  70.  * only call Tcl_DeleteCommandFromToken() is using Tcl/Tk 8.0 or later
  71.  *
  72.  * Revision 1.39  1997/12/13 02:26:02  brianp
  73.  * test for STEREO to enable SGI stereo code
  74.  * general code clean-up
  75.  *
  76.  * Revision 1.38  1997/12/11 02:21:18  brianp
  77.  * added support for Tcl/Tk 8.0p2
  78.  *
  79.  * Revision 1.37  1997/11/15 04:11:30  brianp
  80.  * added Adrian J. Chung's widget destroy code
  81.  *
  82.  * Revision 1.36  1997/11/15 03:33:13  brianp
  83.  * fixed multi-expose/redraw problem (Andy Colebourne)
  84.  *
  85.  * Revision 1.35  1997/11/15 03:28:42  brianp
  86.  * removed code in Togl_Configure(), added for stereo, that caused a new bug
  87.  *
  88.  * Revision 1.34  1997/11/15 02:58:48  brianp
  89.  * added Togl_TkWin() per Glenn Lewis
  90.  *
  91.  * Revision 1.33  1997/10/01 02:50:57  brianp
  92.  * added SGI stereo functions from Ben Evans
  93.  *
  94.  * Revision 1.32  1997/10/01 00:25:22  brianp
  95.  * made small change for HP compilation (Glenn Lewis)
  96.  *
  97.  * Revision 1.31  1997/09/17 02:41:07  brianp
  98.  * added Geza Groma's Windows NT/95 patches
  99.  *
  100.  * Revision 1.30  1997/09/12 01:21:05  brianp
  101.  * a few more tweaks for Windows compilation
  102.  */
  103. /*
  104.  * Currently support X11 and WIN32
  105.  */
  106. #ifndef WIN32
  107. #define X11
  108. #endif
  109. /*** Windows headers ***/
  110. #ifdef WIN32
  111. #define WIN32_LEAN_AND_MEAN
  112. #include <windows.h>
  113. #undef WIN32_LEAN_AND_MEAN
  114. #include <winnt.h>
  115. #endif /* WIN32 */
  116. /*** Standard C headers ***/
  117. #include <assert.h>
  118. #include <stdio.h>
  119. #include <stdlib.h>
  120. #include <string.h>
  121. /*** X Window System headers ***/
  122. #ifdef X11
  123. #include <X11/Xlib.h>
  124. #include <X11/Xutil.h>
  125. #include <X11/Xatom.h>  /* for XA_RGB_DEFAULT_MAP atom */
  126. #if defined(__vms)
  127. #include <X11/StdCmap.h>  /* for XmuLookupStandardColormap */
  128. #else
  129. #include <X11/Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
  130. #endif
  131. #include <GL/glx.h>
  132. #endif /*X11*/
  133. /*** Tcl/Tk headers ***/
  134. #ifdef X11
  135. #ifndef _TKPORT
  136. #define _TKPORT  /* This eliminates need to include a bunch of Tk baggage */
  137. #endif /* X11 */
  138. #endif
  139. #include <tcl.h>
  140. #include <tk.h>
  141. #if defined(X11)
  142. #if TK_MAJOR_VERSION==4 && TK_MINOR_VERSION==0
  143. #  include "tkInt4.0.h"
  144. #  define NO_TK_CURSOR
  145. #elif TK_MAJOR_VERSION==4 && TK_MINOR_VERSION==1
  146. #  include "tkInt4.1.h"
  147. #elif TK_MAJOR_VERSION==4 && TK_MINOR_VERSION==2
  148. #  include "tkInt4.2.h"
  149. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==0 && TK_RELEASE_SERIAL==0
  150. #  include "tkInt8.0.h"
  151. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==0 && TK_RELEASE_SERIAL==2
  152. #  include "tkInt8.0p2.h"
  153. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==0 && TK_RELEASE_SERIAL==2
  154. #  include "tkInt8.0p2.h"
  155. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==0 && TK_RELEASE_SERIAL==4
  156. #  include "tkInt8.0.4.h"
  157. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==0 && TK_RELEASE_SERIAL==5
  158. #  include "tkInt8.0.5.h"
  159. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==3 && TK_RELEASE_SERIAL==1
  160. #  include "tkInt8.3.2.h"
  161. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==3 && TK_RELEASE_SERIAL==2
  162. #  include "tkInt8.3.2.h"
  163. #elif TK_MAJOR_VERSION==8 && TK_MINOR_VERSION==3 && TK_RELEASE_SERIAL==3
  164. #  include "tkInt8.3.2.h"
  165. #else
  166. #error   Sorry, you will have to edit togl.c to include the right tkInt.h file
  167. #endif
  168. #elif defined(WIN32)
  169. #if TK_MAJOR_VERSION<8
  170.    Sorry Windows version requires Tcl/Tk ver 8.0 or higher.
  171. #endif
  172. #include "tkInt.h"
  173. #include "tkWinInt.h"
  174. #endif /* X11 */
  175. #include "togl.h"
  176. /* Defaults */
  177. #define DEFAULT_WIDTH "400"
  178. #define DEFAULT_HEIGHT "400"
  179. #define DEFAULT_IDENT ""
  180. #define DEFAULT_FONTNAME "fixed"
  181. #define DEFAULT_TIME "1"
  182. #ifdef WIN32
  183. /* maximum size of a logical palette corresponding to a colormap in color index mode */
  184. #define MAX_CI_COLORMAP_SIZE 4096
  185. #endif /* WIN32 */
  186. #define MAX(a,b) (((a)>(b))?(a):(b))
  187. #define TCL_ERR(interp, string) {Tcl_ResetResult(interp);
  188.          Tcl_AppendResult(interp, string, NULL);
  189.  return(TCL_ERROR);}
  190. #define ALL_EVENTS_MASK 
  191.     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|
  192.     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask|
  193.     VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|ColormapChangeMask
  194. struct Togl
  195. {
  196.    struct Togl *Next;           /* next in linked list */
  197. #if defined(WIN32)
  198.    HDC tglGLHdc;                /* Device context of device that OpenGL calls will be drawn on */
  199.    HGLRC tglGLHglrc;            /* OpenGL rendering context to be made current */
  200.    int CiColormapSize;          /* (Maximum) size of colormap in color index mode */
  201. #elif defined(X11)
  202.    GLXContext GlCtx; /* Normal planes GLX context */
  203. #endif /* WIN32 */
  204.    Display *display; /* X's token for the window's display. */
  205.    Tk_Window  TkWin; /* Tk window structure */
  206.    Tcl_Interp *Interp; /* Tcl interpreter */
  207.    Tcl_Command widgetCmd;       /* Token for togl's widget command */
  208. #ifndef NO_TK_CURSOR
  209.    Tk_Cursor Cursor; /* The widget's cursor */
  210. #endif
  211.    int Width, Height; /* Dimensions of window */
  212.    int Time; /* Time value for timer */
  213. #if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705
  214.    Tcl_TimerToken timerHandler; /* Token for togl's timer handler */
  215. #else
  216.    Tk_TimerToken timerHandler;  /* Token for togl's timer handler */
  217. #endif
  218.    int RgbaFlag; /* configuration flags (ala GLX parameters) */
  219.    int RgbaRed;
  220.    int RgbaGreen;
  221.    int RgbaBlue;
  222.    int DoubleFlag;
  223.    int DepthFlag;
  224.    int DepthSize;
  225.    int AccumFlag;
  226.    int AccumRed;
  227.    int AccumGreen;
  228.    int AccumBlue;
  229.    int AccumAlpha;
  230.    int AlphaFlag;
  231.    int AlphaSize;
  232.    int StencilFlag;
  233.    int StencilSize;
  234.    int PrivateCmapFlag;
  235.    int OverlayFlag;
  236.    int StereoFlag;
  237.    int AuxNumber;
  238.    char *ShareList;             /* name (ident) of Togl to share dlists with */
  239.    char *ShareContext;          /* name (ident) to share OpenGL context with */
  240.    char *Ident; /* User's identification string */
  241.    ClientData Client_Data; /* Pointer to user data */
  242.    GLboolean UpdatePending; /* Should normal planes be redrawn? */
  243.    Togl_Callback *CreateProc; /* Callback when widget is created */
  244.    Togl_Callback *DisplayProc; /* Callback when widget is rendered */
  245.    Togl_Callback *ReshapeProc; /* Callback when window size changes */
  246.    Togl_Callback *DestroyProc; /* Callback when widget is destroyed */
  247.    Togl_Callback *TimerProc; /* Callback when widget is idle */
  248.    /* Overlay stuff */
  249. #if defined(X11)
  250.    GLXContext OverlayCtx; /* Overlay planes OpenGL context */
  251. #elif defined(WIN32)
  252.    HGLRC tglGLOverlayHglrc;
  253. #endif /* X11 */
  254.    Window OverlayWindow; /* The overlay window, or 0 */
  255.    Togl_Callback *OverlayDisplayProc; /* Overlay redraw proc */
  256.    GLboolean OverlayUpdatePending; /* Should overlay be redrawn? */
  257.    Colormap OverlayCmap; /* colormap for overlay is created */
  258.    int OverlayTransparentPixel; /* transparent pixel */
  259.    int OverlayIsMapped;
  260.    /* for DumpToEpsFile: Added by Miguel A. de Riera Pasenau 10.01.1997 */
  261.    XVisualInfo *VisInfo; /* Visual info of the current */
  262. /* context needed for DumpToEpsFile */
  263.    GLfloat *EpsRedMap; /* Index2RGB Maps for Color index modes */
  264.    GLfloat *EpsGreenMap;
  265.    GLfloat *EpsBlueMap;
  266.    GLint EpsMapSize;             /* = Number of indices in our Togl */
  267. };
  268. /* NTNTNT need to change to handle Windows Data Types */
  269. /*
  270.  * Prototypes for functions local to this file
  271.  */
  272. static int Togl_Cmd(ClientData clientData, Tcl_Interp *interp,
  273.                     int argc, char **argv);
  274. static void Togl_EventProc(ClientData clientData, XEvent *eventPtr);
  275. static int Togl_MakeWindowExist(struct Togl *togl);
  276. #ifdef MESA_COLOR_HACK
  277. static int get_free_color_cells( Display *display, int screen,
  278.                                  Colormap colormap);
  279. static void free_default_color_cells( Display *display, Colormap colormap);
  280. #endif
  281. static void ToglCmdDeletedProc( ClientData );
  282. #if defined(__sgi) && defined(STEREO)
  283. /* SGI-only stereo */
  284. static void stereoMakeCurrent( Display *dpy, Window win, GLXContext ctx );
  285. static void stereoInit( struct Togl *togl,int stereoEnabled );
  286. #endif
  287. /*
  288.  * Setup Togl widget configuration options:
  289.  */
  290. static Tk_ConfigSpec configSpecs[] = {
  291.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  292.      DEFAULT_HEIGHT, Tk_Offset(struct Togl, Height), 0, NULL},
  293.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  294.      DEFAULT_WIDTH, Tk_Offset(struct Togl, Width), 0, NULL},
  295.     {TK_CONFIG_BOOLEAN, "-rgba", "rgba", "Rgba",
  296.      "true", Tk_Offset(struct Togl, RgbaFlag), 0, NULL},
  297.     {TK_CONFIG_INT, "-redsize", "redsize", "RedSize",
  298.      "1", Tk_Offset(struct Togl, RgbaRed), 0, NULL},
  299.     {TK_CONFIG_INT, "-greensize", "greensize", "GreenSize",
  300.      "1", Tk_Offset(struct Togl, RgbaGreen), 0, NULL},
  301.     {TK_CONFIG_INT, "-bluesize", "bluesize", "BlueSize",
  302.      "1", Tk_Offset(struct Togl, RgbaBlue), 0, NULL},
  303.     {TK_CONFIG_BOOLEAN, "-double", "double", "Double",
  304.      "false", Tk_Offset(struct Togl, DoubleFlag), 0, NULL},
  305.     {TK_CONFIG_BOOLEAN, "-depth", "depth", "Depth",
  306.      "false", Tk_Offset(struct Togl, DepthFlag), 0, NULL},
  307.     {TK_CONFIG_INT, "-depthsize", "depthsize", "DepthSize",
  308.      "1", Tk_Offset(struct Togl, DepthSize), 0, NULL},
  309.     {TK_CONFIG_BOOLEAN, "-accum", "accum", "Accum",
  310.      "false", Tk_Offset(struct Togl, AccumFlag), 0, NULL},
  311.     {TK_CONFIG_INT, "-accumredsize", "accumredsize", "AccumRedSize",
  312.      "1", Tk_Offset(struct Togl, AccumRed), 0, NULL},
  313.     {TK_CONFIG_INT, "-accumgreensize", "accumgreensize", "AccumGreenSize",
  314.      "1", Tk_Offset(struct Togl, AccumGreen), 0, NULL},
  315.     {TK_CONFIG_INT, "-accumbluesize", "accumbluesize", "AccumBlueSize",
  316.      "1", Tk_Offset(struct Togl, AccumBlue), 0, NULL},
  317.     {TK_CONFIG_INT, "-accumalphasize", "accumalphasize", "AccumAlphaSize",
  318.      "1", Tk_Offset(struct Togl, AccumAlpha), 0, NULL},
  319.     {TK_CONFIG_BOOLEAN, "-alpha", "alpha", "Alpha",
  320.      "false", Tk_Offset(struct Togl, AlphaFlag), 0, NULL},
  321.     {TK_CONFIG_INT, "-alphasize", "alphasize", "AlphaSize",
  322.      "1", Tk_Offset(struct Togl, AlphaSize), 0, NULL},
  323.     {TK_CONFIG_BOOLEAN, "-stencil", "stencil", "Stencil",
  324.      "false", Tk_Offset(struct Togl, StencilFlag), 0, NULL},
  325.     {TK_CONFIG_INT, "-stencilsize", "stencilsize", "StencilSize",
  326.      "1", Tk_Offset(struct Togl, StencilSize), 0, NULL},
  327.     {TK_CONFIG_INT, "-auxbuffers", "auxbuffers", "AuxBuffers",
  328.      "0", Tk_Offset(struct Togl, AuxNumber), 0, NULL},
  329.     {TK_CONFIG_BOOLEAN, "-privatecmap", "privateCmap", "PrivateCmap",
  330.      "false", Tk_Offset(struct Togl, PrivateCmapFlag), 0, NULL},
  331.     {TK_CONFIG_BOOLEAN, "-overlay", "overlay", "Overlay",
  332.      "false", Tk_Offset(struct Togl, OverlayFlag), 0, NULL},
  333.     {TK_CONFIG_BOOLEAN, "-stereo", "stereo", "Stereo",
  334.      "false", Tk_Offset(struct Togl, StereoFlag), 0, NULL},
  335. #ifndef NO_TK_CURSOR
  336.     { TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  337.      "", Tk_Offset(struct Togl, Cursor), TK_CONFIG_NULL_OK },
  338. #endif
  339.     {TK_CONFIG_INT, "-time", "time", "Time",
  340.      DEFAULT_TIME, Tk_Offset(struct Togl, Time), 0, NULL},
  341.     {TK_CONFIG_STRING, "-sharelist", "sharelist", "ShareList",
  342.      NULL, Tk_Offset(struct Togl, ShareList), 0, NULL},
  343.     {TK_CONFIG_STRING, "-sharecontext", "sharecontext", "ShareContext",
  344.      NULL, Tk_Offset(struct Togl, ShareContext), 0, NULL},
  345.     {TK_CONFIG_STRING, "-ident", "ident", "Ident",
  346.      DEFAULT_IDENT, Tk_Offset(struct Togl, Ident), 0, NULL},
  347.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  348.      (char *) NULL, 0, 0, NULL}
  349. };
  350. static Togl_Callback *CreateProc = NULL;
  351. static Togl_Callback *DisplayProc = NULL;
  352. static Togl_Callback *ReshapeProc = NULL;
  353. static Togl_Callback *DestroyProc = NULL;
  354. static Togl_Callback *OverlayDisplayProc = NULL;
  355. static Togl_Callback *TimerProc = NULL;
  356. static ClientData DefaultClientData = NULL;
  357. static Tcl_HashTable CommandTable;
  358. static struct Togl *ToglHead = NULL;  /* head of linked list */
  359. /*
  360.  * Add given togl widget to linked list.
  361.  */
  362. static void AddToList(struct Togl *t)
  363. {
  364.    t->Next = ToglHead;
  365.    ToglHead = t;
  366. }
  367. /*
  368.  * Remove given togl widget from linked list.
  369.  */
  370. static void RemoveFromList(struct Togl *t)
  371. {
  372.    struct Togl *prev = NULL;
  373.    struct Togl *pos = ToglHead;
  374.    while (pos) {
  375.       if (pos == t) {
  376.          if (prev) {
  377.             prev->Next = pos->Next;
  378.          }
  379.          else {
  380.             ToglHead = pos->Next;
  381.          }
  382.          return;
  383.       }
  384.       prev = pos;
  385.       pos = pos->Next;
  386.    }
  387. }
  388. /*
  389.  * Return pointer to togl widget given a user identifier string.
  390.  */
  391. static struct Togl *FindTogl(const char *ident)
  392. {
  393.    struct Togl *t = ToglHead;
  394.    while (t) {
  395.       if (strcmp(t->Ident, ident) == 0)
  396.          return t;
  397.       t = t->Next;
  398.    }
  399.    return NULL;
  400. }
  401. #if defined(X11)
  402. /*
  403.  * Return an X colormap to use for OpenGL RGB-mode rendering.
  404.  * Input:  dpy - the X display
  405.  *         scrnum - the X screen number
  406.  *         visinfo - the XVisualInfo as returned by glXChooseVisual()
  407.  * Return:  an X Colormap or 0 if there's a _serious_ error.
  408.  */
  409. static Colormap
  410. get_rgb_colormap( Display *dpy, int scrnum, const XVisualInfo *visinfo )
  411. {
  412.    Atom hp_cr_maps;
  413.    Status status;
  414.    int numCmaps;
  415.    int i;
  416.    XStandardColormap *standardCmaps;
  417.    Window root = RootWindow(dpy,scrnum);
  418.    int using_mesa;
  419.    /*
  420.     * First check if visinfo's visual matches the default/root visual.
  421.     */
  422.    if (visinfo->visual==DefaultVisual(dpy,scrnum)) {
  423.       /* use the default/root colormap */
  424.       Colormap cmap;
  425.       cmap = DefaultColormap( dpy, scrnum );
  426. #ifdef MESA_COLOR_HACK
  427.       (void) get_free_color_cells( dpy, scrnum, cmap);
  428. #endif
  429.       return cmap;
  430.    }
  431.    /*
  432.     * Check if we're using Mesa.
  433.     */
  434.    if (strstr(glXQueryServerString( dpy, scrnum, GLX_VERSION ), "Mesa")) {
  435.       using_mesa = 1;
  436.    }
  437.    else {
  438.       using_mesa = 0;
  439.    }
  440.    /*
  441.     * Next, if we're using Mesa and displaying on an HP with the "Color
  442.     * Recovery" feature and the visual is 8-bit TrueColor, search for a
  443.     * special colormap initialized for dithering.  Mesa will know how to
  444.     * dither using this colormap.
  445.     */
  446.    if (using_mesa) {
  447.       hp_cr_maps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", True );
  448.       if (hp_cr_maps
  449. #ifdef __cplusplus
  450.   && visinfo->visual->c_class==TrueColor
  451. #else
  452.   && visinfo->visual->class==TrueColor
  453. #endif
  454.   && visinfo->depth==8) {
  455.  status = XGetRGBColormaps( dpy, root, &standardCmaps,
  456.     &numCmaps, hp_cr_maps );
  457.  if (status) {
  458.     for (i=0; i<numCmaps; i++) {
  459.        if (standardCmaps[i].visualid == visinfo->visual->visualid) {
  460.                   Colormap cmap = standardCmaps[i].colormap;
  461.                   XFree( standardCmaps );
  462.   return cmap;
  463.        }
  464.     }
  465.             XFree(standardCmaps);
  466.  }
  467.       }
  468.    }
  469.    /*
  470.     * Next, try to find a standard X colormap.
  471.     */
  472. #ifndef SOLARIS_BUG
  473.    status = XmuLookupStandardColormap( dpy, visinfo->screen,
  474.        visinfo->visualid, visinfo->depth,
  475.        XA_RGB_DEFAULT_MAP,
  476.        /* replace */ False, /* retain */ True);
  477.    if (status == 1) {
  478.       status = XGetRGBColormaps( dpy, root, &standardCmaps,
  479.  &numCmaps, XA_RGB_DEFAULT_MAP);
  480.       if (status == 1) {
  481.          for (i = 0; i < numCmaps; i++) {
  482.     if (standardCmaps[i].visualid == visinfo->visualid) {
  483.                Colormap cmap = standardCmaps[i].colormap;
  484.        XFree(standardCmaps);
  485.        return cmap;
  486.     }
  487.  }
  488.          XFree(standardCmaps);
  489.       }
  490.    }
  491. #endif
  492.    /*
  493.     * If we get here, give up and just allocate a new colormap.
  494.     */
  495.    return XCreateColormap( dpy, root, visinfo->visual, AllocNone );
  496. }
  497. #elif defined(WIN32)
  498. /* Code to create RGB palette is taken from the GENGL sample program
  499.    of Win32 SDK */
  500. static unsigned char threeto8[8] = {
  501.     0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
  502. };
  503. static unsigned char twoto8[4] = {
  504.     0, 0x55, 0xaa, 0xff
  505. };
  506. static unsigned char oneto8[2] = {
  507.     0, 255
  508. };
  509. static int defaultOverride[13] = {
  510.     0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91
  511. };
  512. static PALETTEENTRY defaultPalEntry[20] = {
  513.     { 0,   0,   0,    0 },
  514.     { 0x80,0,   0,    0 },
  515.     { 0,   0x80,0,    0 },
  516.     { 0x80,0x80,0,    0 },
  517.     { 0,   0,   0x80, 0 },
  518.     { 0x80,0,   0x80, 0 },
  519.     { 0,   0x80,0x80, 0 },
  520.     { 0xC0,0xC0,0xC0, 0 },
  521.     { 192, 220, 192,  0 },
  522.     { 166, 202, 240,  0 },
  523.     { 255, 251, 240,  0 },
  524.     { 160, 160, 164,  0 },
  525.     { 0x80,0x80,0x80, 0 },
  526.     { 0xFF,0,   0,    0 },
  527.     { 0,   0xFF,0,    0 },
  528.     { 0xFF,0xFF,0,    0 },
  529.     { 0,   0,   0xFF, 0 },
  530.     { 0xFF,0,   0xFF, 0 },
  531.     { 0,   0xFF,0xFF, 0 },
  532.     { 0xFF,0xFF,0xFF, 0 }
  533. };
  534. static unsigned char
  535. ComponentFromIndex(int i, UINT nbits, UINT shift)
  536. {
  537.     unsigned char val;
  538.     val = (unsigned char) (i >> shift);
  539.     switch (nbits) {
  540.     case 1:
  541.         val &= 0x1;
  542.         return oneto8[val];
  543.     case 2:
  544.         val &= 0x3;
  545.         return twoto8[val];
  546.     case 3:
  547.         val &= 0x7;
  548.         return threeto8[val];
  549.     default:
  550.         return 0;
  551.     }
  552. }
  553. static Colormap Win32CreateRgbColormap(PIXELFORMATDESCRIPTOR pfd)
  554. {
  555.     TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof(TkWinColormap));
  556.     LOGPALETTE *pPal;
  557.     int n, i;
  558.     n = 1 << pfd.cColorBits;
  559.     pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
  560.             n * sizeof(PALETTEENTRY));
  561.     pPal->palVersion = 0x300;
  562.     pPal->palNumEntries = n;
  563.     for (i=0; i<n; i++) {
  564.         pPal->palPalEntry[i].peRed =
  565.                 ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift);
  566.         pPal->palPalEntry[i].peGreen =
  567.                 ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift);
  568.         pPal->palPalEntry[i].peBlue =
  569.                 ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift);
  570.         pPal->palPalEntry[i].peFlags = 0;
  571.     }
  572.     /* fix up the palette to include the default GDI palette */
  573.     if ((pfd.cColorBits == 8)                           &&
  574.         (pfd.cRedBits   == 3) && (pfd.cRedShift   == 0) &&
  575.         (pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) &&
  576.         (pfd.cBlueBits  == 2) && (pfd.cBlueShift  == 6)
  577.        ) {
  578.         for (i = 1 ; i <= 12 ; i++)
  579.             pPal->palPalEntry[defaultOverride[i]] = defaultPalEntry[i];
  580.     }
  581.     cmap->palette = CreatePalette(pPal);
  582.     LocalFree(pPal);
  583.     cmap->size = n;
  584.     cmap->stale = 0;
  585.     /* Since this is a private colormap of a fix size, we do not need
  586.        a valid hash table, but a dummy one */
  587.     Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS);
  588.     return (Colormap)cmap;
  589. }
  590. static Colormap Win32CreateCiColormap(struct Togl *togl)
  591. {
  592.     /* Create a colormap with size of togl->CiColormapSize and set all
  593.        entries to black */
  594.     LOGPALETTE logPalette;
  595.     TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof(TkWinColormap));
  596.     logPalette.palVersion = 0x300;
  597.     logPalette.palNumEntries = 1;
  598.     logPalette.palPalEntry[0].peRed = 0;
  599.     logPalette.palPalEntry[0].peGreen = 0;
  600.     logPalette.palPalEntry[0].peBlue = 0;
  601.     logPalette.palPalEntry[0].peFlags = 0;
  602.     cmap->palette = CreatePalette(&logPalette);
  603.     cmap->size = togl->CiColormapSize;
  604.     ResizePalette(cmap->palette, cmap->size);  /* sets new entries to black */
  605.     cmap->stale = 0;
  606.     /* Since this is a private colormap of a fix size, we do not need
  607.        a valid hash table, but a dummy one */
  608.     Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS);
  609.     return (Colormap)cmap;
  610. }
  611. #endif /*X11*/
  612. /*
  613.  * Togl_Init
  614.  *
  615.  *   Called upon system startup to create Togl command.
  616.  */
  617. int Togl_Init(Tcl_Interp *interp)
  618. {
  619.    /* The Tcl_PkgProvide() function isn't available in Tcl 7.4 or earlier */
  620. #if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) > 704
  621.    /* The following allows Togl to be loaded dynamically into a running
  622.     * tclsh, if togl is made into a shared lib.  Contributed by Kerel
  623.     * Zuiderveld (karel.zuiderveld@cv.ruu.nl)
  624.     */
  625.    if (Tcl_PkgProvide(interp, "Togl", TOGL_VERSION) != TCL_OK) {
  626.       return TCL_ERROR;
  627.    }
  628. #endif
  629.    Tcl_CreateCommand(interp, "togl", Togl_Cmd,
  630.                      (ClientData) Tk_MainWindow(interp), NULL);
  631.    Tcl_InitHashTable(&CommandTable, TCL_STRING_KEYS);
  632.    return TCL_OK;
  633. }
  634. /*
  635.  * Register a C function to be called when an Togl widget is realized.
  636.  */
  637. void Togl_CreateFunc( Togl_Callback *proc )
  638. {
  639.    CreateProc = proc;
  640. }
  641. /*
  642.  * Register a C function to be called when an Togl widget must be redrawn.
  643.  */
  644. void Togl_DisplayFunc( Togl_Callback *proc )
  645. {
  646.    DisplayProc = proc;
  647. }
  648. /*
  649.  * Register a C function to be called when an Togl widget is resized.
  650.  */
  651. void Togl_ReshapeFunc( Togl_Callback *proc )
  652. {
  653.    ReshapeProc = proc;
  654. }
  655. /*
  656.  * Register a C function to be called when an Togl widget is destroyed.
  657.  */
  658. void Togl_DestroyFunc( Togl_Callback *proc )
  659. {
  660.    DestroyProc = proc;
  661. }
  662. /*
  663.  * Register a C function to be called from TimerEventHandler.
  664.  */
  665. void Togl_TimerFunc( Togl_Callback *proc )
  666. {
  667.    TimerProc = proc;
  668. }
  669. /*
  670.  * Reset default callback pointers to NULL.
  671.  */
  672. void Togl_ResetDefaultCallbacks( void )
  673. {
  674.    CreateProc = NULL;
  675.    DisplayProc = NULL;
  676.    ReshapeProc = NULL;
  677.    DestroyProc = NULL;
  678.    OverlayDisplayProc = NULL;
  679.    TimerProc = NULL;
  680.    DefaultClientData = NULL;
  681. }
  682. /*
  683.  * Change the create callback for a specific Togl widget.
  684.  */
  685. void Togl_SetCreateFunc( struct Togl *togl, Togl_Callback *proc )
  686. {
  687.    togl->CreateProc = proc;
  688. }
  689. Togl_Callback* Togl_GetCreateFunc( struct Togl *togl)
  690. {
  691.   return togl->CreateProc;
  692. }
  693. /*
  694.  * Change the display/redraw callback for a specific Togl widget.
  695.  */
  696. void Togl_SetDisplayFunc( struct Togl *togl, Togl_Callback *proc )
  697. {
  698.    togl->DisplayProc = proc;
  699. }
  700. Togl_Callback* Togl_GetDisplayFunc( struct Togl *togl)
  701. {
  702.   return togl->DisplayProc;
  703. }
  704. /*
  705.  * Change the reshape callback for a specific Togl widget.
  706.  */
  707. void Togl_SetReshapeFunc( struct Togl *togl, Togl_Callback *proc )
  708. {
  709.    togl->ReshapeProc = proc;
  710. }
  711. Togl_Callback* Togl_GetReshapeFunc( struct Togl *togl)
  712. {
  713.   return togl->ReshapeProc;
  714. }
  715. /*
  716.  * Change the timer callback for a specific Togl widget.
  717.  */
  718. static void Togl_Timer( ClientData clientData );
  719. void Togl_SetTimerFunc( struct Togl *togl, Togl_Callback *proc )
  720. {
  721.    togl->TimerProc = proc;
  722.    if (!TimerProc)    /* not already set */
  723.      Tk_CreateTimerHandler( togl->Time, Togl_Timer, (ClientData)togl );
  724. }
  725. Togl_Callback* Togl_GetTimerFunc( struct Togl *togl)
  726. {
  727.   return togl->TimerProc;
  728. }
  729. /*
  730.  * Change the destroy callback for a specific Togl widget.
  731.  */
  732. void Togl_SetDestroyFunc( struct Togl *togl, Togl_Callback *proc )
  733. {
  734.    togl->DestroyProc = proc;
  735. }
  736. Togl_Callback* Togl_GetDestroyFunc( struct Togl *togl)
  737. {
  738.   return togl->DestroyProc;
  739. }
  740. /*
  741.  * Togl_Timer
  742.  *
  743.  * Gets called from Tk_CreateTimerHandler.
  744.  */
  745. static void Togl_Timer( ClientData clientData )
  746. {
  747.    struct Togl *togl = (struct Togl *) clientData;
  748.    togl->TimerProc(togl);
  749. #if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401
  750.    togl->timerHandler =
  751.        Tcl_CreateTimerHandler( togl->Time, Togl_Timer, (ClientData)togl );
  752. #else
  753.    togl->timerHandler =
  754.        Tk_CreateTimerHandler( togl->Time, Togl_Timer, (ClientData)togl );
  755. #endif
  756. }
  757. /*
  758.  * Togl_CreateCommand
  759.  *
  760.  *   Declares a new C sub-command of Togl callable from Tcl.
  761.  *   Every time the sub-command is called from Tcl, the
  762.  *   C routine will be called with all the arguments from Tcl.
  763.  */
  764. void Togl_CreateCommand( char *cmd_name, Togl_CmdProc *cmd_proc)
  765. {
  766.    int new_item;
  767.    Tcl_HashEntry *entry;
  768.    entry = Tcl_CreateHashEntry(&CommandTable, cmd_name, &new_item);
  769.    Tcl_SetHashValue(entry, cmd_proc);
  770. }
  771. /*
  772.  * Togl_MakeCurrent
  773.  *
  774.  *   Bind the OpenGL rendering context to the specified
  775.  *   Togl widget.
  776.  */
  777. void Togl_MakeCurrent( const struct Togl *togl )
  778. {
  779. #if defined(WIN32)
  780.    int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc);
  781.    assert(res == TRUE);
  782. #elif defined(X11)
  783.    glXMakeCurrent( Tk_Display(togl->TkWin),
  784.                    Tk_WindowId(togl->TkWin),
  785.                    togl->GlCtx );
  786. #if defined(__sgi) && defined(STEREO)
  787.    stereoMakeCurrent( Tk_Display(togl->TkWin),
  788.                       Tk_WindowId(togl->TkWin),
  789.                       togl->GlCtx );
  790. #endif /*__sgi STEREO */
  791. #endif /* WIN32 */
  792. }
  793. /*
  794.  * Called when the widget's contents must be redrawn.  Basically, we
  795.  * just call the user's render callback function.
  796.  *
  797.  * Note that the parameter type is ClientData so this function can be
  798.  * passed to Tk_DoWhenIdle().
  799.  */
  800. static void Togl_Render( ClientData clientData )
  801. {
  802.    struct Togl *togl = (struct Togl *)clientData;
  803.    if (togl->DisplayProc) {
  804.       Togl_MakeCurrent(togl);
  805.       togl->DisplayProc(togl);
  806.    }
  807.    togl->UpdatePending = GL_FALSE;
  808. }
  809. static void RenderOverlay( ClientData clientData )
  810. {
  811.    struct Togl *togl = (struct Togl *)clientData;
  812.    if (togl->OverlayFlag && togl->OverlayDisplayProc) {
  813. #if defined(WIN32)
  814.       int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc);
  815.       assert(res == TRUE);
  816. #elif defined(X11)
  817.       glXMakeCurrent( Tk_Display(togl->TkWin),
  818.       togl->OverlayWindow,
  819.       togl->OverlayCtx );
  820. #if defined(__sgi) && defined(STEREO)
  821.       stereoMakeCurrent( Tk_Display(togl->TkWin),
  822.                          togl->OverlayWindow,
  823.                          togl->OverlayCtx );
  824. #endif /*__sgi STEREO */
  825. #endif /* WIN32 */
  826.       togl->OverlayDisplayProc(togl);
  827.    }
  828.    togl->OverlayUpdatePending = GL_FALSE;
  829. }
  830. /*
  831.  * It's possible to change with this function or in a script some
  832.  * options like RGBA - ColorIndex ; Z-buffer and so on
  833.  */
  834. int Togl_Configure(Tcl_Interp *interp, struct Togl *togl,
  835.                    int argc, char *argv[], int flags)
  836. {
  837.    int oldRgbaFlag    = togl->RgbaFlag;
  838.    int oldRgbaRed     = togl->RgbaRed;
  839.    int oldRgbaGreen   = togl->RgbaGreen;
  840.    int oldRgbaBlue    = togl->RgbaBlue;
  841.    int oldDoubleFlag  = togl->DoubleFlag;
  842.    int oldDepthFlag   = togl->DepthFlag;
  843.    int oldDepthSize   = togl->DepthSize;
  844.    int oldAccumFlag   = togl->AccumFlag;
  845.    int oldAccumRed    = togl->AccumRed;
  846.    int oldAccumGreen  = togl->AccumGreen;
  847.    int oldAccumBlue   = togl->AccumBlue;
  848.    int oldAccumAlpha  = togl->AccumAlpha;
  849.    int oldAlphaFlag   = togl->AlphaFlag;
  850.    int oldAlphaSize   = togl->AlphaSize;
  851.    int oldStencilFlag = togl->StencilFlag;
  852.    int oldStencilSize = togl->StencilSize;
  853.    int oldAuxNumber   = togl->AuxNumber;
  854.    if (Tk_ConfigureWidget(interp, togl->TkWin, configSpecs,
  855.                           argc, argv, (char *)togl, flags) == TCL_ERROR) {
  856.       return(TCL_ERROR);
  857.    }
  858.    Tk_GeometryRequest(togl->TkWin, togl->Width, togl->Height);
  859.    if (togl->RgbaFlag != oldRgbaFlag
  860.        || togl->RgbaRed != oldRgbaRed
  861.        || togl->RgbaGreen != oldRgbaGreen
  862.        || togl->RgbaBlue != oldRgbaBlue
  863.        || togl->DoubleFlag != oldDoubleFlag
  864.        || togl->DepthFlag != oldDepthFlag
  865.        || togl->DepthSize != oldDepthSize
  866.        || togl->AccumFlag != oldAccumFlag
  867.        || togl->AccumRed != oldAccumRed
  868.        || togl->AccumGreen != oldAccumGreen
  869.        || togl->AccumBlue != oldAccumBlue
  870.        || togl->AccumAlpha != oldAccumAlpha
  871.        || togl->AlphaFlag != oldAlphaFlag
  872.        || togl->AlphaSize != oldAlphaSize
  873.        || togl->StencilFlag != oldStencilFlag
  874.        || togl->StencilSize != oldStencilSize
  875.        || togl->AuxNumber != oldAuxNumber) {
  876. #ifdef MESA_COLOR_HACK
  877.       free_default_color_cells( Tk_Display(togl->TkWin),
  878.                                 Tk_Colormap(togl->TkWin) );
  879. #endif
  880.       /* Have to recreate the window and GLX context */
  881.       if (Togl_MakeWindowExist(togl)==TCL_ERROR) {
  882.          return TCL_ERROR;
  883.       }
  884.    }
  885. #if defined(__sgi) && defined(STEREO)
  886.    stereoInit(togl,togl->StereoFlag);
  887. #endif
  888.    return TCL_OK;
  889. }
  890. int Togl_Widget(ClientData clientData, Tcl_Interp *interp,
  891.        int argc, char *argv[])
  892. {
  893.    struct Togl *togl = (struct Togl *)clientData;
  894.    int result = TCL_OK;
  895.    Tcl_HashEntry *entry;
  896.    Tcl_HashSearch search;
  897.    Togl_CmdProc *cmd_proc;
  898.    if (argc < 2) {
  899.       Tcl_AppendResult(interp, "wrong # args: should be "",
  900.                        argv[0], " ?options?"", NULL);
  901.       return TCL_ERROR;
  902.    }
  903.    Tk_Preserve((ClientData)togl);
  904.    if (!strncmp(argv[1], "configure", MAX(1, strlen(argv[1])))) {
  905.       if (argc == 2) {
  906.          /* Return list of all configuration parameters */
  907.          result = Tk_ConfigureInfo(interp, togl->TkWin, configSpecs,
  908.                                    (char *)togl, (char *)NULL, 0);
  909.       }
  910.       else if (argc == 3) {
  911.          if (strcmp(argv[2],"-extensions")==0) {
  912.             /* Return a list of OpenGL extensions available */
  913.             char *extensions;
  914.             extensions = (char *) glGetString(GL_EXTENSIONS);
  915.             Tcl_SetResult( interp, extensions, TCL_STATIC );
  916.             result = TCL_OK;
  917.          }
  918.          else {
  919.             /* Return a specific configuration parameter */
  920.             result = Tk_ConfigureInfo(interp, togl->TkWin, configSpecs,
  921.                                       (char *)togl, argv[2], 0);
  922.          }
  923.       }
  924.       else {
  925.          /* Execute a configuration change */
  926.          result = Togl_Configure(interp, togl, argc-2, argv+2,
  927.                                 TK_CONFIG_ARGV_ONLY);
  928.       }
  929.    }
  930.    else if (!strncmp(argv[1], "render", MAX(1, strlen(argv[1])))) {
  931.       /* force the widget to be redrawn */
  932.       Togl_Render((ClientData) togl);
  933.    }
  934.    else if (!strncmp(argv[1], "swapbuffers", MAX(1, strlen(argv[1])))) {
  935.       /* force the widget to be redrawn */
  936.       Togl_SwapBuffers(togl);
  937.    }
  938.    else if (!strncmp(argv[1], "makecurrent", MAX(1, strlen(argv[1])))) {
  939.       /* force the widget to be redrawn */
  940.       Togl_MakeCurrent(togl);
  941.    }
  942.    else {
  943.       /* Probably a user-defined function */
  944.       entry = Tcl_FindHashEntry(&CommandTable, argv[1]);
  945.       if (entry != NULL) {
  946.          cmd_proc = (Togl_CmdProc *)Tcl_GetHashValue(entry);
  947.          result = cmd_proc(togl, argc, argv);
  948.       }
  949.       else {
  950.          Tcl_AppendResult(interp, "Togl: Unknown option: ", argv[1], "n",
  951.                           "Try: configure or rendern",
  952.                           "or one of the user-defined commands:n",
  953.                           NULL);
  954.          entry = Tcl_FirstHashEntry(&CommandTable, &search);
  955.          while (entry) {
  956.             Tcl_AppendResult(interp, "  ",
  957.                              Tcl_GetHashKey(&CommandTable, entry),
  958.                              "n", NULL);
  959.             entry = Tcl_NextHashEntry(&search);
  960.          }
  961.          result = TCL_ERROR;
  962.       }
  963.    }
  964.    Tk_Release((ClientData)togl);
  965.    return result;
  966. }
  967. /*
  968.  * Togl_Cmd
  969.  *
  970.  *   Called when Togl is executed - creation of a Togl widget.
  971.  *     * Creates a new window
  972.  *     * Creates an 'Togl' data structure
  973.  *     * Creates an event handler for this window
  974.  *     * Creates a command that handles this object
  975.  *     * Configures this Togl for the given arguments
  976.  */
  977. static int Togl_Cmd(ClientData clientData, Tcl_Interp *interp,
  978.                     int argc, char **argv)
  979. {
  980.    char *name;
  981.    Tk_Window main = (Tk_Window)clientData;
  982.    Tk_Window tkwin;
  983.    struct Togl *togl;
  984.    if (argc <= 1) {
  985.       TCL_ERR(interp, "wrong # args: should be "pathName read filename"");
  986.    }
  987.    /* Create the window. */
  988.    name = argv[1];
  989.    tkwin = Tk_CreateWindowFromPath(interp, main, name, (char *) NULL);
  990.    if (tkwin == NULL) {
  991.       return TCL_ERROR;
  992.    }
  993.    Tk_SetClass(tkwin, "Togl");
  994.    /* Create Togl data structure */
  995.    togl = (struct Togl *)malloc(sizeof(struct Togl));
  996.    if (!togl) {
  997.       return TCL_ERROR;
  998.    }
  999.    togl->Next = NULL;
  1000. #if defined(WIN32)
  1001.    togl->tglGLHdc = NULL;
  1002.    togl->tglGLHglrc = NULL;
  1003. #elif defined(X11)
  1004.    togl->GlCtx = NULL;
  1005.    togl->OverlayCtx = NULL;
  1006. #endif /* WIN32 */ 
  1007.    togl->display = Tk_Display( tkwin );
  1008.    togl->TkWin = tkwin;
  1009.    togl->Interp = interp;
  1010. #ifndef NO_TK_CURSOR
  1011.    togl->Cursor = None;
  1012. #endif
  1013.    togl->Width = 0;
  1014.    togl->Height = 0;
  1015.    togl->Time = 0;
  1016.    togl->RgbaFlag = 1;
  1017.    togl->RgbaRed = 1;
  1018.    togl->RgbaGreen = 1;
  1019.    togl->RgbaBlue = 1;
  1020.    togl->DoubleFlag = 0;
  1021.    togl->DepthFlag = 0;
  1022.    togl->DepthSize = 1;
  1023.    togl->AccumFlag = 0;
  1024.    togl->AccumRed = 1;
  1025.    togl->AccumGreen = 1;
  1026.    togl->AccumBlue = 1;
  1027.    togl->AccumAlpha = 1;
  1028.    togl->AlphaFlag = 0;
  1029.    togl->AlphaSize = 1;
  1030.    togl->StencilFlag = 0;
  1031.    togl->StencilSize = 1;
  1032.    togl->OverlayFlag = 0;
  1033.    togl->StereoFlag = 0;
  1034.    togl->AuxNumber = 0;
  1035.    togl->UpdatePending = GL_FALSE;
  1036.    togl->OverlayUpdatePending = GL_FALSE;
  1037.    togl->CreateProc = CreateProc;
  1038.    togl->DisplayProc = DisplayProc;
  1039.    togl->ReshapeProc = ReshapeProc;
  1040.    togl->DestroyProc = DestroyProc;
  1041.    togl->TimerProc = TimerProc;
  1042.    togl->OverlayDisplayProc = OverlayDisplayProc;
  1043.    togl->ShareList = NULL;
  1044.    togl->ShareContext = NULL;
  1045.    togl->Ident = NULL;
  1046.    togl->Client_Data = DefaultClientData;
  1047.    /* for EPS Output */ 
  1048.    togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL;
  1049.    togl->EpsMapSize = 0;
  1050.    /* Create command event handler */ 
  1051.    togl->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(tkwin),
  1052.        Togl_Widget, (ClientData)togl,
  1053.        (Tcl_CmdDeleteProc*) ToglCmdDeletedProc);
  1054.    Tk_CreateEventHandler(tkwin,
  1055.                          ExposureMask | StructureNotifyMask,
  1056.                          Togl_EventProc,
  1057.                          (ClientData)togl);
  1058.    /* Configure Togl widget */
  1059.    if (Togl_Configure(interp, togl, argc-2, argv+2, 0) == TCL_ERROR) {
  1060.    Tk_DestroyWindow(tkwin);
  1061.    goto error;
  1062.    }
  1063.    /*
  1064.     * If OpenGL window wasn't already created by Togl_Configure() we
  1065.     * create it now.  We can tell by checking if the GLX context has
  1066.     * been initialized.
  1067.     */ 
  1068. #if defined(WIN32)
  1069.    if (!togl->tglGLHdc) {
  1070. #elif defined(X11)
  1071.    if (!togl->GlCtx) {
  1072. #endif /* WIN32 */ 
  1073.       if (Togl_MakeWindowExist(togl) == TCL_ERROR) {
  1074.          goto error;
  1075.       }
  1076.    }
  1077.    /* If defined, call create callback */ 
  1078.    if (togl->CreateProc) {
  1079.       togl->CreateProc(togl);
  1080.    }
  1081.    /* If defined, call reshape proc */ 
  1082.    if (togl->ReshapeProc) {
  1083.       togl->ReshapeProc(togl);
  1084.    }
  1085.    /* If defined, setup timer */ 
  1086.    if (togl->TimerProc){
  1087.       Tk_CreateTimerHandler( togl->Time, Togl_Timer, (ClientData)togl );
  1088.    }
  1089.    Tcl_AppendResult(interp, Tk_PathName(tkwin), NULL);
  1090.    /* Add to linked list */ 
  1091.    AddToList(togl);
  1092.    return TCL_OK;
  1093. error:
  1094.    Tcl_DeleteCommand(interp, "togl");
  1095.    /*free(togl);   Don't free it, if we do a crash occurs later...*/
  1096.    return TCL_ERROR;
  1097. }
  1098. /*
  1099.  * Do all the setup for overlay planes
  1100.  * Return:   TCL_OK or TCL_ERROR
  1101.  */
  1102. static int SetupOverlay( struct Togl *togl )
  1103. {
  1104. #if defined(X11)
  1105. #ifdef GLX_TRANSPARENT_TYPE_EXT
  1106.    static int ovAttributeList[] = {
  1107.       GLX_BUFFER_SIZE, 2,
  1108.       GLX_LEVEL, 1,
  1109.       GLX_TRANSPARENT_TYPE_EXT, GLX_TRANSPARENT_INDEX_EXT,
  1110.       None
  1111.    };
  1112. #else
  1113.    static int ovAttributeList[] = {
  1114.       GLX_BUFFER_SIZE, 2,
  1115.       GLX_LEVEL, 1,
  1116.       None
  1117.    };
  1118. #endif
  1119.    Display *dpy;
  1120.    XVisualInfo *visinfo;
  1121.    TkWindow *winPtr = (TkWindow *) togl->TkWin;
  1122.    XSetWindowAttributes swa;
  1123.    Tcl_HashEntry *hPtr;
  1124.    int new_flag;
  1125.    dpy = Tk_Display(togl->TkWin);
  1126.    visinfo = glXChooseVisual( dpy, DefaultScreen(dpy), ovAttributeList );
  1127.    if (!visinfo){
  1128.       Tcl_AppendResult(togl->Interp,Tk_PathName(winPtr),
  1129.                        ": No suitable overlay index visual available",
  1130.                        (char *) NULL);
  1131.       togl->OverlayCtx = 0;
  1132.       togl->OverlayWindow = 0;
  1133.       togl->OverlayCmap = 0;
  1134.       return TCL_ERROR;
  1135.    }
  1136. #ifdef GLX_TRANSPARENT_INDEX_EXT
  1137.    {
  1138.       int fail = glXGetConfig(dpy, visinfo,GLX_TRANSPARENT_INDEX_VALUE_EXT,
  1139.                               &togl->OverlayTransparentPixel);
  1140.       if (fail)
  1141.          togl->OverlayTransparentPixel=0; /* maybe, maybe ... */
  1142.    }
  1143. #else
  1144.    togl->OverlayTransparentPixel=0; /* maybe, maybe ... */
  1145. #endif
  1146.    /*
  1147.    togl->OverlayCtx = glXCreateContext( dpy, visinfo, None, GL_TRUE );
  1148.    */
  1149.    /* NEW in Togl 1.5 beta 3 */
  1150.    /* share display lists with normal layer context */
  1151.    togl->OverlayCtx = glXCreateContext( dpy, visinfo,
  1152.                                         togl->GlCtx, GL_TRUE );
  1153.    swa.colormap = XCreateColormap( dpy, RootWindow(dpy, visinfo->screen),
  1154.                                    visinfo->visual, AllocNone );
  1155.    togl->OverlayCmap = swa.colormap;
  1156.    swa.border_pixel = 0;
  1157.    swa.event_mask = ALL_EVENTS_MASK;
  1158.    togl->OverlayWindow = XCreateWindow( dpy, Tk_WindowId(togl->TkWin), 0, 0,
  1159.                                         togl->Width, togl->Height, 0,
  1160.                                         visinfo->depth, InputOutput,
  1161.                                         visinfo->visual,
  1162.                                         CWBorderPixel|CWColormap|CWEventMask,
  1163.                                         &swa );
  1164.    hPtr = Tcl_CreateHashEntry( &winPtr->dispPtr->winTable,
  1165.                                (char *) togl->OverlayWindow, &new_flag );
  1166.    Tcl_SetHashValue( hPtr, winPtr );
  1167. /*   XMapWindow( dpy, togl->OverlayWindow );*/
  1168.    togl->OverlayIsMapped = 0;
  1169.    /* Make sure window manager installs our colormap */
  1170.    XSetWMColormapWindows( dpy, togl->OverlayWindow, &togl->OverlayWindow, 1 );
  1171.    return TCL_OK;
  1172. #elif defined(WIN32)       /* not yet implemented on Windows*/
  1173.    return TCL_ERROR;
  1174. #endif /* X11 */
  1175. }
  1176. #ifdef WIN32
  1177. #define TOGL_CLASS_NAME "Togl Class"
  1178. static ToglClassInitialized = 0;
  1179. // turn off optimizations so release version doesn't crash
  1180. #pragma optimize("g", off)
  1181. static LRESULT CALLBACK Win32WinProc( HWND hwnd, UINT message,
  1182.                                     WPARAM wParam, LPARAM lParam)
  1183. {
  1184.     LONG result;
  1185.     struct Togl *togl = (struct Togl*) GetWindowLong(hwnd, 0);
  1186.     TkWinColormap *cmap;
  1187.     HPALETTE OldPal;
  1188.     UINT i;
  1189. switch( message ){
  1190.     case WM_WINDOWPOSCHANGED:
  1191.         /* Should be processed by DefWindowProc, otherwise a double buffered
  1192.         context is not properly resized when the corresponding window is resized.*/ 
  1193.         break;
  1194.     case WM_DESTROY:
  1195.         if (togl->tglGLHglrc) {
  1196.             wglDeleteContext(togl->tglGLHglrc);
  1197.         }
  1198.         if (togl->tglGLHdc) {
  1199.             ReleaseDC(hwnd, togl->tglGLHdc);
  1200.         }
  1201.         break;
  1202.     default: 
  1203. return TkWinChildProc(hwnd, message, wParam, lParam);
  1204.     }
  1205.     result = DefWindowProc(hwnd, message, wParam, lParam);
  1206.     Tcl_ServiceAll();
  1207.     return result;
  1208. }
  1209. #pragma optimize("g", on)
  1210. #endif /* WIN32 */
  1211. /*
  1212.  * Togl_MakeWindowExist
  1213.  *
  1214.  *   Modified version of Tk_MakeWindowExist.
  1215.  *   Creates an OpenGL window for the Togl widget.
  1216.  */
  1217. static int Togl_MakeWindowExist(struct Togl *togl)
  1218. {
  1219.    XVisualInfo *visinfo = NULL;
  1220.    Display *dpy;
  1221.    int dummy;
  1222.    int attrib_list[1000];
  1223.    int attrib_count;
  1224.    TkWindow *winPtr = (TkWindow *) togl->TkWin;
  1225.    TkWindow *winPtr2;
  1226.    Window parent;
  1227.    Colormap cmap;
  1228.    XSetWindowAttributes swa;
  1229.    Tcl_HashEntry *hPtr;
  1230.    int new_flag;
  1231.    int scrnum;
  1232.    int attempt;
  1233. #if defined(X11)
  1234. #define MAX_ATTEMPTS 12
  1235.    static int ci_depths[MAX_ATTEMPTS] = {
  1236.       8, 4, 2, 1, 12, 16, 8, 4, 2, 1, 12, 16
  1237.    };
  1238.    static int dbl_flags[MAX_ATTEMPTS] = {
  1239.       0, 0, 0, 0,  0,  0, 1, 1, 1, 1,  1,  1
  1240.    };
  1241. #elif defined(WIN32)
  1242.    HWND hwnd, parentWin;
  1243.    int style, pixelformat;
  1244.    HANDLE hInstance;
  1245.    WNDCLASS ToglClass;
  1246.    PIXELFORMATDESCRIPTOR pfd;
  1247.    XVisualInfo VisInf;
  1248. #endif /* X11 */
  1249.    dpy = Tk_Display(togl->TkWin);
  1250.    if (winPtr->window != None) {
  1251.       XDestroyWindow(dpy, winPtr->window);
  1252.       winPtr->window = 0;
  1253.    }
  1254. #if defined(X11)
  1255.    /* Make sure OpenGL's GLX extension supported */
  1256.    if (!glXQueryExtension(dpy, &dummy, &dummy)) {
  1257.       TCL_ERR(togl->Interp, "Togl: X server has no OpenGL GLX extension");
  1258.    }
  1259.    if (togl->ShareContext && FindTogl(togl->ShareContext)) {
  1260.       /* share OpenGL context with existing Togl widget */
  1261.       struct Togl *shareWith = FindTogl(togl->ShareContext);
  1262.       assert(shareWith);
  1263.       assert(shareWith->GlCtx);
  1264.       togl->GlCtx = shareWith->GlCtx;
  1265.       togl->VisInfo = shareWith->VisInfo;
  1266.       visinfo = togl->VisInfo;
  1267.       printf("SHARE CTXn");
  1268.    }
  1269.    else {
  1270.       /* It may take a few tries to get a visual */
  1271.       for (attempt=0; attempt<MAX_ATTEMPTS; attempt++) {
  1272.          attrib_count = 0;
  1273.          attrib_list[attrib_count++] = GLX_USE_GL;
  1274.          if (togl->RgbaFlag) {
  1275.             /* RGB[A] mode */
  1276.             attrib_list[attrib_count++] = GLX_RGBA;
  1277.             attrib_list[attrib_count++] = GLX_RED_SIZE;
  1278.             attrib_list[attrib_count++] = togl->RgbaRed;
  1279.             attrib_list[attrib_count++] = GLX_GREEN_SIZE;
  1280.             attrib_list[attrib_count++] = togl->RgbaGreen;
  1281.             attrib_list[attrib_count++] = GLX_BLUE_SIZE;
  1282.             attrib_list[attrib_count++] = togl->RgbaBlue;
  1283.             if (togl->AlphaFlag) {
  1284.                attrib_list[attrib_count++] = GLX_ALPHA_SIZE;
  1285.                attrib_list[attrib_count++] = togl->AlphaSize;
  1286.             }
  1287.             /* for EPS Output */
  1288.             if ( togl->EpsRedMap) free( ( char *)togl->EpsRedMap);
  1289.             if ( togl->EpsGreenMap) free( ( char *)togl->EpsGreenMap);
  1290.             if ( togl->EpsBlueMap) free( ( char *)togl->EpsBlueMap);
  1291.             togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL;
  1292.             togl->EpsMapSize = 0;
  1293.          }
  1294.          else {
  1295.             /* Color index mode */
  1296.             int depth;
  1297.             attrib_list[attrib_count++] = GLX_BUFFER_SIZE;
  1298.             depth = ci_depths[attempt];
  1299.             attrib_list[attrib_count++] = depth;
  1300.          }
  1301.          if (togl->DepthFlag) {
  1302.             attrib_list[attrib_count++] = GLX_DEPTH_SIZE;
  1303.             attrib_list[attrib_count++] = togl->DepthSize;
  1304.          }
  1305.          if (togl->DoubleFlag || dbl_flags[attempt]) {
  1306.             attrib_list[attrib_count++] = GLX_DOUBLEBUFFER;
  1307.          }
  1308.          if (togl->StencilFlag) {
  1309.             attrib_list[attrib_count++] = GLX_STENCIL_SIZE;
  1310.             attrib_list[attrib_count++] = togl->StencilSize;
  1311.          }
  1312.          if (togl->AccumFlag) {
  1313.             attrib_list[attrib_count++] = GLX_ACCUM_RED_SIZE;
  1314.             attrib_list[attrib_count++] = togl->AccumRed;
  1315.             attrib_list[attrib_count++] = GLX_ACCUM_GREEN_SIZE;
  1316.             attrib_list[attrib_count++] = togl->AccumGreen;
  1317.             attrib_list[attrib_count++] = GLX_ACCUM_BLUE_SIZE;
  1318.             attrib_list[attrib_count++] = togl->AccumBlue;
  1319.             if (togl->AlphaFlag) {
  1320.                attrib_list[attrib_count++] = GLX_ACCUM_ALPHA_SIZE;
  1321.                attrib_list[attrib_count++] = togl->AccumAlpha;
  1322.             }
  1323.          }
  1324.          if (togl->AuxNumber != 0) {
  1325.             attrib_list[attrib_count++] = GLX_AUX_BUFFERS;
  1326.             attrib_list[attrib_count++] = togl->AuxNumber;
  1327.          }
  1328.          /* stereo hack */
  1329.          /*
  1330.            if (togl->StereoFlag) {
  1331.            attrib_list[attrib_count++] = GLX_STEREO;
  1332.            }
  1333.          */
  1334.          attrib_list[attrib_count++] = None;
  1335.          visinfo = glXChooseVisual( dpy, DefaultScreen(dpy), attrib_list );
  1336.          if (visinfo) {
  1337.             /* found a GLX visual! */
  1338.             break;
  1339.          }
  1340.       }
  1341.       togl->VisInfo = visinfo;
  1342.       if (visinfo==NULL) {
  1343.          TCL_ERR(togl->Interp, "Togl: couldn't get visual");
  1344.       }
  1345.       /*
  1346.        * Create a new OpenGL rendering context.
  1347.        */
  1348.       if (togl->ShareList) {
  1349.          /* share display lists with existing togl widget */
  1350.          struct Togl *shareWith = FindTogl(togl->ShareList);
  1351.          GLXContext shareCtx;
  1352.          if (shareWith)
  1353.             shareCtx = shareWith->GlCtx;
  1354.          else
  1355.             shareCtx = None;
  1356.          togl->GlCtx = glXCreateContext(dpy, visinfo, shareCtx, GL_TRUE);
  1357.       }
  1358.       else {
  1359.          /* don't share display lists */
  1360.          togl->GlCtx = glXCreateContext(dpy, visinfo, None, GL_TRUE);
  1361.       }
  1362.       if (togl->GlCtx == NULL) {
  1363.          TCL_ERR(togl->Interp, "could not create rendering context");
  1364.       }
  1365.    }
  1366. #endif /* X11 */
  1367.    /* Find parent of window */
  1368.    /* Necessary for creation */
  1369.    if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
  1370.       parent = XRootWindow(winPtr->display, winPtr->screenNum);
  1371.    }
  1372.    else {
  1373.       if (winPtr->parentPtr->window == None) {
  1374.          Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
  1375.       }
  1376.       parent = winPtr->parentPtr->window;
  1377.    }
  1378. #ifdef WIN32
  1379.    parentWin = Tk_GetHWND(parent);
  1380.    hInstance = Tk_GetHINSTANCE();
  1381.    if (ToglClassInitialized == 0) {
  1382.    ToglClassInitialized = 1;
  1383.        ToglClass.style = CS_HREDRAW | CS_VREDRAW;
  1384.        ToglClass.cbClsExtra = 0;
  1385.        ToglClass.cbWndExtra = 4;   /* to save struct Togl* */
  1386.        ToglClass.hInstance = hInstance;
  1387.        ToglClass.hbrBackground = NULL;
  1388.        ToglClass.lpszMenuName = NULL;
  1389.        ToglClass.lpszClassName = TOGL_CLASS_NAME;
  1390.        ToglClass.lpfnWndProc = Win32WinProc;
  1391.        ToglClass.hIcon = NULL;
  1392.        ToglClass.hCursor = NULL;
  1393.        if (!RegisterClass(&ToglClass)){
  1394.            TCL_ERR(togl->Interp, "unable register Togl window class");
  1395.        }
  1396.    }
  1397.    hwnd = CreateWindow(TOGL_CLASS_NAME, NULL, WS_CHILD | WS_CLIPCHILDREN
  1398.                        | WS_CLIPSIBLINGS, 0, 0, togl->Width, togl->Height,
  1399.                        parentWin, NULL, hInstance, NULL);
  1400.    
  1401.    SetWindowLong(hwnd, 0, (LONG) togl);
  1402.    SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
  1403.                SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  1404.    togl->tglGLHdc = GetDC(hwnd);
  1405.    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  1406.    pfd.nVersion = 1;
  1407.    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
  1408.    if (togl->DoubleFlag) {
  1409.         pfd.dwFlags |= PFD_DOUBLEBUFFER;
  1410.    }
  1411.    /* The stereo flag is not supported in the current generic OpenGL
  1412.     * implementation, but may be supported by specific hardware devices.
  1413.     */
  1414.    if (togl->StereoFlag) {
  1415.         pfd.dwFlags |= PFD_STEREO;
  1416.    }
  1417.    pfd.cColorBits = togl->RgbaRed + togl->RgbaGreen + togl->RgbaBlue;
  1418.    pfd.iPixelType = togl->RgbaFlag ? PFD_TYPE_RGBA : PFD_TYPE_COLORINDEX;
  1419.    /* Alpha bitplanes are not supported in the current generic OpenGL
  1420.     * implementation, but may be supported by specific hardware devices.
  1421.     */
  1422.    pfd.cAlphaBits = togl->AlphaFlag ? togl->AlphaSize : 0;
  1423.    pfd.cAccumBits = togl->AccumFlag ? (togl->AccumRed + togl->AccumGreen +
  1424.                                        togl->AccumBlue +togl->AccumAlpha) : 0;
  1425.    pfd.cDepthBits = togl->DepthFlag ? togl->DepthSize : 0;
  1426.    pfd.cStencilBits = togl->StencilFlag ? togl->StencilSize : 0;
  1427.    /* Auxiliary buffers are not supported in the current generic OpenGL
  1428.     * implementation, but may be supported by specific hardware devices.
  1429.     */
  1430.    pfd.cAuxBuffers = togl->AuxNumber;
  1431.    pfd.iLayerType = PFD_MAIN_PLANE;
  1432.    if ( (pixelformat = ChoosePixelFormat(togl->tglGLHdc, &pfd)) == 0 ) {
  1433.         TCL_ERR(togl->Interp, "Togl: couldn't choose pixel format");
  1434.    }
  1435.    if (SetPixelFormat(togl->tglGLHdc, pixelformat, &pfd) == FALSE) {
  1436.         TCL_ERR(togl->Interp, "Togl: couldn't choose pixel format");
  1437.    }
  1438.    /* Get the actual pixel format */
  1439.    DescribePixelFormat(togl->tglGLHdc, pixelformat, sizeof(pfd), &pfd);
  1440.    /* Create an OpenGL rendering context */
  1441.    togl->tglGLHglrc = wglCreateContext(togl->tglGLHdc);
  1442.    if (!togl->tglGLHglrc) {
  1443.         TCL_ERR(togl->Interp, "could not create rendering context");
  1444.    }
  1445.    /* Just for portability, define the simplest visinfo */
  1446.    visinfo = &VisInf;
  1447.    visinfo->visual = DefaultVisual(dpy, DefaultScreen(dpy));
  1448.    visinfo->depth = visinfo->visual->bits_per_rgb;
  1449. #endif /*WIN32 */
  1450.    /*
  1451.     * find a colormap
  1452.     */
  1453.    scrnum = DefaultScreen(dpy);
  1454.    if (togl->RgbaFlag) {
  1455.       /* Colormap for RGB mode */
  1456. #if defined(X11)
  1457.       cmap = get_rgb_colormap( dpy, scrnum, visinfo );
  1458. #elif defined(WIN32)
  1459.       if (pfd.dwFlags & PFD_NEED_PALETTE) {
  1460.          cmap = Win32CreateRgbColormap(pfd);
  1461.       }
  1462.       else {
  1463.          cmap = DefaultColormap(dpy,scrnum);
  1464.       }
  1465.       /* for EPS Output */
  1466.       if ( togl->EpsRedMap) free( ( char *)togl->EpsRedMap);
  1467.       if ( togl->EpsGreenMap) free( ( char *)togl->EpsGreenMap);
  1468.       if ( togl->EpsBlueMap) free( ( char *)togl->EpsBlueMap);
  1469.       togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL;
  1470.       togl->EpsMapSize = 0;
  1471. #endif /* X11 */
  1472.    }
  1473.    else {
  1474.       /* Colormap for CI mode */
  1475. #ifdef WIN32
  1476.       togl->CiColormapSize = 1 << pfd.cColorBits;
  1477.       togl->CiColormapSize = togl->CiColormapSize < MAX_CI_COLORMAP_SIZE ?
  1478.                              togl->CiColormapSize : MAX_CI_COLORMAP_SIZE;
  1479. #endif /* WIN32 */
  1480.       if (togl->PrivateCmapFlag) {
  1481.          /* need read/write colormap so user can store own color entries */
  1482. #if defined(X11)
  1483.          cmap = XCreateColormap(dpy, RootWindow(dpy, visinfo->screen),
  1484.                                 visinfo->visual, AllocAll);
  1485. #elif defined(WIN32)
  1486.          cmap = Win32CreateCiColormap(togl);
  1487. #endif /* X11 */
  1488.       }
  1489.       else {
  1490.          if (visinfo->visual==DefaultVisual(dpy, scrnum)) {
  1491.             /* share default/root colormap */
  1492.             cmap = DefaultColormap(dpy,scrnum);
  1493.          }
  1494.          else {
  1495.             /* make a new read-only colormap */
  1496.             cmap = XCreateColormap(dpy, RootWindow(dpy, visinfo->screen),
  1497.                                    visinfo->visual, AllocNone);
  1498.          }
  1499.       }
  1500.    }
  1501.    /* Make sure Tk knows to switch to the new colormap when the cursor
  1502.     * is over this window when running in color index mode.
  1503.     */
  1504.    Tk_SetWindowVisual(togl->TkWin, visinfo->visual, visinfo->depth, cmap);
  1505. #ifdef WIN32
  1506.    /* Install the colormap */
  1507.    SelectPalette(togl->tglGLHdc, ((TkWinColormap *)cmap)->palette, TRUE);
  1508.    RealizePalette(togl->tglGLHdc);
  1509. #endif /* WIN32 */
  1510. #if defined(X11)
  1511.    swa.colormap = cmap;
  1512.    swa.border_pixel = 0;
  1513.    swa.event_mask = ALL_EVENTS_MASK;
  1514.    winPtr->window = XCreateWindow(dpy, parent,
  1515.                                   0, 0, togl->Width, togl->Height,
  1516.                                   0, visinfo->depth,
  1517.                                   InputOutput, visinfo->visual,
  1518.                                   CWBorderPixel | CWColormap | CWEventMask,
  1519.                                   &swa);
  1520.    /* Make sure window manager installs our colormap */
  1521.    XSetWMColormapWindows( dpy, winPtr->window, &winPtr->window, 1 );
  1522. #elif defined(WIN32)
  1523.    winPtr->window = Tk_AttachHWND((Tk_Window)winPtr, hwnd);
  1524. #endif /* X11 */
  1525.    hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,
  1526.                               (char *) winPtr->window, &new_flag);
  1527.    Tcl_SetHashValue(hPtr, winPtr);
  1528.    winPtr->dirtyAtts = 0;
  1529.    winPtr->dirtyChanges = 0;
  1530. #ifdef TK_USE_INPUT_METHODS
  1531.    winPtr->inputContext = NULL;
  1532. #endif /* TK_USE_INPUT_METHODS */
  1533.    if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1534.       /*
  1535.        * If any siblings higher up in the stacking order have already
  1536.        * been created then move this window to its rightful position
  1537.        * in the stacking order.
  1538.        *
  1539.        * NOTE: this code ignores any changes anyone might have made
  1540.        * to the sibling and stack_mode field of the window's attributes,
  1541.        * so it really isn't safe for these to be manipulated except
  1542.        * by calling Tk_RestackWindow.
  1543.        */
  1544.       for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
  1545.            winPtr2 = winPtr2->nextPtr) {
  1546.          if ((winPtr2->window != None) && !(winPtr2->flags & TK_TOP_LEVEL)) {
  1547.             XWindowChanges changes;
  1548.             changes.sibling = winPtr2->window;
  1549.             changes.stack_mode = Below;
  1550.             XConfigureWindow(winPtr->display, winPtr->window,
  1551.                              CWSibling|CWStackMode, &changes);
  1552.             break;
  1553.          }
  1554.       }
  1555.       /*
  1556.        * If this window has a different colormap than its parent, add
  1557.        * the window to the WM_COLORMAP_WINDOWS property for its top-level.
  1558.        */
  1559.       if ((winPtr->parentPtr != NULL) &&
  1560.           (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {
  1561.          TkWmAddToColormapWindows(winPtr);
  1562.       }
  1563.    }
  1564.    if (togl->OverlayFlag) {
  1565.       if (SetupOverlay( togl )==TCL_ERROR) {
  1566.          fprintf(stderr,"Warning: couldn't setup overlay.n");
  1567.          togl->OverlayFlag = 0;
  1568.       }
  1569.    }
  1570.    /*
  1571.     * Issue a ConfigureNotify event if there were deferred configuration
  1572.     * changes (but skip it if the window is being deleted;  the
  1573.     * ConfigureNotify event could cause problems if we're being called
  1574.     * from Tk_DestroyWindow under some conditions).
  1575.     */
  1576.    if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
  1577.        && !(winPtr->flags & TK_ALREADY_DEAD)){
  1578.       XEvent event;
  1579.       winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
  1580.       event.type = ConfigureNotify;
  1581.       event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
  1582.       event.xconfigure.send_event = False;
  1583.       event.xconfigure.display = winPtr->display;
  1584.       event.xconfigure.event = winPtr->window;
  1585.       event.xconfigure.window = winPtr->window;
  1586.       event.xconfigure.x = winPtr->changes.x;
  1587.       event.xconfigure.y = winPtr->changes.y;
  1588.       event.xconfigure.width = winPtr->changes.width;
  1589.       event.xconfigure.height = winPtr->changes.height;
  1590.       event.xconfigure.border_width = winPtr->changes.border_width;
  1591.       if (winPtr->changes.stack_mode == Above) {
  1592.          event.xconfigure.above = winPtr->changes.sibling;
  1593.       }
  1594.       else {
  1595.          event.xconfigure.above = None;
  1596.       }
  1597.       event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  1598.       Tk_HandleEvent(&event);
  1599.    }
  1600.    /* Request the X window to be displayed */
  1601.    XMapWindow(dpy, Tk_WindowId(togl->TkWin));
  1602.    /* Bind the context to the window and make it the current context. */
  1603.    Togl_MakeCurrent(togl);
  1604. #if defined(X11)
  1605.    /* Check for a single/double buffering snafu */
  1606.    {
  1607.       int dbl_flag;
  1608.       if (glXGetConfig( dpy, visinfo, GLX_DOUBLEBUFFER, &dbl_flag )) {
  1609.          if (togl->DoubleFlag==0 && dbl_flag) {
  1610.             /* We requested single buffering but had to accept a */
  1611.             /* double buffered visual.  Set the GL draw buffer to */
  1612.             /* be the front buffer to simulate single buffering. */
  1613.             glDrawBuffer( GL_FRONT );
  1614.          }
  1615.       }
  1616.    }
  1617. #endif /* X11 */
  1618.    /* for EPS Output */
  1619.    if ( !togl->RgbaFlag) {
  1620.       GLint index_bits;
  1621.       int index_size;
  1622. #if defined(X11)
  1623.       glGetIntegerv( GL_INDEX_BITS, &index_bits );
  1624.       index_size = 1 << index_bits;
  1625. #elif defined(WIN32)
  1626.       index_size = togl->CiColormapSize;
  1627. #endif /* X11 */
  1628.       if ( togl->EpsMapSize != index_size) {
  1629.          if ( togl->EpsRedMap) free( ( char *)togl->EpsRedMap);
  1630.          if ( togl->EpsGreenMap) free( ( char *)togl->EpsGreenMap);
  1631.          if ( togl->EpsBlueMap) free( ( char *)togl->EpsBlueMap);
  1632.          togl->EpsMapSize = index_size;
  1633.          togl->EpsRedMap = ( GLfloat *)calloc( index_size, sizeof( GLfloat));
  1634.          togl->EpsGreenMap = ( GLfloat *)calloc( index_size, sizeof( GLfloat));
  1635.          togl->EpsBlueMap = ( GLfloat *)calloc( index_size, sizeof( GLfloat));
  1636.       }
  1637.    }
  1638.    return TCL_OK;
  1639. }
  1640. /*
  1641.  * ToglCmdDeletedProc
  1642.  *
  1643.  *      This procedure is invoked when a widget command is deleted.  If
  1644.  *      the widget isn't already in the process of being destroyed,
  1645.  *      this command destroys it.
  1646.  *
  1647.  * Results:
  1648.  *      None.
  1649.  *
  1650.  * Side effects:
  1651.  *      The widget is destroyed.
  1652.  *
  1653.  *----------------------------------------------------------------------
  1654.  */ 
  1655. static void ToglCmdDeletedProc( ClientData clientData )
  1656. {
  1657.    struct Togl *togl = (struct Togl *)clientData;
  1658.    Tk_Window tkwin = togl->TkWin;
  1659.    /*
  1660.     * This procedure could be invoked either because the window was
  1661.     * destroyed and the command was then deleted (in which case tkwin
  1662.     * is NULL) or because the command was deleted, and then this procedure
  1663.     * destroys the widget.
  1664.     */
  1665.    /* NEW in togl 1.5 beta 3 */
  1666.    if (togl && tkwin) {
  1667.       Tk_DeleteEventHandler(tkwin,
  1668.                          ExposureMask | StructureNotifyMask,
  1669.                          Togl_EventProc,
  1670.                          (ClientData)togl);
  1671.    }
  1672.    /* NEW in togl 1.5 beta 3 */
  1673. #if defined(X11)
  1674.    if (togl->GlCtx) {
  1675.       /* XXX this might be bad if two or more Togl widgets share a context */
  1676.       glXDestroyContext( togl->display, togl->GlCtx );
  1677.       togl->GlCtx = NULL;
  1678.    }
  1679.    if (togl->OverlayCtx) {
  1680.       Tcl_HashEntry *entryPtr;
  1681.       TkWindow *winPtr = (TkWindow *) togl->TkWin;
  1682.       if (winPtr != NULL) {
  1683. entryPtr = Tcl_FindHashEntry(&winPtr->dispPtr->winTable,
  1684.      (char *) togl->OverlayWindow );
  1685. Tcl_DeleteHashEntry(entryPtr);
  1686.       }
  1687.       assert (togl->display && togl->OverlayCtx);
  1688.       glXDestroyContext( togl->display, togl->OverlayCtx );
  1689.       togl->OverlayCtx = NULL;
  1690.    }
  1691. #endif
  1692.    if (tkwin != NULL) {
  1693.       togl->TkWin = NULL;
  1694.       Tk_DestroyWindow(tkwin);
  1695.    }
  1696. }
  1697. /*
  1698.  * Togl_Destroy
  1699.  *
  1700.  * Gets called when an Togl widget is destroyed.
  1701.  */
  1702. #if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401
  1703. static void Togl_Destroy( char *clientData )
  1704. #else
  1705. static void Togl_Destroy( ClientData clientData )
  1706. #endif
  1707. {
  1708.    struct Togl *togl = (struct Togl *)clientData;
  1709.    if (togl->DestroyProc) {
  1710.       togl->DestroyProc(togl);
  1711.    }
  1712.    Tk_FreeOptions(configSpecs, (char *)togl, togl->display, 0);
  1713. #ifndef NO_TK_CURSOR
  1714.    if (togl->Cursor != None) {
  1715.       Tk_FreeCursor(togl->display, togl->Cursor);
  1716.    }
  1717. #endif
  1718.    /* remove from linked list */
  1719.    RemoveFromList(togl);
  1720.    free(togl);
  1721. }
  1722. /*
  1723.  * This gets called to handle Togl window configuration events
  1724.  */
  1725. static void Togl_EventProc(ClientData clientData, XEvent *eventPtr)
  1726. {
  1727.    struct Togl *togl = (struct Togl *)clientData;
  1728.    switch (eventPtr->type) {
  1729.       case Expose:
  1730.          if (eventPtr->xexpose.count == 0) {
  1731.             if (!togl->UpdatePending &&
  1732.                 eventPtr->xexpose.window==Tk_WindowId(togl->TkWin)) {
  1733.                Togl_PostRedisplay(togl);
  1734.             }
  1735. #if defined(X11)
  1736.             if (!togl->OverlayUpdatePending && togl->OverlayFlag
  1737.                 && togl->OverlayIsMapped
  1738.                 && eventPtr->xexpose.window==togl->OverlayWindow){
  1739.                Togl_PostOverlayRedisplay(togl);
  1740.             }
  1741. #endif /*X11*/
  1742.          }
  1743.          break;
  1744.       case ConfigureNotify:
  1745.          if (togl->Width != Tk_Width(togl->TkWin) ||
  1746.              togl->Height != Tk_Height(togl->TkWin)) {
  1747.             togl->Width = Tk_Width(togl->TkWin);
  1748.             togl->Height = Tk_Height(togl->TkWin);
  1749.             XResizeWindow(Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin),
  1750.                           togl->Width, togl->Height);
  1751. #if defined(X11)
  1752.             if (togl->OverlayFlag) {
  1753.                XResizeWindow( Tk_Display(togl->TkWin), togl->OverlayWindow,
  1754.                               togl->Width, togl->Height );
  1755.                XRaiseWindow( Tk_Display(togl->TkWin), togl->OverlayWindow );
  1756.             }
  1757. #endif /*X11*/
  1758.             Togl_MakeCurrent(togl);
  1759.             if (togl->ReshapeProc) {
  1760.                togl->ReshapeProc(togl);
  1761.             }
  1762.             else {
  1763.                glViewport(0, 0, togl->Width, togl->Height);
  1764. #if defined(X11)
  1765.                if (togl->OverlayFlag) {
  1766.                   Togl_UseLayer( togl,TOGL_OVERLAY );
  1767.                   glViewport( 0, 0, togl->Width, togl->Height );
  1768.                   Togl_UseLayer( togl, TOGL_NORMAL );
  1769.                }
  1770. #endif /*X11*/
  1771.             }
  1772. #ifndef WIN32 /* causes double redisplay on Win32 platform */
  1773.             Togl_PostRedisplay(togl);
  1774. #endif /* WIN32 */
  1775.          }
  1776.          break;
  1777.       case MapNotify:
  1778.          break;
  1779.       case DestroyNotify:
  1780.  if (togl->TkWin != NULL) {
  1781.     togl->TkWin = NULL;
  1782. #if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 800
  1783.             /* This function new in Tcl/Tk 8.0 */
  1784.             Tcl_DeleteCommandFromToken( togl->Interp, togl->widgetCmd );
  1785. #endif
  1786.  }
  1787.  if (togl->TimerProc != NULL) {
  1788. #if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401
  1789.     Tcl_DeleteTimerHandler(togl->timerHandler);
  1790. #else
  1791.     Tk_DeleteTimerHandler(togl->timerHandler);
  1792. #endif
  1793.     
  1794.  }
  1795.  if (togl->UpdatePending) {
  1796. #if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705
  1797.             Tcl_CancelIdleCall(Togl_Render, (ClientData) togl);
  1798. #else
  1799.             Tk_CancelIdleCall(Togl_Render, (ClientData) togl);
  1800. #endif
  1801.  }
  1802. #if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401
  1803.          Tcl_EventuallyFree( (ClientData) togl, Togl_Destroy );
  1804. #else
  1805.          Tk_EventuallyFree((ClientData)togl, Togl_Destroy);
  1806. #endif
  1807.          break;
  1808.       default:
  1809.          /*nothing*/
  1810.          ;
  1811.    }
  1812. }
  1813. void Togl_PostRedisplay( struct Togl *togl )
  1814. {
  1815.    if (!togl->UpdatePending) {
  1816.       Tk_DoWhenIdle( Togl_Render, (ClientData) togl );
  1817.       togl->UpdatePending = GL_TRUE;
  1818.    }
  1819. }
  1820. void Togl_SwapBuffers( const struct Togl *togl )
  1821. {
  1822.    if (togl->DoubleFlag) {
  1823. #if defined(WIN32)
  1824.       int res = SwapBuffers(togl->tglGLHdc);
  1825.       assert(res == TRUE);
  1826. #elif defined(X11)
  1827.       glXSwapBuffers( Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin) );
  1828. #endif /* WIN32 */
  1829.    }
  1830.    else {
  1831.       glFlush();
  1832.    }
  1833. }
  1834. char *Togl_Ident( const struct Togl *togl )
  1835. {
  1836.    return togl->Ident;
  1837. }
  1838. int Togl_Width( const struct Togl *togl )
  1839. {
  1840.    return togl->Width;
  1841. }
  1842. int Togl_Height( const struct Togl *togl )
  1843. {
  1844.    return togl->Height;
  1845. }
  1846. Tcl_Interp *Togl_Interp( const struct Togl *togl )
  1847. {
  1848.    return togl->Interp;
  1849. }
  1850. Tk_Window Togl_TkWin( const struct Togl *togl )
  1851. {
  1852.    return togl->TkWin;
  1853. }
  1854. #if defined(X11)
  1855. /*
  1856.  * A replacement for XAllocColor.  This function should never
  1857.  * fail to allocate a color.  When XAllocColor fails, we return
  1858.  * the nearest matching color.  If we have to allocate many colors
  1859.  * this function isn't too efficient; the XQueryColors() could be
  1860.  * done just once.
  1861.  * Written by Michael Pichler, Brian Paul, Mark Kilgard
  1862.  * Input:  dpy - X display
  1863.  *         cmap - X colormap
  1864.  *         cmapSize - size of colormap
  1865.  * In/Out: color - the XColor struct
  1866.  * Output:  exact - 1=exact color match, 0=closest match
  1867.  */
  1868. static void
  1869. noFaultXAllocColor( Display *dpy, Colormap cmap, int cmapSize,
  1870.                     XColor *color, int *exact )
  1871. {
  1872.    XColor *ctable, subColor;
  1873.    int i, bestmatch;
  1874.    double mindist;       /* 3*2^16^2 exceeds long int precision.
  1875.                           */
  1876.    /* First try just using XAllocColor. */
  1877.    if (XAllocColor(dpy, cmap, color)) {
  1878.       *exact = 1;
  1879.       return;
  1880.    }
  1881.    /* Retrieve color table entries. */
  1882.    /* XXX alloca candidate. */
  1883.    ctable = (XColor *) malloc(cmapSize * sizeof(XColor));
  1884.    for (i = 0; i < cmapSize; i++) {
  1885.       ctable[i].pixel = i;
  1886.    }
  1887.    XQueryColors(dpy, cmap, ctable, cmapSize);
  1888.    /* Find best match. */
  1889.    bestmatch = -1;
  1890.    mindist = 0.0;
  1891.    for (i = 0; i < cmapSize; i++) {
  1892.       double dr = (double) color->red - (double) ctable[i].red;
  1893.       double dg = (double) color->green - (double) ctable[i].green;
  1894.       double db = (double) color->blue - (double) ctable[i].blue;
  1895.       double dist = dr * dr + dg * dg + db * db;
  1896.       if (bestmatch < 0 || dist < mindist) {
  1897.          bestmatch = i;
  1898.          mindist = dist;
  1899.       }
  1900.    }
  1901.    /* Return result. */
  1902.    subColor.red = ctable[bestmatch].red;
  1903.    subColor.green = ctable[bestmatch].green;
  1904.    subColor.blue = ctable[bestmatch].blue;
  1905.    free(ctable);
  1906.    /* Try to allocate the closest match color.  This should only
  1907.     * fail if the cell is read/write.  Otherwise, we're incrementing
  1908.     * the cell's reference count.
  1909.     */
  1910.    if (!XAllocColor(dpy, cmap, &subColor)) {
  1911.       /* do this to work around a problem reported by Frank Ortega */
  1912.       subColor.pixel = (unsigned long) bestmatch;
  1913.       subColor.red   = ctable[bestmatch].red;
  1914.       subColor.green = ctable[bestmatch].green;
  1915.       subColor.blue  = ctable[bestmatch].blue;
  1916.       subColor.flags = DoRed | DoGreen | DoBlue;
  1917.    }
  1918.    *color = subColor;
  1919. }
  1920. #elif defined(WIN32)
  1921. static UINT Win32AllocColor( const struct Togl *togl,
  1922.                              float red, float green, float blue )
  1923. {
  1924. /* Modified version of XAllocColor emulation of Tk.
  1925. *      - returns index, instead of color itself
  1926. *      - allocates logical palette entry even for non-palette devices
  1927. */
  1928.     TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin);
  1929.     UINT index;
  1930.     COLORREF newColor, closeColor;
  1931.     PALETTEENTRY entry, closeEntry;
  1932.     int new, refCount;
  1933.     Tcl_HashEntry *entryPtr;
  1934.     entry.peRed =  red*255 + .5;
  1935.     entry.peGreen = green*255 + .5;
  1936.     entry.peBlue = blue*255 + .5;
  1937.     entry.peFlags = 0;
  1938. /*
  1939.  * Find the nearest existing palette entry.
  1940.  */
  1941.     newColor = RGB(entry.peRed, entry.peGreen, entry.peBlue);
  1942.     index = GetNearestPaletteIndex(cmap->palette, newColor);
  1943.     GetPaletteEntries(cmap->palette, index, 1, &closeEntry);
  1944.     closeColor = RGB(closeEntry.peRed, closeEntry.peGreen,  closeEntry.peBlue);
  1945.      /*
  1946.  * If this is not a duplicate and colormap is not full, allocate a new entry.
  1947.  */
  1948. if (newColor != closeColor) {
  1949.         if (cmap->size == togl->CiColormapSize) {
  1950.             entry = closeEntry;
  1951.         }
  1952.         else {
  1953.             cmap->size++;
  1954.     ResizePalette(cmap->palette, cmap->size);
  1955.     index = cmap->size -1;
  1956.     SetPaletteEntries(cmap->palette, index, 1, &entry);
  1957.     SelectPalette(togl->tglGLHdc, cmap->palette, TRUE);
  1958.     RealizePalette(togl->tglGLHdc);
  1959. }
  1960. }
  1961. newColor = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue);
  1962. entryPtr = Tcl_CreateHashEntry(&cmap->refCounts, (char *) newColor, &new);
  1963. if (new) {
  1964.     refCount = 1;
  1965. } else {
  1966.     refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
  1967. }
  1968. Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  1969.    /* for EPS output */
  1970.     togl->EpsRedMap[index] = entry.peRed / 255.0;
  1971.     togl->EpsGreenMap[index] = entry.peGreen / 255.0;
  1972.     togl->EpsBlueMap[index] = entry.peBlue / 255.0;
  1973.     return index;
  1974. }
  1975. static void Win32FreeColor( const struct Togl *togl, unsigned long index )
  1976. {
  1977.     TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin);
  1978.     COLORREF cref;
  1979.     UINT count, refCount;
  1980.     PALETTEENTRY entry, *entries;
  1981.     Tcl_HashEntry *entryPtr;
  1982. if (index >= cmap->size ) {
  1983. panic("Tried to free a color that isn't allocated.");
  1984. }
  1985. GetPaletteEntries(cmap->palette, index, 1, &entry);
  1986. cref = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue);
  1987. entryPtr = Tcl_FindHashEntry(&cmap->refCounts, (char *) cref);
  1988. if (!entryPtr) {
  1989. panic("Tried to free a color that isn't allocated.");
  1990. }
  1991. refCount = (int) Tcl_GetHashValue(entryPtr) - 1;
  1992. if (refCount == 0) {
  1993. count = cmap->size - index;
  1994. entries = (PALETTEENTRY *) ckalloc(sizeof(PALETTEENTRY)* count);
  1995. GetPaletteEntries(cmap->palette, index+1, count, entries);
  1996. SetPaletteEntries(cmap->palette, index, count, entries);
  1997. SelectPalette(togl->tglGLHdc, cmap->palette, TRUE);
  1998. RealizePalette(togl->tglGLHdc);
  1999. ckfree((char *) entries);
  2000. cmap->size--;
  2001. Tcl_DeleteHashEntry(entryPtr);
  2002. } else {
  2003. Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  2004. }
  2005. }
  2006. static void Win32SetColor( const struct Togl *togl,
  2007.                     unsigned long index, float red, float green, float blue )
  2008. {
  2009.     TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin);
  2010.     PALETTEENTRY entry;
  2011.     entry.peRed =  red*255 + .5;
  2012.     entry.peGreen = green*255 + .5;
  2013.     entry.peBlue = blue*255 + .5;
  2014.     entry.peFlags = 0;
  2015.     SetPaletteEntries(cmap->palette, index, 1, &entry);
  2016. SelectPalette(togl->tglGLHdc, cmap->palette, TRUE);
  2017. RealizePalette(togl->tglGLHdc);
  2018. /* for EPS output */
  2019.     togl->EpsRedMap[index] = entry.peRed / 255.0;
  2020.     togl->EpsGreenMap[index] = entry.peGreen / 255.0;
  2021.     togl->EpsBlueMap[index] = entry.peBlue / 255.0;
  2022. }
  2023. #endif /* X11 */
  2024. unsigned long Togl_AllocColor( const struct Togl *togl,
  2025.                                float red, float green, float blue )
  2026. {
  2027.    XColor xcol;
  2028.    int exact;
  2029.    if (togl->RgbaFlag) {
  2030.       fprintf(stderr,"Error: Togl_AllocColor illegal in RGBA mode.n");
  2031.       return 0;
  2032.    }
  2033.    /* TODO: maybe not... */
  2034.    if (togl->PrivateCmapFlag) {
  2035.       fprintf(stderr,"Error: Togl_FreeColor illegal with private colormapn");
  2036.       return 0;
  2037.    }
  2038. #if defined(X11)
  2039.    xcol.red   = (short) (red   * 65535.0);
  2040.    xcol.green = (short) (green * 65535.0);
  2041.    xcol.blue  = (short) (blue  * 65535.0);
  2042.    noFaultXAllocColor( Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin),
  2043.                        Tk_Visual(togl->TkWin)->map_entries, &xcol, &exact );
  2044.    /* for EPS output */
  2045.    togl->EpsRedMap[ xcol.pixel] = xcol.red / 65535.0;
  2046.    togl->EpsGreenMap[ xcol.pixel] = xcol.green / 65535.0;
  2047.    togl->EpsBlueMap[ xcol.pixel] = xcol.blue / 65535.0;
  2048.    return xcol.pixel;
  2049. #elif defined(WIN32)
  2050.    return Win32AllocColor( togl, red, green, blue );
  2051. #endif /* X11 */
  2052. }
  2053. void Togl_FreeColor( const struct Togl *togl, unsigned long pixel )
  2054. {
  2055.    if (togl->RgbaFlag) {
  2056.       fprintf(stderr,"Error: Togl_AllocColor illegal in RGBA mode.n");
  2057.       return;
  2058.    }
  2059.    /* TODO: maybe not... */
  2060.    if (togl->PrivateCmapFlag) {
  2061.       fprintf(stderr,"Error: Togl_FreeColor illegal with private colormapn");
  2062.       return;
  2063.    }
  2064. #if defined(X11)
  2065.    XFreeColors( Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin),
  2066.                 &pixel, 1, 0 );
  2067. #elif defined(WIN32)
  2068.    Win32FreeColor(togl, pixel);
  2069. #endif /* X11 */
  2070. }
  2071. void Togl_SetColor( const struct Togl *togl,
  2072.                     unsigned long index, float red, float green, float blue )
  2073. {
  2074.    XColor xcol;
  2075.    if (togl->RgbaFlag) {
  2076.       fprintf(stderr,"Error: Togl_AllocColor illegal in RGBA mode.n");
  2077.       return;
  2078.    }
  2079.    if (!togl->PrivateCmapFlag) {
  2080.       fprintf(stderr,"Error: Togl_SetColor requires a private colormapn");
  2081.       return;
  2082.    }
  2083. #if defined(X11)
  2084.    xcol.pixel = index;
  2085.    xcol.red   = (short) (red   * 65535.0);
  2086.    xcol.green = (short) (green * 65535.0);
  2087.    xcol.blue  = (short) (blue  * 65535.0);
  2088.    xcol.flags = DoRed | DoGreen | DoBlue;
  2089.    XStoreColor( Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), &xcol );
  2090.    /* for EPS output */
  2091.    togl->EpsRedMap[ xcol.pixel] = xcol.red / 65535.0;
  2092.    togl->EpsGreenMap[ xcol.pixel] = xcol.green / 65535.0;
  2093.    togl->EpsBlueMap[ xcol.pixel] = xcol.blue / 65535.0;
  2094. #elif defined(WIN32)
  2095.    Win32SetColor( togl, index, red, green, blue );
  2096. #endif /* X11 */
  2097. }
  2098. #if defined(WIN32)
  2099. #include "tkFont.h"
  2100. /*
  2101.  * The following structure represents Windows' implementation of a font.
  2102.  */
  2103. typedef struct WinFont {
  2104.     TkFont font; /* Stuff used by generic font package.  Must
  2105.  * be first in structure. */
  2106.     HFONT hFont; /* Windows information about font. */
  2107.     HWND hwnd; /* Toplevel window of application that owns
  2108.  * this font, used for getting HDC. */
  2109.     int widths[256]; /* Widths of first 256 chars in this font. */
  2110. } WinFont;
  2111. #endif /* WIN32 */
  2112. #define MAX_FONTS 1000
  2113. static GLuint ListBase[MAX_FONTS];
  2114. static GLuint ListCount[MAX_FONTS];
  2115. /*
  2116.  * Load the named bitmap font as a sequence of bitmaps in a display list.
  2117.  * fontname may be one of the predefined fonts like TOGL_BITMAP_8_BY_13
  2118.  * or an X font name, or a Windows font name, etc.
  2119.  */
  2120. GLuint Togl_LoadBitmapFont( const struct Togl *togl, const char *fontname )
  2121. {
  2122.    static int FirstTime = 1;
  2123. #if defined(X11)
  2124.    XFontStruct *fontinfo;
  2125. #elif defined(WIN32)
  2126.    WinFont *winfont;
  2127.    HFONT oldFont;
  2128.    TEXTMETRIC tm;
  2129. #endif /* X11 */
  2130.    int first, last, count;
  2131.    GLuint fontbase;
  2132.    const char *name;
  2133.    /* Initialize the ListBase and ListCount arrays */
  2134.    if (FirstTime) {
  2135.       int i;
  2136.       for (i=0;i<MAX_FONTS;i++) {
  2137.          ListBase[i] = ListCount[i] = 0;
  2138.       }
  2139.       FirstTime = 0;
  2140.    }
  2141.    /*
  2142.     * This method of selecting X fonts according to a TOGL_ font name
  2143.     * is a kludge.  To be fixed when I find time...
  2144.     */
  2145.    if (fontname==TOGL_BITMAP_8_BY_13) {
  2146.       name = "8x13";
  2147.    }
  2148.    else if (fontname==TOGL_BITMAP_9_BY_15) {
  2149.       name = "9x15";
  2150.    }
  2151.    else if (fontname==TOGL_BITMAP_TIMES_ROMAN_10) {
  2152.       name = "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1";
  2153.    }
  2154.    else if (fontname==TOGL_BITMAP_TIMES_ROMAN_24) {
  2155.       name = "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1";
  2156.    }
  2157.    else if (fontname==TOGL_BITMAP_HELVETICA_10) {
  2158.       name = "-adobe-helvetica-medium-r-normal--10-100-75-75-p-57-iso8859-1";
  2159.    }
  2160.    else if (fontname==TOGL_BITMAP_HELVETICA_12) {
  2161.       name = "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1";
  2162.    }
  2163.    else if (fontname==TOGL_BITMAP_HELVETICA_18) {
  2164.       name = "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1";
  2165.    }
  2166.    else if (!fontname) {
  2167.       name = DEFAULT_FONTNAME;
  2168.    }
  2169.    else {
  2170.       name = (const char *) fontname;
  2171.    }
  2172.    assert( name );
  2173. #if defined(X11)
  2174.    fontinfo = XLoadQueryFont( Tk_Display(togl->TkWin), name );
  2175.    if (!fontinfo) {
  2176.       return 0;
  2177.    }
  2178.    first = fontinfo->min_char_or_byte2;
  2179.    last = fontinfo->max_char_or_byte2;
  2180. #elif defined(WIN32)
  2181.    winfont = (WinFont*) Tk_GetFont(togl->Interp, togl->TkWin, name);
  2182.    if (!winfont) {
  2183.       return 0;
  2184.    }
  2185.    oldFont = SelectObject(togl->tglGLHdc, winfont->hFont);
  2186.    GetTextMetrics(togl->tglGLHdc, &tm);
  2187.    first = tm.tmFirstChar;
  2188.    last = tm.tmLastChar;
  2189. #endif /* X11 */
  2190.    count = last-first+1;
  2191.    fontbase = glGenLists( (GLuint) (last+1) );
  2192.    if (fontbase==0) {
  2193. #ifdef WIN32
  2194.       SelectObject(togl->tglGLHdc, oldFont);
  2195.       Tk_FreeFont((Tk_Font) winfont);
  2196. #endif /* WIN32 */
  2197.       return 0;
  2198.    }
  2199. #if defined(WIN32)
  2200.    wglUseFontBitmaps(togl->tglGLHdc, first, count, (int) fontbase+first );
  2201.    SelectObject(togl->tglGLHdc, oldFont);
  2202.    Tk_FreeFont((Tk_Font) winfont);
  2203. #elif defined(X11)
  2204.    glXUseXFont( fontinfo->fid, first, count, (int) fontbase+first );
  2205. #endif
  2206.    /* Record the list base and number of display lists
  2207.     * for Togl_UnloadBitmapFont().
  2208.     */
  2209.    {
  2210.       int i;
  2211.       for (i=0;i<MAX_FONTS;i++) {
  2212.          if (ListBase[i]==0) {
  2213.             ListBase[i] = fontbase;
  2214.             ListCount[i] = last+1;
  2215.             break;
  2216.          }
  2217.       }
  2218.    }
  2219.    return fontbase;
  2220. }
  2221. /*
  2222.  * Release the display lists which were generated by Togl_LoadBitmapFont().
  2223.  */
  2224. void Togl_UnloadBitmapFont( const struct Togl *togl, GLuint fontbase )
  2225. {
  2226.    int i;
  2227.    (void) togl;
  2228.    for (i=0;i<MAX_FONTS;i++) {
  2229.       if (ListBase[i]==fontbase) {
  2230.          glDeleteLists( ListBase[i], ListCount[i] );
  2231.          ListBase[i] = ListCount[i] = 0;
  2232.          return;
  2233.       }
  2234.    }
  2235. }
  2236. /*
  2237.  * Overlay functions
  2238.  */
  2239. void Togl_UseLayer( struct Togl *togl, int layer )
  2240. {
  2241.    if (togl->OverlayWindow) {
  2242.       if (layer==TOGL_OVERLAY) {
  2243. #if defined(WIN32)
  2244.          int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLOverlayHglrc);
  2245.          assert(res == TRUE);
  2246. #elif defined(X11)
  2247.  glXMakeCurrent( Tk_Display(togl->TkWin),
  2248.  togl->OverlayWindow,
  2249.  togl->OverlayCtx );
  2250. #if defined(__sgi) && defined(STEREO)
  2251. stereoMakeCurrent( Tk_Display(togl->TkWin),
  2252.    togl->OverlayWindow,
  2253.    togl->OverlayCtx );
  2254. #endif /* __sgi STEREO */
  2255. #endif /*WIN32 */
  2256.       }
  2257.       else if (layer==TOGL_NORMAL) {
  2258. #if defined(WIN32)
  2259. int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc);
  2260. assert(res == TRUE);
  2261. #elif defined(X11)
  2262. glXMakeCurrent( Tk_Display(togl->TkWin),
  2263. Tk_WindowId(togl->TkWin),
  2264. togl->GlCtx );
  2265. #if defined(__sgi) && defined(STEREO)
  2266. stereoMakeCurrent( Tk_Display(togl->TkWin),
  2267. Tk_WindowId(togl->TkWin),
  2268. togl->GlCtx );
  2269. #endif /* __sgi STEREO */
  2270. #endif /* WIN32 */
  2271.       }
  2272.       else {
  2273.          /* error */
  2274.       }
  2275.    }
  2276. }
  2277. void Togl_ShowOverlay( struct Togl *togl )
  2278. {
  2279. #if defined(X11)  /* not yet implemented on Windows*/
  2280.    if (togl->OverlayWindow) {
  2281.       XMapWindow( Tk_Display(togl->TkWin), togl->OverlayWindow );
  2282.       XInstallColormap(Tk_Display(togl->TkWin),togl->OverlayCmap);
  2283.       togl->OverlayIsMapped = 1;
  2284.    }
  2285. #endif /* X11 */
  2286. }
  2287. void Togl_HideOverlay( struct Togl *togl )
  2288. {
  2289.    if (togl->OverlayWindow && togl->OverlayIsMapped) {
  2290.       XUnmapWindow( Tk_Display(togl->TkWin), togl->OverlayWindow );
  2291.       togl->OverlayIsMapped=0;
  2292.    }
  2293. }
  2294. void Togl_PostOverlayRedisplay( struct Togl *togl )
  2295. {
  2296.    if (!togl->OverlayUpdatePending
  2297.        && togl->OverlayWindow && togl->OverlayDisplayProc) {
  2298.       Tk_DoWhenIdle( RenderOverlay, (ClientData) togl );
  2299.       togl->OverlayUpdatePending = 1;
  2300.    } 
  2301. }
  2302. void Togl_OverlayDisplayFunc( Togl_Callback *proc )
  2303. {
  2304.    OverlayDisplayProc = proc;
  2305. }
  2306. int Togl_ExistsOverlay( const struct Togl *togl )
  2307. {
  2308.    return togl->OverlayFlag;
  2309. }
  2310. int Togl_GetOverlayTransparentValue( const struct Togl *togl )
  2311. {
  2312.    return togl->OverlayTransparentPixel;
  2313. }
  2314. int Togl_IsMappedOverlay( const struct Togl *togl )
  2315. {
  2316.    return togl->OverlayFlag && togl->OverlayIsMapped;
  2317. }
  2318. unsigned long Togl_AllocColorOverlay( const struct Togl *togl,
  2319.                                       float red, float green, float blue )
  2320. {
  2321. #if defined(X11) /* not yet implemented on Windows*/
  2322.    if (togl->OverlayFlag && togl->OverlayCmap) {
  2323.       XColor xcol;
  2324.       xcol.red   = (short) (red* 65535.0);
  2325.       xcol.green = (short) (green* 65535.0);
  2326.       xcol.blue  = (short) (blue* 65535.0);
  2327.       if (!XAllocColor(Tk_Display(togl->TkWin),togl->OverlayCmap,&xcol))
  2328.          return (unsigned long) -1;
  2329.       return xcol.pixel;
  2330. #else /* X11 */
  2331.    if (0) {
  2332. #endif /* X11 */
  2333.    }
  2334.    else {
  2335.       return (unsigned long) -1;
  2336.    }
  2337. }
  2338. void Togl_FreeColorOverlay( const struct Togl *togl, unsigned long pixel )
  2339. {
  2340. #if defined(X11) /* not yet implemented on Windows*/
  2341.    if (togl->OverlayFlag && togl->OverlayCmap) {
  2342.       XFreeColors( Tk_Display(togl->TkWin), togl->OverlayCmap,
  2343.                    &pixel, 1, 0 );
  2344.    }
  2345. #endif /* X11 */
  2346. }
  2347. /*
  2348.  * User client data
  2349.  */
  2350. void Togl_ClientData( ClientData clientData )
  2351. {
  2352.    DefaultClientData = clientData;
  2353. }
  2354. ClientData Togl_GetClientData( const struct Togl *togl )
  2355. {
  2356.    return togl->Client_Data;
  2357. }
  2358. void Togl_SetClientData( struct Togl *togl, ClientData clientData )
  2359. {
  2360.    togl->Client_Data = clientData;
  2361. }
  2362. /*
  2363.  * X11-only functions
  2364.  * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES)
  2365.  */
  2366. Display* Togl_Display( const struct Togl *togl)
  2367. {
  2368.    return Tk_Display(togl->TkWin);
  2369. }
  2370. Screen* Togl_Screen( const struct Togl *togl)
  2371. {
  2372.    return Tk_Screen(togl->TkWin);
  2373. }
  2374. int Togl_ScreenNumber( const struct Togl *togl)
  2375. {
  2376.    return Tk_ScreenNumber(togl->TkWin);
  2377. }
  2378. Colormap Togl_Colormap( const struct Togl *togl)
  2379. {
  2380.    return Tk_Colormap(togl->TkWin);
  2381. }
  2382. #ifdef MESA_COLOR_HACK
  2383. /*
  2384.  * Let's know how many free colors do we have
  2385.  */
  2386. #if 0
  2387. static unsigned char rojo[] = { 4, 39, 74, 110, 145, 181, 216, 251},
  2388.                      verde[] = { 4, 39, 74, 110, 145, 181, 216, 251},
  2389.      azul[] = { 4, 39, 74, 110, 145, 181, 216, 251};
  2390. unsigned char rojo[] = { 4, 36, 72, 109, 145, 182, 218, 251},
  2391.               verde[] = { 4, 36, 72, 109, 145, 182, 218, 251},
  2392.               azul[] = { 4, 36, 72, 109, 145, 182, 218, 251};
  2393.               azul[] = { 0, 85, 170, 255};
  2394. #endif
  2395. #define RLEVELS     5
  2396. #define GLEVELS     9
  2397. #define BLEVELS     5
  2398. /* to free dithered_rgb_colormap pixels allocated by Mesa */
  2399. static unsigned long *ToglMesaUsedPixelCells = NULL;
  2400. static int ToglMesaUsedFreeCells = 0;
  2401. static int get_free_color_cells( Display *display, int screen,
  2402.                                  Colormap colormap)
  2403. {
  2404.    if ( !ToglMesaUsedPixelCells) {
  2405.       XColor xcol;
  2406.       int i;
  2407.       int colorsfailed, ncolors = XDisplayCells( display, screen);
  2408.       long r, g, b;
  2409.       ToglMesaUsedPixelCells = ( unsigned long *)calloc( ncolors, sizeof( unsigned long));
  2410.       /* Allocate X colors and initialize color_table[], red_table[], etc */
  2411.       /* de Mesa 2.1: xmesa1.c setup_dithered_(...) */
  2412.       i = colorsfailed = 0;
  2413.       for (r = 0; r < RLEVELS; r++)
  2414.          for (g = 0; g < GLEVELS; g++)
  2415.             for (b = 0; b < BLEVELS; b++) {
  2416.                int exact;
  2417.                xcol.red   = ( r*65535)/(RLEVELS-1);
  2418.                xcol.green = ( g*65535)/(GLEVELS-1);
  2419.                xcol.blue  = ( b*65535)/(BLEVELS-1);
  2420.                noFaultXAllocColor( display, colormap, ncolors,
  2421.                                    &xcol, &exact );
  2422.                ToglMesaUsedPixelCells[ i++] = xcol.pixel;
  2423.                if (!exact) {
  2424.                   colorsfailed++;
  2425.                }
  2426.             }
  2427.       ToglMesaUsedFreeCells = i;
  2428.       XFreeColors( display, colormap, ToglMesaUsedPixelCells,
  2429.                    ToglMesaUsedFreeCells, 0x00000000);
  2430.    }
  2431.    return ToglMesaUsedFreeCells;
  2432. }
  2433. static void free_default_color_cells( Display *display, Colormap colormap)
  2434. {
  2435.    if ( ToglMesaUsedPixelCells) {
  2436.       XFreeColors( display, colormap, ToglMesaUsedPixelCells,
  2437.                    ToglMesaUsedFreeCells, 0x00000000);
  2438.       free( ( char *)ToglMesaUsedPixelCells);
  2439.       ToglMesaUsedPixelCells = NULL;
  2440.       ToglMesaUsedFreeCells = 0;
  2441.    }
  2442. }
  2443. #endif
  2444. /*
  2445.  * Generate EPS file.
  2446.  * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES)
  2447.  */
  2448. /* Function that creates a EPS File from a created pixmap on the current
  2449.  * context.
  2450.  * Based on the code from Copyright (c) Mark J. Kilgard, 1996.
  2451.  * Parameters: name_file, b&w / Color flag, redraw function.
  2452.  * The redraw function is needed in order to draw things into the new
  2453.  * created pixmap.
  2454.  */
  2455. /* Copyright (c) Mark J. Kilgard, 1996. */
  2456. static GLvoid *grabPixels(int inColor, unsigned int width, unsigned int height)
  2457. {
  2458.    GLvoid *buffer;
  2459.    GLint swapbytes, lsbfirst, rowlength;
  2460.    GLint skiprows, skippixels, alignment;
  2461.    GLenum format;
  2462.    unsigned int size;
  2463.    if (inColor) {
  2464.       format = GL_RGB;
  2465.       size = width * height * 3;
  2466.    }
  2467.    else {
  2468.       format = GL_LUMINANCE;
  2469.       size = width * height * 1;
  2470.    }
  2471.    buffer = (GLvoid *) malloc(size);
  2472.    if (buffer == NULL)
  2473.       return NULL;
  2474.    /* Save current modes. */
  2475.    glGetIntegerv(GL_PACK_SWAP_BYTES, &swapbytes);
  2476.    glGetIntegerv(GL_PACK_LSB_FIRST, &lsbfirst);
  2477.    glGetIntegerv(GL_PACK_ROW_LENGTH, &rowlength);
  2478.    glGetIntegerv(GL_PACK_SKIP_ROWS, &skiprows);
  2479.    glGetIntegerv(GL_PACK_SKIP_PIXELS, &skippixels);
  2480.    glGetIntegerv(GL_PACK_ALIGNMENT, &alignment);
  2481.    /* Little endian machines (DEC Alpha for example) could
  2482.       benefit from setting GL_PACK_LSB_FIRST to GL_TRUE
  2483.       instead of GL_FALSE, but this would require changing the
  2484.       generated bitmaps too. */
  2485.    glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE);
  2486.    glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE);
  2487.    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
  2488.    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
  2489.    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
  2490.    glPixelStorei(GL_PACK_ALIGNMENT, 1);
  2491.    /* Actually read the pixels. */
  2492.    glReadPixels(0, 0, width, height, format,
  2493.                 GL_UNSIGNED_BYTE, (GLvoid *) buffer);
  2494.    /* Restore saved modes. */
  2495.    glPixelStorei(GL_PACK_SWAP_BYTES, swapbytes);
  2496.    glPixelStorei(GL_PACK_LSB_FIRST, lsbfirst);
  2497.    glPixelStorei(GL_PACK_ROW_LENGTH, rowlength);
  2498.    glPixelStorei(GL_PACK_SKIP_ROWS, skiprows);
  2499.    glPixelStorei(GL_PACK_SKIP_PIXELS, skippixels);
  2500.    glPixelStorei(GL_PACK_ALIGNMENT, alignment);
  2501.    return buffer;
  2502. }
  2503. static int generateEPS(const char *filename, int inColor,
  2504.                        unsigned int width, unsigned int height)
  2505. {
  2506.    FILE *fp;
  2507.    GLvoid *pixels;
  2508.    unsigned char *curpix;
  2509.    unsigned int components, i;
  2510.    int pos;
  2511.    unsigned char bitpixel;
  2512.    pixels = grabPixels(inColor, width, height);
  2513.    if (pixels == NULL)
  2514.       return 1;
  2515.    if (inColor)
  2516.       components = 3;     /* Red, green, blue. */
  2517.    else
  2518.       components = 1;     /* Luminance. */
  2519.    fp = fopen(filename, "w");
  2520.    if (fp == NULL) {
  2521.       return 2;
  2522.    }
  2523.    fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2n");
  2524.    fprintf(fp, "%%%%Creator: OpenGL pixmap render outputn");
  2525.    fprintf(fp, "%%%%BoundingBox: 0 0 %d %dn", width, height);
  2526.    fprintf(fp, "%%%%EndCommentsn");
  2527.    i = ((( width * height) + 7) / 8 ) / 40; /* # of lines, 40 bytes per line */
  2528.    fprintf(fp, "%%%%BeginPreview: %d %d %d %dn%%", width, height, 1, i);
  2529.    pos = 0;
  2530.    curpix = ( unsigned char *)pixels;
  2531.    for ( i = 0; i < width * height * components; ) {
  2532.       bitpixel = 0;
  2533.       if ( inColor) {
  2534.          double pix = 0.0;
  2535.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2536.          if ( pix > 127.0) bitpixel |= 0x80;
  2537.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2538.          if ( pix > 127.0) bitpixel |= 0x40;
  2539.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2540.          if ( pix > 127.0) bitpixel |= 0x20;
  2541.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2542.          if ( pix > 127.0) bitpixel |= 0x10;
  2543.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2544.          if ( pix > 127.0) bitpixel |= 0x08;
  2545.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2546.          if ( pix > 127.0) bitpixel |= 0x04;
  2547.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2548.          if ( pix > 127.0) bitpixel |= 0x02;
  2549.          pix = 0.30 * ( double)curpix[ i++] + 0.59 * ( double)curpix[ i++] + 0.11 * ( double)curpix[ i++];
  2550.          if ( pix > 127.0) bitpixel |= 0x01;
  2551.       }
  2552.       else {
  2553.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x80;
  2554.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x40;
  2555.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x20;
  2556.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x10;
  2557.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x08;
  2558.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x04;
  2559.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x02;
  2560.          if ( curpix[ i++] > 0x7f) bitpixel |= 0x01;
  2561.       }
  2562.       fprintf(fp, "%02hx", bitpixel);
  2563.       if (++pos >= 40) {
  2564.          fprintf(fp, "n%%");
  2565.          pos = 0;
  2566.       }
  2567.    }
  2568.    if (pos)
  2569.       fprintf(fp, "n%%%%EndPreviewn");
  2570.    else
  2571.       fprintf(fp, "%%EndPreviewn");
  2572.    fprintf(fp, "gsaven");
  2573.    fprintf(fp, "/bwproc {n");
  2574.    fprintf(fp, "    rgbprocn");
  2575.    fprintf(fp, "    dup length 3 idiv string 0 3 0n");
  2576.    fprintf(fp, "    5 -1 roll {n");
  2577.    fprintf(fp, "    add 2 1 roll 1 sub dup 0 eqn");
  2578.    fprintf(fp, "    { pop 3 idiv 3 -1 roll dup 4 -1 roll dupn");
  2579.    fprintf(fp, "        3 1 roll 5 -1 roll put 1 add 3 0 }n");
  2580.    fprintf(fp, "    { 2 1 roll } ifelsen");
  2581.    fprintf(fp, "    } foralln");
  2582.    fprintf(fp, "    pop pop popn");
  2583.    fprintf(fp, "} defn");
  2584.    fprintf(fp, "systemdict /colorimage known not {n");
  2585.    fprintf(fp, "    /colorimage {n");
  2586.    fprintf(fp, "        popn");
  2587.    fprintf(fp, "        popn");
  2588.    fprintf(fp, "        /rgbproc exch defn");
  2589.    fprintf(fp, "        { bwproc } imagen");
  2590.    fprintf(fp, "    } defn");
  2591.    fprintf(fp, "} ifn");
  2592.    fprintf(fp, "/picstr %d string defn", width * components);
  2593.    fprintf(fp, "%d %d scalen", width, height);
  2594.    fprintf(fp, "%d %d %dn", width, height, 8);
  2595.    fprintf(fp, "[%d 0 0 %d 0 0]n", width, height);
  2596.    fprintf(fp, "{currentfile picstr readhexstring pop}n");
  2597.    fprintf(fp, "false %dn", components);
  2598.    fprintf(fp, "colorimagen");
  2599.    curpix = (unsigned char *) pixels;
  2600.    pos = 0;
  2601.    for (i = width * height * components; i > 0; i--) {
  2602.       fprintf(fp, "%02hx", *curpix++);
  2603.       if (++pos >= 40) {
  2604.  fprintf(fp, "n");
  2605.  pos = 0;
  2606.       }
  2607.    }
  2608.    if (pos)
  2609.       fprintf(fp, "n");
  2610.    fprintf(fp, "grestoren");
  2611.    free(pixels);
  2612.    fclose(fp);
  2613.    return 0;
  2614. }
  2615. /* int Togl_DumpToEpsFile( const struct Togl *togl, const char *filename,
  2616.                         int inColor, void (*user_redraw)(void)) */
  2617. /* changed by GG */
  2618. int Togl_DumpToEpsFile( const struct Togl *togl, const char *filename,
  2619.                         int inColor, void (*user_redraw)( const struct Togl *))
  2620. {
  2621.    int using_mesa = 0;
  2622. #if 0
  2623.    Pixmap eps_pixmap;
  2624.    GLXPixmap eps_glxpixmap;
  2625.    XVisualInfo *vi = togl->VisInfo;
  2626.    Window win = Tk_WindowId( togl->TkWin);
  2627. #endif
  2628.    Display *dpy = Tk_Display( togl->TkWin);
  2629.    int retval;
  2630.    int scrnum = Tk_ScreenNumber(togl->TkWin);
  2631.    unsigned int width = togl->Width, height = togl->Height;
  2632. #if defined(X11)
  2633.    if (strstr(glXQueryServerString( dpy, scrnum, GLX_VERSION ), "Mesa"))
  2634.       using_mesa = 1;
  2635.    else
  2636. #endif /* X11 */
  2637.       using_mesa = 0;
  2638.    /* I don't use Pixmap do drawn into, because the code should link
  2639.     * with Mesa libraries and OpenGL libraries, and the which library
  2640.     * we use at run time should not matter, but the name of the calls
  2641.     * differs one from another:
  2642.     * MesaGl: glXCreateGLXPixmapMESA( dpy, vi, eps_pixmap, Tk_Colormap(togl->TkWin))
  2643.     * OpenGl: glXCreateGLXPixmap( dpy, vi, eps_pixmap);
  2644.     *
  2645.     * instead of this I read direct from back buffer of the screeen.
  2646.     */
  2647. #if 0
  2648.    eps_pixmap = XCreatePixmap( dpy, win, width, height, vi->depth);
  2649.    if ( using_mesa)
  2650.       eps_glxpixmap = glXCreateGLXPixmapMESA( dpy, vi, eps_pixmap, Tk_Colormap(togl->TkWin));
  2651.    else
  2652.       eps_glxpixmap = glXCreateGLXPixmap( dpy, vi, eps_pixmap);
  2653.    glXMakeCurrent( dpy, eps_glxpixmap, togl->GlCtx);
  2654.    user_redraw();
  2655. #endif
  2656.    if ( !togl->RgbaFlag) {
  2657. #if defined(WIN32)
  2658. /* Due to the lack of a unique inverse mapping from the frame buffer to
  2659.    the logical palette we need a translation map from the complete
  2660.    logical palette. */
  2661.        {
  2662.            int n, i;
  2663.            TkWinColormap *cmap = (TkWinColormap *)Tk_Colormap(togl->TkWin);
  2664.            LPPALETTEENTRY entry = malloc(togl->EpsMapSize * sizeof(PALETTEENTRY));
  2665.            n = GetPaletteEntries(cmap->palette, 0, togl->EpsMapSize, entry);
  2666.            for (i=0; i<n; i++) {
  2667.                togl->EpsRedMap[i] = entry[i].peRed / 255.0;
  2668.                togl->EpsGreenMap[i] = entry[i].peGreen / 255.0;
  2669.                togl->EpsBlueMap[i] = entry[i].peBlue / 255.0;
  2670.            }
  2671.            free(entry);
  2672.        }
  2673. #endif /* WIN32 */
  2674.       glPixelMapfv( GL_PIXEL_MAP_I_TO_R, togl->EpsMapSize, togl->EpsRedMap);
  2675.       glPixelMapfv( GL_PIXEL_MAP_I_TO_G, togl->EpsMapSize, togl->EpsGreenMap);
  2676.       glPixelMapfv( GL_PIXEL_MAP_I_TO_B, togl->EpsMapSize, togl->EpsBlueMap);
  2677.    }
  2678.    /*  user_redraw(); */
  2679.    user_redraw(togl);  /* changed by GG */
  2680.    /* glReadBuffer( GL_FRONT); */
  2681.    /* by default it read GL_BACK in double buffer mode*/
  2682.    glFlush();
  2683.    retval = generateEPS( filename, inColor, width, height);
  2684. #if 0
  2685.    glXMakeCurrent( dpy, win, togl->GlCtx );
  2686.    glXDestroyGLXPixmap( dpy, eps_glxpixmap);
  2687.    XFreePixmap( dpy, eps_pixmap);
  2688. #endif
  2689.    return retval;
  2690. }
  2691. /*
  2692.  * Full screen stereo for SGI graphics
  2693.  * Contributed by Ben Evans (Ben.Evans@anusf.anu.edu.au)
  2694.  * This code was based on SGI's /usr/share/src/OpenGL/teach/stereo
  2695.  */
  2696. #if defined(__sgi) && defined(STEREO)
  2697. static struct stereoStateRec {
  2698.     Bool        useSGIStereo;
  2699.     Display     *currentDisplay;
  2700.     Window      currentWindow;
  2701.     GLXContext  currentContext;
  2702.     GLenum      currentDrawBuffer;
  2703.     int         currentStereoBuffer;
  2704.     Bool        enabled;
  2705.     char        *stereoCommand;
  2706.     char        *restoreCommand;
  2707. } stereo;
  2708. /* call instead of glDrawBuffer */
  2709. void
  2710. Togl_StereoDrawBuffer(GLenum mode)
  2711. {
  2712.   if (stereo.useSGIStereo) {
  2713.     stereo.currentDrawBuffer = mode;
  2714.     switch (mode) {
  2715.     case GL_FRONT:
  2716.     case GL_BACK:
  2717.     case GL_FRONT_AND_BACK:
  2718.       /*
  2719.       ** Simultaneous drawing to both left and right buffers isn't
  2720.       ** really possible if we don't have a stereo capable visual.
  2721.       ** For now just fall through and use the left buffer.
  2722.       */
  2723.     case GL_LEFT:
  2724.     case GL_FRONT_LEFT:
  2725.     case GL_BACK_LEFT:
  2726.       stereo.currentStereoBuffer = STEREO_BUFFER_LEFT;
  2727.       break;
  2728.     case GL_RIGHT:
  2729.     case GL_FRONT_RIGHT: 
  2730.       stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
  2731.       mode = GL_FRONT;
  2732.       break;
  2733.     case GL_BACK_RIGHT:
  2734.       stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
  2735.       mode = GL_BACK;
  2736.       break;
  2737.     default:
  2738.       break;
  2739.     }
  2740.     if (stereo.currentDisplay && stereo.currentWindow) {
  2741.       glXWaitGL();  /* sync with GL command stream before calling X */
  2742.       XSGISetStereoBuffer(stereo.currentDisplay,
  2743.   stereo.currentWindow,
  2744.   stereo.currentStereoBuffer);
  2745.       glXWaitX();   /* sync with X command stream before calling GL */
  2746.     }
  2747.   }
  2748.   glDrawBuffer(mode);
  2749. }
  2750. /* call instead of glClear */
  2751. void
  2752. Togl_StereoClear(GLbitfield mask)
  2753. {
  2754.   GLenum drawBuffer;
  2755.   if (stereo.useSGIStereo) {
  2756.     drawBuffer = stereo.currentDrawBuffer;
  2757.     switch (drawBuffer) {
  2758.     case GL_FRONT:
  2759.       stereoDrawBuffer(GL_FRONT_RIGHT);
  2760.       glClear(mask);
  2761.       stereoDrawBuffer(drawBuffer);
  2762.       break;
  2763.     case GL_BACK:
  2764.       stereoDrawBuffer(GL_BACK_RIGHT);
  2765.       glClear(mask);
  2766.       stereoDrawBuffer(drawBuffer);
  2767.       break;
  2768.     case GL_FRONT_AND_BACK:
  2769.       stereoDrawBuffer(GL_RIGHT);
  2770.       glClear(mask);
  2771.       stereoDrawBuffer(drawBuffer);
  2772.       break;
  2773.     case GL_LEFT:
  2774.     case GL_FRONT_LEFT:
  2775.     case GL_BACK_LEFT:
  2776.     case GL_RIGHT:
  2777.     case GL_FRONT_RIGHT:
  2778.     case GL_BACK_RIGHT:
  2779.     default:
  2780.       break;
  2781.     }
  2782.   }
  2783.   glClear(mask);
  2784. }
  2785. static void
  2786. stereoMakeCurrent(Display *dpy, Window win, GLXContext ctx)
  2787. {
  2788.   
  2789.   if (stereo.useSGIStereo) {
  2790.     if (dpy && (dpy != stereo.currentDisplay)) {
  2791.       int event, error;
  2792.       /* Make sure new Display supports SGIStereo */
  2793.       if (XSGIStereoQueryExtension(dpy, &event, &error) == False) {
  2794. dpy = NULL;
  2795.       }
  2796.     }
  2797.     if (dpy && win && (win != stereo.currentWindow)) {
  2798.       /* Make sure new Window supports SGIStereo */
  2799.       if (XSGIQueryStereoMode(dpy, win) == X_STEREO_UNSUPPORTED) {
  2800. win = None;
  2801.       }
  2802.     }
  2803.     if (ctx && (ctx != stereo.currentContext)) {
  2804.       GLint drawBuffer;
  2805.       glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer);
  2806.       stereoDrawBuffer((GLenum) drawBuffer);
  2807.     }
  2808.     stereo.currentDisplay = dpy;
  2809.     stereo.currentWindow = win;
  2810.     stereo.currentContext = ctx;
  2811.   }
  2812. }
  2813. /* call before using stereo */
  2814. static void
  2815. stereoInit(struct Togl *togl,int stereoEnabled)
  2816. {
  2817.   stereo.useSGIStereo = stereoEnabled;
  2818.   stereo.currentDisplay = NULL;
  2819.   stereo.currentWindow = None;
  2820.   stereo.currentContext = NULL;
  2821.   stereo.currentDrawBuffer = GL_NONE;
  2822.   stereo.currentStereoBuffer = STEREO_BUFFER_NONE;
  2823.   stereo.enabled = False;
  2824. }
  2825. void
  2826. Togl_StereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
  2827.                GLfloat near, GLfloat far, GLfloat eyeDist, GLfloat eyeOffset)
  2828. {
  2829.   GLfloat eyeShift = (eyeDist - near) * (eyeOffset / eyeDist);
  2830.   
  2831.   glFrustum(left+eyeShift, right+eyeShift, bottom, top, near, far);
  2832.   glTranslatef(-eyeShift, 0.0, 0.0);
  2833. }
  2834. #endif /* __sgi STEREO */