miindex.c revision 05b261ec
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 { 57 policy = PictureCmapPolicyAll; 58 } 59 else 60 { 61 int avail = pColormap->pVisual->ColormapEntries; 62 policy = PictureCmapPolicy; 63 if (policy == PictureCmapPolicyDefault) 64 { 65 if (avail >= 256 && (pColormap->pVisual->class|DynamicClass) == PseudoColor) 66 policy = PictureCmapPolicyColor; 67 else if (avail >= 64) 68 policy = PictureCmapPolicyGray; 69 else 70 policy = PictureCmapPolicyMono; 71 } 72 } 73 /* 74 * Make sure enough cells are free for the chosen policy 75 */ 76 for (;;) 77 { 78 switch (policy) { 79 case PictureCmapPolicyAll: 80 needed = 0; 81 break; 82 case PictureCmapPolicyColor: 83 needed = 71; 84 break; 85 case PictureCmapPolicyGray: 86 needed = 11; 87 break; 88 case PictureCmapPolicyMono: 89 default: 90 needed = 0; 91 break; 92 } 93 if (needed <= pColormap->freeRed) 94 break; 95 policy--; 96 } 97 98 /* 99 * Compute size of cube and gray ramps 100 */ 101 cube = gray = 0; 102 switch (policy) { 103 case PictureCmapPolicyAll: 104 /* 105 * Allocate as big a cube as possible 106 */ 107 if ((pColormap->pVisual->class|DynamicClass) == PseudoColor) 108 { 109 for (cube = 1; cube * cube * cube < pColormap->pVisual->ColormapEntries; cube++) 110 ; 111 cube--; 112 if (cube == 1) 113 cube = 0; 114 } 115 else 116 cube = 0; 117 /* 118 * Figure out how many gray levels to use so that they 119 * line up neatly with the cube 120 */ 121 if (cube) 122 { 123 needed = pColormap->pVisual->ColormapEntries - (cube*cube*cube); 124 /* levels to fill in with */ 125 gray = needed / (cube - 1); 126 /* total levels */ 127 gray = (gray + 1) * (cube - 1) + 1; 128 } 129 else 130 gray = pColormap->pVisual->ColormapEntries; 131 break; 132 133 case PictureCmapPolicyColor: 134 cube = NUM_CUBE_LEVELS; 135 /* fall through ... */ 136 case PictureCmapPolicyGray: 137 gray = NUM_GRAY_LEVELS; 138 break; 139 case PictureCmapPolicyMono: 140 default: 141 gray = 2; 142 break; 143 } 144 145 memset (used, '\0', pColormap->pVisual->ColormapEntries * sizeof (Bool)); 146 for (r = 0; r < cube; r++) 147 for (g = 0; g < cube; g++) 148 for (b = 0; b < cube; b++) 149 { 150 red = (r * 65535 + (cube-1)/2) / (cube - 1); 151 green = (g * 65535 + (cube-1)/2) / (cube - 1); 152 blue = (b * 65535 + (cube-1)/2) / (cube - 1); 153 if (AllocColor (pColormap, &red, &green, 154 &blue, &pixel, 0) != Success) 155 return FALSE; 156 used[pixel] = TRUE; 157 } 158 for (g = 0; g < gray; g++) 159 { 160 red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); 161 if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) 162 return FALSE; 163 used[pixel] = TRUE; 164 } 165 n = 0; 166 for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) 167 if (used[i]) 168 pixels[n++] = i; 169 170 *nump = n; 171 172 return TRUE; 173} 174 175/* 0 <= red, green, blue < 32 */ 176static Pixel 177FindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, 178 int red, int green, int blue) 179{ 180 Pixel best = pixels[0]; 181 int bestDist = 1 << 30; 182 int dist; 183 int dr, dg, db; 184 while (num--) 185 { 186 Pixel pixel = *pixels++; 187 CARD32 v = pIndexed->rgba[pixel]; 188 189 dr = ((v >> 19) & 0x1f); 190 dg = ((v >> 11) & 0x1f); 191 db = ((v >> 3) & 0x1f); 192 dr = dr - red; 193 dg = dg - green; 194 db = db - blue; 195 dist = dr * dr + dg * dg + db * db; 196 if (dist < bestDist) 197 { 198 bestDist = dist; 199 best = pixel; 200 } 201 } 202 return best; 203} 204 205/* 0 <= gray < 32768 */ 206static Pixel 207FindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) 208{ 209 Pixel best = pixels[0]; 210 int bestDist = 1 << 30; 211 int dist; 212 int dr; 213 int r; 214 215 while (num--) 216 { 217 Pixel pixel = *pixels++; 218 CARD32 v = pIndexed->rgba[pixel]; 219 220 r = v & 0xff; 221 r = r | (r << 8); 222 dr = gray - (r >> 1); 223 dist = dr * dr; 224 if (dist < bestDist) 225 { 226 bestDist = dist; 227 best = pixel; 228 } 229 } 230 return best; 231} 232 233Bool 234miInitIndexed (ScreenPtr pScreen, 235 PictFormatPtr pFormat) 236{ 237 ColormapPtr pColormap = pFormat->index.pColormap; 238 VisualPtr pVisual = pColormap->pVisual; 239 miIndexedPtr pIndexed; 240 Pixel pixels[MI_MAX_INDEXED]; 241 xrgb rgb[MI_MAX_INDEXED]; 242 int num; 243 int i; 244 Pixel p, r, g, b; 245 246 if (pVisual->ColormapEntries > MI_MAX_INDEXED) 247 return FALSE; 248 249 if (pVisual->class & DynamicClass) 250 { 251 if (!miBuildRenderColormap (pColormap, pixels, &num)) 252 return FALSE; 253 } 254 else 255 { 256 num = pVisual->ColormapEntries; 257 for (p = 0; p < num; p++) 258 pixels[p] = p; 259 } 260 261 pIndexed = xalloc (sizeof (miIndexedRec)); 262 if (!pIndexed) 263 return FALSE; 264 265 pFormat->index.nvalues = num; 266 pFormat->index.pValues = xalloc (num * sizeof (xIndexValue)); 267 if (!pFormat->index.pValues) 268 { 269 xfree (pIndexed); 270 return FALSE; 271 } 272 273 274 /* 275 * Build mapping from pixel value to ARGB 276 */ 277 QueryColors (pColormap, num, pixels, rgb); 278 for (i = 0; i < num; i++) 279 { 280 p = pixels[i]; 281 pFormat->index.pValues[i].pixel = p; 282 pFormat->index.pValues[i].red = rgb[i].red; 283 pFormat->index.pValues[i].green = rgb[i].green; 284 pFormat->index.pValues[i].blue = rgb[i].blue; 285 pFormat->index.pValues[i].alpha = 0xffff; 286 pIndexed->rgba[p] = (0xff000000 | 287 ((rgb[i].red & 0xff00) << 8) | 288 ((rgb[i].green & 0xff00) ) | 289 ((rgb[i].blue & 0xff00) >> 8)); 290 } 291 292 /* 293 * Build mapping from RGB to pixel value. This could probably be 294 * done a bit quicker... 295 */ 296 switch (pVisual->class | DynamicClass) { 297 case GrayScale: 298 pIndexed->color = FALSE; 299 for (r = 0; r < 32768; r++) 300 pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); 301 break; 302 case PseudoColor: 303 pIndexed->color = TRUE; 304 p = 0; 305 for (r = 0; r < 32; r++) 306 for (g = 0; g < 32; g++) 307 for (b = 0; b < 32; b++) 308 { 309 pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, 310 r, g, b); 311 p++; 312 } 313 break; 314 } 315 pFormat->index.devPrivate = pIndexed; 316 return TRUE; 317} 318 319void 320miCloseIndexed (ScreenPtr pScreen, 321 PictFormatPtr pFormat) 322{ 323 if (pFormat->index.devPrivate) 324 { 325 xfree (pFormat->index.devPrivate); 326 pFormat->index.devPrivate = 0; 327 } 328 if (pFormat->index.pValues) 329 { 330 xfree (pFormat->index.pValues); 331 pFormat->index.pValues = 0; 332 } 333} 334 335void 336miUpdateIndexed (ScreenPtr pScreen, 337 PictFormatPtr pFormat, 338 int ndef, 339 xColorItem *pdef) 340{ 341 miIndexedPtr pIndexed = pFormat->index.devPrivate; 342 343 if (pIndexed) 344 { 345 while (ndef--) 346 { 347 pIndexed->rgba[pdef->pixel] = (0xff000000 | 348 ((pdef->red & 0xff00) << 8) | 349 ((pdef->green & 0xff00) ) | 350 ((pdef->blue & 0xff00) >> 8)); 351 pdef++; 352 } 353 } 354} 355 356#endif /* _MIINDEX_H_ */ 357