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