1706f2543Smrg/* 2706f2543Smrg * 3706f2543Smrg * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. 4706f2543Smrg * 5706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 7706f2543Smrg * the above copyright notice appear in all copies and that both that 8706f2543Smrg * copyright notice and this permission notice appear in supporting 9706f2543Smrg * documentation, and that the name of Keith Packard not be used in 10706f2543Smrg * advertising or publicity pertaining to distribution of the software without 11706f2543Smrg * specific, written prior permission. Keith Packard makes no 12706f2543Smrg * representations about the suitability of this software for any purpose. It 13706f2543Smrg * is provided "as is" without express or implied warranty. 14706f2543Smrg * 15706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 22706f2543Smrg */ 23706f2543Smrg 24706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 25706f2543Smrg#include <dix-config.h> 26706f2543Smrg#endif 27706f2543Smrg 28706f2543Smrg#ifndef _MIINDEX_H_ 29706f2543Smrg#define _MIINDEX_H_ 30706f2543Smrg 31706f2543Smrg#include "scrnintstr.h" 32706f2543Smrg#include "gcstruct.h" 33706f2543Smrg#include "pixmapstr.h" 34706f2543Smrg#include "windowstr.h" 35706f2543Smrg#include "mi.h" 36706f2543Smrg#include "picturestr.h" 37706f2543Smrg#include "mipict.h" 38706f2543Smrg#include "colormapst.h" 39706f2543Smrg 40706f2543Smrg#define NUM_CUBE_LEVELS 4 41706f2543Smrg#define NUM_GRAY_LEVELS 13 42706f2543Smrg 43706f2543Smrgstatic Bool 44706f2543SmrgmiBuildRenderColormap (ColormapPtr pColormap, Pixel *pixels, int *nump) 45706f2543Smrg{ 46706f2543Smrg int r, g, b; 47706f2543Smrg unsigned short red, green, blue; 48706f2543Smrg Pixel pixel; 49706f2543Smrg Bool used[MI_MAX_INDEXED]; 50706f2543Smrg int needed; 51706f2543Smrg int policy; 52706f2543Smrg int cube, gray; 53706f2543Smrg int i, n; 54706f2543Smrg 55706f2543Smrg if (pColormap->mid != pColormap->pScreen->defColormap) 56706f2543Smrg { 57706f2543Smrg policy = PictureCmapPolicyAll; 58706f2543Smrg } 59706f2543Smrg else 60706f2543Smrg { 61706f2543Smrg int avail = pColormap->pVisual->ColormapEntries; 62706f2543Smrg policy = PictureCmapPolicy; 63706f2543Smrg if (policy == PictureCmapPolicyDefault) 64706f2543Smrg { 65706f2543Smrg if (avail >= 256 && (pColormap->pVisual->class|DynamicClass) == PseudoColor) 66706f2543Smrg policy = PictureCmapPolicyColor; 67706f2543Smrg else if (avail >= 64) 68706f2543Smrg policy = PictureCmapPolicyGray; 69706f2543Smrg else 70706f2543Smrg policy = PictureCmapPolicyMono; 71706f2543Smrg } 72706f2543Smrg } 73706f2543Smrg /* 74706f2543Smrg * Make sure enough cells are free for the chosen policy 75706f2543Smrg */ 76706f2543Smrg for (;;) 77706f2543Smrg { 78706f2543Smrg switch (policy) { 79706f2543Smrg case PictureCmapPolicyAll: 80706f2543Smrg needed = 0; 81706f2543Smrg break; 82706f2543Smrg case PictureCmapPolicyColor: 83706f2543Smrg needed = 71; 84706f2543Smrg break; 85706f2543Smrg case PictureCmapPolicyGray: 86706f2543Smrg needed = 11; 87706f2543Smrg break; 88706f2543Smrg case PictureCmapPolicyMono: 89706f2543Smrg default: 90706f2543Smrg needed = 0; 91706f2543Smrg break; 92706f2543Smrg } 93706f2543Smrg if (needed <= pColormap->freeRed) 94706f2543Smrg break; 95706f2543Smrg policy--; 96706f2543Smrg } 97706f2543Smrg 98706f2543Smrg /* 99706f2543Smrg * Compute size of cube and gray ramps 100706f2543Smrg */ 101706f2543Smrg cube = gray = 0; 102706f2543Smrg switch (policy) { 103706f2543Smrg case PictureCmapPolicyAll: 104706f2543Smrg /* 105706f2543Smrg * Allocate as big a cube as possible 106706f2543Smrg */ 107706f2543Smrg if ((pColormap->pVisual->class|DynamicClass) == PseudoColor) 108706f2543Smrg { 109706f2543Smrg for (cube = 1; cube * cube * cube < pColormap->pVisual->ColormapEntries; cube++) 110706f2543Smrg ; 111706f2543Smrg cube--; 112706f2543Smrg if (cube == 1) 113706f2543Smrg cube = 0; 114706f2543Smrg } 115706f2543Smrg else 116706f2543Smrg cube = 0; 117706f2543Smrg /* 118706f2543Smrg * Figure out how many gray levels to use so that they 119706f2543Smrg * line up neatly with the cube 120706f2543Smrg */ 121706f2543Smrg if (cube) 122706f2543Smrg { 123706f2543Smrg needed = pColormap->pVisual->ColormapEntries - (cube*cube*cube); 124706f2543Smrg /* levels to fill in with */ 125706f2543Smrg gray = needed / (cube - 1); 126706f2543Smrg /* total levels */ 127706f2543Smrg gray = (gray + 1) * (cube - 1) + 1; 128706f2543Smrg } 129706f2543Smrg else 130706f2543Smrg gray = pColormap->pVisual->ColormapEntries; 131706f2543Smrg break; 132706f2543Smrg 133706f2543Smrg case PictureCmapPolicyColor: 134706f2543Smrg cube = NUM_CUBE_LEVELS; 135706f2543Smrg /* fall through ... */ 136706f2543Smrg case PictureCmapPolicyGray: 137706f2543Smrg gray = NUM_GRAY_LEVELS; 138706f2543Smrg break; 139706f2543Smrg case PictureCmapPolicyMono: 140706f2543Smrg default: 141706f2543Smrg gray = 2; 142706f2543Smrg break; 143706f2543Smrg } 144706f2543Smrg 145706f2543Smrg memset (used, '\0', pColormap->pVisual->ColormapEntries * sizeof (Bool)); 146706f2543Smrg for (r = 0; r < cube; r++) 147706f2543Smrg for (g = 0; g < cube; g++) 148706f2543Smrg for (b = 0; b < cube; b++) 149706f2543Smrg { 150706f2543Smrg pixel = 0; 151706f2543Smrg red = (r * 65535 + (cube-1)/2) / (cube - 1); 152706f2543Smrg green = (g * 65535 + (cube-1)/2) / (cube - 1); 153706f2543Smrg blue = (b * 65535 + (cube-1)/2) / (cube - 1); 154706f2543Smrg if (AllocColor (pColormap, &red, &green, 155706f2543Smrg &blue, &pixel, 0) != Success) 156706f2543Smrg return FALSE; 157706f2543Smrg used[pixel] = TRUE; 158706f2543Smrg } 159706f2543Smrg for (g = 0; g < gray; g++) 160706f2543Smrg { 161706f2543Smrg pixel = 0; 162706f2543Smrg red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); 163706f2543Smrg if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) 164706f2543Smrg return FALSE; 165706f2543Smrg used[pixel] = TRUE; 166706f2543Smrg } 167706f2543Smrg n = 0; 168706f2543Smrg for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) 169706f2543Smrg if (used[i]) 170706f2543Smrg pixels[n++] = i; 171706f2543Smrg 172706f2543Smrg *nump = n; 173706f2543Smrg 174706f2543Smrg return TRUE; 175706f2543Smrg} 176706f2543Smrg 177706f2543Smrg/* 0 <= red, green, blue < 32 */ 178706f2543Smrgstatic Pixel 179706f2543SmrgFindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, 180706f2543Smrg int red, int green, int blue) 181706f2543Smrg{ 182706f2543Smrg Pixel best = pixels[0]; 183706f2543Smrg int bestDist = 1 << 30; 184706f2543Smrg int dist; 185706f2543Smrg int dr, dg, db; 186706f2543Smrg while (num--) 187706f2543Smrg { 188706f2543Smrg Pixel pixel = *pixels++; 189706f2543Smrg CARD32 v = pIndexed->rgba[pixel]; 190706f2543Smrg 191706f2543Smrg dr = ((v >> 19) & 0x1f); 192706f2543Smrg dg = ((v >> 11) & 0x1f); 193706f2543Smrg db = ((v >> 3) & 0x1f); 194706f2543Smrg dr = dr - red; 195706f2543Smrg dg = dg - green; 196706f2543Smrg db = db - blue; 197706f2543Smrg dist = dr * dr + dg * dg + db * db; 198706f2543Smrg if (dist < bestDist) 199706f2543Smrg { 200706f2543Smrg bestDist = dist; 201706f2543Smrg best = pixel; 202706f2543Smrg } 203706f2543Smrg } 204706f2543Smrg return best; 205706f2543Smrg} 206706f2543Smrg 207706f2543Smrg/* 0 <= gray < 32768 */ 208706f2543Smrgstatic Pixel 209706f2543SmrgFindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) 210706f2543Smrg{ 211706f2543Smrg Pixel best = pixels[0]; 212706f2543Smrg int bestDist = 1 << 30; 213706f2543Smrg int dist; 214706f2543Smrg int dr; 215706f2543Smrg int r; 216706f2543Smrg 217706f2543Smrg while (num--) 218706f2543Smrg { 219706f2543Smrg Pixel pixel = *pixels++; 220706f2543Smrg CARD32 v = pIndexed->rgba[pixel]; 221706f2543Smrg 222706f2543Smrg r = v & 0xff; 223706f2543Smrg r = r | (r << 8); 224706f2543Smrg dr = gray - (r >> 1); 225706f2543Smrg dist = dr * dr; 226706f2543Smrg if (dist < bestDist) 227706f2543Smrg { 228706f2543Smrg bestDist = dist; 229706f2543Smrg best = pixel; 230706f2543Smrg } 231706f2543Smrg } 232706f2543Smrg return best; 233706f2543Smrg} 234706f2543Smrg 235706f2543SmrgBool 236706f2543SmrgmiInitIndexed (ScreenPtr pScreen, 237706f2543Smrg PictFormatPtr pFormat) 238706f2543Smrg{ 239706f2543Smrg ColormapPtr pColormap = pFormat->index.pColormap; 240706f2543Smrg VisualPtr pVisual = pColormap->pVisual; 241706f2543Smrg miIndexedPtr pIndexed; 242706f2543Smrg Pixel pixels[MI_MAX_INDEXED]; 243706f2543Smrg xrgb rgb[MI_MAX_INDEXED]; 244706f2543Smrg int num; 245706f2543Smrg int i; 246706f2543Smrg Pixel p, r, g, b; 247706f2543Smrg 248706f2543Smrg if (pVisual->ColormapEntries > MI_MAX_INDEXED) 249706f2543Smrg return FALSE; 250706f2543Smrg 251706f2543Smrg if (pVisual->class & DynamicClass) 252706f2543Smrg { 253706f2543Smrg if (!miBuildRenderColormap (pColormap, pixels, &num)) 254706f2543Smrg return FALSE; 255706f2543Smrg } 256706f2543Smrg else 257706f2543Smrg { 258706f2543Smrg num = pVisual->ColormapEntries; 259706f2543Smrg for (p = 0; p < num; p++) 260706f2543Smrg pixels[p] = p; 261706f2543Smrg } 262706f2543Smrg 263706f2543Smrg pIndexed = malloc(sizeof (miIndexedRec)); 264706f2543Smrg if (!pIndexed) 265706f2543Smrg return FALSE; 266706f2543Smrg 267706f2543Smrg pFormat->index.nvalues = num; 268706f2543Smrg pFormat->index.pValues = malloc(num * sizeof (xIndexValue)); 269706f2543Smrg if (!pFormat->index.pValues) 270706f2543Smrg { 271706f2543Smrg free(pIndexed); 272706f2543Smrg return FALSE; 273706f2543Smrg } 274706f2543Smrg 275706f2543Smrg 276706f2543Smrg /* 277706f2543Smrg * Build mapping from pixel value to ARGB 278706f2543Smrg */ 279706f2543Smrg QueryColors (pColormap, num, pixels, rgb, serverClient); 280706f2543Smrg for (i = 0; i < num; i++) 281706f2543Smrg { 282706f2543Smrg p = pixels[i]; 283706f2543Smrg pFormat->index.pValues[i].pixel = p; 284706f2543Smrg pFormat->index.pValues[i].red = rgb[i].red; 285706f2543Smrg pFormat->index.pValues[i].green = rgb[i].green; 286706f2543Smrg pFormat->index.pValues[i].blue = rgb[i].blue; 287706f2543Smrg pFormat->index.pValues[i].alpha = 0xffff; 288706f2543Smrg pIndexed->rgba[p] = (0xff000000 | 289706f2543Smrg ((rgb[i].red & 0xff00) << 8) | 290706f2543Smrg ((rgb[i].green & 0xff00) ) | 291706f2543Smrg ((rgb[i].blue & 0xff00) >> 8)); 292706f2543Smrg } 293706f2543Smrg 294706f2543Smrg /* 295706f2543Smrg * Build mapping from RGB to pixel value. This could probably be 296706f2543Smrg * done a bit quicker... 297706f2543Smrg */ 298706f2543Smrg switch (pVisual->class | DynamicClass) { 299706f2543Smrg case GrayScale: 300706f2543Smrg pIndexed->color = FALSE; 301706f2543Smrg for (r = 0; r < 32768; r++) 302706f2543Smrg pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); 303706f2543Smrg break; 304706f2543Smrg case PseudoColor: 305706f2543Smrg pIndexed->color = TRUE; 306706f2543Smrg p = 0; 307706f2543Smrg for (r = 0; r < 32; r++) 308706f2543Smrg for (g = 0; g < 32; g++) 309706f2543Smrg for (b = 0; b < 32; b++) 310706f2543Smrg { 311706f2543Smrg pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, 312706f2543Smrg r, g, b); 313706f2543Smrg p++; 314706f2543Smrg } 315706f2543Smrg break; 316706f2543Smrg } 317706f2543Smrg pFormat->index.devPrivate = pIndexed; 318706f2543Smrg return TRUE; 319706f2543Smrg} 320706f2543Smrg 321706f2543Smrgvoid 322706f2543SmrgmiCloseIndexed (ScreenPtr pScreen, 323706f2543Smrg PictFormatPtr pFormat) 324706f2543Smrg{ 325706f2543Smrg free(pFormat->index.devPrivate); 326706f2543Smrg pFormat->index.devPrivate = NULL; 327706f2543Smrg free(pFormat->index.pValues); 328706f2543Smrg pFormat->index.pValues = NULL; 329706f2543Smrg} 330706f2543Smrg 331706f2543Smrgvoid 332706f2543SmrgmiUpdateIndexed (ScreenPtr pScreen, 333706f2543Smrg PictFormatPtr pFormat, 334706f2543Smrg int ndef, 335706f2543Smrg xColorItem *pdef) 336706f2543Smrg{ 337706f2543Smrg miIndexedPtr pIndexed = pFormat->index.devPrivate; 338706f2543Smrg 339706f2543Smrg if (pIndexed) 340706f2543Smrg { 341706f2543Smrg while (ndef--) 342706f2543Smrg { 343706f2543Smrg pIndexed->rgba[pdef->pixel] = (0xff000000 | 344706f2543Smrg ((pdef->red & 0xff00) << 8) | 345706f2543Smrg ((pdef->green & 0xff00) ) | 346706f2543Smrg ((pdef->blue & 0xff00) >> 8)); 347706f2543Smrg pdef++; 348706f2543Smrg } 349706f2543Smrg } 350706f2543Smrg} 351706f2543Smrg 352706f2543Smrg#endif /* _MIINDEX_H_ */ 353