Fix IO memory access .. SB128 driver makes noises in VMWare - CMI is untested (Curren...
[AROS.git] / rom / hidds / graphics / convertpixels.c
blobd35ba90d785f4a2b727821ca405121ebf9baf3ec
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <string.h>
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)
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 = *(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) \
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 { *(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); \
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 // bug("[ %p => %p ] \n", srcpix, dstpix);
222 /* Write the pixel to the destination buffer */
223 PUT_TRUE_PIX(d, dstpix, dstfmt);
225 } /* for (x) */
227 src += msg->srcMod;
228 dst += msg->dstMod;
230 } /* for (y) */
232 *msg->srcPixels = src;
233 *msg->dstBuf = dst;
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;
244 INIT_VARS()
245 INIT_FMTVARS()
246 ULONG x, y, c;
247 ULONG cols;
249 D(bug("[ConvertPixels] true_to_pal(): pixlut is 0x%p, colormap is 0x%p\n", lut, cmap));
251 if (lut)
252 cols = lut->entries;
253 else if (cmap)
254 cols = cmap->entries;
255 else
256 cols = 0;
258 for (y = 0; y < msg->height; y ++) {
259 UBYTE * s = src;
260 UBYTE * d = dst;
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;
267 ULONG a, r, g, b;
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;
278 ULONG distance;
280 D(bug("[ConvertPixels] Checking against %u ", c));
281 if (lut) {
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);
287 } else {
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;
299 dstpix = c;
303 D(bug("[ConvertPixels] Found color %u\n", dstpix));
304 PUT_PAL_PIX(d, dstpix, dstfmt);
306 src += msg->srcMod;
307 dst += msg->dstMod;
309 *msg->srcPixels = src;
310 *msg->dstBuf = dst;
313 static VOID pal_to_true(OOP_Class *cl, OOP_Object *o,
314 struct pHidd_BitMap_ConvertPixels *msg)
316 HIDDT_PixelLUT *lut;
317 struct HIDDBitMapData *data = OOP_INST_DATA(cl, o);
319 INIT_VARS()
320 INIT_FMTVARS()
322 LONG x, y;
324 lut = msg->pixlut;
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 ++)
330 APTR s = src;
331 APTR d = dst;
333 for (x = 0; x < msg->width; x ++)
335 ULONG srcpix = 0;
337 if (lut) {
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);
343 } else {
344 if (data->colmap) {
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
350 buffer. */
351 GET_PAL_PIX_CM(s, srcpix, srcfmt);
352 HIDD_CM_GetColor(data->colmap, srcpix, &col);
353 red = col.red;
354 green = col.green;
355 blue = col.blue;
356 alpha = col.alpha;
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);
366 src += msg->srcMod;
367 dst += msg->dstMod;
368 DB2(bug("\n"));
371 *msg->srcPixels = src;
372 *msg->dstBuf = dst;
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 */
392 else
394 /* Convert pixel-by pixel */
398 return;
401 /****************************************************************************************/
403 static void native32_to_native(OOP_Class *cl, OOP_Object *o,
404 struct pHidd_BitMap_ConvertPixels *msg)
406 INIT_VARS()
407 HIDDT_PixelFormat *dstfmt = msg->dstPixFmt;
408 LONG x, y;
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 ++)
415 UBYTE *d = dst;
416 UBYTE *s = src;
418 for (x = 0; x < msg->width; x ++)
421 switch (dstfmt->bytes_per_pixel)
423 case 4:
424 *(ULONG *)d = (ULONG)*((HIDDT_Pixel *)s);
425 d += 4; s += sizeof(HIDDT_Pixel);
426 break;
428 case 3:
430 HIDDT_Pixel dstpix;
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);
439 break;
442 case 2:
443 *((UWORD *)d) = (UWORD)(*((HIDDT_Pixel *)s));
444 d += 2; s += sizeof(HIDDT_Pixel);
445 break;
447 case 1:
448 *d = (UBYTE)*((HIDDT_Pixel *)s);
449 d += 1; s += sizeof(HIDDT_Pixel);
450 break;
452 #if 0
453 case 0:
454 if (dstfmt->depth == 1)
456 UBYTE mask;
458 mask = XCOORD_TO_MASK(x);
459 d = ((UBYTE *)dst) + XCOORD_TO_BYTEIDX(x);
460 if (*((HIDDT_Pixel *)s) ++) {
461 *((UBYTE *)d) |= mask;
462 } else {
463 *((UBYTE *)d) &= ~mask;
466 break;
467 #endif
469 } /* switch() */
471 } /* for (x) */
473 src += msg->srcMod;
474 dst += msg->dstMod;
478 *msg->srcPixels = src;
479 *msg->dstBuf = dst;
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 */
488 INIT_VARS()
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);
498 else
500 ULONG i;
501 ULONG copy_width;
503 copy_width = msg->width * srcfmt->bytes_per_pixel;
505 for (i = 0; i < msg->height; i ++)
507 memcpy(dst, src, copy_width);
508 src += msg->srcMod;
509 dst += msg->dstMod;
513 *msg->srcPixels = src;
514 *msg->dstBuf = dst;
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);
552 return;
556 if ( srcfmt->stdpixfmt == vHidd_StdPixFmt_Native32
557 && dstfmt->stdpixfmt == vHidd_StdPixFmt_Native )
560 native32_to_native(cl, o, msg);
561 return;
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];
582 if (f)
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);
592 break;
597 ReleaseSemaphore(&CSD(cl)->rgbconvertfuncs_sem);
601 true_to_true(cl, o, msg);
602 break;
605 case vHidd_ColorModel_Palette:
606 case vHidd_ColorModel_StaticPalette:
607 true_to_pal(cl, o, msg);
608 break;
611 break;
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);
619 break;
621 case vHidd_ColorModel_Palette:
622 case vHidd_ColorModel_StaticPalette:
623 pal_to_pal(cl,o, msg);
624 break;
627 break;
630 return;
633 /****************************************************************************************/