1/*
2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "splashscreen_gfx_impl.h"
27
28/* *INDENT-OFF* */
29const byte_t baseDitherMatrix[DITHER_SIZE][DITHER_SIZE] = {
30  /* Bayer's order-4 dither array.  Generated by the code given in
31   * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
32   */
33  {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
34  { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
35  {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
36  { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
37  {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
38  { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
39  {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
40  { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
41  {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
42  { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
43  {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
44  { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
45  {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
46  { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
47  {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
48  { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
49};
50/* *INDENT-ON* */
51
52// FIXME: tinting on some colormaps (e.g. 1-2-1) means something is slightly wrong with
53// colormap calculation... probably it's some rounding error
54
55/*  calculates the colorTable for mapping from 0..255 to 0..numColors-1
56    also calculates the dithering matrix, scaling baseDitherMatrix accordingly */
57void
58initDither(DitherSettings * pDither, int numColors, int scale)
59{
60    int i, j;
61
62    pDither->numColors = numColors;
63    for (i = 0; i < (MAX_COLOR_VALUE + 1) * 2; i++) {
64        pDither->colorTable[i] =
65            (((i > MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : i) *
66             (numColors - 1) / MAX_COLOR_VALUE) * scale;
67    }
68    for (i = 0; i < DITHER_SIZE; i++)
69        for (j = 0; j < DITHER_SIZE; j++)
70            pDither->matrix[i][j] =
71                (int) baseDitherMatrix[i][j] / (numColors - 1);
72}
73
74/* scale a number on the range of 0..numColorsIn-1 to 0..numColorsOut-1
75 0 maps to 0 and numColorsIn-1 maps to numColorsOut-1
76 intermediate values are spread evenly between 0 and numColorsOut-1 */
77INLINE int
78scaleColor(int color, int numColorsIn, int numColorsOut)
79{
80    return (color * (numColorsOut - 1) + (numColorsIn - 1) / 2)
81        / (numColorsIn - 1);
82}
83
84/*  build a colormap for a color cube and a dithering matrix. color cube is quantized
85    according to the provided maximum number of colors */
86int
87quantizeColors(int maxNumColors, int *numColors)
88{
89
90    // static const int scale[3]={10000/11,10000/69,10000/30};
91    // FIXME: sort out the adaptive color cube subdivision... realistic 11:69:30 is good on photos,
92    // but would be bad on other pictures. A stupid approximation is used now.
93
94    static const int scale[3] = { 8, 4, 6 };
95
96    // maxNumColors should be at least 2x2x2=8, or we lose some color components completely
97    numColors[0] = numColors[1] = numColors[2] = 2;
98
99    while (1) {
100        int idx[3] = { 0, 1, 2 };
101        /* bubble sort the three indexes according to scaled numColors values */
102#define SORT(i,j) \
103        if (numColors[idx[i]]*scale[idx[i]]>numColors[idx[j]]*scale[idx[j]]) \
104            { int t = idx[i]; idx[i] = idx[j]; idx[j] = t; }
105        SORT(0, 1);
106        SORT(1, 2);
107        SORT(0, 1);
108        /* try increasing numColors for the first color */
109        if ((numColors[idx[0]] + 1) * numColors[idx[1]] *
110            numColors[idx[2]] <= maxNumColors) {
111                numColors[idx[0]]++;
112        } else if (numColors[idx[0]] * (numColors[idx[1]] + 1) *
113            numColors[idx[2]] <= maxNumColors) {
114            numColors[idx[1]]++;
115        } else if (numColors[idx[0]] * numColors[idx[1]] *
116            (numColors[idx[2]] + 1) <= maxNumColors) {
117            numColors[idx[2]]++;
118        } else {
119            break;
120        }
121    }
122    return numColors[0] * numColors[1] * numColors[2];
123}
124
125void
126initColorCube(int *numColors, rgbquad_t * pColorMap, DitherSettings * pDithers,
127              rgbquad_t * colorIndex)
128{
129    int r, g, b, n;
130
131    n = 0;
132    for (r = 0; r < numColors[2]; r++) {
133        for (g = 0; g < numColors[1]; g++)
134            for (b = 0; b < numColors[0]; b++) {
135                pColorMap[colorIndex[n++]] =
136                    scaleColor(b, numColors[0], MAX_COLOR_VALUE) +
137                    (scaleColor(g, numColors[1], MAX_COLOR_VALUE) << 8) +
138                    (scaleColor(r, numColors[2], MAX_COLOR_VALUE) << 16);
139            }
140    }
141    initDither(pDithers + 0, numColors[0], 1);
142    initDither(pDithers + 1, numColors[1], numColors[0]);
143    initDither(pDithers + 2, numColors[2], numColors[1] * numColors[0]);
144}
145
146/*
147    the function below is a line conversion loop
148
149    incSrc and incDst are pSrc and pDst increment values for the loop, in bytes
150    mode defines how the pixels should be processed
151
152    mode==CVT_COPY means the pixels should be copied as is
153    mode==CVT_ALPHATEST means pixels should be skipped when source pixel alpha is above the threshold
154    mode==CVT_BLEND means alpha blending between source and destination should be performed, while
155    destination alpha should be retained. source alpha is used for blending.
156*/
157void
158convertLine(void *pSrc, int incSrc, void *pDst, int incDst, int numSamples,
159            ImageFormat * srcFormat, ImageFormat * dstFormat, int doAlpha,
160            void *pSrc2, int incSrc2, ImageFormat * srcFormat2,
161            int row, int col)
162{
163    int i;
164
165    switch (doAlpha) {
166    case CVT_COPY:
167        for (i = 0; i < numSamples; ++i) {
168            putRGBADither(getRGBA(pSrc, srcFormat), pDst, dstFormat,
169                row, col++);
170            INCPN(byte_t, pSrc, incSrc);
171            INCPN(byte_t, pDst, incDst);
172        }
173        break;
174    case CVT_ALPHATEST:
175        for (i = 0; i < numSamples; ++i) {
176            rgbquad_t color = getRGBA(pSrc, srcFormat);
177
178            if (color >= ALPHA_THRESHOLD) {     // test for alpha component >50%. that's an extra branch, and it's bad...
179                putRGBADither(color, pDst, dstFormat, row, col++);
180            }
181            INCPN(byte_t, pSrc, incSrc);
182            INCPN(byte_t, pDst, incDst);
183        }
184        break;
185    case CVT_BLEND:
186        for (i = 0; i < numSamples; ++i) {
187            rgbquad_t src = getRGBA(pSrc, srcFormat);
188            rgbquad_t src2 = getRGBA(pSrc2, srcFormat);
189
190            putRGBADither(blendRGB(src, src2,
191                QUAD_ALPHA(src2)) | (src & QUAD_ALPHA_MASK), pDst, dstFormat,
192                row, col++);
193            INCPN(byte_t, pSrc, incSrc);
194            INCPN(byte_t, pDst, incDst);
195            INCPN(byte_t, pSrc2, incSrc2);
196        }
197        break;
198    }
199}
200
201/* initialize ImageRect structure according to function arguments */
202void
203initRect(ImageRect * pRect, int x, int y, int width, int height, int jump,
204         int stride, void *pBits, ImageFormat * format)
205{
206    int depthBytes = format->depthBytes;
207
208    pRect->pBits = pBits;
209    INCPN(byte_t, pRect->pBits, y * stride + x * depthBytes);
210    pRect->numLines = height;
211    pRect->numSamples = width;
212    pRect->stride = stride * jump;
213    pRect->depthBytes = depthBytes;
214    pRect->format = format;
215    pRect->row = y;
216    pRect->col = x;
217    pRect->jump = jump;
218}
219
220/*  copy image rectangle from source to destination, or from two sources with blending */
221
222int
223convertRect(ImageRect * pSrcRect, ImageRect * pDstRect, int mode)
224{
225    return convertRect2(pSrcRect, pDstRect, mode, NULL);
226}
227
228int
229convertRect2(ImageRect * pSrcRect, ImageRect * pDstRect, int mode,
230             ImageRect * pSrcRect2)
231{
232    int numLines = pSrcRect->numLines;
233    int numSamples = pSrcRect->numSamples;
234    void *pSrc = pSrcRect->pBits;
235    void *pDst = pDstRect->pBits;
236    void *pSrc2 = NULL;
237    int j, row;
238
239    if (pDstRect->numLines < numLines)
240        numLines = pDstRect->numLines;
241    if (pDstRect->numSamples < numSamples) {
242        numSamples = pDstRect->numSamples;
243    }
244    if (pSrcRect2) {
245        if (pSrcRect2->numLines < numLines) {
246            numLines = pSrcRect2->numLines;
247        }
248        if (pSrcRect2->numSamples < numSamples) {
249            numSamples = pSrcRect2->numSamples;
250        }
251        pSrc2 = pSrcRect2->pBits;
252    }
253    row = pDstRect->row;
254    for (j = 0; j < numLines; j++) {
255        convertLine(pSrc, pSrcRect->depthBytes, pDst, pDstRect->depthBytes,
256            numSamples, pSrcRect->format, pDstRect->format, mode,
257            pSrc2, pSrcRect2 ? pSrcRect2->depthBytes : 0,
258            pSrcRect2 ? pSrcRect2->format : 0, row, pDstRect->col);
259        INCPN(byte_t, pSrc, pSrcRect->stride);
260        INCPN(byte_t, pDst, pDstRect->stride);
261        if (pSrcRect2) {
262            INCPN(byte_t, pSrc2, pSrcRect2->stride);
263        }
264        row += pDstRect->jump;
265    }
266    return numLines * pSrcRect->stride;
267}
268
269int
270fillRect(rgbquad_t color, ImageRect * pDstRect)
271{
272    int numLines = pDstRect->numLines;
273    int numSamples = pDstRect->numSamples;
274    void *pDst = pDstRect->pBits;
275    int j, row;
276
277    row = pDstRect->row;
278    for (j = 0; j < numLines; j++) {
279        fillLine(color, pDst, pDstRect->depthBytes, numSamples,
280            pDstRect->format, row, pDstRect->col);
281        INCPN(byte_t, pDst, pDstRect->stride);
282        row += pDstRect->jump;
283    }
284    return numLines * pDstRect->stride;
285}
286
287/* init the masks; all other parameters are initialized to default values */
288void
289initFormat(ImageFormat * format, int redMask, int greenMask, int blueMask,
290           int alphaMask)
291{
292    int i, shift, numBits;
293
294    format->byteOrder = BYTE_ORDER_NATIVE;
295    format->colorMap = NULL;
296    format->depthBytes = 4;
297    format->fixedBits = 0;
298    format->premultiplied = 0;
299    format->mask[0] = blueMask;
300    format->mask[1] = greenMask;
301    format->mask[2] = redMask;
302    format->mask[3] = alphaMask;
303    for (i = 0; i < 4; i++) {
304        getMaskShift(format->mask[i], &shift, &numBits);
305        format->shift[i] = shift + numBits - i * 8 - 8;
306    }
307}
308
309/* dump the visual format */
310void
311dumpFormat(ImageFormat * format)
312{
313#ifdef _DEBUG
314    int i;
315
316    printf("byteorder=%d colormap=%08x depthBytes=%d fixedBits=%08x transparentColor=%u ",
317        format->byteOrder, (unsigned) format->colorMap, format->depthBytes,
318        (unsigned) format->fixedBits, (unsigned) format->transparentColor);
319    for (i = 0; i < 4; i++) {
320        printf("mask[%d]=%08x shift[%d]=%d\n", i, (unsigned) format->mask[i], i,
321            format->shift[i]);
322    }
323    printf("\n");
324#endif
325}
326
327/* optimize the format */
328void
329optimizeFormat(ImageFormat * format)
330{
331    if (platformByteOrder() == format->byteOrder && format->depthBytes != 3) {
332        format->byteOrder = BYTE_ORDER_NATIVE;
333    }
334    /* FIXME: some advanced optimizations are possible, especially for format pairs */
335}
336
337int
338platformByteOrder()
339{
340    int test = 1;
341
342    *(char *) &test = 0;
343    return test ? BYTE_ORDER_MSBFIRST : BYTE_ORDER_LSBFIRST;
344}
345