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