optional icu diff.
[AROS.git] / rom / hidds / gfx / gfx_bitmapconvertpixels.c
blob0eb15636a37c7c43ebabc1330d03a681eaf43d2a
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <string.h>
8 #include <hidd/gfx.h>
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)
24 #if AROS_BIG_ENDIAN
25 #define GETPIX24(s, pix) \
26 do \
27 { \
28 pix = (((UBYTE *)s)[0] << 16) | \
29 (((UBYTE *)s)[1] << 8) | \
30 ((UBYTE *)s)[2]; \
31 s = (UBYTE *)s + 3; \
32 } while (0);
34 #else
35 #define GETPIX24(s, pix) \
36 do \
37 { \
38 pix = (((UBYTE *)s)[2] << 16) | \
39 (((UBYTE *)s)[1] << 8) | \
40 ((UBYTE *)s)[0]; \
41 s = (UBYTE *)s + 3; \
42 } while (0);
44 #endif
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) \
60 GETPIX16OE(s, pix); \
61 else \
62 GETPIX16(s, pix); \
63 break; \
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; \
74 } \
75 pix = lut[pix];
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)
89 #if AROS_BIG_ENDIAN
90 #define PUTPIX24(d, pix) \
91 do \
92 { \
93 ((UBYTE *)d)[0] = (UBYTE)((pix >> 16) & 0x000000FF); \
94 ((UBYTE *)d)[1] = (UBYTE)((pix >> 8 ) & 0x000000FF); \
95 ((UBYTE *)d)[2] = (UBYTE)( pix & 0x000000FF); \
96 d = (UBYTE *)d + 3; \
97 } while (0)
98 #else
99 #define PUTPIX24(d, pix) \
100 do \
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; \
106 } while (0)
108 #endif
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); \
125 else \
126 PUTPIX16(d, pix); \
127 break; \
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;
163 INIT_VARS()
164 INIT_FMTVARS()
166 LONG x, y;
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;
175 #if 0
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",
181 srcfmt->alpha_mask,
182 srcfmt->red_mask,
183 srcfmt->green_mask,
184 srcfmt->blue_mask);
185 bug("destmasks = %p %p %p %p diffs = %d %d %d %d\n",
186 dstfmt->alpha_mask,
187 dstfmt->red_mask,
188 dstfmt->green_mask,
189 dstfmt->blue_mask,
190 alpha_diff,
191 red_diff,
192 green_diff,
193 blue_diff);
194 #endif
195 for (y = 0; y < msg->height; y ++)
197 UBYTE * s = src;
198 UBYTE * d = dst;
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);
212 #if 0
213 bug("[ %p, %p, %p, %p ] "
214 , srcpix
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);
219 #endif
221 /* Write the pixel to the destination buffer */
222 PUT_TRUE_PIX(d, dstpix, dstfmt);
224 } /* for (x) */
226 src += msg->srcMod;
227 dst += msg->dstMod;
229 } /* for (y) */
231 *msg->srcPixels = src;
232 *msg->dstBuf = dst;
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;
243 INIT_VARS()
244 INIT_FMTVARS()
245 ULONG x, y, c;
246 ULONG cols;
248 D(bug("[ConvertPixels] true_to_pal(): pixlut is 0x%p, colormap is 0x%p\n", lut, cmap));
250 if (lut)
251 cols = lut->entries;
252 else if (cmap)
253 cols = cmap->entries;
254 else
255 cols = 0;
257 for (y = 0; y < msg->height; y ++)
259 UBYTE * s = src;
260 UBYTE * d = dst;
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;
268 ULONG a, r, g, b;
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;
280 ULONG distance;
282 D(bug("[ConvertPixels] Checking against %u ", c));
283 if (lut)
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);
291 else
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;
305 dstpix = c;
309 D(bug("[ConvertPixels] Found color %u\n", dstpix));
310 PUT_PAL_PIX(d, dstpix, dstfmt);
312 src += msg->srcMod;
313 dst += msg->dstMod;
316 *msg->srcPixels = src;
317 *msg->dstBuf = dst;
320 static VOID pal_to_true(OOP_Class *cl, OOP_Object *o,
321 struct pHidd_BitMap_ConvertPixels *msg)
323 HIDDT_PixelLUT *lut;
324 struct HIDDBitMapData *data = OOP_INST_DATA(cl, o);
326 INIT_VARS()
327 INIT_FMTVARS()
329 LONG x, y;
331 lut = msg->pixlut;
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 ++)
337 APTR s = src;
338 APTR d = dst;
340 for (x = 0; x < msg->width; x ++)
342 ULONG srcpix = 0;
344 if (lut)
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);
352 else
354 if (data->colmap)
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
361 buffer. */
362 GET_PAL_PIX_CM(s, srcpix, srcfmt);
363 HIDD_CM_GetColor(data->colmap, srcpix, &col);
364 red = col.red;
365 green = col.green;
366 blue = col.blue;
367 alpha = col.alpha;
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);
378 src += msg->srcMod;
379 dst += msg->dstMod;
380 DB2(bug("\n"));
383 *msg->srcPixels = src;
384 *msg->dstBuf = dst;
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 */
403 else
405 /* Convert pixel-by pixel */
408 return;
411 /****************************************************************************************/
413 static void native32_to_native(OOP_Class *cl, OOP_Object *o,
414 struct pHidd_BitMap_ConvertPixels *msg)
416 INIT_VARS()
417 HIDDT_PixelFormat *dstfmt = msg->dstPixFmt;
418 LONG x, y;
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 ++)
425 UBYTE *d = dst;
426 UBYTE *s = src;
428 for (x = 0; x < msg->width; x ++)
431 switch (dstfmt->bytes_per_pixel)
433 case 4:
434 *(ULONG *)d = (ULONG)*((HIDDT_Pixel *)s);
435 d += 4; s += sizeof(HIDDT_Pixel);
436 break;
438 case 3:
440 HIDDT_Pixel dstpix;
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);
449 break;
452 case 2:
453 *((UWORD *)d) = (UWORD)(*((HIDDT_Pixel *)s));
454 d += 2; s += sizeof(HIDDT_Pixel);
455 break;
457 case 1:
458 *d = (UBYTE)*((HIDDT_Pixel *)s);
459 d += 1; s += sizeof(HIDDT_Pixel);
460 break;
462 #if 0
463 case 0:
464 if (dstfmt->depth == 1)
466 UBYTE mask;
468 mask = XCOORD_TO_MASK(x);
469 d = ((UBYTE *)dst) + XCOORD_TO_BYTEIDX(x);
470 if (*((HIDDT_Pixel *)s) ++) {
471 *((UBYTE *)d) |= mask;
472 } else {
473 *((UBYTE *)d) &= ~mask;
476 break;
477 #endif
479 } /* switch() */
481 } /* for (x) */
483 src += msg->srcMod;
484 dst += msg->dstMod;
488 *msg->srcPixels = src;
489 *msg->dstBuf = dst;
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 */
498 INIT_VARS()
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);
508 else
510 ULONG i;
511 ULONG copy_width;
513 copy_width = msg->width * srcfmt->bytes_per_pixel;
515 for (i = 0; i < msg->height; i ++)
517 memcpy(dst, src, copy_width);
518 src += msg->srcMod;
519 dst += msg->dstMod;
523 *msg->srcPixels = src;
524 *msg->dstBuf = dst;
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);
560 return;
564 if (srcfmt->stdpixfmt == vHidd_StdPixFmt_Native32
565 && dstfmt->stdpixfmt == vHidd_StdPixFmt_Native)
567 native32_to_native(cl, o, msg);
568 return;
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];
594 if (f)
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);
603 break;
609 true_to_true(cl, o, msg);
610 break;
613 case vHidd_ColorModel_Palette:
614 case vHidd_ColorModel_StaticPalette:
615 true_to_pal(cl, o, msg);
616 break;
618 break;
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);
626 break;
628 case vHidd_ColorModel_Palette:
629 case vHidd_ColorModel_StaticPalette:
630 pal_to_pal(cl,o, msg);
631 break;
634 break;
637 return;
640 /****************************************************************************************/