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 4435c4bbdfSmrgmiBuildRenderColormap(ColormapPtr pColormap, Pixel * pixels, int *nump) 4505b261ecSmrg{ 4635c4bbdfSmrg int r, g, b; 4735c4bbdfSmrg unsigned short red, green, blue; 4835c4bbdfSmrg Pixel pixel; 4935c4bbdfSmrg Bool used[MI_MAX_INDEXED]; 5035c4bbdfSmrg int needed; 5135c4bbdfSmrg int policy; 5235c4bbdfSmrg int cube, gray; 5335c4bbdfSmrg int i, n; 5435c4bbdfSmrg 5535c4bbdfSmrg if (pColormap->mid != pColormap->pScreen->defColormap) { 5635c4bbdfSmrg policy = PictureCmapPolicyAll; 5705b261ecSmrg } 5835c4bbdfSmrg else { 5935c4bbdfSmrg int avail = pColormap->pVisual->ColormapEntries; 6035c4bbdfSmrg 6135c4bbdfSmrg policy = PictureCmapPolicy; 6235c4bbdfSmrg if (policy == PictureCmapPolicyDefault) { 6335c4bbdfSmrg if (avail >= 256 && 6435c4bbdfSmrg (pColormap->pVisual->class | DynamicClass) == PseudoColor) 6535c4bbdfSmrg policy = PictureCmapPolicyColor; 6635c4bbdfSmrg else if (avail >= 64) 6735c4bbdfSmrg policy = PictureCmapPolicyGray; 6835c4bbdfSmrg else 6935c4bbdfSmrg policy = PictureCmapPolicyMono; 7035c4bbdfSmrg } 7105b261ecSmrg } 7205b261ecSmrg /* 7305b261ecSmrg * Make sure enough cells are free for the chosen policy 7405b261ecSmrg */ 7535c4bbdfSmrg for (;;) { 7635c4bbdfSmrg switch (policy) { 7735c4bbdfSmrg case PictureCmapPolicyAll: 7835c4bbdfSmrg needed = 0; 7935c4bbdfSmrg break; 8035c4bbdfSmrg case PictureCmapPolicyColor: 8135c4bbdfSmrg needed = 71; 8235c4bbdfSmrg break; 8335c4bbdfSmrg case PictureCmapPolicyGray: 8435c4bbdfSmrg needed = 11; 8535c4bbdfSmrg break; 8635c4bbdfSmrg case PictureCmapPolicyMono: 8735c4bbdfSmrg default: 8835c4bbdfSmrg needed = 0; 8935c4bbdfSmrg break; 9035c4bbdfSmrg } 9135c4bbdfSmrg if (needed <= pColormap->freeRed) 9235c4bbdfSmrg break; 9335c4bbdfSmrg policy--; 9435c4bbdfSmrg } 9535c4bbdfSmrg 9605b261ecSmrg /* 9705b261ecSmrg * Compute size of cube and gray ramps 9805b261ecSmrg */ 9905b261ecSmrg cube = gray = 0; 10005b261ecSmrg switch (policy) { 10105b261ecSmrg case PictureCmapPolicyAll: 10235c4bbdfSmrg /* 10335c4bbdfSmrg * Allocate as big a cube as possible 10435c4bbdfSmrg */ 10535c4bbdfSmrg if ((pColormap->pVisual->class | DynamicClass) == PseudoColor) { 10635c4bbdfSmrg for (cube = 1; 10735c4bbdfSmrg cube * cube * cube < pColormap->pVisual->ColormapEntries; 10835c4bbdfSmrg cube++); 10935c4bbdfSmrg cube--; 11035c4bbdfSmrg if (cube == 1) 11135c4bbdfSmrg cube = 0; 11235c4bbdfSmrg } 11335c4bbdfSmrg else 11435c4bbdfSmrg cube = 0; 11535c4bbdfSmrg /* 11635c4bbdfSmrg * Figure out how many gray levels to use so that they 11735c4bbdfSmrg * line up neatly with the cube 11835c4bbdfSmrg */ 11935c4bbdfSmrg if (cube) { 12035c4bbdfSmrg needed = pColormap->pVisual->ColormapEntries - (cube * cube * cube); 12135c4bbdfSmrg /* levels to fill in with */ 12235c4bbdfSmrg gray = needed / (cube - 1); 12335c4bbdfSmrg /* total levels */ 12435c4bbdfSmrg gray = (gray + 1) * (cube - 1) + 1; 12535c4bbdfSmrg } 12635c4bbdfSmrg else 12735c4bbdfSmrg gray = pColormap->pVisual->ColormapEntries; 12835c4bbdfSmrg break; 12935c4bbdfSmrg 13005b261ecSmrg case PictureCmapPolicyColor: 13135c4bbdfSmrg cube = NUM_CUBE_LEVELS; 13235c4bbdfSmrg /* fall through ... */ 13305b261ecSmrg case PictureCmapPolicyGray: 13435c4bbdfSmrg gray = NUM_GRAY_LEVELS; 13535c4bbdfSmrg break; 13605b261ecSmrg case PictureCmapPolicyMono: 13705b261ecSmrg default: 13835c4bbdfSmrg gray = 2; 13935c4bbdfSmrg break; 14005b261ecSmrg } 14135c4bbdfSmrg 14235c4bbdfSmrg memset(used, '\0', pColormap->pVisual->ColormapEntries * sizeof(Bool)); 14305b261ecSmrg for (r = 0; r < cube; r++) 14435c4bbdfSmrg for (g = 0; g < cube; g++) 14535c4bbdfSmrg for (b = 0; b < cube; b++) { 14635c4bbdfSmrg pixel = 0; 14735c4bbdfSmrg red = (r * 65535 + (cube - 1) / 2) / (cube - 1); 14835c4bbdfSmrg green = (g * 65535 + (cube - 1) / 2) / (cube - 1); 14935c4bbdfSmrg blue = (b * 65535 + (cube - 1) / 2) / (cube - 1); 15035c4bbdfSmrg if (AllocColor(pColormap, &red, &green, 15135c4bbdfSmrg &blue, &pixel, 0) != Success) 15235c4bbdfSmrg return FALSE; 15335c4bbdfSmrg used[pixel] = TRUE; 15435c4bbdfSmrg } 15535c4bbdfSmrg for (g = 0; g < gray; g++) { 15635c4bbdfSmrg pixel = 0; 15735c4bbdfSmrg red = green = blue = (g * 65535 + (gray - 1) / 2) / (gray - 1); 15835c4bbdfSmrg if (AllocColor(pColormap, &red, &green, &blue, &pixel, 0) != Success) 15935c4bbdfSmrg return FALSE; 16035c4bbdfSmrg used[pixel] = TRUE; 16105b261ecSmrg } 16205b261ecSmrg n = 0; 16305b261ecSmrg for (i = 0; i < pColormap->pVisual->ColormapEntries; i++) 16435c4bbdfSmrg if (used[i]) 16535c4bbdfSmrg pixels[n++] = i; 16605b261ecSmrg 16705b261ecSmrg *nump = n; 16835c4bbdfSmrg 16905b261ecSmrg return TRUE; 17005b261ecSmrg} 17105b261ecSmrg 17205b261ecSmrg/* 0 <= red, green, blue < 32 */ 17305b261ecSmrgstatic Pixel 17435c4bbdfSmrgFindBestColor(miIndexedPtr pIndexed, Pixel * pixels, int num, 17535c4bbdfSmrg int red, int green, int blue) 17605b261ecSmrg{ 17735c4bbdfSmrg Pixel best = pixels[0]; 17835c4bbdfSmrg int bestDist = 1 << 30; 17935c4bbdfSmrg int dist; 18035c4bbdfSmrg int dr, dg, db; 18105b261ecSmrg 18235c4bbdfSmrg while (num--) { 18335c4bbdfSmrg Pixel pixel = *pixels++; 18435c4bbdfSmrg CARD32 v = pIndexed->rgba[pixel]; 18535c4bbdfSmrg 18635c4bbdfSmrg dr = ((v >> 19) & 0x1f); 18735c4bbdfSmrg dg = ((v >> 11) & 0x1f); 18835c4bbdfSmrg db = ((v >> 3) & 0x1f); 18935c4bbdfSmrg dr = dr - red; 19035c4bbdfSmrg dg = dg - green; 19135c4bbdfSmrg db = db - blue; 19235c4bbdfSmrg dist = dr * dr + dg * dg + db * db; 19335c4bbdfSmrg if (dist < bestDist) { 19435c4bbdfSmrg bestDist = dist; 19535c4bbdfSmrg best = pixel; 19635c4bbdfSmrg } 19705b261ecSmrg } 19805b261ecSmrg return best; 19905b261ecSmrg} 20005b261ecSmrg 20105b261ecSmrg/* 0 <= gray < 32768 */ 20205b261ecSmrgstatic Pixel 20335c4bbdfSmrgFindBestGray(miIndexedPtr pIndexed, Pixel * pixels, int num, int gray) 20405b261ecSmrg{ 20535c4bbdfSmrg Pixel best = pixels[0]; 20635c4bbdfSmrg int bestDist = 1 << 30; 20735c4bbdfSmrg int dist; 20835c4bbdfSmrg int dr; 20935c4bbdfSmrg int r; 21035c4bbdfSmrg 21135c4bbdfSmrg while (num--) { 21235c4bbdfSmrg Pixel pixel = *pixels++; 21335c4bbdfSmrg CARD32 v = pIndexed->rgba[pixel]; 21405b261ecSmrg 21535c4bbdfSmrg r = v & 0xff; 21635c4bbdfSmrg r = r | (r << 8); 21735c4bbdfSmrg dr = gray - (r >> 1); 21835c4bbdfSmrg dist = dr * dr; 21935c4bbdfSmrg if (dist < bestDist) { 22035c4bbdfSmrg bestDist = dist; 22135c4bbdfSmrg best = pixel; 22235c4bbdfSmrg } 22305b261ecSmrg } 22405b261ecSmrg return best; 22505b261ecSmrg} 22605b261ecSmrg 22705b261ecSmrgBool 22835c4bbdfSmrgmiInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat) 22905b261ecSmrg{ 23035c4bbdfSmrg ColormapPtr pColormap = pFormat->index.pColormap; 23135c4bbdfSmrg VisualPtr pVisual = pColormap->pVisual; 23235c4bbdfSmrg miIndexedPtr pIndexed; 23335c4bbdfSmrg Pixel pixels[MI_MAX_INDEXED]; 23435c4bbdfSmrg xrgb rgb[MI_MAX_INDEXED]; 23535c4bbdfSmrg int num; 23635c4bbdfSmrg int i; 23735c4bbdfSmrg Pixel p, r, g, b; 23805b261ecSmrg 23905b261ecSmrg if (pVisual->ColormapEntries > MI_MAX_INDEXED) 24035c4bbdfSmrg return FALSE; 24135c4bbdfSmrg 24235c4bbdfSmrg if (pVisual->class & DynamicClass) { 24335c4bbdfSmrg if (!miBuildRenderColormap(pColormap, pixels, &num)) 24435c4bbdfSmrg return FALSE; 24505b261ecSmrg } 24635c4bbdfSmrg else { 24735c4bbdfSmrg num = pVisual->ColormapEntries; 24835c4bbdfSmrg for (p = 0; p < num; p++) 24935c4bbdfSmrg pixels[p] = p; 25005b261ecSmrg } 25135c4bbdfSmrg 25235c4bbdfSmrg pIndexed = malloc(sizeof(miIndexedRec)); 25305b261ecSmrg if (!pIndexed) 25435c4bbdfSmrg return FALSE; 25535c4bbdfSmrg 25605b261ecSmrg pFormat->index.nvalues = num; 25735c4bbdfSmrg pFormat->index.pValues = xallocarray(num, sizeof(xIndexValue)); 25835c4bbdfSmrg if (!pFormat->index.pValues) { 25935c4bbdfSmrg free(pIndexed); 26035c4bbdfSmrg return FALSE; 26105b261ecSmrg } 26235c4bbdfSmrg 26305b261ecSmrg /* 26405b261ecSmrg * Build mapping from pixel value to ARGB 26505b261ecSmrg */ 26635c4bbdfSmrg QueryColors(pColormap, num, pixels, rgb, serverClient); 26735c4bbdfSmrg for (i = 0; i < num; i++) { 26835c4bbdfSmrg p = pixels[i]; 26935c4bbdfSmrg pFormat->index.pValues[i].pixel = p; 27035c4bbdfSmrg pFormat->index.pValues[i].red = rgb[i].red; 27135c4bbdfSmrg pFormat->index.pValues[i].green = rgb[i].green; 27235c4bbdfSmrg pFormat->index.pValues[i].blue = rgb[i].blue; 27335c4bbdfSmrg pFormat->index.pValues[i].alpha = 0xffff; 27435c4bbdfSmrg pIndexed->rgba[p] = (0xff000000 | 27535c4bbdfSmrg ((rgb[i].red & 0xff00) << 8) | 27635c4bbdfSmrg ((rgb[i].green & 0xff00)) | 27735c4bbdfSmrg ((rgb[i].blue & 0xff00) >> 8)); 27805b261ecSmrg } 27905b261ecSmrg 28005b261ecSmrg /* 28105b261ecSmrg * Build mapping from RGB to pixel value. This could probably be 28205b261ecSmrg * done a bit quicker... 28305b261ecSmrg */ 28405b261ecSmrg switch (pVisual->class | DynamicClass) { 28505b261ecSmrg case GrayScale: 28635c4bbdfSmrg pIndexed->color = FALSE; 28735c4bbdfSmrg for (r = 0; r < 32768; r++) 28835c4bbdfSmrg pIndexed->ent[r] = FindBestGray(pIndexed, pixels, num, r); 28935c4bbdfSmrg break; 29005b261ecSmrg case PseudoColor: 29135c4bbdfSmrg pIndexed->color = TRUE; 29235c4bbdfSmrg p = 0; 29335c4bbdfSmrg for (r = 0; r < 32; r++) 29435c4bbdfSmrg for (g = 0; g < 32; g++) 29535c4bbdfSmrg for (b = 0; b < 32; b++) { 29635c4bbdfSmrg pIndexed->ent[p] = FindBestColor(pIndexed, pixels, num, 29735c4bbdfSmrg r, g, b); 29835c4bbdfSmrg p++; 29935c4bbdfSmrg } 30035c4bbdfSmrg break; 30105b261ecSmrg } 30205b261ecSmrg pFormat->index.devPrivate = pIndexed; 30305b261ecSmrg return TRUE; 30405b261ecSmrg} 30505b261ecSmrg 30605b261ecSmrgvoid 30735c4bbdfSmrgmiCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat) 30805b261ecSmrg{ 3099ace9065Smrg free(pFormat->index.devPrivate); 3109ace9065Smrg pFormat->index.devPrivate = NULL; 3119ace9065Smrg free(pFormat->index.pValues); 3129ace9065Smrg pFormat->index.pValues = NULL; 31305b261ecSmrg} 31405b261ecSmrg 31505b261ecSmrgvoid 31635c4bbdfSmrgmiUpdateIndexed(ScreenPtr pScreen, 31735c4bbdfSmrg PictFormatPtr pFormat, int ndef, xColorItem * pdef) 31805b261ecSmrg{ 31905b261ecSmrg miIndexedPtr pIndexed = pFormat->index.devPrivate; 32005b261ecSmrg 32135c4bbdfSmrg if (pIndexed) { 32235c4bbdfSmrg while (ndef--) { 32335c4bbdfSmrg pIndexed->rgba[pdef->pixel] = (0xff000000 | 32435c4bbdfSmrg ((pdef->red & 0xff00) << 8) | 32535c4bbdfSmrg ((pdef->green & 0xff00)) | 32635c4bbdfSmrg ((pdef->blue & 0xff00) >> 8)); 32735c4bbdfSmrg pdef++; 32835c4bbdfSmrg } 32905b261ecSmrg } 33005b261ecSmrg} 33105b261ecSmrg 33235c4bbdfSmrg#endif /* _MIINDEX_H_ */ 333