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 pixel = 0; 151 red = (r * 65535 + (cube-1)/2) / (cube - 1); 152 green = (g * 65535 + (cube-1)/2) / (cube - 1); 153 blue = (b * 65535 + (cube-1)/2) / (cube - 1); 154 if (AllocColor (pColormap, &red, &green, 155 &blue, &pixel, 0) != Success) 156 return FALSE; 157 used[pixel] = TRUE; 158 } 159 for (g = 0; g < gray; g++) 160 { 161 pixel = 0; 162 red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); 163 if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) 164 return FALSE; 165 used[pixel] = TRUE; 166 } 167 n = 0; 168 for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) 169 if (used[i]) 170 pixels[n++] = i; 171 172 *nump = n; 173 174 return TRUE; 175} 176 177/* 0 <= red, green, blue < 32 */ 178static Pixel 179FindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, 180 int red, int green, int blue) 181{ 182 Pixel best = pixels[0]; 183 int bestDist = 1 << 30; 184 int dist; 185 int dr, dg, db; 186 while (num--) 187 { 188 Pixel pixel = *pixels++; 189 CARD32 v = pIndexed->rgba[pixel]; 190 191 dr = ((v >> 19) & 0x1f); 192 dg = ((v >> 11) & 0x1f); 193 db = ((v >> 3) & 0x1f); 194 dr = dr - red; 195 dg = dg - green; 196 db = db - blue; 197 dist = dr * dr + dg * dg + db * db; 198 if (dist < bestDist) 199 { 200 bestDist = dist; 201 best = pixel; 202 } 203 } 204 return best; 205} 206 207/* 0 <= gray < 32768 */ 208static Pixel 209FindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) 210{ 211 Pixel best = pixels[0]; 212 int bestDist = 1 << 30; 213 int dist; 214 int dr; 215 int r; 216 217 while (num--) 218 { 219 Pixel pixel = *pixels++; 220 CARD32 v = pIndexed->rgba[pixel]; 221 222 r = v & 0xff; 223 r = r | (r << 8); 224 dr = gray - (r >> 1); 225 dist = dr * dr; 226 if (dist < bestDist) 227 { 228 bestDist = dist; 229 best = pixel; 230 } 231 } 232 return best; 233} 234 235Bool 236miInitIndexed (ScreenPtr pScreen, 237 PictFormatPtr pFormat) 238{ 239 ColormapPtr pColormap = pFormat->index.pColormap; 240 VisualPtr pVisual = pColormap->pVisual; 241 miIndexedPtr pIndexed; 242 Pixel pixels[MI_MAX_INDEXED]; 243 xrgb rgb[MI_MAX_INDEXED]; 244 int num; 245 int i; 246 Pixel p, r, g, b; 247 248 if (pVisual->ColormapEntries > MI_MAX_INDEXED) 249 return FALSE; 250 251 if (pVisual->class & DynamicClass) 252 { 253 if (!miBuildRenderColormap (pColormap, pixels, &num)) 254 return FALSE; 255 } 256 else 257 { 258 num = pVisual->ColormapEntries; 259 for (p = 0; p < num; p++) 260 pixels[p] = p; 261 } 262 263 pIndexed = malloc(sizeof (miIndexedRec)); 264 if (!pIndexed) 265 return FALSE; 266 267 pFormat->index.nvalues = num; 268 pFormat->index.pValues = malloc(num * sizeof (xIndexValue)); 269 if (!pFormat->index.pValues) 270 { 271 free(pIndexed); 272 return FALSE; 273 } 274 275 276 /* 277 * Build mapping from pixel value to ARGB 278 */ 279 QueryColors (pColormap, num, pixels, rgb, serverClient); 280 for (i = 0; i < num; i++) 281 { 282 p = pixels[i]; 283 pFormat->index.pValues[i].pixel = p; 284 pFormat->index.pValues[i].red = rgb[i].red; 285 pFormat->index.pValues[i].green = rgb[i].green; 286 pFormat->index.pValues[i].blue = rgb[i].blue; 287 pFormat->index.pValues[i].alpha = 0xffff; 288 pIndexed->rgba[p] = (0xff000000 | 289 ((rgb[i].red & 0xff00) << 8) | 290 ((rgb[i].green & 0xff00) ) | 291 ((rgb[i].blue & 0xff00) >> 8)); 292 } 293 294 /* 295 * Build mapping from RGB to pixel value. This could probably be 296 * done a bit quicker... 297 */ 298 switch (pVisual->class | DynamicClass) { 299 case GrayScale: 300 pIndexed->color = FALSE; 301 for (r = 0; r < 32768; r++) 302 pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); 303 break; 304 case PseudoColor: 305 pIndexed->color = TRUE; 306 p = 0; 307 for (r = 0; r < 32; r++) 308 for (g = 0; g < 32; g++) 309 for (b = 0; b < 32; b++) 310 { 311 pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, 312 r, g, b); 313 p++; 314 } 315 break; 316 } 317 pFormat->index.devPrivate = pIndexed; 318 return TRUE; 319} 320 321void 322miCloseIndexed (ScreenPtr pScreen, 323 PictFormatPtr pFormat) 324{ 325 free(pFormat->index.devPrivate); 326 pFormat->index.devPrivate = NULL; 327 free(pFormat->index.pValues); 328 pFormat->index.pValues = NULL; 329} 330 331void 332miUpdateIndexed (ScreenPtr pScreen, 333 PictFormatPtr pFormat, 334 int ndef, 335 xColorItem *pdef) 336{ 337 miIndexedPtr pIndexed = pFormat->index.devPrivate; 338 339 if (pIndexed) 340 { 341 while (ndef--) 342 { 343 pIndexed->rgba[pdef->pixel] = (0xff000000 | 344 ((pdef->red & 0xff00) << 8) | 345 ((pdef->green & 0xff00) ) | 346 ((pdef->blue & 0xff00) >> 8)); 347 pdef++; 348 } 349 } 350} 351 352#endif /* _MIINDEX_H_ */ 353