2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
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>
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
;
90 D(bug("picture.datatype/ConvertTC2TC: TrueColor source/dest, no remapping required, PixelFormat %ld\n", pd
->SrcPixelFormat
));
92 InitRastPort( &DestRP
);
93 DestRP
.BitMap
= pd
->DestBM
;
96 success
= WritePixelArray( pd
->SrcBuffer
, // src buffer
99 pd
->SrcWidthBytes
, // src mod
103 pd
->SrcWidth
, // width
104 pd
->SrcHeight
, // height
105 pd
->SrcPixelFormat
); // src format
109 success
= ScaleArraySimple( pd
, DestRP
);
112 return success
? TRUE
: FALSE
;
115 BOOL
ConvertCM2TC( struct Picture_Data
*pd
)
117 struct RastPort DestRP
;
120 D(bug("picture.datatype/ConvertCM2TC: Colormapped source, TrueColor dest, no remapping required\n"));
122 InitRastPort( &DestRP
);
123 DestRP
.BitMap
= pd
->DestBM
;
126 success
= WriteLUTPixelArray( pd
->SrcBuffer
, // src buffer
129 pd
->SrcWidthBytes
, // src mod
131 pd
->ColTableXRGB
, // coltable
134 pd
->SrcWidth
, // width
135 pd
->SrcHeight
, // height
136 CTABFMT_XRGB8
); // coltable format
140 success
= ScaleArraySimple( pd
, DestRP
);
143 return success
? TRUE
: FALSE
;
146 BOOL
ConvertCM2CM( struct Picture_Data
*pd
)
148 struct RastPort DestRP
;
153 D(bug("picture.datatype/ConvertCM2CM: Colormapped source, Colormapped dest, remapping pens\n"));
154 success
= RemapCM2CM( pd
);
158 D(bug("picture.datatype/ConvertCM2CM: Colormapped source, Colormapped dest, remapping disabled\n"));
160 InitRastPort( &DestRP
);
161 DestRP
.BitMap
= pd
->DestBM
;
162 WriteChunkyPixels( &DestRP
,
175 BOOL
ConvertTC2CM( struct Picture_Data
*pd
)
179 D(bug("picture.datatype/ConvertCM2CM: Truecolor source, Colormapped dest, decreasing depth and remapping\n"));
180 success
= RemapTC2CM( pd
);
184 /**************************************************************************************************/
186 static void ScaleLineSimple( UBYTE
*srcxptr
, UBYTE
*destxptr
, ULONG destwidth
, UWORD srcpixelbytes
, ULONG xscale
)
188 unsigned int destx
, srcxinc
;
190 UBYTE r
=0, g
=0, b
=0, a
;
196 if( srcpixelbytes
== 1 )
204 srcxinc
= srcxpos
>> 16;
206 // D(bug("picture.datatxpe/TC2TC Scale: destx %d srcxpos %06lx srcxinc %d\n", destx, srcxpos, srcxinc));
222 if( srcpixelbytes
== 4 )
229 srcxinc
= srcxpos
>> 16;
231 // D(bug("picture.datatxpe/TC2TC Scale: destx %d srcxpos %06lx srcxinc %d\n", destx, srcxpos, srcxinc));
239 srcxptr
+= srcpixelbytes
;
240 else if( srcpixelbytes
== 4 )
241 srcxptr
+= srcxinc
<<2;
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
;
255 UBYTE
*srcyptr
, *destline
;
257 destwidth
= pd
->DestWidth
;
258 pixelformat
= pd
->SrcPixelFormat
;
259 srcpixelbytes
= pd
->SrcPixelBytes
;
260 destline
= AllocLineBuffer( destwidth
, 1, 4 );
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
279 destwidth
, // src mod
281 pd
->ColTableXRGB
, // coltable
286 CTABFMT_XRGB8
); // coltable format
290 success
= WritePixelArray( destline
, // src buffer
293 destwidth
, // src mod
299 RECTFMT_ARGB
); // src format
301 if( !success
) return FALSE
;
304 if( srcyinc
== 1 ) srcyptr
+= pd
->SrcWidthBytes
;
305 else srcyptr
+= pd
->SrcWidthBytes
* srcyinc
;
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
);
321 D(bug("picture.datatype/AllocSrcBuffer: Chunky source buffer allocation failed !\n"));
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
)));
332 static UBYTE
* AllocLineBuffer( long width
, long height
, int pixelbytes
)
337 widthbytes
= MOD16( width
* pixelbytes
);
338 buffer
= AllocVec( widthbytes
* height
, MEMF_ANY
);
341 D(bug("picture.datatype/AllocLineBuffer: Line buffer allocation failed !\n"));
344 D(bug("picture.datatype/AllocLineBuffer: Line buffer allocated, %ld bytes\n", (long)(widthbytes
* height
)));
348 static ULONG pixelformats
[] = {
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
,
379 D(bug("picture.datatype/AllocDestBM: DestBitmap allocation failed !\n"));
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
)));
387 void FreeSource( struct Picture_Data
*pd
)
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
);
403 void FreeDest( struct Picture_Data
*pd
)
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
] );
415 pd
->RemapScreen
= NULL
;
420 D(bug("picture.datatype/FreeDest: Freeing MaskPlane\n"));
421 FreeVec( (void *) pd
->MaskPlane
);
422 pd
->MaskPlane
= NULL
;
427 D(bug("picture.datatype/FreeDest: Freeing DestBitmap\n"));
428 FreeBitMap( pd
->DestBM
);
433 /**************************************************************************************************/
435 static void CopyColTable( struct Picture_Data
*pd
)
438 ULONG colR
, colG
, colB
;
441 for( i
=0; i
<256; i
++ )
443 colR
= pd
->DestColRegs
[j
] = pd
->SrcColRegs
[j
];
445 colG
= pd
->DestColRegs
[j
] = pd
->SrcColRegs
[j
];
447 colB
= pd
->DestColRegs
[j
] = pd
->SrcColRegs
[j
];
449 pd
->ColTableXRGB
[i
] = ((colR
>>8) & 0x00ff0000) | ((colG
>>16) & 0x0000ff00) | ((colB
>>24) & 0x000000ff);
453 void InitGreyColTable( struct Picture_Data
*pd
)
458 colregs
= pd
->SrcColRegs
;
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
)
476 colregs
= pd
->SrcColRegs
;
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
;
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 ) )
509 /* Copy the source Bitmap into the Chunky source buffer */
510 InitRastPort( &SrcRP
);
511 SrcRP
.BitMap
= pd
->SrcBM
;
513 buffer
= pd
->SrcBuffer
;
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
;
523 D(bug("picture.datatype/Bitmap2Chunky: Slow ReadPixel() conversion\n"));
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
;
540 BOOL
ConvertChunky2Bitmap( struct Picture_Data
*pd
)
542 struct RastPort SrcRP
;
544 if( !pd
->SrcBuffer
|| pd
->TrueColorSrc
)
548 /* Allocate source Bitmap */
549 pd
->SrcBM
= AllocBitMap( pd
->SrcWidth
,
556 D(bug("picture.datatype/Chunky2Bitmap: Bitmap allocation failed !\n"));
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
);
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"));
577 if( !pd
->MaskPlane
&& pd
->bmhd
.bmh_Masking
== mskHasTransparentColor
)
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
);
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"));
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
;
602 UBYTE maskbyte
= 0x00;
604 for(x
= 0; x
< srcwidth
; x
++)
606 if( *srcbuf
++ != transp
)
619 maskptr
+= maskwidth
;
620 srcbuf
+= srcwidthadd
;
626 /**************************************************************************************************/
628 static BOOL
RemapTC2CM( struct Picture_Data
*pd
)
630 unsigned int DestNumColors
;
632 int srccnt
, destcnt
, index
;
633 ULONG
*srccolregs
, *destcolregs
;
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
648 srccolregs
= pd
->SrcColRegs
;
650 destcolregs
= pd
->DestColRegs
;
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
;
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 );
691 destline
= AllocLineBuffer( destwidth
, 1, 1 );
697 InitRastPort( &DestRP
);
698 DestRP
.BitMap
= pd
->DestBM
;
702 if( pd
->DitherQuality
)
704 int rval
, gval
, bval
;
705 long rerr
, gerr
, berr
;
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 ?
719 ScaleLineSimple( srcbuf
, srcline
, destwidth
, pd
->SrcPixelBytes
, pd
->XScale
);
728 rerr
= gerr
= berr
= 0;
733 thissrc
++; // skip alpha
740 rerr
+= (*thissrc
++);
741 gerr
+= (*thissrc
++);
742 berr
+= (*thissrc
++);
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;
757 srcypos
+= pd
->YScale
;
758 srcyinc
= (srcypos
>> 16) - srcy
;
760 WriteChunkyPixels( &DestRP
,
769 if( srcyinc
== 1 ) srcbuf
+= pd
->SrcWidthBytes
;
770 else srcbuf
+= pd
->SrcWidthBytes
* srcyinc
;
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 ?
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
];
796 ScaleLineSimple( srcline
, destline
, destwidth
, 1, pd
->XScale
);
800 srcypos
+= pd
->YScale
;
801 srcyinc
= (srcypos
>> 16) - srcy
;
803 WriteChunkyPixels( &DestRP
,
812 if( srcyinc
== 1 ) srcbuf
+= pd
->SrcWidthBytes
;
813 else srcbuf
+= pd
->SrcWidthBytes
* srcyinc
;
819 FreeVec( (void *) srcline
);
821 FreeVec( (void *) destline
);
826 static BOOL
RemapCM2CM( struct Picture_Data
*pd
)
828 struct HistEntry TheHist
[256];
830 int DestNumColors
, NumColors
;
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
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
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
;
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 );
933 destline
= AllocLineBuffer( destwidth
, 1, 1 );
939 InitRastPort( &DestRP
);
940 DestRP
.BitMap
= pd
->DestBM
;
944 for( desty
=0; desty
<pd
->DestHeight
; desty
++ )
946 if( srcyinc
) // incremented source line after last line scaling ?
953 *thisdest
++ = sparsetable
[*thissrc
++];
956 ScaleLineSimple( srcline
, destline
, destwidth
, 1, pd
->XScale
);
960 srcypos
+= pd
->YScale
;
961 srcyinc
= (srcypos
>> 16) - srcy
;
963 WriteChunkyPixels( &DestRP
,
972 if( srcyinc
== 1 ) srcbuf
+= pd
->SrcWidthBytes
;
973 else srcbuf
+= pd
->SrcWidthBytes
* srcyinc
;
978 FreeVec( (void *) srcline
);
980 FreeVec( (void *) destline
);
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
)
1002 * Remember screen so that we can undo remapping.
1004 pd
->RemapScreen
= pd
->DestScreen
;
1007 * Obtain pens for DestColRegs (GRegs)
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
,
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)));
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
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
];
1077 #if 0 /* optionally display resulting sparse table with color values for debugging */
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));
1092 /**************************************************************************************************/