miindex.c revision 05b261ec
105b261ecSmrg/* 205b261ecSmrg * 305b261ecSmrg * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that 805b261ecSmrg * copyright notice and this permission notice appear in supporting 905b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1105b261ecSmrg * specific, written prior permission. Keith Packard makes no 1205b261ecSmrg * representations about the suitability of this software for any purpose. It 1305b261ecSmrg * is provided "as is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 2505b261ecSmrg#include <dix-config.h> 2605b261ecSmrg#endif 2705b261ecSmrg 2805b261ecSmrg#ifndef _MIINDEX_H_ 2905b261ecSmrg#define _MIINDEX_H_ 3005b261ecSmrg 3105b261ecSmrg#include "scrnintstr.h" 3205b261ecSmrg#include "gcstruct.h" 3305b261ecSmrg#include "pixmapstr.h" 3405b261ecSmrg#include "windowstr.h" 3505b261ecSmrg#include "mi.h" 3605b261ecSmrg#include "picturestr.h" 3705b261ecSmrg#include "mipict.h" 3805b261ecSmrg#include "colormapst.h" 3905b261ecSmrg 4005b261ecSmrg#define NUM_CUBE_LEVELS 4 4105b261ecSmrg#define NUM_GRAY_LEVELS 13 4205b261ecSmrg 4305b261ecSmrgstatic Bool 4405b261ecSmrgmiBuildRenderColormap (ColormapPtr pColormap, Pixel *pixels, int *nump) 4505b261ecSmrg{ 4605b261ecSmrg int r, g, b; 4705b261ecSmrg unsigned short red, green, blue; 4805b261ecSmrg Pixel pixel; 4905b261ecSmrg Bool used[MI_MAX_INDEXED]; 5005b261ecSmrg int needed; 5105b261ecSmrg int policy; 5205b261ecSmrg int cube, gray; 5305b261ecSmrg int i, n; 5405b261ecSmrg 5505b261ecSmrg if (pColormap->mid != pColormap->pScreen->defColormap) 5605b261ecSmrg { 5705b261ecSmrg policy = PictureCmapPolicyAll; 5805b261ecSmrg } 5905b261ecSmrg else 6005b261ecSmrg { 6105b261ecSmrg int avail = pColormap->pVisual->ColormapEntries; 6205b261ecSmrg policy = PictureCmapPolicy; 6305b261ecSmrg if (policy == PictureCmapPolicyDefault) 6405b261ecSmrg { 6505b261ecSmrg if (avail >= 256 && (pColormap->pVisual->class|DynamicClass) == PseudoColor) 6605b261ecSmrg policy = PictureCmapPolicyColor; 6705b261ecSmrg else if (avail >= 64) 6805b261ecSmrg policy = PictureCmapPolicyGray; 6905b261ecSmrg else 7005b261ecSmrg policy = PictureCmapPolicyMono; 7105b261ecSmrg } 7205b261ecSmrg } 7305b261ecSmrg /* 7405b261ecSmrg * Make sure enough cells are free for the chosen policy 7505b261ecSmrg */ 7605b261ecSmrg for (;;) 7705b261ecSmrg { 7805b261ecSmrg switch (policy) { 7905b261ecSmrg case PictureCmapPolicyAll: 8005b261ecSmrg needed = 0; 8105b261ecSmrg break; 8205b261ecSmrg case PictureCmapPolicyColor: 8305b261ecSmrg needed = 71; 8405b261ecSmrg break; 8505b261ecSmrg case PictureCmapPolicyGray: 8605b261ecSmrg needed = 11; 8705b261ecSmrg break; 8805b261ecSmrg case PictureCmapPolicyMono: 8905b261ecSmrg default: 9005b261ecSmrg needed = 0; 9105b261ecSmrg break; 9205b261ecSmrg } 9305b261ecSmrg if (needed <= pColormap->freeRed) 9405b261ecSmrg break; 9505b261ecSmrg policy--; 9605b261ecSmrg } 9705b261ecSmrg 9805b261ecSmrg /* 9905b261ecSmrg * Compute size of cube and gray ramps 10005b261ecSmrg */ 10105b261ecSmrg cube = gray = 0; 10205b261ecSmrg switch (policy) { 10305b261ecSmrg case PictureCmapPolicyAll: 10405b261ecSmrg /* 10505b261ecSmrg * Allocate as big a cube as possible 10605b261ecSmrg */ 10705b261ecSmrg if ((pColormap->pVisual->class|DynamicClass) == PseudoColor) 10805b261ecSmrg { 10905b261ecSmrg for (cube = 1; cube * cube * cube < pColormap->pVisual->ColormapEntries; cube++) 11005b261ecSmrg ; 11105b261ecSmrg cube--; 11205b261ecSmrg if (cube == 1) 11305b261ecSmrg cube = 0; 11405b261ecSmrg } 11505b261ecSmrg else 11605b261ecSmrg cube = 0; 11705b261ecSmrg /* 11805b261ecSmrg * Figure out how many gray levels to use so that they 11905b261ecSmrg * line up neatly with the cube 12005b261ecSmrg */ 12105b261ecSmrg if (cube) 12205b261ecSmrg { 12305b261ecSmrg needed = pColormap->pVisual->ColormapEntries - (cube*cube*cube); 12405b261ecSmrg /* levels to fill in with */ 12505b261ecSmrg gray = needed / (cube - 1); 12605b261ecSmrg /* total levels */ 12705b261ecSmrg gray = (gray + 1) * (cube - 1) + 1; 12805b261ecSmrg } 12905b261ecSmrg else 13005b261ecSmrg gray = pColormap->pVisual->ColormapEntries; 13105b261ecSmrg break; 13205b261ecSmrg 13305b261ecSmrg case PictureCmapPolicyColor: 13405b261ecSmrg cube = NUM_CUBE_LEVELS; 13505b261ecSmrg /* fall through ... */ 13605b261ecSmrg case PictureCmapPolicyGray: 13705b261ecSmrg gray = NUM_GRAY_LEVELS; 13805b261ecSmrg break; 13905b261ecSmrg case PictureCmapPolicyMono: 14005b261ecSmrg default: 14105b261ecSmrg gray = 2; 14205b261ecSmrg break; 14305b261ecSmrg } 14405b261ecSmrg 14505b261ecSmrg memset (used, '\0', pColormap->pVisual->ColormapEntries * sizeof (Bool)); 14605b261ecSmrg for (r = 0; r < cube; r++) 14705b261ecSmrg for (g = 0; g < cube; g++) 14805b261ecSmrg for (b = 0; b < cube; b++) 14905b261ecSmrg { 15005b261ecSmrg red = (r * 65535 + (cube-1)/2) / (cube - 1); 15105b261ecSmrg green = (g * 65535 + (cube-1)/2) / (cube - 1); 15205b261ecSmrg blue = (b * 65535 + (cube-1)/2) / (cube - 1); 15305b261ecSmrg if (AllocColor (pColormap, &red, &green, 15405b261ecSmrg &blue, &pixel, 0) != Success) 15505b261ecSmrg return FALSE; 15605b261ecSmrg used[pixel] = TRUE; 15705b261ecSmrg } 15805b261ecSmrg for (g = 0; g < gray; g++) 15905b261ecSmrg { 16005b261ecSmrg red = green = blue = (g * 65535 + (gray-1)/2) / (gray - 1); 16105b261ecSmrg if (AllocColor (pColormap, &red, &green, &blue, &pixel, 0) != Success) 16205b261ecSmrg return FALSE; 16305b261ecSmrg used[pixel] = TRUE; 16405b261ecSmrg } 16505b261ecSmrg n = 0; 16605b261ecSmrg for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) 16705b261ecSmrg if (used[i]) 16805b261ecSmrg pixels[n++] = i; 16905b261ecSmrg 17005b261ecSmrg *nump = n; 17105b261ecSmrg 17205b261ecSmrg return TRUE; 17305b261ecSmrg} 17405b261ecSmrg 17505b261ecSmrg/* 0 <= red, green, blue < 32 */ 17605b261ecSmrgstatic Pixel 17705b261ecSmrgFindBestColor (miIndexedPtr pIndexed, Pixel *pixels, int num, 17805b261ecSmrg int red, int green, int blue) 17905b261ecSmrg{ 18005b261ecSmrg Pixel best = pixels[0]; 18105b261ecSmrg int bestDist = 1 << 30; 18205b261ecSmrg int dist; 18305b261ecSmrg int dr, dg, db; 18405b261ecSmrg while (num--) 18505b261ecSmrg { 18605b261ecSmrg Pixel pixel = *pixels++; 18705b261ecSmrg CARD32 v = pIndexed->rgba[pixel]; 18805b261ecSmrg 18905b261ecSmrg dr = ((v >> 19) & 0x1f); 19005b261ecSmrg dg = ((v >> 11) & 0x1f); 19105b261ecSmrg db = ((v >> 3) & 0x1f); 19205b261ecSmrg dr = dr - red; 19305b261ecSmrg dg = dg - green; 19405b261ecSmrg db = db - blue; 19505b261ecSmrg dist = dr * dr + dg * dg + db * db; 19605b261ecSmrg if (dist < bestDist) 19705b261ecSmrg { 19805b261ecSmrg bestDist = dist; 19905b261ecSmrg best = pixel; 20005b261ecSmrg } 20105b261ecSmrg } 20205b261ecSmrg return best; 20305b261ecSmrg} 20405b261ecSmrg 20505b261ecSmrg/* 0 <= gray < 32768 */ 20605b261ecSmrgstatic Pixel 20705b261ecSmrgFindBestGray (miIndexedPtr pIndexed, Pixel *pixels, int num, int gray) 20805b261ecSmrg{ 20905b261ecSmrg Pixel best = pixels[0]; 21005b261ecSmrg int bestDist = 1 << 30; 21105b261ecSmrg int dist; 21205b261ecSmrg int dr; 21305b261ecSmrg int r; 21405b261ecSmrg 21505b261ecSmrg while (num--) 21605b261ecSmrg { 21705b261ecSmrg Pixel pixel = *pixels++; 21805b261ecSmrg CARD32 v = pIndexed->rgba[pixel]; 21905b261ecSmrg 22005b261ecSmrg r = v & 0xff; 22105b261ecSmrg r = r | (r << 8); 22205b261ecSmrg dr = gray - (r >> 1); 22305b261ecSmrg dist = dr * dr; 22405b261ecSmrg if (dist < bestDist) 22505b261ecSmrg { 22605b261ecSmrg bestDist = dist; 22705b261ecSmrg best = pixel; 22805b261ecSmrg } 22905b261ecSmrg } 23005b261ecSmrg return best; 23105b261ecSmrg} 23205b261ecSmrg 23305b261ecSmrgBool 23405b261ecSmrgmiInitIndexed (ScreenPtr pScreen, 23505b261ecSmrg PictFormatPtr pFormat) 23605b261ecSmrg{ 23705b261ecSmrg ColormapPtr pColormap = pFormat->index.pColormap; 23805b261ecSmrg VisualPtr pVisual = pColormap->pVisual; 23905b261ecSmrg miIndexedPtr pIndexed; 24005b261ecSmrg Pixel pixels[MI_MAX_INDEXED]; 24105b261ecSmrg xrgb rgb[MI_MAX_INDEXED]; 24205b261ecSmrg int num; 24305b261ecSmrg int i; 24405b261ecSmrg Pixel p, r, g, b; 24505b261ecSmrg 24605b261ecSmrg if (pVisual->ColormapEntries > MI_MAX_INDEXED) 24705b261ecSmrg return FALSE; 24805b261ecSmrg 24905b261ecSmrg if (pVisual->class & DynamicClass) 25005b261ecSmrg { 25105b261ecSmrg if (!miBuildRenderColormap (pColormap, pixels, &num)) 25205b261ecSmrg return FALSE; 25305b261ecSmrg } 25405b261ecSmrg else 25505b261ecSmrg { 25605b261ecSmrg num = pVisual->ColormapEntries; 25705b261ecSmrg for (p = 0; p < num; p++) 25805b261ecSmrg pixels[p] = p; 25905b261ecSmrg } 26005b261ecSmrg 26105b261ecSmrg pIndexed = xalloc (sizeof (miIndexedRec)); 26205b261ecSmrg if (!pIndexed) 26305b261ecSmrg return FALSE; 26405b261ecSmrg 26505b261ecSmrg pFormat->index.nvalues = num; 26605b261ecSmrg pFormat->index.pValues = xalloc (num * sizeof (xIndexValue)); 26705b261ecSmrg if (!pFormat->index.pValues) 26805b261ecSmrg { 26905b261ecSmrg xfree (pIndexed); 27005b261ecSmrg return FALSE; 27105b261ecSmrg } 27205b261ecSmrg 27305b261ecSmrg 27405b261ecSmrg /* 27505b261ecSmrg * Build mapping from pixel value to ARGB 27605b261ecSmrg */ 27705b261ecSmrg QueryColors (pColormap, num, pixels, rgb); 27805b261ecSmrg for (i = 0; i < num; i++) 27905b261ecSmrg { 28005b261ecSmrg p = pixels[i]; 28105b261ecSmrg pFormat->index.pValues[i].pixel = p; 28205b261ecSmrg pFormat->index.pValues[i].red = rgb[i].red; 28305b261ecSmrg pFormat->index.pValues[i].green = rgb[i].green; 28405b261ecSmrg pFormat->index.pValues[i].blue = rgb[i].blue; 28505b261ecSmrg pFormat->index.pValues[i].alpha = 0xffff; 28605b261ecSmrg pIndexed->rgba[p] = (0xff000000 | 28705b261ecSmrg ((rgb[i].red & 0xff00) << 8) | 28805b261ecSmrg ((rgb[i].green & 0xff00) ) | 28905b261ecSmrg ((rgb[i].blue & 0xff00) >> 8)); 29005b261ecSmrg } 29105b261ecSmrg 29205b261ecSmrg /* 29305b261ecSmrg * Build mapping from RGB to pixel value. This could probably be 29405b261ecSmrg * done a bit quicker... 29505b261ecSmrg */ 29605b261ecSmrg switch (pVisual->class | DynamicClass) { 29705b261ecSmrg case GrayScale: 29805b261ecSmrg pIndexed->color = FALSE; 29905b261ecSmrg for (r = 0; r < 32768; r++) 30005b261ecSmrg pIndexed->ent[r] = FindBestGray (pIndexed, pixels, num, r); 30105b261ecSmrg break; 30205b261ecSmrg case PseudoColor: 30305b261ecSmrg pIndexed->color = TRUE; 30405b261ecSmrg p = 0; 30505b261ecSmrg for (r = 0; r < 32; r++) 30605b261ecSmrg for (g = 0; g < 32; g++) 30705b261ecSmrg for (b = 0; b < 32; b++) 30805b261ecSmrg { 30905b261ecSmrg pIndexed->ent[p] = FindBestColor (pIndexed, pixels, num, 31005b261ecSmrg r, g, b); 31105b261ecSmrg p++; 31205b261ecSmrg } 31305b261ecSmrg break; 31405b261ecSmrg } 31505b261ecSmrg pFormat->index.devPrivate = pIndexed; 31605b261ecSmrg return TRUE; 31705b261ecSmrg} 31805b261ecSmrg 31905b261ecSmrgvoid 32005b261ecSmrgmiCloseIndexed (ScreenPtr pScreen, 32105b261ecSmrg PictFormatPtr pFormat) 32205b261ecSmrg{ 32305b261ecSmrg if (pFormat->index.devPrivate) 32405b261ecSmrg { 32505b261ecSmrg xfree (pFormat->index.devPrivate); 32605b261ecSmrg pFormat->index.devPrivate = 0; 32705b261ecSmrg } 32805b261ecSmrg if (pFormat->index.pValues) 32905b261ecSmrg { 33005b261ecSmrg xfree (pFormat->index.pValues); 33105b261ecSmrg pFormat->index.pValues = 0; 33205b261ecSmrg } 33305b261ecSmrg} 33405b261ecSmrg 33505b261ecSmrgvoid 33605b261ecSmrgmiUpdateIndexed (ScreenPtr pScreen, 33705b261ecSmrg PictFormatPtr pFormat, 33805b261ecSmrg int ndef, 33905b261ecSmrg xColorItem *pdef) 34005b261ecSmrg{ 34105b261ecSmrg miIndexedPtr pIndexed = pFormat->index.devPrivate; 34205b261ecSmrg 34305b261ecSmrg if (pIndexed) 34405b261ecSmrg { 34505b261ecSmrg while (ndef--) 34605b261ecSmrg { 34705b261ecSmrg pIndexed->rgba[pdef->pixel] = (0xff000000 | 34805b261ecSmrg ((pdef->red & 0xff00) << 8) | 34905b261ecSmrg ((pdef->green & 0xff00) ) | 35005b261ecSmrg ((pdef->blue & 0xff00) >> 8)); 35105b261ecSmrg pdef++; 35205b261ecSmrg } 35305b261ecSmrg } 35405b261ecSmrg} 35505b261ecSmrg 35605b261ecSmrg#endif /* _MIINDEX_H_ */ 357