blob: 1c55702fe73ac8f7d26487a24324cb466e59bb4a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#ifndef SPLASHSCREEN_GFX_IMPL_H
27#define SPLASHSCREEN_GFX_IMPL_H
28
29#include "splashscreen_gfx.h"
30
31/* here come some very simple macros */
32
33/* advance a pointer p by sizeof(type)*n bytes */
34#define INCPN(type,p,n) ((p) = (type*)(p)+n)
35
36/* advance a pointer by sizeof(type) */
37#define INCP(type,p) INCPN(type,(p),1)
38
39/* store a typed value to pointed location */
40#define PUT(type,p,v) (*(type*)(p) = (type)(v))
41
42/* load a typed value from pointed location */
43#define GET(type,p) (*(type*)p)
44
45/* same as cond<0?-1:0 */
46enum
47{
48 IFNEG_SHIFT_BITS = sizeof(int) * 8 - 1
49};
50
51#define IFNEG(cond) ((int)(cond)>>IFNEG_SHIFT_BITS)
52
53/* same as cond<0?n1:n2 */
54#define IFNEGPOS(cond,n1,n2) ((IFNEG(cond)&(n1))|((~IFNEG(cond))&(n2)))
55
56/* value shifted left by n bits, negative n is allowed */
57#define LSHIFT(value,n) IFNEGPOS((n),(value)>>-(n),(value)<<(n))
58
59/* value shifted right by n bits, negative n is allowed */
60#define RSHIFT(value,n) IFNEGPOS(n,(value)<<-(n),(value)>>(n))
61
62/* converts a single i'th component to the specific format defined by format->shift[i] and format->mask[i] */
63#define CONVCOMP(quad,format,i) \
64 (LSHIFT((quad),(format)->shift[i])&(format)->mask[i])
65
66/* extracts the component defined by format->shift[i] and format->mask[i] from a specific-format value */
67#define UNCONVCOMP(value,format,i) \
68 (RSHIFT((value)&(format)->mask[i],(format)->shift[i]))
69
70/* dithers the color using the dither matrices and colormap from format
71 indices to dither matrices are passed as arguments */
72INLINE unsigned
73ditherColor(rgbquad_t value, ImageFormat * format, int row, int col)
74{
75 int blue = QUAD_BLUE(value);
76 int green = QUAD_GREEN(value);
77 int red = QUAD_RED(value);
78
79 blue = format->dithers[0].colorTable[blue +
80 format->dithers[0].matrix[col & DITHER_MASK][row & DITHER_MASK]];
81 green = format->dithers[1].colorTable[green +
82 format->dithers[1].matrix[col & DITHER_MASK][row & DITHER_MASK]];
83 red = format->dithers[2].colorTable[red +
84 format->dithers[2].matrix[col & DITHER_MASK][row & DITHER_MASK]];
85 return red + green + blue;
86}
87
88/* blend (lerp between) two rgb quads
89 src and dst alpha is ignored
90 the algorithm: src*alpha+dst*(1-alpha)=(src-dst)*alpha+dst, rb and g are done separately
91 it's possible to verify that it's almost accurate indeed */
92
93INLINE rgbquad_t
94blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha)
95{
96 const rgbquad_t dstrb = dst & 0xFF00FF;
97 const rgbquad_t dstg = dst & 0xFF00;
98 const rgbquad_t srcrb = src & 0xFF00FF;
99 const rgbquad_t srcg = src & 0xFF00;
100
101 rgbquad_t drb = srcrb - dstrb;
102 rgbquad_t dg = srcg - dstg;
103
104 alpha += 1;
105
106 drb *= alpha;
107 dg *= alpha;
108 drb >>= 8;
109 dg >>= 8;
110
111 return ((drb + dstrb) & 0xFF00FF) | ((dg + dstg) & 0xFF00);
112}
113
114/* scales rgb quad by alpha. basically similar to what's above. src alpha is retained.
115 used for premultiplying alpha
116
117 btw: braindead MSVC6 generates _three_ mul instructions for this function */
118
119INLINE rgbquad_t
120premultiplyRGBA(rgbquad_t src)
121{
122 rgbquad_t srb = src & 0xFF00FF;
123 rgbquad_t sg = src & 0xFF00;
124 rgbquad_t alpha = src >> QUAD_ALPHA_SHIFT;
125
126 alpha += 1;
127
128 srb *= alpha;
129 sg *= alpha;
130 srb >>= 8;
131 sg >>= 8;
132
133 return (src & 0xFF000000) | (srb & 0xFF00FF) | (sg & 0xFF00);
134}
135
136/* The functions below are inherently ineffective, but the performance seems to be
137 more or less adequate for the case of splash screens. They can be optimized later
138 if needed. The idea of optimization is to provide inlineable form of putRGBADither and
139 getRGBA at least for certain most frequently used visuals. Something like this is
140 done in Java 2D ("loops"). This would be possible with C++ templates, but making it
141 clean for C would require ugly preprocessor tricks. Leaving it out for later.
142*/
143
144/* convert a single pixel color value from rgbquad according to visual format
145 and place it to pointed location
146 ordered dithering used when necessary */
147INLINE void
148putRGBADither(rgbquad_t value, void *ptr, ImageFormat * format,
149 int row, int col)
150{
151 if (format->premultiplied) {
152 value = premultiplyRGBA(value);
153 }
154 if (format->dithers) {
155 value = format->colorIndex[ditherColor(value, format, row, col)];
156 }
157 else {
158 value = CONVCOMP(value, format, 0) | CONVCOMP(value, format, 1) |
159 CONVCOMP(value, format, 2) | CONVCOMP(value, format, 3);
160 }
161 switch (format->byteOrder) {
162 case BYTE_ORDER_LSBFIRST:
163 switch (format->depthBytes) { /* lack of *break*'s is intentional */
164 case 4:
165 PUT(byte_t, ptr, value & 0xff);
166 value >>= 8;
167 INCP(byte_t, ptr);
168 case 3:
169 PUT(byte_t, ptr, value & 0xff);
170 value >>= 8;
171 INCP(byte_t, ptr);
172 case 2:
173 PUT(byte_t, ptr, value & 0xff);
174 value >>= 8;
175 INCP(byte_t, ptr);
176 case 1:
177 PUT(byte_t, ptr, value & 0xff);
178 }
179 break;
180 case BYTE_ORDER_MSBFIRST:
181 switch (format->depthBytes) { /* lack of *break*'s is intentional */
182 case 4:
183 PUT(byte_t, ptr, (value >> 24) & 0xff);
184 INCP(byte_t, ptr);
185 case 3:
186 PUT(byte_t, ptr, (value >> 16) & 0xff);
187 INCP(byte_t, ptr);
188 case 2:
189 PUT(byte_t, ptr, (value >> 8) & 0xff);
190 INCP(byte_t, ptr);
191 case 1:
192 PUT(byte_t, ptr, value & 0xff);
193 }
194 break;
195 case BYTE_ORDER_NATIVE:
196 switch (format->depthBytes) {
197 case 4:
198 PUT(rgbquad_t, ptr, value);
199 break;
200 case 3: /* not supported, LSB or MSB should always be specified */
201 *(int *) 0 = 0; /* crash */
202 break;
203 case 2:
204 PUT(word_t, ptr, value);
205 break;
206 case 1:
207 PUT(byte_t, ptr, value);
208 break;
209 }
210 }
211}
212
213/* load a single pixel color value and un-convert it to rgbquad according to visual format */
214INLINE rgbquad_t
215getRGBA(void *ptr, ImageFormat * format)
216{
217 /*
218 FIXME: color is not un-alpha-premultiplied on get
219 this is not required by current code, but it makes the implementation inconsistent
220 i.e. put(get) will not work right for alpha-premultiplied images */
221
222 /* get the value basing on depth and byte order */
223 rgbquad_t value = 0;
224
225 switch (format->byteOrder) {
226 case BYTE_ORDER_LSBFIRST:
227 switch (format->depthBytes) {
228 case 4:
229 value |= GET(byte_t, ptr);
230 value <<= 8;
231 INCP(byte_t, ptr);
232 case 3:
233 value |= GET(byte_t, ptr);
234 value <<= 8;
235 INCP(byte_t, ptr);
236 case 2:
237 value |= GET(byte_t, ptr);
238 value <<= 8;
239 INCP(byte_t, ptr);
240 case 1:
241 value |= GET(byte_t, ptr);
242 }
243 break;
244 case BYTE_ORDER_MSBFIRST:
245 switch (format->depthBytes) { /* lack of *break*'s is intentional */
246 case 4:
247 value |= (GET(byte_t, ptr) << 24);
248 INCP(byte_t, ptr);
249 case 3:
250 value |= (GET(byte_t, ptr) << 16);
251 INCP(byte_t, ptr);
252 case 2:
253 value |= (GET(byte_t, ptr) << 8);
254 INCP(byte_t, ptr);
255 case 1:
256 value |= GET(byte_t, ptr);
257 }
258 break;
259 case BYTE_ORDER_NATIVE:
260 switch (format->depthBytes) {
261 case 4:
262 value = GET(rgbquad_t, ptr);
263 break;
264 case 3: /* not supported, LSB or MSB should always be specified */
265 *(int *) 0 = 0;
266 break;
267 case 2:
268 value = (rgbquad_t) GET(word_t, ptr);
269 break;
270 case 1:
271 value = (rgbquad_t) GET(byte_t, ptr);
272 break;
273 }
274 break;
275 }
276 /* now un-convert the value */
277 if (format->colorMap) {
278 if (value == format->transparentColor)
279 return 0;
280 else
281 return format->colorMap[value];
282 }
283 else {
284 return UNCONVCOMP(value, format, 0) | UNCONVCOMP(value, format, 1) |
285 UNCONVCOMP(value, format, 2) | UNCONVCOMP(value, format, 3) |
286 format->fixedBits;
287 }
288}
289
290/* fill the line with the specified color according to visual format */
291INLINE void
292fillLine(rgbquad_t color, void *pDst, int incDst, int n,
293 ImageFormat * dstFormat, int row, int col)
294{
295 int i;
296
297 for (i = 0; i < n; ++i) {
298 putRGBADither(color, pDst, dstFormat, row, col++);
299 INCPN(byte_t, pDst, incDst);
300 }
301}
302
303/* find the shift for specified mask, also verify the mask is valid */
304INLINE int
305getMaskShift(rgbquad_t mask, int *pShift, int *pnumBits)
306{
307 int shift = 0, numBits = 0;
308
309 /* check the mask is not empty */
310 if (!mask)
311 return 0;
312 /* calculate the shift */
313 while ((mask & 1) == 0) {
314 ++shift;
315 mask >>= 1;
316 }
317 /* check the mask is contigious */
318 if ((mask & (mask + 1)) != 0)
319 return 0;
320 /* calculate the number of bits */
321 do {
322 ++numBits;
323 mask >>= 1;
324 } while ((mask & 1) != 0);
325 *pShift = shift;
326 *pnumBits = numBits;
327 return 1;
328}
329
330#endif