Cancel redefinition of DOSBase for the 'cdrom' test utility. Now the
[AROS.git] / workbench / classes / datatypes / picture / colorhandling.c
blobdd5d27d690288208815ebfabea4f28ba793dbc7a
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #include <exec/memory.h>
11 #include <graphics/gfxbase.h>
12 #include <graphics/rpattr.h>
13 #include <intuition/imageclass.h>
14 #include <intuition/icclass.h>
15 #include <intuition/gadgetclass.h>
16 #include <intuition/cghooks.h>
17 #include <datatypes/datatypesclass.h>
18 #include <datatypes/pictureclass.h>
19 #include <cybergraphx/cybergraphics.h>
21 #include <clib/alib_protos.h>
22 #include <proto/exec.h>
23 #include <proto/intuition.h>
24 #include <proto/graphics.h>
25 #include <proto/utility.h>
26 #include <proto/cybergraphics.h>
28 #include "debug.h"
29 #include "pictureclass.h"
30 #include "colorhandling.h"
32 static void ScaleLineSimple( UBYTE *srcxptr, UBYTE *destxptr, ULONG destwidth, UWORD srcpixelbytes, ULONG xscale );
33 static BOOL ScaleArraySimple( struct Picture_Data *pd, struct RastPort rp );
34 static UBYTE * AllocLineBuffer( long width, long height, int pixelbytes );
35 static void CopyColTable( struct Picture_Data *pd );
36 static BOOL RemapCM2CM( struct Picture_Data *pd );
37 static BOOL RemapTC2CM( struct Picture_Data *pd );
38 static int HistSort( const void *HistEntry1, const void *HistEntry2 );
39 static void RemapPens( struct Picture_Data *pd, int NumColors, int DestNumColors );
41 /**************************************************************************************************/
43 static const UBYTE defcolmap[] =
45 0,118,14,117,116,15,115,4,233,232,234,230,229,228,251,162,
46 30,70,29,127,114,28,79,19,149,227,246,226,225,224,223,245,
47 244,222,221,220,219,161,218,217,27,113,22,108,111,23,110,31,
48 216,215,214,213,212,134,132,143,5,109,13,106,107,17,120,7,
49 50,105,37,104,103,63,68,61,211,210,243,145,138,148,254,208,
50 58,67,2,80,81,44,82,45,242,152,207,206,205,204,235,153,
51 202,201,200,199,198,197,196,195,57,88,62,84,85,56,77,55,
52 167,255,168,169,130,248,170,165,54,66,53,86,87,52,69,51,
53 60,78,49,89,65,46,123,34,141,172,173,159,136,174,175,176,
54 41,90,47,122,124,35,121,43,177,135,163,236,178,142,179,249,
55 180,181,146,241,237,182,157,183,48,95,42,93,71,3,72,38,
56 184,158,185,186,187,155,189,190,36,94,59,119,96,40,73,39,
57 6,97,10,75,99,12,100,8,137,191,253,192,166,252,193,140,
58 18,101,26,102,98,32,126,25,194,164,156,188,239,147,250,131,
59 139,171,238,128,247,150,203,151,24,64,20,125,76,21,92,33,
60 209,129,240,144,160,133,154,231,9,91,16,83,112,11,74,1
63 static const UBYTE defcolmap[] =
65 0,66,8,68,64,10,65,2,136,130,150,142,153,148,149,151,
66 16,72,17,76,70,18,79,20,141,131,144,162,160,168,169,164,
67 177,147,174,170,143,176,180,178,21,77,22,83,80,23,82,24,
68 140,173,181,175,182,184,172,179,3,84,9,85,86,13,88,5,
69 36,89,38,91,92,35,90,37,137,157,156,190,165,185,191,188,
70 39,93,40,75,81,33,96,43,135,128,146,171,194,196,195,193,
71 163,167,129,186,192,197,187,189,44,87,32,94,95,46,97,47,
72 183,199,198,138,201,200,203,202,45,98,49,99,100,48,102,50,
73 34,103,54,71,67,41,74,51,158,208,210,212,211,213,209,205,
74 42,107,55,108,110,52,109,53,152,155,159,207,216,218,219,221,
75 139,161,154,166,206,204,133,215,56,69,58,114,73,59,78,57,
76 145,217,214,220,222,223,224,225,60,105,61,113,101,63,106,62,
77 4,115,12,112,104,14,117,6,228,132,227,229,230,231,234,236,
78 25,119,26,121,118,27,120,28,235,237,239,238,240,241,242,243,
79 232,244,247,226,249,250,253,252,19,124,29,125,116,30,111,31,
80 134,233,246,245,255,254,248,251,7,122,11,123,126,15,127,1
83 /**************************************************************************************************/
85 BOOL ConvertTC2TC( struct Picture_Data *pd )
87 struct RastPort DestRP;
88 long success;
90 D(bug("picture.datatype/ConvertTC2TC: TrueColor source/dest, no remapping required, PixelFormat %ld\n", pd->SrcPixelFormat));
91 CopyColTable( pd );
92 InitRastPort( &DestRP );
93 DestRP.BitMap = pd->DestBM;
94 if( !pd->Scale )
96 success = WritePixelArray( pd->SrcBuffer, // src buffer
97 0, // src x
98 0, // src y
99 pd->SrcWidthBytes, // src mod
100 &DestRP, // rastport
101 0, // dest x
102 0, // dest y
103 pd->SrcWidth, // width
104 pd->SrcHeight, // height
105 pd->SrcPixelFormat); // src format
107 else
109 success = ScaleArraySimple( pd, DestRP );
112 return success ? TRUE : FALSE;
115 BOOL ConvertCM2TC( struct Picture_Data *pd )
117 struct RastPort DestRP;
118 long success;
120 D(bug("picture.datatype/ConvertCM2TC: Colormapped source, TrueColor dest, no remapping required\n"));
121 CopyColTable( pd );
122 InitRastPort( &DestRP );
123 DestRP.BitMap = pd->DestBM;
124 if( !pd->Scale )
126 success = WriteLUTPixelArray( pd->SrcBuffer, // src buffer
127 0, // src x
128 0, // src y
129 pd->SrcWidthBytes, // src mod
130 &DestRP, // rastport
131 pd->ColTableXRGB, // coltable
132 0, // dest x
133 0, // dest y
134 pd->SrcWidth, // width
135 pd->SrcHeight, // height
136 CTABFMT_XRGB8 ); // coltable format
138 else
140 success = ScaleArraySimple( pd, DestRP );
143 return success ? TRUE : FALSE;
146 BOOL ConvertCM2CM( struct Picture_Data *pd )
148 struct RastPort DestRP;
149 BOOL success;
151 if( pd->Remap )
153 D(bug("picture.datatype/ConvertCM2CM: Colormapped source, Colormapped dest, remapping pens\n"));
154 success = RemapCM2CM( pd );
156 else
158 D(bug("picture.datatype/ConvertCM2CM: Colormapped source, Colormapped dest, remapping disabled\n"));
159 CopyColTable( pd );
160 InitRastPort( &DestRP );
161 DestRP.BitMap = pd->DestBM;
162 WriteChunkyPixels( &DestRP,
165 pd->SrcWidth-1,
166 pd->SrcHeight-1,
167 pd->SrcBuffer,
168 pd->SrcWidthBytes );
170 success = TRUE;
172 return success;
175 BOOL ConvertTC2CM( struct Picture_Data *pd )
177 BOOL success;
179 D(bug("picture.datatype/ConvertCM2CM: Truecolor source, Colormapped dest, decreasing depth and remapping\n"));
180 success = RemapTC2CM( pd );
181 return success;
184 /**************************************************************************************************/
186 static void ScaleLineSimple( UBYTE *srcxptr, UBYTE *destxptr, ULONG destwidth, UWORD srcpixelbytes, ULONG xscale )
188 unsigned int destx, srcxinc;
189 ULONG srcxpos;
190 UBYTE r=0, g=0, b=0, a;
191 UBYTE *srcxpixel;
193 a = 0;
194 srcxinc = 1;
195 srcxpos = 0;
196 if( srcpixelbytes == 1 )
198 destx = destwidth;
199 while( destx-- )
201 if( srcxinc )
202 a = *srcxptr;
203 srcxpos += xscale;
204 srcxinc = srcxpos >> 16;
205 srcxpos &= 0xffff;
206 // D(bug("picture.datatxpe/TC2TC Scale: destx %d srcxpos %06lx srcxinc %d\n", destx, srcxpos, srcxinc));
207 *destxptr++ = a;
208 if( srcxinc )
210 srcxptr += srcxinc;
214 else
216 destx = destwidth;
217 while( destx-- )
219 if( srcxinc )
221 srcxpixel = srcxptr;
222 if( srcpixelbytes == 4 )
223 a = *srcxpixel++;
224 r = *srcxpixel++;
225 g = *srcxpixel++;
226 b = *srcxpixel++;
228 srcxpos += xscale;
229 srcxinc = srcxpos >> 16;
230 srcxpos &= 0xffff;
231 // D(bug("picture.datatxpe/TC2TC Scale: destx %d srcxpos %06lx srcxinc %d\n", destx, srcxpos, srcxinc));
232 *destxptr++ = a;
233 *destxptr++ = r;
234 *destxptr++ = g;
235 *destxptr++ = b;
236 if( srcxinc )
238 if( srcxinc == 1 )
239 srcxptr += srcpixelbytes;
240 else if( srcpixelbytes == 4 )
241 srcxptr += srcxinc<<2;
242 else
243 srcxptr += (srcxinc<<2) - srcxinc;
249 static BOOL ScaleArraySimple( struct Picture_Data *pd, struct RastPort rp )
251 unsigned int srcy, desty, srcyinc;
252 ULONG srcypos, pixelformat, success;
253 UWORD srcpixelbytes;
254 ULONG destwidth;
255 UBYTE *srcyptr, *destline;
257 destwidth = pd->DestWidth;
258 pixelformat = pd->SrcPixelFormat;
259 srcpixelbytes = pd->SrcPixelBytes;
260 destline = AllocLineBuffer( destwidth, 1, 4 );
261 if( !destline )
262 return FALSE;
263 srcy = 0;
264 srcyinc = 1;
265 srcypos = 0;
266 srcyptr = pd->SrcBuffer;
267 for( desty=0; desty<pd->DestHeight; desty++ )
269 if( srcyinc ) // incremented source line after last line scaling ?
270 ScaleLineSimple( srcyptr, destline, destwidth, srcpixelbytes, pd->XScale );
271 srcypos += pd->YScale;
272 srcyinc = (srcypos >> 16) - srcy;
273 // D(bug("picture.datatype/TC2TC Scale: srcy %d desty %d srcypos %06lx srcyinc %d\n", srcy, desty, srcypos, srcyinc));
274 if( pixelformat == PBPAFMT_LUT8 )
276 success = WriteLUTPixelArray( destline, // src buffer
277 0, // src x
278 0, // src y
279 destwidth, // src mod
280 &rp, // rastport
281 pd->ColTableXRGB, // coltable
282 0, // dest x
283 desty, // dest y
284 destwidth, // width
285 1, // height
286 CTABFMT_XRGB8 ); // coltable format
288 else
290 success = WritePixelArray( destline, // src buffer
291 0, // src x
292 0, // src y
293 destwidth, // src mod
294 &rp, // rastport
295 0, // dest x
296 desty, // dest y
297 destwidth, // width
298 1, // height
299 RECTFMT_ARGB); // src format
301 if( !success ) return FALSE;
302 if( srcyinc )
304 if( srcyinc == 1 ) srcyptr += pd->SrcWidthBytes;
305 else srcyptr += pd->SrcWidthBytes * srcyinc;
306 srcy += srcyinc;
309 FreeVec( destline );
310 return TRUE;
313 /**************************************************************************************************/
315 BOOL AllocSrcBuffer( struct Picture_Data *pd, long width, long height, ULONG pixelformat, int pixelbytes )
317 pd->SrcWidthBytes = MOD16( width * pixelbytes);
318 pd->SrcBuffer = AllocVec( pd->SrcWidthBytes * height, MEMF_ANY );
319 if( !pd->SrcBuffer )
321 D(bug("picture.datatype/AllocSrcBuffer: Chunky source buffer allocation failed !\n"));
322 return FALSE;
324 pd->SrcWidth = width;
325 pd->SrcHeight = height;
326 pd->SrcPixelFormat = pixelformat;
327 pd->SrcPixelBytes = pixelbytes;
328 D(bug("picture.datatype/AllocSrcBuffer: Chunky source buffer allocated, %ld bytes\n", (long)(pd->SrcWidthBytes * height)));
329 return TRUE;
332 static UBYTE * AllocLineBuffer( long width, long height, int pixelbytes )
334 long widthbytes;
335 UBYTE *buffer;
337 widthbytes = MOD16( width * pixelbytes);
338 buffer = AllocVec( widthbytes * height, MEMF_ANY );
339 if( !buffer )
341 D(bug("picture.datatype/AllocLineBuffer: Line buffer allocation failed !\n"));
342 return FALSE;
344 D(bug("picture.datatype/AllocLineBuffer: Line buffer allocated, %ld bytes\n", (long)(widthbytes * height)));
345 return buffer;
348 static ULONG pixelformats[] = {
349 PIXFMT_RGB24,
350 PIXFMT_RGBA32,
351 PIXFMT_ARGB32,
352 PIXFMT_LUT8,
353 PIXFMT_LUT8
356 BOOL AllocDestBM( struct Picture_Data *pd )
358 ULONG flags = BMF_MINPLANES;
359 struct BitMap *friend_bm = NULL;
361 if (pd->UseFriendBM && pd->DestScreen &&
362 (pd->SrcPixelFormat != 1 && pd->SrcPixelFormat != 2))
364 /* Use friend bitmap, unless the source data has alpha component
365 * in which case a 32bit bitmap is required for proper blitting
367 friend_bm = pd->DestScreen->RastPort.BitMap;
369 else if (pd->TrueColorDest && (pd->SrcPixelFormat != -1))
370 flags |= (BMF_SPECIALFMT | SHIFT_PIXFMT(pixelformats[pd->SrcPixelFormat]));
371 D(bug("[AllocDestBM] Friend: 0x%p, flags: 0x%08lX\n", friend_bm, flags));
372 pd->DestBM = AllocBitMap( pd->DestWidth,
373 pd->DestHeight,
374 pd->DestDepth,
375 flags,
376 friend_bm);
377 if( !pd->DestBM )
379 D(bug("picture.datatype/AllocDestBM: DestBitmap allocation failed !\n"));
380 return FALSE;;
382 D(bug("picture.datatype/AllocDestBM: DestBM allocated: Flags %ld Width %ld Height %ld Depth %ld\n", (long)GetBitMapAttr(pd->DestBM, BMA_FLAGS),
383 (long)GetBitMapAttr(pd->DestBM, BMA_WIDTH), (long)GetBitMapAttr(pd->DestBM, BMA_HEIGHT), (long)GetBitMapAttr(pd->DestBM, BMA_DEPTH)));
384 return TRUE;
387 void FreeSource( struct Picture_Data *pd )
389 if( pd->SrcBuffer )
391 D(bug("picture.datatype/FreeSource: Freeing SrcBuffer\n"));
392 FreeVec( (void *) pd->SrcBuffer );
393 pd->SrcBuffer = NULL;
395 if( pd->SrcBM && !pd->KeepSrcBM )
397 D(bug("picture.datatype/FreeSource: Freeing SrcBitmap\n"));
398 FreeBitMap( pd->SrcBM );
399 pd->SrcBM = NULL;
403 void FreeDest( struct Picture_Data *pd )
405 int i;
407 if( pd->NumAlloc && pd->RemapScreen)
409 D(bug("picture.datatype/FreeDest: Freeing %ld pens\n", (long)pd->NumAlloc));
410 for(i=0; i<pd->NumAlloc; i++)
412 ReleasePen( pd->RemapScreen->ViewPort.ColorMap, pd->ColTable[i] );
414 pd->NumAlloc=0;
415 pd->RemapScreen = NULL;
418 if( pd->MaskPlane )
420 D(bug("picture.datatype/FreeDest: Freeing MaskPlane\n"));
421 FreeVec( (void *) pd->MaskPlane );
422 pd->MaskPlane = NULL;
425 if( pd->DestBM )
427 D(bug("picture.datatype/FreeDest: Freeing DestBitmap\n"));
428 FreeBitMap( pd->DestBM );
429 pd->DestBM = NULL;
433 /**************************************************************************************************/
435 static void CopyColTable( struct Picture_Data *pd )
437 int i, j;
438 ULONG colR, colG, colB;
440 j = 0;
441 for( i=0; i<256; i++ )
443 colR = pd->DestColRegs[j] = pd->SrcColRegs[j];
444 j++;
445 colG = pd->DestColRegs[j] = pd->SrcColRegs[j];
446 j++;
447 colB = pd->DestColRegs[j] = pd->SrcColRegs[j];
448 j++;
449 pd->ColTableXRGB[i] = ((colR>>8) & 0x00ff0000) | ((colG>>16) & 0x0000ff00) | ((colB>>24) & 0x000000ff);
453 void InitGreyColTable( struct Picture_Data *pd )
455 int i, cnt;
456 ULONG * colregs;
458 colregs = pd->SrcColRegs;
459 cnt = 0;
460 for( i=0; i<256; i++ )
462 colregs[cnt++] = i<<24;
463 colregs[cnt++] = i<<24;
464 colregs[cnt++] = i<<24;
468 void InitRGBColTable( struct Picture_Data *pd )
470 int i, j, k, cnt;
471 ULONG * colregs;
472 ULONG Col7, Col3;
474 Col7 = 0xFFFFFFFF/7;
475 Col3 = 0xFFFFFFFF/3;
476 colregs = pd->SrcColRegs;
477 cnt = 0;
478 for( i=0; i<4; i++ ) /* blue */
480 for( j=0; j<8; j++ ) /* red */
482 for( k=0; k<8; k++ ) /* green */
484 colregs[cnt++] = j*Col7;
485 colregs[cnt++] = k*Col7;
486 colregs[cnt++] = i*Col3;
492 BOOL ConvertBitmap2Chunky( struct Picture_Data *pd )
494 struct RastPort SrcRP;
495 ULONG y, offset;
496 ULONG width, height;
497 UBYTE *buffer;
499 if( !pd->SrcBM )
500 return FALSE;
501 D(bug("picture.datatype/Bitmap2Chunky: SrcBM; Flags %ld Width %ld Height %ld Depth %ld\n", (long)GetBitMapAttr(pd->SrcBM, BMA_FLAGS),
502 (long)GetBitMapAttr(pd->SrcBM, BMA_WIDTH), (long)GetBitMapAttr(pd->SrcBM, BMA_HEIGHT), (long)GetBitMapAttr(pd->SrcBM, BMA_DEPTH)));
503 /* Determine size and allocate Chunky source buffer */
504 width = pd->bmhd.bmh_Width;
505 height = pd->bmhd.bmh_Height;
506 if( !AllocSrcBuffer( pd, width, height, PBPAFMT_LUT8, 1 ) )
507 return FALSE;
509 /* Copy the source Bitmap into the Chunky source buffer */
510 InitRastPort( &SrcRP );
511 SrcRP.BitMap = pd->SrcBM;
512 offset = 0;
513 buffer = pd->SrcBuffer;
515 #ifdef __AROS__
516 for(y=0; y<height; y++)
518 /* AROS ReadPixelLine/Array8 does not need a temprp */
519 ReadPixelLine8( &SrcRP, 0, y, width, &buffer[offset], NULL );
520 offset += pd->SrcWidthBytes;
522 #else
523 D(bug("picture.datatype/Bitmap2Chunky: Slow ReadPixel() conversion\n"));
525 ULONG x;
526 for(y=0; y<height; y++)
528 for(x=0; x<width; x++)
530 buffer[x + offset] = ReadPixel(&SrcRP, x, y);
532 offset += pd->SrcWidthBytes;
535 #endif
537 return TRUE;
540 BOOL ConvertChunky2Bitmap( struct Picture_Data *pd )
542 struct RastPort SrcRP;
544 if( !pd->SrcBuffer || pd->TrueColorSrc )
545 return FALSE;
546 if( !pd->SrcBM )
548 /* Allocate source Bitmap */
549 pd->SrcBM = AllocBitMap( pd->SrcWidth,
550 pd->SrcHeight,
551 pd->bmhd.bmh_Depth,
552 BMF_STANDARD,
553 NULL );
554 if( !pd->SrcBM )
556 D(bug("picture.datatype/Chunky2Bitmap: Bitmap allocation failed !\n"));
557 return FALSE;;
559 D(bug("picture.datatype/Chunky2Bitmap: SrcBM allocated; Flags %ld Width %ld Height %ld Depth %ld\n", (long)GetBitMapAttr(pd->SrcBM, BMA_FLAGS),
560 (long)GetBitMapAttr(pd->SrcBM, BMA_WIDTH), (long)GetBitMapAttr(pd->SrcBM, BMA_HEIGHT), (long)GetBitMapAttr(pd->SrcBM, BMA_DEPTH)));
562 /* Copy the Chunky source buffer to the source Bitmap */
563 InitRastPort( &SrcRP );
564 SrcRP.BitMap = pd->SrcBM;
565 WriteChunkyPixels( &SrcRP, 0, 0, pd->SrcWidth-1, pd->SrcHeight-1, pd->SrcBuffer, pd->SrcWidthBytes );
567 return TRUE;
570 BOOL CreateMaskPlane( struct Picture_Data *pd )
572 if( !pd->SrcBuffer || !pd->DestBM || pd->SrcPixelBytes != 1 || pd->Scale)
574 D(bug("picture.datatype/CreateMask: Wrong conditions to create a mask !\n"));
575 return FALSE;
577 if( !pd->MaskPlane && pd->bmhd.bmh_Masking == mskHasTransparentColor )
579 int x, y;
580 UBYTE transp = pd->bmhd.bmh_Transparent;
581 UBYTE *srcbuf = pd->SrcBuffer;
582 int srcwidth = pd->SrcWidth;
583 int srcheight = pd->SrcHeight;
584 int width16 = MOD16( GetBitMapAttr( pd->DestBM, BMA_WIDTH ) );
585 int height = GetBitMapAttr( pd->DestBM, BMA_HEIGHT );
586 UBYTE *maskptr;
587 int maskwidth = width16 / 8;
588 ULONG srcwidthadd = pd->SrcWidthBytes - srcwidth * pd->SrcPixelBytes;
590 if( !(maskptr = AllocVec( maskwidth * height, MEMF_ANY )) )
592 D(bug("picture.datatype/CreateMask: Mask allocation failed !\n"));
593 return FALSE;
595 pd->MaskPlane = maskptr;
596 D(bug("picture.datatype/CreateMask: Mask allocated size %d x %d bytes\n", maskwidth, height));
598 for(y = 0; y < srcheight; y++)
600 UBYTE *maskx = maskptr;
601 UBYTE mask = 0x80;
602 UBYTE maskbyte = 0x00;
604 for(x = 0; x < srcwidth; x++)
606 if( *srcbuf++ != transp )
607 maskbyte |= mask;
609 mask >>= 1;
610 if( !mask )
612 mask = 0x80;
613 *maskx++ = maskbyte;
614 maskbyte = 0x00;
617 if( mask != 0x80)
618 *maskx = maskbyte;
619 maskptr += maskwidth;
620 srcbuf += srcwidthadd;
623 return TRUE;
626 /**************************************************************************************************/
628 static BOOL RemapTC2CM( struct Picture_Data *pd )
630 unsigned int DestNumColors;
631 int i, j, k;
632 int srccnt, destcnt, index;
633 ULONG *srccolregs, *destcolregs;
634 ULONG Col7, Col3;
636 pd->NumSparse = pd->NumColors = 256;
637 DestNumColors = 1<<pd->DestDepth;
638 if( pd->MaxDitherPens )
639 DestNumColors = pd->MaxDitherPens;
642 * Create color tables: src is (already present) in "natural" order,
643 * dest is sorted by priority using a precalculated table;
644 * "natural" is bits: bbrr.rggg
646 Col7 = 0xFFFFFFFF/7;
647 Col3 = 0xFFFFFFFF/3;
648 srccolregs = pd->SrcColRegs;
649 srccnt = 0;
650 destcolregs = pd->DestColRegs;
651 destcnt = 0;
652 for( i=0; i<4; i++ ) /* blue */
654 for( j=0; j<8; j++ ) /* red */
656 for( k=0; k<8; k++ ) /* green */
658 index = 3 * defcolmap[destcnt++];
659 destcolregs[index++] = srccolregs[srccnt++] = j*Col7;
660 destcolregs[index++] = srccolregs[srccnt++] = k*Col7;
661 destcolregs[index] = srccolregs[srccnt++] = i*Col3;
667 * Allocate Pens and create sparse table for remapping
669 RemapPens( pd, 256, DestNumColors );
672 * Remap line-by-line truecolor source buffer to destination using sparse table
675 struct RastPort DestRP;
676 ULONG x, srcy, srcyinc, srcypos;
677 ULONG desty;
678 UBYTE *srcline, *destline, *thissrc, *thisdest;
680 UBYTE *srcbuf = pd->SrcBuffer;
681 ULONG srcwidth = pd->SrcWidth;
682 ULONG destwidth = pd->DestWidth;
683 UBYTE *sparsetable = pd->SparseTable;
684 BOOL argb = pd->SrcPixelFormat==PBPAFMT_ARGB;
685 BOOL scale = pd->Scale;
687 srcline = AllocLineBuffer( MAX(srcwidth, destwidth) * 4, 1, 1 );
688 if( !srcline )
689 return FALSE;
690 if( scale )
691 destline = AllocLineBuffer( destwidth, 1, 1 );
692 else
693 destline = srcline;
694 if( !destline )
695 return FALSE;
697 InitRastPort( &DestRP );
698 DestRP.BitMap = pd->DestBM;
699 srcy = 0;
700 srcyinc = 1;
701 srcypos = 0;
702 if( pd->DitherQuality )
704 int rval, gval, bval;
705 long rerr, gerr, berr;
706 UBYTE destindex;
707 ULONG *colregs;
708 int feedback;
710 D(bug("picture.datatype/RemapTC2CM: remapping buffer with dither of %d\n", (int)pd->DitherQuality));
711 feedback = 4 - pd->DitherQuality;
712 destcolregs = pd->DestColRegs;
713 for( desty=0; desty<pd->DestHeight; desty++ )
715 if( srcyinc ) // incremented source line after last line scaling ?
717 if( scale )
719 ScaleLineSimple( srcbuf, srcline, destwidth, pd->SrcPixelBytes, pd->XScale );
720 argb = TRUE;
721 thissrc = srcline;
723 else
725 thissrc = srcbuf;
727 thisdest = destline;
728 rerr = gerr = berr = 0;
729 x = destwidth;
730 while( x-- )
732 if( argb )
733 thissrc++; // skip alpha
734 if( feedback )
736 rerr >>= feedback;
737 gerr >>= feedback;
738 berr >>= feedback;
740 rerr += (*thissrc++);
741 gerr += (*thissrc++);
742 berr += (*thissrc++);
743 rval = CLIP( rerr );
744 gval = CLIP( gerr );
745 bval = CLIP( berr );
746 index = (rval>>2 & 0x38) | (gval>>5 & 0x07) | (bval & 0xc0);
747 destindex = sparsetable[index];
748 *thisdest++ = destindex;
749 colregs = destcolregs + destindex*3;
750 rerr -= (*colregs++)>>24;
751 gerr -= (*colregs++)>>24;
752 berr -= (*colregs)>>24;
755 if( scale )
757 srcypos += pd->YScale;
758 srcyinc = (srcypos >> 16) - srcy;
760 WriteChunkyPixels( &DestRP,
762 desty,
763 destwidth-1,
764 desty,
765 destline,
766 destwidth );
767 if( srcyinc )
769 if( srcyinc == 1 ) srcbuf += pd->SrcWidthBytes;
770 else srcbuf += pd->SrcWidthBytes * srcyinc;
771 srcy += srcyinc;
775 else
777 D(bug("picture.datatype/RemapTC2CM: remapping buffer without dithering\n"));
778 for( desty=0; desty<pd->DestHeight; desty++ )
780 if( srcyinc ) // incremented source line after last line scaling ?
782 thissrc = srcbuf;
783 thisdest = srcline;
784 x = srcwidth;
785 while( x-- )
787 if( argb )
788 thissrc++; // skip alpha
789 index = (*thissrc++)>>2 & 0x38; // red
790 index |= (*thissrc++)>>5 & 0x07; // green
791 index |= (*thissrc++) & 0xc0; // blue
793 *thisdest++ = sparsetable[index];
795 if( scale )
796 ScaleLineSimple( srcline, destline, destwidth, 1, pd->XScale );
798 if( scale )
800 srcypos += pd->YScale;
801 srcyinc = (srcypos >> 16) - srcy;
803 WriteChunkyPixels( &DestRP,
805 desty,
806 destwidth-1,
807 desty,
808 destline,
809 destwidth );
810 if( srcyinc )
812 if( srcyinc == 1 ) srcbuf += pd->SrcWidthBytes;
813 else srcbuf += pd->SrcWidthBytes * srcyinc;
814 srcy += srcyinc;
819 FreeVec( (void *) srcline );
820 if( scale )
821 FreeVec( (void *) destline );
823 return TRUE;
826 static BOOL RemapCM2CM( struct Picture_Data *pd )
828 struct HistEntry TheHist[256];
829 ULONG width, height;
830 int DestNumColors, NumColors;
831 int i, j, index;
833 width = pd->SrcWidth;
834 height = pd->SrcHeight;
836 NumColors = pd->NumColors;
837 DestNumColors = 1<<pd->DestDepth;
838 if( pd->MaxDitherPens )
839 DestNumColors = pd->MaxDitherPens;
840 if( NumColors < DestNumColors )
841 DestNumColors = NumColors;
843 memset( pd->DestColRegs, 0xFF, 768*sizeof(ULONG) ); /* initialize GRegs table */
844 memset( pd->SparseTable, 0x0, 256 ); /* initialize Sparse table */
845 pd->NumSparse = NumColors;
848 * Fill in histogram with source colors
850 index = 0;
851 for(i=0; i<NumColors; i++)
853 TheHist[i].Count = 0;
854 TheHist[i].Red = pd->SrcColRegs[index++];
855 TheHist[i].Green = pd->SrcColRegs[index++];
856 TheHist[i].Blue = pd->SrcColRegs[index++];
860 * Determine the number of colors in histogram
863 UBYTE *sb = pd->SrcBuffer;
865 for( i=0; i<height; i++ )
867 for( j=0; j<width; j++ )
869 TheHist[sb[j]].Count++;
871 sb += pd->SrcWidthBytes;
876 * Remove duplicate colors in histogram
878 for( i=0; i<NumColors-1; i++ )
880 for( j=i+1; j<NumColors; j++ )
882 if( (TheHist[j].Red == TheHist[i].Red ) &&
883 (TheHist[j].Green == TheHist[i].Green) &&
884 (TheHist[j].Blue == TheHist[i].Blue ) )
886 TheHist[i].Count += TheHist[j].Count;
887 TheHist[j].Count = 0;
893 * Sort histogram by most used colors
895 qsort( (void *) TheHist, NumColors, sizeof(struct HistEntry), HistSort );
898 * Copy colors to dest, most used colors first
900 index = 0;
901 for( i=0; i<DestNumColors; i++ )
903 pd->DestColRegs[index++] = TheHist[i].Red;
904 pd->DestColRegs[index++] = TheHist[i].Green;
905 pd->DestColRegs[index++] = TheHist[i].Blue;
909 * Allocate Pens in this order and create sparse table for remapping
911 RemapPens( pd, NumColors, DestNumColors );
914 * Remap source buffer to dest Bitmap
916 D(bug("picture.datatype/RemapCM2CM: remapping buffer to new pens\n"));
918 struct RastPort DestRP;
919 ULONG x, srcy, srcyinc, srcypos;
920 ULONG desty;
921 UBYTE *srcline, *destline, *thissrc, *thisdest;
923 UBYTE *srcbuf = pd->SrcBuffer;
924 ULONG srcwidth = pd->SrcWidth;
925 ULONG destwidth = pd->DestWidth;
926 BOOL scale = pd->Scale;
927 UBYTE *sparsetable = pd->SparseTable;
929 srcline = AllocLineBuffer( srcwidth, 1, 1 );
930 if( !srcline )
931 return FALSE;
932 if( scale )
933 destline = AllocLineBuffer( destwidth, 1, 1 );
934 else
935 destline = srcline;
936 if( !destline )
937 return FALSE;
939 InitRastPort( &DestRP );
940 DestRP.BitMap = pd->DestBM;
941 srcy = 0;
942 srcyinc = 1;
943 srcypos = 0;
944 for( desty=0; desty<pd->DestHeight; desty++ )
946 if( srcyinc ) // incremented source line after last line scaling ?
948 thissrc = srcbuf;
949 thisdest = srcline;
950 x = srcwidth;
951 while( x-- )
953 *thisdest++ = sparsetable[*thissrc++];
955 if( scale )
956 ScaleLineSimple( srcline, destline, destwidth, 1, pd->XScale );
958 if( scale )
960 srcypos += pd->YScale;
961 srcyinc = (srcypos >> 16) - srcy;
963 WriteChunkyPixels( &DestRP,
965 desty,
966 destwidth-1,
967 desty,
968 destline,
969 destwidth );
970 if( srcyinc )
972 if( srcyinc == 1 ) srcbuf += pd->SrcWidthBytes;
973 else srcbuf += pd->SrcWidthBytes * srcyinc;
974 srcy += srcyinc;
978 FreeVec( (void *) srcline );
979 if( scale )
980 FreeVec( (void *) destline );
983 return TRUE;
986 static int HistSort( const void *HistEntry1, const void *HistEntry2 )
988 struct HistEntry *HE1, *HE2;
990 HE1 = (struct HistEntry *) HistEntry1;
991 HE2 = (struct HistEntry *) HistEntry2;
993 return ((int) (HE2->Count - HE1->Count));
996 static void RemapPens( struct Picture_Data *pd, int NumColors, int DestNumColors )
998 int i, j, index;
999 int pen;
1002 * Remember screen so that we can undo remapping.
1004 pd->RemapScreen = pd->DestScreen;
1007 * Obtain pens for DestColRegs (GRegs)
1009 index = 0;
1010 for( i=0; i<DestNumColors; i++ )
1012 pd->ColTable[i] = ObtainBestPen( pd->DestScreen->ViewPort.ColorMap,
1013 pd->DestColRegs[index+0],
1014 pd->DestColRegs[index+1],
1015 pd->DestColRegs[index+2],
1016 OBP_Precision, pd->Precision,
1017 OBP_FailIfBad, FALSE,
1018 TAG_DONE);
1019 // D(bug("picture.datatype/RemapPens: %d Pen %d: R %d G %d B %d\n",
1020 // (int)i, (int)pd->ColTable[i], (int)(pd->DestColRegs[index]>>24), (int)(pd->DestColRegs[index+1]>>24), (int)(pd->DestColRegs[index+2]>>24)));
1021 index += 3;
1022 pd->NumAlloc++;
1024 D(bug("picture.datatype/RemapPens: NumColors: %ld DestNumColors: %ld NumAlloc: %ld Depth: %ld\n",
1025 (long)pd->NumColors, (long)DestNumColors, (long)pd->NumAlloc, (long)pd->DestDepth));
1028 * Get Pen's real colors
1030 for( i=0; i<DestNumColors; i++ )
1032 pen = pd->ColTable[i];
1033 GetRGB32( pd->DestScreen->ViewPort.ColorMap, pen, 1, pd->DestColRegs+pen*3 );
1034 // D(bug("picture.datatype/RemapPens: %d Pen %d: R %d G %d B %d\n",
1035 // i, pen, (int)(pd->DestColRegs[pen*3]>>24), (int)(pd->DestColRegs[pen*3+1]>>24), (int)(pd->DestColRegs[pen*3+2]>>24)));
1039 * Determine SparseTable by minimum distance method
1041 index = 0;
1042 for( i=0; i<NumColors; i++ )
1044 ULONG Diff, LastDiff;
1045 int CRed, GRed, CGreen, GGreen, CBlue, GBlue;
1047 LastDiff=0xFFFFFFFF;
1049 CRed = pd->SrcColRegs[index++]>>17;
1050 CGreen = pd->SrcColRegs[index++]>>17;
1051 CBlue = pd->SrcColRegs[index++]>>17;
1053 for( j=0; j<DestNumColors; j++ )
1055 pen = pd->ColTable[j] * 3;
1056 GRed = pd->DestColRegs[pen++]>>17;
1057 GGreen = pd->DestColRegs[pen++]>>17;
1058 GBlue = pd->DestColRegs[pen]>>17;
1060 Diff = abs(CRed - GRed ) +
1061 abs(CGreen - GGreen) +
1062 abs(CBlue - GBlue );
1064 if( Diff <= LastDiff )
1066 pd->SparseTable[i] = pd->ColTable[j];
1067 LastDiff = Diff;
1070 if(LastDiff==0)
1072 break;
1077 #if 0 /* optionally display resulting sparse table with color values for debugging */
1079 int sp;
1080 D(bug("picture.datatype/RemapPens: sparse table: source col -> dest pen\n"));
1081 for( i=0; i<NumColors; i++ )
1083 sp = pd->SparseTable[i];
1084 D(bug("picture.datatype/RemapPens: %d (R %d G %d B %d) -> %d (R %d G %d B %d)\n",
1085 i, pd->SrcColRegs[i*3]>>24, pd->SrcColRegs[i*3+1]>>24, pd->SrcColRegs[i*3+2]>>24,
1086 sp, pd->DestColRegs[sp*3]>>24, pd->DestColRegs[sp*3+1]>>24, pd->DestColRegs[sp*3+2]>>24));
1089 #endif
1092 /**************************************************************************************************/