2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
9 #include "gfx_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 = *(UBYTE *)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 { *(UBYTE *)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 /* Write the pixel to the destination buffer */
222 PUT_TRUE_PIX(d
, dstpix
, dstfmt
);
231 *msg
->srcPixels
= src
;
235 /****************************************************************************************/
237 static VOID
true_to_pal(OOP_Class
*cl
, OOP_Object
*o
,
238 struct pHidd_BitMap_ConvertPixels
*msg
)
240 HIDDT_PixelLUT
*lut
= msg
->pixlut
;
241 struct HIDDBitMapData
*data
= OOP_INST_DATA(cl
, o
);
242 HIDDT_ColorLUT
*cmap
= (HIDDT_ColorLUT
*)data
->colmap
;
248 D(bug("[ConvertPixels] true_to_pal(): pixlut is 0x%p, colormap is 0x%p\n", lut
, cmap
));
253 cols
= cmap
->entries
;
257 for (y
= 0; y
< msg
->height
; y
++)
262 for (x
= 0; x
< msg
->width
; x
++)
264 /* Get the source pixel */
265 HIDDT_Pixel srcpix
= 0;
266 HIDDT_Pixel dstpix
= 0;
267 ULONG best_distance
= (ULONG
)-1;
270 GET_TRUE_PIX(s
, srcpix
, srcfmt
);
271 a
= ALPHA_COMP(srcpix
, srcfmt
);
272 r
= RED_COMP(srcpix
, srcfmt
);
273 g
= GREEN_COMP(srcpix
, srcfmt
);
274 b
= BLUE_COMP(srcpix
, srcfmt
);
276 D(bug("[ConvertPixels] Find best match for 0x%08X\n", srcpix
));
277 for (c
= 0; c
< cols
; c
++)
279 ULONG ca
, cr
, cg
, cb
;
282 D(bug("[ConvertPixels] Checking against %u ", c
));
285 D(bug("(0x%08lX)\n", lut
->pixels
[c
]));
286 ca
= ALPHA_COMP(lut
->pixels
[c
], srcfmt
);
287 cr
= RED_COMP(lut
->pixels
[c
], srcfmt
);
288 cg
= GREEN_COMP(lut
->pixels
[c
], srcfmt
);
289 cb
= BLUE_COMP(lut
->pixels
[c
], srcfmt
);
293 D(bug("(0x%08lX)\n", cmap
->colors
[c
].pixval
));
294 ca
= cmap
->colors
[c
].alpha
;
295 cr
= cmap
->colors
[c
].red
;
296 cg
= cmap
->colors
[c
].green
;
297 cb
= cmap
->colors
[c
].blue
;
299 distance
= color_distance(a
, r
, g
, b
, ca
, cr
, cg
, cb
);
300 D(bug("[ConvertPixels] Distance is %u\n", distance
));
301 if (distance
< best_distance
)
303 D(bug("[ConvertPixels] Best distance was %u, new best match is %u\n", best_distance
, c
));
304 best_distance
= distance
;
309 D(bug("[ConvertPixels] Found color %u\n", dstpix
));
310 PUT_PAL_PIX(d
, dstpix
, dstfmt
);
316 *msg
->srcPixels
= src
;
320 static VOID
pal_to_true(OOP_Class
*cl
, OOP_Object
*o
,
321 struct pHidd_BitMap_ConvertPixels
*msg
)
324 struct HIDDBitMapData
*data
= OOP_INST_DATA(cl
, o
);
332 D(bug("[ConvertPixels] pal_to_true(): pixlut is 0x%p, colormap is 0x%p\n", lut
, data
->colmap
));
334 DB2(bug("[ConvertPixels] Buffer contents:\n"));
335 for (y
= 0; y
< msg
->height
; y
++)
340 for (x
= 0; x
< msg
->width
; x
++)
346 GET_PAL_PIX(s
, srcpix
, srcfmt
, lut
->pixels
);
348 DB2(bug("0x%08lX ", srcpix
));
349 /* We now have a pixel in Native32 format. Put it back */
350 PUT_TRUE_PIX(d
, srcpix
, dstfmt
);
356 HIDDT_Color col
= {0};
357 HIDDT_Pixel red
, green
, blue
, alpha
;
359 /* For optimization purposes we don't swap bytes after MAP_RGBA
360 in order not to swap them back when putting into destination
362 GET_PAL_PIX_CM(s
, srcpix
, srcfmt
);
363 HIDD_CM_GetColor(data
->colmap
, srcpix
, &col
);
368 srcpix
= MAP_RGBA(red
, green
, blue
, alpha
, dstfmt
);
370 /* If there's neither pixlut nor colormap provided
371 we'll end up in all black. At least won't crash
372 and make the problem clearly visible */
373 DB2(bug("0x%08lX ", srcpix
));
374 PUT_TRUE_PIX_CM(d
, srcpix
, dstfmt
);
383 *msg
->srcPixels
= src
;
387 /****************************************************************************************/
389 static VOID
pal_to_pal(OOP_Class
*cl
, OOP_Object
*o
,
390 struct pHidd_BitMap_ConvertPixels
*msg
)
392 HIDDT_PixelFormat
*spf
, *dpf
;
394 spf
= msg
->srcPixFmt
;
395 dpf
= msg
->dstPixFmt
;
398 if (spf
->clut_shift
== dpf
->clut_shift
399 && spf
->clut_mask
== dpf
->clut_mask
)
401 /* This one is rather easy, just copy the data */
405 /* Convert pixel-by pixel */
411 /****************************************************************************************/
413 static void native32_to_native(OOP_Class
*cl
, OOP_Object
*o
,
414 struct pHidd_BitMap_ConvertPixels
*msg
)
417 HIDDT_PixelFormat
*dstfmt
= msg
->dstPixFmt
;
420 D(bug("SRC: Native32, DST: Native, height=%d, width=%d, bytes per pixel: %d, srcmod: %d, dstmod: %d, depth: %d\n"
421 , msg
->height
, msg
->width
, dstfmt
->bytes_per_pixel
, msg
->srcMod
, msg
->dstMod
, dstfmt
->depth
));
423 for ( y
= 0; y
< msg
->height
; y
++)
428 for (x
= 0; x
< msg
->width
; x
++)
431 switch (dstfmt
->bytes_per_pixel
)
434 *(ULONG
*)d
= (ULONG
)*((HIDDT_Pixel
*)s
);
435 d
+= 4; s
+= sizeof(HIDDT_Pixel
);
442 dstpix
= *((HIDDT_Pixel
*)s
);
444 d
[0] = (UBYTE
)((dstpix
>> 16) & 0x000000FF);
445 d
[1] = (UBYTE
)((dstpix
>> 8) & 0x000000FF);
446 d
[2] = (UBYTE
)(dstpix
& 0x000000FF);
448 d
+= 3; s
+= sizeof(HIDDT_Pixel
);
453 *((UWORD
*)d
) = (UWORD
)(*((HIDDT_Pixel
*)s
));
454 d
+= 2; s
+= sizeof(HIDDT_Pixel
);
458 *d
= (UBYTE
)*((HIDDT_Pixel
*)s
);
459 d
+= 1; s
+= sizeof(HIDDT_Pixel
);
464 if (dstfmt
->depth
== 1)
468 mask
= XCOORD_TO_MASK(x
);
469 d
= ((UBYTE
*)dst
) + XCOORD_TO_BYTEIDX(x
);
470 if (*((HIDDT_Pixel
*)s
) ++) {
471 *((UBYTE
*)d
) |= mask
;
473 *((UBYTE
*)d
) &= ~mask
;
488 *msg
->srcPixels
= src
;
492 /****************************************************************************************/
494 static VOID
quick_copy(OOP_Class
*cl
, OOP_Object
*o
,
495 struct pHidd_BitMap_ConvertPixels
*msg
)
497 /* Just do a simple memcpy() of the pixels */
499 HIDDT_PixelFormat
*srcfmt
= msg
->srcPixFmt
;
500 ULONG bpl
= msg
->width
* srcfmt
->bytes_per_pixel
;
502 /* FIXME: This does not work well for formats with bytes_per_pixel < 1 */
504 if (msg
->srcMod
== bpl
&& msg
->dstMod
== bpl
)
506 memcpy(dst
, src
, bpl
* msg
->height
);
513 copy_width
= msg
->width
* srcfmt
->bytes_per_pixel
;
515 for (i
= 0; i
< msg
->height
; i
++)
517 memcpy(dst
, src
, copy_width
);
523 *msg
->srcPixels
= src
;
528 /****************************************************************************************/
530 /* TODO: Discuss this design decision: */
532 /* Should we pass HIDDT_PixelFormat * or HIDDT_StdPixFmt ?
533 The first is more flexible for the user, as he will not only be restricted
534 to standard pixel formats. However the user will have to convert
535 from HIDDT_StdPixFmt to HIDDT_PixelFormat manually.
537 In the latter case this conversion will be done inside the method below.
538 This means that we can call an internal function directly
539 to do the conversion and save two method calls.
542 /****************************************************************************************/
544 VOID
BM__Hidd_BitMap__ConvertPixels(OOP_Class
*cl
, OOP_Object
*o
,
545 struct pHidd_BitMap_ConvertPixels
*msg
)
547 /* For now we assume truecolor */
548 HIDDT_PixelFormat
*srcfmt
, *dstfmt
;
550 srcfmt
= msg
->srcPixFmt
;
551 dstfmt
= msg
->dstPixFmt
;
554 D(bug("ConvertPixels: src=%d, dst=%d\n", srcfmt
->stdpixfmt
, dstfmt
->stdpixfmt
));
556 /* Check if source and dest are the same format */
557 if (srcfmt
->stdpixfmt
== dstfmt
->stdpixfmt
)
559 quick_copy(cl
, o
, msg
);
564 if (srcfmt
->stdpixfmt
== vHidd_StdPixFmt_Native32
565 && dstfmt
->stdpixfmt
== vHidd_StdPixFmt_Native
)
567 native32_to_native(cl
, o
, msg
);
571 switch (HIDD_PF_COLMODEL(srcfmt
))
573 case vHidd_ColorModel_TrueColor
:
574 switch (HIDD_PF_COLMODEL(dstfmt
))
576 case vHidd_ColorModel_TrueColor
:
577 if ((srcfmt
->stdpixfmt
>= FIRST_RGB_STDPIXFMT
) &&
578 (dstfmt
->stdpixfmt
>= FIRST_RGB_STDPIXFMT
) &&
579 (srcfmt
->stdpixfmt
<= LAST_RGB_STDPIXFMT
) &&
580 (dstfmt
->stdpixfmt
<= LAST_RGB_STDPIXFMT
))
582 HIDDT_RGBConversionFunction f
;
584 /* No semaphore protection here because:
585 * a) rgbconvertfuncs is never reallocated
586 * b) accesing a pointer is atomic
587 * c) semaphore does not protect from someone unloading the code
588 * without unregistering
591 f
= CSD(cl
)->rgbconvertfuncs
[srcfmt
->stdpixfmt
- FIRST_RGB_STDPIXFMT
]
592 [dstfmt
->stdpixfmt
- FIRST_RGB_STDPIXFMT
];
596 if ((*f
)(*msg
->srcPixels
, msg
->srcMod
, srcfmt
->stdpixfmt
,
597 *msg
->dstBuf
, msg
->dstMod
, dstfmt
->stdpixfmt
,
598 msg
->width
, msg
->height
))
600 *msg
->srcPixels
+= (msg
->srcMod
* msg
->height
);
601 *msg
->dstBuf
+= (msg
->dstMod
* msg
->height
);
609 true_to_true(cl
, o
, msg
);
613 case vHidd_ColorModel_Palette
:
614 case vHidd_ColorModel_StaticPalette
:
615 true_to_pal(cl
, o
, msg
);
620 case vHidd_ColorModel_Palette
:
621 case vHidd_ColorModel_StaticPalette
:
622 switch (HIDD_PF_COLMODEL(dstfmt
))
624 case vHidd_ColorModel_TrueColor
:
625 pal_to_true(cl
, o
, msg
);
628 case vHidd_ColorModel_Palette
:
629 case vHidd_ColorModel_StaticPalette
:
630 pal_to_pal(cl
,o
, msg
);
640 /****************************************************************************************/