1 /* 2 * Copyright (c) 2005, 2010, 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 #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 */ 46 enum 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 */ 72 INLINE unsigned 73 ditherColor(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 */ 92 INLINE rgbquad_t 93 blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha) 94 { 95 const rgbquad_t a = alpha; 96 const rgbquad_t a1 = 0xFF - alpha; 97 98 return MAKE_QUAD( 99 (rgbquad_t)((QUAD_RED(src) * a + QUAD_RED(dst) * a1) / 0xFF), 100 (rgbquad_t)((QUAD_GREEN(src) * a + QUAD_GREEN(dst) * a1) / 0xFF), 101 (rgbquad_t)((QUAD_BLUE(src) * a + QUAD_BLUE(dst) * a1) / 0xFF), 102 0); 103 } 104 105 /* scales rgb quad by alpha. basically similar to what's above. src alpha is retained. 106 used for premultiplying alpha 107 108 btw: braindead MSVC6 generates _three_ mul instructions for this function */ 109 110 INLINE rgbquad_t 111 premultiplyRGBA(rgbquad_t src) 112 { 113 rgbquad_t srb = src & 0xFF00FF; 114 rgbquad_t sg = src & 0xFF00; 115 rgbquad_t alpha = src >> QUAD_ALPHA_SHIFT; 116 117 alpha += 1; 118 119 srb *= alpha; 120 sg *= alpha; 121 srb >>= 8; 122 sg >>= 8; 123 124 return (src & 0xFF000000) | (srb & 0xFF00FF) | (sg & 0xFF00); 125 } 126 127 /* The functions below are inherently ineffective, but the performance seems to be 128 more or less adequate for the case of splash screens. They can be optimized later 129 if needed. The idea of optimization is to provide inlineable form of putRGBADither and 130 getRGBA at least for certain most frequently used visuals. Something like this is 131 done in Java 2D ("loops"). This would be possible with C++ templates, but making it 132 clean for C would require ugly preprocessor tricks. Leaving it out for later. 133 */ 134 135 /* convert a single pixel color value from rgbquad according to visual format 136 and place it to pointed location 137 ordered dithering used when necessary */ 138 INLINE void 139 putRGBADither(rgbquad_t value, void *ptr, ImageFormat * format, 140 int row, int col) 141 { 142 if (format->premultiplied) { 143 value = premultiplyRGBA(value); 144 } 145 if (format->dithers) { 146 value = format->colorIndex[ditherColor(value, format, row, col)]; 147 } 148 else { 149 value = CONVCOMP(value, format, 0) | CONVCOMP(value, format, 1) | 150 CONVCOMP(value, format, 2) | CONVCOMP(value, format, 3); 151 } 152 switch (format->byteOrder) { 153 case BYTE_ORDER_LSBFIRST: 154 switch (format->depthBytes) { /* lack of *break*'s is intentional */ 155 case 4: 156 PUT(byte_t, ptr, value & 0xff); 157 value >>= 8; 158 INCP(byte_t, ptr); 159 case 3: 160 PUT(byte_t, ptr, value & 0xff); 161 value >>= 8; 162 INCP(byte_t, ptr); 163 case 2: 164 PUT(byte_t, ptr, value & 0xff); 165 value >>= 8; 166 INCP(byte_t, ptr); 167 case 1: 168 PUT(byte_t, ptr, value & 0xff); 169 } 170 break; 171 case BYTE_ORDER_MSBFIRST: 172 switch (format->depthBytes) { /* lack of *break*'s is intentional */ 173 case 4: 174 PUT(byte_t, ptr, (value >> 24) & 0xff); 175 INCP(byte_t, ptr); 176 case 3: 177 PUT(byte_t, ptr, (value >> 16) & 0xff); 178 INCP(byte_t, ptr); 179 case 2: 180 PUT(byte_t, ptr, (value >> 8) & 0xff); 181 INCP(byte_t, ptr); 182 case 1: 183 PUT(byte_t, ptr, value & 0xff); 184 } 185 break; 186 case BYTE_ORDER_NATIVE: 187 switch (format->depthBytes) { 188 case 4: 189 PUT(rgbquad_t, ptr, value); 190 break; 191 case 3: /* not supported, LSB or MSB should always be specified */ 192 *(int *) 0 = 0; /* crash */ 193 break; 194 case 2: 195 PUT(word_t, ptr, value); 196 break; 197 case 1: 198 PUT(byte_t, ptr, value); 199 break; 200 } 201 } 202 } 203 204 /* load a single pixel color value and un-convert it to rgbquad according to visual format */ 205 INLINE rgbquad_t 206 getRGBA(void *ptr, ImageFormat * format) 207 { 208 /* 209 FIXME: color is not un-alpha-premultiplied on get 210 this is not required by current code, but it makes the implementation inconsistent 211 i.e. put(get) will not work right for alpha-premultiplied images */ 212 213 /* get the value basing on depth and byte order */ 214 rgbquad_t value = 0; 215 216 switch (format->byteOrder) { 217 case BYTE_ORDER_LSBFIRST: 218 switch (format->depthBytes) { 219 case 4: 220 value |= GET(byte_t, ptr); 221 value <<= 8; 222 INCP(byte_t, ptr); 223 case 3: 224 value |= GET(byte_t, ptr); 225 value <<= 8; 226 INCP(byte_t, ptr); 227 case 2: 228 value |= GET(byte_t, ptr); 229 value <<= 8; 230 INCP(byte_t, ptr); 231 case 1: 232 value |= GET(byte_t, ptr); 233 } 234 break; 235 case BYTE_ORDER_MSBFIRST: 236 switch (format->depthBytes) { /* lack of *break*'s is intentional */ 237 case 4: 238 value |= (GET(byte_t, ptr) << 24); 239 INCP(byte_t, ptr); 240 case 3: 241 value |= (GET(byte_t, ptr) << 16); 242 INCP(byte_t, ptr); 243 case 2: 244 value |= (GET(byte_t, ptr) << 8); 245 INCP(byte_t, ptr); 246 case 1: 247 value |= GET(byte_t, ptr); 248 } 249 break; 250 case BYTE_ORDER_NATIVE: 251 switch (format->depthBytes) { 252 case 4: 253 value = GET(rgbquad_t, ptr); 254 break; 255 case 3: /* not supported, LSB or MSB should always be specified */ 256 *(int *) 0 = 0; 257 break; 258 case 2: 259 value = (rgbquad_t) GET(word_t, ptr); 260 break; 261 case 1: 262 value = (rgbquad_t) GET(byte_t, ptr); 263 break; 264 } 265 break; 266 } 267 /* now un-convert the value */ 268 if (format->colorMap) { 269 if (value == format->transparentColor) 270 return 0; 271 else 272 return format->colorMap[value]; 273 } 274 else { 275 return UNCONVCOMP(value, format, 0) | UNCONVCOMP(value, format, 1) | 276 UNCONVCOMP(value, format, 2) | UNCONVCOMP(value, format, 3) | 277 format->fixedBits; 278 } 279 } 280 281 /* fill the line with the specified color according to visual format */ 282 INLINE void 283 fillLine(rgbquad_t color, void *pDst, int incDst, int n, 284 ImageFormat * dstFormat, int row, int col) 285 { 286 int i; 287 288 for (i = 0; i < n; ++i) { 289 putRGBADither(color, pDst, dstFormat, row, col++); 290 INCPN(byte_t, pDst, incDst); 291 } 292 } 293 294 /* find the shift for specified mask, also verify the mask is valid */ 295 INLINE int 296 getMaskShift(rgbquad_t mask, int *pShift, int *pnumBits) 297 { 298 int shift = 0, numBits = 0; 299 300 /* check the mask is not empty */ 301 if (!mask) 302 return 0; 303 /* calculate the shift */ 304 while ((mask & 1) == 0) { 305 ++shift; 306 mask >>= 1; 307 } 308 /* check the mask is contigious */ 309 if ((mask & (mask + 1)) != 0) 310 return 0; 311 /* calculate the number of bits */ 312 do { 313 ++numBits; 314 mask >>= 1; 315 } while ((mask & 1) != 0); 316 *pShift = shift; 317 *pnumBits = numBits; 318 return 1; 319 } 320 321 #endif