1 
2 /* Copyright (c) Mark J. Kilgard, 1994, 1996. */
3 
4 /* This program is freely distributable without licensing fees
5    and is provided without guarantee or warrantee expressed or
6    implied. This program is -not- in the public domain. */
7 
8 #include <stdlib.h>
9 #include <GL/glut.h>
10 #include "glutint.h"
11 #include "layerutil.h"
12 
13 GLUTcolormap *__glutColormapList = NULL;
14 
15 static GLUTcolormap *
associateNewColormap(XVisualInfo * vis)16 associateNewColormap(XVisualInfo * vis)
17 {
18   GLUTcolormap *cmap;
19   int transparentPixel, i;
20   unsigned long pixels[255];
21 
22   cmap = (GLUTcolormap *) malloc(sizeof(GLUTcolormap));
23   if (!cmap)
24     __glutFatalError("out of memory.");
25   cmap->visual = vis->visual;
26   cmap->refcnt = 1;
27   cmap->size = vis->visual->map_entries;
28   cmap->cells = (GLUTcolorcell *)
29     malloc(sizeof(GLUTcolorcell) * cmap->size);
30   /* make all color cell entries be invalid */
31   for (i = cmap->size - 1; i >= 0; i--) {
32     cmap->cells[i].component[GLUT_RED] = -1.0;
33     cmap->cells[i].component[GLUT_GREEN] = -1.0;
34     cmap->cells[i].component[GLUT_BLUE] = -1.0;
35   }
36   if (!cmap->cells)
37     __glutFatalError("out of memory.");
38   transparentPixel = __glutGetTransparentPixel(__glutDisplay, vis);
39   if (transparentPixel == -1 || transparentPixel >= vis->visual->map_entries) {
40 
41     /* If there is no transparent pixel or if the transparent
42        pixel is outside the range of valid colormap cells (HP
43        can implement their overlays this smart way since their
44        transparent pixel is 255), we can AllocAll the colormap.
45        See note below.  */
46 
47     cmap->cmap = XCreateColormap(__glutDisplay,
48       __glutRoot, vis->visual, AllocAll);
49   } else {
50 
51     /* On machines where zero (or some other value in the range
52        of 0 through map_entries-1), BadAlloc may be generated
53        when an AllocAll overlay colormap is allocated since the
54        transparent pixel precludes all the cells in the colormap
55        being allocated (the transparent pixel is pre-allocated).
56        So in this case, use XAllocColorCells to allocate
57        map_entries-1 pixels (that is, all but the transparent
58        pixel.  */
59 
60     cmap->cmap = XCreateColormap(__glutDisplay,
61       __glutRoot, vis->visual, AllocNone);
62     XAllocColorCells(__glutDisplay, cmap->cmap, False, 0, 0,
63       pixels, vis->visual->map_entries - 1);
64   }
65   cmap->next = __glutColormapList;
66   __glutColormapList = cmap;
67   return cmap;
68 }
69 
70 GLUTcolormap *
__glutAssociateColormap(XVisualInfo * vis)71 __glutAssociateColormap(XVisualInfo * vis)
72 {
73   GLUTcolormap *cmap = __glutColormapList;
74 
75   while (cmap != NULL) {
76     /* Play safe: compare visual IDs, not Visual*'s */
77     if (cmap->visual->visualid == vis->visual->visualid) {
78       /* already have created colormap for the visual */
79       cmap->refcnt++;
80       return cmap;
81     }
82     cmap = cmap->next;
83   }
84   return associateNewColormap(vis);
85 }
86 
87 #define CLAMP(i) ((i) > 1.0 ? 1.0 : ((i) < 0.0 ? 0.0 : (i)))
88 
89 void
glutSetColor(int ndx,GLfloat red,GLfloat green,GLfloat blue)90 glutSetColor(int ndx, GLfloat red, GLfloat green, GLfloat blue)
91 {
92   GLUTcolormap *cmap, *newcmap;
93   XVisualInfo *vis;
94   XColor color;
95   int i;
96 
97   if (__glutCurrentWindow->renderWin == __glutCurrentWindow->win) {
98     cmap = __glutCurrentWindow->colormap;
99     vis = __glutCurrentWindow->vis;
100   } else {
101     cmap = __glutCurrentWindow->overlay->colormap;
102     vis = __glutCurrentWindow->overlay->vis;
103     if (ndx == __glutCurrentWindow->overlay->transparentPixel) {
104       __glutWarning(
105 	"glutSetColor: cannot set color of overlay transparent index %d\n",
106 	ndx);
107       return;
108     }
109   }
110 
111   if (!cmap) {
112     __glutWarning("glutSetColor: current window is RGBA");
113     return;
114   }
115   if (ndx >= vis->visual->map_entries ||
116     ndx < 0) {
117     __glutWarning("glutSetColor: index %d out of range", ndx);
118     return;
119   }
120   if (cmap->refcnt > 1) {
121     GLUTwindow *toplevel;
122 
123     newcmap = associateNewColormap(vis);
124     cmap->refcnt--;
125     /* Wouldn't it be nice if XCopyColormapAndFree could be
126        told not to free the old colormap's entries! */
127     for (i = cmap->size - 1; i >= 0; i--) {
128       if (i == ndx) {
129         /* We are going to set this cell shortly! */
130         continue;
131       }
132       if (cmap->cells[i].component[GLUT_RED] >= 0.0) {
133         color.pixel = i;
134         newcmap->cells[i].component[GLUT_RED] =
135           cmap->cells[i].component[GLUT_RED];
136         color.red = (GLfloat) 0xffff *
137           cmap->cells[i].component[GLUT_RED];
138         newcmap->cells[i].component[GLUT_GREEN] =
139           cmap->cells[i].component[GLUT_GREEN];
140         color.green = (GLfloat) 0xffff *
141           cmap->cells[i].component[GLUT_GREEN];
142         newcmap->cells[i].component[GLUT_BLUE] =
143           cmap->cells[i].component[GLUT_BLUE];
144         color.blue = (GLfloat) 0xffff *
145           cmap->cells[i].component[GLUT_BLUE];
146         color.flags = DoRed | DoGreen | DoBlue;
147         XStoreColor(__glutDisplay, newcmap->cmap, &color);
148       } else {
149         /* leave unallocated entries unallocated */
150       }
151     }
152     cmap = newcmap;
153     if (__glutCurrentWindow->renderWin == __glutCurrentWindow->win) {
154       __glutCurrentWindow->colormap = cmap;
155       __glutCurrentWindow->cmap = cmap->cmap;
156     } else {
157       __glutCurrentWindow->overlay->colormap = cmap;
158       __glutCurrentWindow->overlay->cmap = cmap->cmap;
159     }
160     XSetWindowColormap(__glutDisplay, __glutCurrentWindow->renderWin, cmap->cmap);
161 
162     toplevel = __glutToplevelOf(__glutCurrentWindow);
163     if (toplevel->cmap != cmap->cmap) {
164       __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
165     }
166   }
167   color.pixel = ndx;
168   red = CLAMP(red);
169   cmap->cells[ndx].component[GLUT_RED] = red;
170   color.red = (GLfloat) 0xffff *red;
171   green = CLAMP(green);
172   cmap->cells[ndx].component[GLUT_GREEN] = green;
173   color.green = (GLfloat) 0xffff *green;
174   blue = CLAMP(blue);
175   cmap->cells[ndx].component[GLUT_BLUE] = blue;
176   color.blue = (GLfloat) 0xffff *blue;
177   color.flags = DoRed | DoGreen | DoBlue;
178   XStoreColor(__glutDisplay, cmap->cmap, &color);
179 }
180 
181 GLfloat
glutGetColor(int ndx,int comp)182 glutGetColor(int ndx, int comp)
183 {
184   GLUTcolormap *colormap;
185   XVisualInfo *vis;
186 
187   if (__glutCurrentWindow->renderWin == __glutCurrentWindow->win) {
188     colormap = __glutCurrentWindow->colormap;
189     vis = __glutCurrentWindow->vis;
190   } else {
191     colormap = __glutCurrentWindow->overlay->colormap;
192     vis = __glutCurrentWindow->overlay->vis;
193     if (ndx == __glutCurrentWindow->overlay->transparentPixel) {
194       __glutWarning("glutGetColor: requesting overlay transparent index %d\n",
195         ndx);
196       return -1.0;
197     }
198   }
199 
200   if (!colormap) {
201     __glutWarning("glutGetColor: current window is RGBA");
202     return -1.0;
203   }
204   if (ndx >= vis->visual->map_entries || ndx < 0) {
205     __glutWarning("glutGetColor: index %d out of range", ndx);
206     return -1.0;
207   }
208   return colormap->cells[ndx].component[comp];
209 }
210 
211 void
__glutFreeColormap(GLUTcolormap * cmap)212 __glutFreeColormap(GLUTcolormap * cmap)
213 {
214   GLUTcolormap *cur, **prev;
215 
216   cmap->refcnt--;
217   if (cmap->refcnt == 0) {
218     /* remove from colormap list */
219     cur = __glutColormapList;
220     prev = &__glutColormapList;
221     while (cur) {
222       if (cur == cmap) {
223         *prev = cmap->next;
224         break;
225       }
226       prev = &(cur->next);
227       cur = cur->next;
228     }
229     /* actually free colormap */
230     XFreeColormap(__glutDisplay, cmap->cmap);
231     free(cmap->cells);
232     free(cmap);
233   }
234 }
235 
236 void
glutCopyColormap(int winnum)237 glutCopyColormap(int winnum)
238 {
239   GLUTwindow *window = __glutWindowList[winnum - 1];
240   GLUTcolormap *oldcmap, *newcmap, *copycmap;
241   XVisualInfo *dstvis;
242   XColor color;
243   int i, last;
244 
245   if (__glutCurrentWindow->renderWin == __glutCurrentWindow->win) {
246     oldcmap = __glutCurrentWindow->colormap;
247     dstvis = __glutCurrentWindow->vis;
248     newcmap = window->colormap;
249   } else {
250     oldcmap = __glutCurrentWindow->overlay->colormap;
251     dstvis = __glutCurrentWindow->overlay->vis;
252     if (!window->overlay) {
253       __glutWarning("glutCopyColormap: window %d has no overlay", winnum);
254       return;
255     }
256     newcmap = window->overlay->colormap;
257   }
258 
259   if (!oldcmap) {
260     __glutWarning("glutCopyColormap: destination colormap must be color index");
261     return;
262   }
263   if (!newcmap) {
264     __glutWarning(
265       "glutCopyColormap: source colormap of window %d must be color index",
266       winnum);
267     return;
268   }
269   if (newcmap == oldcmap) {
270     /* Source and destination are the same; now copy needed. */
271     return;
272   }
273   /* Play safe: compare visual IDs, not Visual*'s */
274   if (newcmap->visual->visualid == oldcmap->visual->visualid) {
275     /* Visuals match!  "Copy" by reference...  */
276     __glutFreeColormap(oldcmap);
277     newcmap->refcnt++;
278     if (__glutCurrentWindow->renderWin == __glutCurrentWindow->win) {
279       __glutCurrentWindow->colormap = newcmap;
280       __glutCurrentWindow->cmap = newcmap->cmap;
281     } else {
282       __glutCurrentWindow->overlay->colormap = newcmap;
283       __glutCurrentWindow->overlay->cmap = newcmap->cmap;
284     }
285     XSetWindowColormap(__glutDisplay, __glutCurrentWindow->renderWin,
286       newcmap->cmap);
287     __glutPutOnWorkList(__glutToplevelOf(window), GLUT_COLORMAP_WORK);
288   } else {
289     /* Visuals different - need a distinct X colormap! */
290     copycmap = associateNewColormap(dstvis);
291     /* Wouldn't it be nice if XCopyColormapAndFree could be
292        told not to free the old colormap's entries! */
293     last = newcmap->size;
294     if (last > copycmap->size) {
295       last = copycmap->size;
296     }
297     for (i = last - 1; i >= 0; i--) {
298       if (newcmap->cells[i].component[GLUT_RED] >= 0.0) {
299         color.pixel = i;
300         copycmap->cells[i].component[GLUT_RED] =
301           newcmap->cells[i].component[GLUT_RED];
302         color.red = (GLfloat) 0xffff *
303           newcmap->cells[i].component[GLUT_RED];
304         copycmap->cells[i].component[GLUT_GREEN] =
305           newcmap->cells[i].component[GLUT_GREEN];
306         color.green = (GLfloat) 0xffff *
307           newcmap->cells[i].component[GLUT_GREEN];
308         copycmap->cells[i].component[GLUT_BLUE] =
309           newcmap->cells[i].component[GLUT_BLUE];
310         color.blue = (GLfloat) 0xffff *
311           newcmap->cells[i].component[GLUT_BLUE];
312         color.flags = DoRed | DoGreen | DoBlue;
313         XStoreColor(__glutDisplay, copycmap->cmap, &color);
314       }
315     }
316   }
317 }
318