Imported Upstream version 1.15.1
[deb_xorg-server.git] / render / miindex.c
CommitLineData
a09e091a
JB
1/*
2 *
3 * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Keith Packard makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#ifndef _MIINDEX_H_
29#define _MIINDEX_H_
30
31#include "scrnintstr.h"
32#include "gcstruct.h"
33#include "pixmapstr.h"
34#include "windowstr.h"
35#include "mi.h"
36#include "picturestr.h"
37#include "mipict.h"
38#include "colormapst.h"
39
40#define NUM_CUBE_LEVELS 4
41#define NUM_GRAY_LEVELS 13
42
43static Bool
44miBuildRenderColormap(ColormapPtr pColormap, Pixel * pixels, int *nump)
45{
46 int r, g, b;
47 unsigned short red, green, blue;
48 Pixel pixel;
49 Bool used[MI_MAX_INDEXED];
50 int needed;
51 int policy;
52 int cube, gray;
53 int i, n;
54
55 if (pColormap->mid != pColormap->pScreen->defColormap) {
56 policy = PictureCmapPolicyAll;
57 }
58 else {
59 int avail = pColormap->pVisual->ColormapEntries;
60
61 policy = PictureCmapPolicy;
62 if (policy == PictureCmapPolicyDefault) {
63 if (avail >= 256 &&
64 (pColormap->pVisual->class | DynamicClass) == PseudoColor)
65 policy = PictureCmapPolicyColor;
66 else if (avail >= 64)
67 policy = PictureCmapPolicyGray;
68 else
69 policy = PictureCmapPolicyMono;
70 }
71 }
72 /*
73 * Make sure enough cells are free for the chosen policy
74 */
75 for (;;) {
76 switch (policy) {
77 case PictureCmapPolicyAll:
78 needed = 0;
79 break;
80 case PictureCmapPolicyColor:
81 needed = 71;
82 break;
83 case PictureCmapPolicyGray:
84 needed = 11;
85 break;
86 case PictureCmapPolicyMono:
87 default:
88 needed = 0;
89 break;
90 }
91 if (needed <= pColormap->freeRed)
92 break;
93 policy--;
94 }
95
96 /*
97 * Compute size of cube and gray ramps
98 */
99 cube = gray = 0;
100 switch (policy) {
101 case PictureCmapPolicyAll:
102 /*
103 * Allocate as big a cube as possible
104 */
105 if ((pColormap->pVisual->class | DynamicClass) == PseudoColor) {
106 for (cube = 1;
107 cube * cube * cube < pColormap->pVisual->ColormapEntries;
108 cube++);
109 cube--;
110 if (cube == 1)
111 cube = 0;
112 }
113 else
114 cube = 0;
115 /*
116 * Figure out how many gray levels to use so that they
117 * line up neatly with the cube
118 */
119 if (cube) {
120 needed = pColormap->pVisual->ColormapEntries - (cube * cube * cube);
121 /* levels to fill in with */
122 gray = needed / (cube - 1);
123 /* total levels */
124 gray = (gray + 1) * (cube - 1) + 1;
125 }
126 else
127 gray = pColormap->pVisual->ColormapEntries;
128 break;
129
130 case PictureCmapPolicyColor:
131 cube = NUM_CUBE_LEVELS;
132 /* fall through ... */
133 case PictureCmapPolicyGray:
134 gray = NUM_GRAY_LEVELS;
135 break;
136 case PictureCmapPolicyMono:
137 default:
138 gray = 2;
139 break;
140 }
141
142 memset(used, '\0', pColormap->pVisual->ColormapEntries * sizeof(Bool));
143 for (r = 0; r < cube; r++)
144 for (g = 0; g < cube; g++)
145 for (b = 0; b < cube; b++) {
146 pixel = 0;
147 red = (r * 65535 + (cube - 1) / 2) / (cube - 1);
148 green = (g * 65535 + (cube - 1) / 2) / (cube - 1);
149 blue = (b * 65535 + (cube - 1) / 2) / (cube - 1);
150 if (AllocColor(pColormap, &red, &green,
151 &blue, &pixel, 0) != Success)
152 return FALSE;
153 used[pixel] = TRUE;
154 }
155 for (g = 0; g < gray; g++) {
156 pixel = 0;
157 red = green = blue = (g * 65535 + (gray - 1) / 2) / (gray - 1);
158 if (AllocColor(pColormap, &red, &green, &blue, &pixel, 0) != Success)
159 return FALSE;
160 used[pixel] = TRUE;
161 }
162 n = 0;
163 for (i = 0; i < pColormap->pVisual->ColormapEntries; i++)
164 if (used[i])
165 pixels[n++] = i;
166
167 *nump = n;
168
169 return TRUE;
170}
171
172/* 0 <= red, green, blue < 32 */
173static Pixel
174FindBestColor(miIndexedPtr pIndexed, Pixel * pixels, int num,
175 int red, int green, int blue)
176{
177 Pixel best = pixels[0];
178 int bestDist = 1 << 30;
179 int dist;
180 int dr, dg, db;
181
182 while (num--) {
183 Pixel pixel = *pixels++;
184 CARD32 v = pIndexed->rgba[pixel];
185
186 dr = ((v >> 19) & 0x1f);
187 dg = ((v >> 11) & 0x1f);
188 db = ((v >> 3) & 0x1f);
189 dr = dr - red;
190 dg = dg - green;
191 db = db - blue;
192 dist = dr * dr + dg * dg + db * db;
193 if (dist < bestDist) {
194 bestDist = dist;
195 best = pixel;
196 }
197 }
198 return best;
199}
200
201/* 0 <= gray < 32768 */
202static Pixel
203FindBestGray(miIndexedPtr pIndexed, Pixel * pixels, int num, int gray)
204{
205 Pixel best = pixels[0];
206 int bestDist = 1 << 30;
207 int dist;
208 int dr;
209 int r;
210
211 while (num--) {
212 Pixel pixel = *pixels++;
213 CARD32 v = pIndexed->rgba[pixel];
214
215 r = v & 0xff;
216 r = r | (r << 8);
217 dr = gray - (r >> 1);
218 dist = dr * dr;
219 if (dist < bestDist) {
220 bestDist = dist;
221 best = pixel;
222 }
223 }
224 return best;
225}
226
227Bool
228miInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
229{
230 ColormapPtr pColormap = pFormat->index.pColormap;
231 VisualPtr pVisual = pColormap->pVisual;
232 miIndexedPtr pIndexed;
233 Pixel pixels[MI_MAX_INDEXED];
234 xrgb rgb[MI_MAX_INDEXED];
235 int num;
236 int i;
237 Pixel p, r, g, b;
238
239 if (pVisual->ColormapEntries > MI_MAX_INDEXED)
240 return FALSE;
241
242 if (pVisual->class & DynamicClass) {
243 if (!miBuildRenderColormap(pColormap, pixels, &num))
244 return FALSE;
245 }
246 else {
247 num = pVisual->ColormapEntries;
248 for (p = 0; p < num; p++)
249 pixels[p] = p;
250 }
251
252 pIndexed = malloc(sizeof(miIndexedRec));
253 if (!pIndexed)
254 return FALSE;
255
256 pFormat->index.nvalues = num;
257 pFormat->index.pValues = malloc(num * sizeof(xIndexValue));
258 if (!pFormat->index.pValues) {
259 free(pIndexed);
260 return FALSE;
261 }
262
263 /*
264 * Build mapping from pixel value to ARGB
265 */
266 QueryColors(pColormap, num, pixels, rgb, serverClient);
267 for (i = 0; i < num; i++) {
268 p = pixels[i];
269 pFormat->index.pValues[i].pixel = p;
270 pFormat->index.pValues[i].red = rgb[i].red;
271 pFormat->index.pValues[i].green = rgb[i].green;
272 pFormat->index.pValues[i].blue = rgb[i].blue;
273 pFormat->index.pValues[i].alpha = 0xffff;
274 pIndexed->rgba[p] = (0xff000000 |
275 ((rgb[i].red & 0xff00) << 8) |
276 ((rgb[i].green & 0xff00)) |
277 ((rgb[i].blue & 0xff00) >> 8));
278 }
279
280 /*
281 * Build mapping from RGB to pixel value. This could probably be
282 * done a bit quicker...
283 */
284 switch (pVisual->class | DynamicClass) {
285 case GrayScale:
286 pIndexed->color = FALSE;
287 for (r = 0; r < 32768; r++)
288 pIndexed->ent[r] = FindBestGray(pIndexed, pixels, num, r);
289 break;
290 case PseudoColor:
291 pIndexed->color = TRUE;
292 p = 0;
293 for (r = 0; r < 32; r++)
294 for (g = 0; g < 32; g++)
295 for (b = 0; b < 32; b++) {
296 pIndexed->ent[p] = FindBestColor(pIndexed, pixels, num,
297 r, g, b);
298 p++;
299 }
300 break;
301 }
302 pFormat->index.devPrivate = pIndexed;
303 return TRUE;
304}
305
306void
307miCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat)
308{
309 free(pFormat->index.devPrivate);
310 pFormat->index.devPrivate = NULL;
311 free(pFormat->index.pValues);
312 pFormat->index.pValues = NULL;
313}
314
315void
316miUpdateIndexed(ScreenPtr pScreen,
317 PictFormatPtr pFormat, int ndef, xColorItem * pdef)
318{
319 miIndexedPtr pIndexed = pFormat->index.devPrivate;
320
321 if (pIndexed) {
322 while (ndef--) {
323 pIndexed->rgba[pdef->pixel] = (0xff000000 |
324 ((pdef->red & 0xff00) << 8) |
325 ((pdef->green & 0xff00)) |
326 ((pdef->blue & 0xff00) >> 8));
327 pdef++;
328 }
329 }
330}
331
332#endif /* _MIINDEX_H_ */