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