2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
8 #include <hidd/graphics.h>
9 #include "graphics_intern.h"
11 /****************************************************************************************
13 * FIXME: Does not yet handle SwapPixelBytes flag of HIDDT_PixelFormat structure!
15 ****************************************************************************************/
17 #define SHIFT_PIX(pix, shift) \
18 (( (shift) < 0) ? (pix) >> (-shift) : (pix) << (shift) )
21 #define GETPIX32(s, pix) \
22 do { pix = *(ULONG *)s; s = (UBYTE *)s + 4; } while (0)
25 #define GETPIX24(s, pix) \
28 pix = (((UBYTE *)s)[0] << 16) | \
29 (((UBYTE *)s)[1] << 8) | \
35 #define GETPIX24(s, pix) \
38 pix = (((UBYTE *)s)[2] << 16) | \
39 (((UBYTE *)s)[1] << 8) | \
46 #define GETPIX16(s, pix) \
47 do { pix = *(UWORD *)s; s = (UBYTE *)s + 2; } while (0)
48 #define GETPIX16OE(s, pix) \
49 do { pix = AROS_SWAP_BYTES_WORD(*(UWORD *)s); s = (UBYTE *)s + 2; } while (0)
52 #define GETPIX8(s, pix) \
53 do { pix = *(BYTE *)s; s = (UBYTE *)s + 1; } while (0)
55 #define GET_TRUE_PIX(s, pix, pf) \
56 switch ((pf)->bytes_per_pixel) { \
57 case 4: GETPIX32(s, pix); break; \
58 case 3: GETPIX24(s, pix); break; \
59 case 2: if ((pf)->flags & vHidd_PixFmt_SwapPixelBytes_Flag) \
64 default: D(bug("RUBBISH BYTES PER PIXEL IN GET_TRUE_PIX()\n")); break; \
67 #define GET_PAL_PIX(s, pix, pf, lut) \
68 switch (pf->bytes_per_pixel) { \
69 case 4: GETPIX32(s, pix); break; \
70 case 3: GETPIX24(s, pix); break; \
71 case 2: GETPIX16(s, pix); break; \
72 case 1: GETPIX8 (s, pix); break; \
73 default: D(bug("RUBBISH BYTES PER PIXEL IN GET_PAL_PIX()\n")); break; \
77 #define PUT_PAL_PIX(d, pix, pf) \
78 switch (pf->bytes_per_pixel) { \
79 case 4: PUTPIX32(d, pix); break; \
80 case 3: PUTPIX24(d, pix); break; \
81 case 2: PUTPIX16(d, pix); break; \
82 case 1: PUTPIX8 (d, pix); break; \
83 default: D(bug("RUBBISH BYTES PER PIXEL IN PUT_TRUE_PIX_CM()\n")); break; \
86 #define PUTPIX32(d, pix) \
87 do { *(ULONG *)d = pix; d = (UBYTE *)d + 4; } while (0)
90 #define PUTPIX24(d, pix) \
93 ((UBYTE *)d)[0] = (UBYTE)((pix >> 16) & 0x000000FF); \
94 ((UBYTE *)d)[1] = (UBYTE)((pix >> 8 ) & 0x000000FF); \
95 ((UBYTE *)d)[2] = (UBYTE)( pix & 0x000000FF); \
99 #define PUTPIX24(d, pix) \
102 ((UBYTE *)d)[2] = (UBYTE)((pix >> 16) & 0x000000FF); \
103 ((UBYTE *)d)[1] = (UBYTE)((pix >> 8 ) & 0x000000FF); \
104 ((UBYTE *)d)[0] = (UBYTE)( pix & 0x000000FF); \
105 d = (UBYTE *)d + 3; \
110 #define PUTPIX16(d, pix) \
111 do { *(UWORD *)d = pix; d = (UBYTE *)d + 2; } while (0)
113 #define PUTPIX16OE(d, pix) \
114 do { *(UWORD *)d = AROS_SWAP_BYTES_WORD(pix); d = (UBYTE *)d + 2; } while (0)
116 #define PUTPIX8(s, pix) \
117 do { *(BYTE *)s = pix; s = (UBYTE *)s + 1; } while (0)
119 #define PUT_TRUE_PIX(d, pix, pf) \
120 switch (pf->bytes_per_pixel) { \
121 case 4: PUTPIX32(d, pix); break; \
122 case 3: PUTPIX24(d, pix); break; \
123 case 2: if ((pf)->flags & vHidd_PixFmt_SwapPixelBytes_Flag) \
124 PUTPIX16OE(d, pix); \
128 default: D(bug("RUBBISH BYTES PER PIXEL IN PUT_TRUE_PIX()\n")); break; \
131 #define GET_PAL_PIX_CM(s, pix, pf) \
132 switch (pf->bytes_per_pixel) { \
133 case 4: GETPIX32(s, pix); break; \
134 case 3: GETPIX24(s, pix); break; \
135 case 2: GETPIX16(s, pix); break; \
136 case 1: GETPIX8 (s, pix); break; \
137 default: D(bug("RUBBISH BYTES PER PIXEL IN GET_PAL_PIX_CM()\n")); break; \
140 #define PUT_TRUE_PIX_CM(d, pix, pf) \
141 switch (pf->bytes_per_pixel) { \
142 case 4: PUTPIX32(d, pix); break; \
143 case 3: PUTPIX24(d, pix); break; \
144 case 2: PUTPIX16(d, pix); break; \
145 default: D(bug("RUBBISH BYTES PER PIXEL IN PUT_TRUE_PIX_CM()\n")); break; \
148 #define INIT_VARS() \
149 UBYTE *src = *msg->srcPixels; \
150 UBYTE *dst = *msg->dstBuf; \
152 #define INIT_FMTVARS() \
153 HIDDT_PixelFormat *srcfmt = msg->srcPixFmt; \
154 HIDDT_PixelFormat *dstfmt = msg->dstPixFmt;
156 /****************************************************************************************/
158 static VOID
true_to_true(OOP_Class
*cl
, OOP_Object
*o
,
159 struct pHidd_BitMap_ConvertPixels
*msg
)
161 LONG alpha_diff
, red_diff
, green_diff
, blue_diff
;
169 alpha_diff
= srcfmt
->alpha_shift
- dstfmt
->alpha_shift
;
170 red_diff
= srcfmt
->red_shift
- dstfmt
->red_shift
;
171 green_diff
= srcfmt
->green_shift
- dstfmt
->green_shift
;
172 blue_diff
= srcfmt
->blue_shift
- dstfmt
->blue_shift
;
176 bug("true_to_true()\n: src = %x dest = %x srcfmt = %d %d %d %d [%d] destfmt = %d %d %d %d [%d]\n",
177 src
, dst
, srcfmt
->alpha_shift
, srcfmt
->red_shift
, srcfmt
->green_shift
, srcfmt
->blue_shift
, srcfmt
->bytes_per_pixel
,
178 dstfmt
->alpha_shift
, dstfmt
->red_shift
, dstfmt
->green_shift
, dstfmt
->blue_shift
, dstfmt
->bytes_per_pixel
);
180 bug("srcmasks = %p %p %p %p\n",
185 bug("destmasks = %p %p %p %p diffs = %d %d %d %d\n",
195 for (y
= 0; y
< msg
->height
; y
++)
200 for (x
= 0; x
< msg
->width
; x
++)
202 /* Get the source pixel */
203 HIDDT_Pixel srcpix
= 0, dstpix
;
205 GET_TRUE_PIX(s
, srcpix
, srcfmt
);
207 dstpix
= (SHIFT_PIX(srcpix
& srcfmt
->alpha_mask
, alpha_diff
) & dstfmt
->alpha_mask
)
208 | (SHIFT_PIX(srcpix
& srcfmt
->red_mask
, red_diff
) & dstfmt
->red_mask
)
209 | (SHIFT_PIX(srcpix
& srcfmt
->green_mask
, green_diff
) & dstfmt
->green_mask
)
210 | (SHIFT_PIX(srcpix
& srcfmt
->blue_mask
, blue_diff
) & dstfmt
->blue_mask
);
213 bug("[ %p, %p, %p, %p ] "
215 , srcpix
& srcfmt
->blue_mask
216 , SHIFT_PIX(srcpix
& srcfmt
->blue_mask
, blue_diff
)
217 , SHIFT_PIX(srcpix
& srcfmt
->blue_mask
, blue_diff
) & dstfmt
->blue_mask
);
221 // bug("[ %p => %p ] \n", srcpix, dstpix);
222 /* Write the pixel to the destination buffer */
223 PUT_TRUE_PIX(d
, dstpix
, dstfmt
);
232 *msg
->srcPixels
= src
;
236 /****************************************************************************************/
238 static VOID
true_to_pal(OOP_Class
*cl
, OOP_Object
*o
,
239 struct pHidd_BitMap_ConvertPixels
*msg
)
241 HIDDT_PixelLUT
*lut
= msg
->pixlut
;
242 struct HIDDBitMapData
*data
= OOP_INST_DATA(cl
, o
);
243 HIDDT_ColorLUT
*cmap
= (HIDDT_ColorLUT
*)data
->colmap
;
249 D(bug("[ConvertPixels] true_to_pal(): pixlut is 0x%p, colormap is 0x%p\n", lut
, cmap
));
254 cols
= cmap
->entries
;
258 for (y
= 0; y
< msg
->height
; y
++) {
262 for (x
= 0; x
< msg
->width
; x
++) {
263 /* Get the source pixel */
264 HIDDT_Pixel srcpix
= 0;
265 HIDDT_Pixel dstpix
= 0;
266 ULONG best_distance
= (ULONG
)-1;
269 GET_TRUE_PIX(s
, srcpix
, srcfmt
);
270 a
= ALPHA_COMP(srcpix
, srcfmt
);
271 r
= RED_COMP(srcpix
, srcfmt
);
272 g
= GREEN_COMP(srcpix
, srcfmt
);
273 b
= BLUE_COMP(srcpix
, srcfmt
);
275 D(bug("[ConvertPixels] Find best match for 0x%08X\n", srcpix
));
276 for (c
= 0; c
< cols
; c
++) {
277 ULONG ca
, cr
, cg
, cb
;
280 D(bug("[ConvertPixels] Checking against %u ", c
));
282 D(bug("(0x%08lX)\n", lut
->pixels
[c
]));
283 ca
= ALPHA_COMP(lut
->pixels
[c
], srcfmt
);
284 cr
= RED_COMP(lut
->pixels
[c
], srcfmt
);
285 cg
= GREEN_COMP(lut
->pixels
[c
], srcfmt
);
286 cb
= BLUE_COMP(lut
->pixels
[c
], srcfmt
);
288 D(bug("(0x%08lX)\n", cmap
->colors
[c
].pixval
));
289 ca
= cmap
->colors
[c
].alpha
;
290 cr
= cmap
->colors
[c
].red
;
291 cg
= cmap
->colors
[c
].green
;
292 cb
= cmap
->colors
[c
].blue
;
294 distance
= color_distance(a
, r
, g
, b
, ca
, cr
, cg
, cb
);
295 D(bug("[ConvertPixels] Distance is %u\n", distance
));
296 if (distance
< best_distance
) {
297 D(bug("[ConvertPixels] Best distance was %u, new best match is %u\n", best_distance
, c
));
298 best_distance
= distance
;
303 D(bug("[ConvertPixels] Found color %u\n", dstpix
));
304 PUT_PAL_PIX(d
, dstpix
, dstfmt
);
309 *msg
->srcPixels
= src
;
313 static VOID
pal_to_true(OOP_Class
*cl
, OOP_Object
*o
,
314 struct pHidd_BitMap_ConvertPixels
*msg
)
317 struct HIDDBitMapData
*data
= OOP_INST_DATA(cl
, o
);
325 D(bug("[ConvertPixels] pal_to_true(): pixlut is 0x%p, colormap is 0x%p\n", lut
, data
->colmap
));
327 DB2(bug("[ConvertPixels] Buffer contents:\n"));
328 for (y
= 0; y
< msg
->height
; y
++)
333 for (x
= 0; x
< msg
->width
; x
++)
338 GET_PAL_PIX(s
, srcpix
, srcfmt
, lut
->pixels
);
340 DB2(bug("0x%08lX ", srcpix
));
341 /* We now have a pixel in Native32 format. Put it back */
342 PUT_TRUE_PIX(d
, srcpix
, dstfmt
);
345 HIDDT_Color col
= {0};
346 HIDDT_Pixel red
, green
, blue
, alpha
;
348 /* For optimization purposes we don't swap bytes after MAP_RGBA
349 in order not to swap them back when putting into destination
351 GET_PAL_PIX_CM(s
, srcpix
, srcfmt
);
352 HIDD_CM_GetColor(data
->colmap
, srcpix
, &col
);
357 srcpix
= MAP_RGBA(red
, green
, blue
, alpha
, dstfmt
);
359 /* If there's neither pixlut nor colormap provided
360 we'll end up in all black. At least won't crash
361 and make the problem clearly visible */
362 DB2(bug("0x%08lX ", srcpix
));
363 PUT_TRUE_PIX_CM(d
, srcpix
, dstfmt
);
371 *msg
->srcPixels
= src
;
375 /****************************************************************************************/
377 static VOID
pal_to_pal(OOP_Class
*cl
, OOP_Object
*o
,
378 struct pHidd_BitMap_ConvertPixels
*msg
)
380 HIDDT_PixelFormat
*spf
, *dpf
;
382 spf
= msg
->srcPixFmt
;
383 dpf
= msg
->dstPixFmt
;
386 if ( spf
->clut_shift
== dpf
->clut_shift
387 && spf
->clut_mask
== dpf
->clut_mask
)
389 /* This one is rather easy, just copy the data */
394 /* Convert pixel-by pixel */
401 /****************************************************************************************/
403 static void native32_to_native(OOP_Class
*cl
, OOP_Object
*o
,
404 struct pHidd_BitMap_ConvertPixels
*msg
)
407 HIDDT_PixelFormat
*dstfmt
= msg
->dstPixFmt
;
410 D(bug("SRC: Native32, DST: Native, height=%d, width=%d, bytes per pixel: %d, srcmod: %d, dstmod: %d, depth: %d\n"
411 , msg
->height
, msg
->width
, dstfmt
->bytes_per_pixel
, msg
->srcMod
, msg
->dstMod
, dstfmt
->depth
));
413 for ( y
= 0; y
< msg
->height
; y
++)
418 for (x
= 0; x
< msg
->width
; x
++)
421 switch (dstfmt
->bytes_per_pixel
)
424 *(ULONG
*)d
= (ULONG
)*((HIDDT_Pixel
*)s
);
425 d
+= 4; s
+= sizeof(HIDDT_Pixel
);
432 dstpix
= *((HIDDT_Pixel
*)s
);
434 d
[0] = (UBYTE
)((dstpix
>> 16) & 0x000000FF);
435 d
[1] = (UBYTE
)((dstpix
>> 8) & 0x000000FF);
436 d
[2] = (UBYTE
)(dstpix
& 0x000000FF);
438 d
+= 3; s
+= sizeof(HIDDT_Pixel
);
443 *((UWORD
*)d
) = (UWORD
)(*((HIDDT_Pixel
*)s
));
444 d
+= 2; s
+= sizeof(HIDDT_Pixel
);
448 *d
= (UBYTE
)*((HIDDT_Pixel
*)s
);
449 d
+= 1; s
+= sizeof(HIDDT_Pixel
);
454 if (dstfmt
->depth
== 1)
458 mask
= XCOORD_TO_MASK(x
);
459 d
= ((UBYTE
*)dst
) + XCOORD_TO_BYTEIDX(x
);
460 if (*((HIDDT_Pixel
*)s
) ++) {
461 *((UBYTE
*)d
) |= mask
;
463 *((UBYTE
*)d
) &= ~mask
;
478 *msg
->srcPixels
= src
;
482 /****************************************************************************************/
484 static VOID
quick_copy(OOP_Class
*cl
, OOP_Object
*o
,
485 struct pHidd_BitMap_ConvertPixels
*msg
)
487 /* Just do a simple memcpy() of the pixels */
489 HIDDT_PixelFormat
*srcfmt
= msg
->srcPixFmt
;
490 ULONG bpl
= msg
->width
* srcfmt
->bytes_per_pixel
;
492 /* FIXME: This does not work well for formats with bytes_per_pixel < 1 */
494 if (msg
->srcMod
== bpl
&& msg
->dstMod
== bpl
)
496 memcpy(dst
, src
, bpl
* msg
->height
);
503 copy_width
= msg
->width
* srcfmt
->bytes_per_pixel
;
505 for (i
= 0; i
< msg
->height
; i
++)
507 memcpy(dst
, src
, copy_width
);
513 *msg
->srcPixels
= src
;
518 /****************************************************************************************/
520 /* TODO: Discuss this design decision: */
522 /* Should we pass HIDDT_PixelFormat * or HIDDT_StdPixFmt ?
523 The first is more flexible for the user, as he will not only be restricted
524 to standard pixek formats. However the user will have to convert
525 from HIDDT_StdPixFmt to HIDDT_PixelFormat manually.
527 In the latter case this conversion will be done inside the method below.
528 This means that we can call an internal function directly
529 to do the conversion and save two method calls.
532 /****************************************************************************************/
534 VOID
BM__Hidd_BitMap__ConvertPixels(OOP_Class
*cl
, OOP_Object
*o
,
535 struct pHidd_BitMap_ConvertPixels
*msg
)
537 /* For now we assume truecolor */
538 HIDDT_PixelFormat
*srcfmt
, *dstfmt
;
540 //bug("bitmap_convertpixels()\n");
542 srcfmt
= msg
->srcPixFmt
;
543 dstfmt
= msg
->dstPixFmt
;
546 D(bug("ConvertPixels: src=%d, dst=%d\n", srcfmt
->stdpixfmt
, dstfmt
->stdpixfmt
));
548 /* Check if source and dest are the same format */
549 if (srcfmt
->stdpixfmt
== dstfmt
->stdpixfmt
)
551 quick_copy(cl
, o
, msg
);
556 if ( srcfmt
->stdpixfmt
== vHidd_StdPixFmt_Native32
557 && dstfmt
->stdpixfmt
== vHidd_StdPixFmt_Native
)
560 native32_to_native(cl
, o
, msg
);
564 switch (HIDD_PF_COLMODEL(srcfmt
))
566 case vHidd_ColorModel_TrueColor
:
567 switch (HIDD_PF_COLMODEL(dstfmt
))
569 case vHidd_ColorModel_TrueColor
:
570 if ((srcfmt
->stdpixfmt
>= FIRST_RGB_STDPIXFMT
) &&
571 (dstfmt
->stdpixfmt
>= FIRST_RGB_STDPIXFMT
) &&
572 (srcfmt
->stdpixfmt
<= LAST_RGB_STDPIXFMT
) &&
573 (dstfmt
->stdpixfmt
<= LAST_RGB_STDPIXFMT
))
575 HIDDT_RGBConversionFunction f
;
577 ObtainSemaphoreShared(&CSD(cl
)->rgbconvertfuncs_sem
);
579 f
= CSD(cl
)->rgbconvertfuncs
[srcfmt
->stdpixfmt
- FIRST_RGB_STDPIXFMT
]
580 [dstfmt
->stdpixfmt
- FIRST_RGB_STDPIXFMT
];
584 if ((*f
)(*msg
->srcPixels
, msg
->srcMod
, srcfmt
->stdpixfmt
,
585 *msg
->dstBuf
, msg
->dstMod
, dstfmt
->stdpixfmt
,
586 msg
->width
, msg
->height
))
588 *msg
->srcPixels
+= (msg
->srcMod
* msg
->height
);
589 *msg
->dstBuf
+= (msg
->dstMod
* msg
->height
);
591 ReleaseSemaphore(&CSD(cl
)->rgbconvertfuncs_sem
);
597 ReleaseSemaphore(&CSD(cl
)->rgbconvertfuncs_sem
);
601 true_to_true(cl
, o
, msg
);
605 case vHidd_ColorModel_Palette
:
606 case vHidd_ColorModel_StaticPalette
:
607 true_to_pal(cl
, o
, msg
);
613 case vHidd_ColorModel_Palette
:
614 case vHidd_ColorModel_StaticPalette
:
615 switch (HIDD_PF_COLMODEL(dstfmt
))
617 case vHidd_ColorModel_TrueColor
:
618 pal_to_true(cl
, o
, msg
);
621 case vHidd_ColorModel_Palette
:
622 case vHidd_ColorModel_StaticPalette
:
623 pal_to_pal(cl
,o
, msg
);
633 /****************************************************************************************/