2
|
1 |
/*
|
5506
|
2 |
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
2
|
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
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
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 |
*
|
5506
|
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.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
#include "splashscreen_gfx_impl.h"
|
|
27 |
|
|
28 |
/* *INDENT-OFF* */
|
|
29 |
const 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 */
|
|
57 |
void
|
|
58 |
initDither(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 */
|
|
77 |
INLINE int
|
|
78 |
scaleColor(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 */
|
|
86 |
int
|
|
87 |
quantizeColors(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 |
|
|
125 |
void
|
|
126 |
initColorCube(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 |
*/
|
|
157 |
void
|
|
158 |
convertLine(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 */
|
|
202 |
void
|
|
203 |
initRect(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 |
|
|
222 |
int
|
|
223 |
convertRect(ImageRect * pSrcRect, ImageRect * pDstRect, int mode)
|
|
224 |
{
|
|
225 |
return convertRect2(pSrcRect, pDstRect, mode, NULL);
|
|
226 |
}
|
|
227 |
|
|
228 |
int
|
|
229 |
convertRect2(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 |
|
|
269 |
int
|
|
270 |
fillRect(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 */
|
|
288 |
void
|
|
289 |
initFormat(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 */
|
|
310 |
void
|
|
311 |
dumpFormat(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 */
|
|
328 |
void
|
|
329 |
optimizeFormat(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 |
|
|
337 |
int
|
|
338 |
platformByteOrder()
|
|
339 |
{
|
|
340 |
int test = 1;
|
|
341 |
|
|
342 |
*(char *) &test = 0;
|
|
343 |
return test ? BYTE_ORDER_MSBFIRST : BYTE_ORDER_LSBFIRST;
|
|
344 |
}
|