Corrections to SVN properties.
[AROS.git] / workbench / classes / zune / nlist / nbitmap_mcc / DitherImage.c
blobc719f88b2e2ea5ca72eb5607c887d708fc491d17
1 /***************************************************************************
3 NBitmap.mcc - New Bitmap MUI Custom Class
4 Copyright (C) 2006 by Daniel Allsopp
5 Copyright (C) 2007-2013 by NList Open Source Team
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 NList classes Support Site: http://www.sf.net/projects/nlist-classes
19 $Id$
21 ***************************************************************************/
23 #include <proto/exec.h>
24 #include <proto/utility.h>
25 #include <mui/NBitmap_mcc.h>
27 #include "private.h"
28 #include "DitherImage.h"
29 #include "Debug.h"
31 #ifndef MEMF_SHARED
32 #define MEMF_SHARED MEMF_ANY
33 #endif
35 #define RAWIDTH(w) ((((UWORD)(w))+15)>>3 & 0xFFFE)
37 APTR DitherImageA(CONST_APTR data, struct TagItem *tags)
39 struct TagItem *tag;
40 uint32 width = 0;
41 uint32 height = 0;
42 uint32 format = 0;
43 const uint32 *colorMap = NULL;
44 const int32 *penMap = NULL;
45 APTR result = NULL;
46 uint8 **maskPtr = NULL;
48 ENTER();
50 while((tag = NextTagItem((APTR)&tags)) != NULL)
52 switch(tag->ti_Tag)
54 case DITHERA_Width:
55 width = tag->ti_Data;
56 break;
58 case DITHERA_Height:
59 height = tag->ti_Data;
60 break;
62 case DITHERA_Format:
63 format = tag->ti_Data;
64 break;
66 case DITHERA_ColorMap:
67 colorMap = (uint32 *)tag->ti_Data;
68 break;
70 case DITHERA_PenMap:
71 penMap = (int32 *)tag->ti_Data;
72 break;
74 case DITHERA_MaskPlane:
75 maskPtr = (uint8 **)tag->ti_Data;
76 break;
80 if(data != NULL && colorMap != NULL && width > 0 && height > 0)
82 // the 8bit chunky data don't need to reside in chip memory
83 if((result = AllocVecShared(width * height, MEMF_ANY)) != NULL)
85 uint8 *mask = NULL;
86 uint8 *mPtr = NULL;
87 uint32 y;
88 uint8 *dataPtr = (uint8 *)data;
89 uint8 *resultPtr = (uint8 *)result;
91 // only ARGB raw data contain transparency data, hence we need to
92 // allocate a mask plane only for these and only if the calling
93 // function is interested in a mask at all
94 if(format == MUIV_NBitmap_Type_ARGB32 && maskPtr != NULL)
96 // the mask MUST reside in chip memory
97 mask = AllocVec(RAWIDTH(width) * height, MEMF_CLEAR|MEMF_CHIP);
98 *maskPtr = mask;
99 mPtr = mask;
102 for(y = 0; y < height; y++)
104 uint32 x;
105 uint8 bitMask = 0x80;
107 for(x = 0; x < width; x++)
109 uint8 a, r, g, b;
110 int32 i;
111 int32 bestIndex;
112 uint32 bestError;
114 // obtain the pixel's A, R, G and B values from the raw data
115 switch(format)
117 case MUIV_NBitmap_Type_CLUT8:
118 a = (colorMap[dataPtr[0]] >> 24) & 0xff;
119 r = (colorMap[dataPtr[0]] >> 16) & 0xff;
120 g = (colorMap[dataPtr[0]] >> 8) & 0xff;
121 b = (colorMap[dataPtr[0]] >> 0) & 0xff;
122 dataPtr += 1;
123 break;
125 case MUIV_NBitmap_Type_RGB24:
126 a = 0xff;
127 r = dataPtr[0];
128 g = dataPtr[1];
129 b = dataPtr[2];
130 dataPtr += 3;
131 break;
133 case MUIV_NBitmap_Type_ARGB32:
134 a = dataPtr[0];
135 r = dataPtr[1];
136 g = dataPtr[2];
137 b = dataPtr[3];
138 dataPtr += 4;
139 break;
141 default:
142 a = 0x00;
143 r = 0x00;
144 g = 0x00;
145 b = 0x00;
146 break;
149 // now calculate the best matching color from the given color map
150 bestIndex = -1;
151 bestError = 0xffffffffUL;
153 for(i = 0; i < 256; i++)
155 int32 dr, dg, db;
156 uint32 error;
158 // calculate the geometric difference to the current color
159 dr = (int32)((colorMap[i] >> 16) & 0xff) - (int32)r;
160 dg = (int32)((colorMap[i] >> 8) & 0xff) - (int32)g;
161 db = (int32)((colorMap[i] >> 0) & 0xff) - (int32)b;
162 error = dr * dr + dg * dg + db * db;
164 if(bestError > error)
166 // remember this as the best matching color so far
167 bestError = error;
168 bestIndex = i;
170 // bail out if we found an exact match
171 if(error == 0x00000000UL)
172 break;
176 // put the calculated color number into the destination LUT8 image
177 // using an additional pen map if available
178 if(bestIndex != -1)
180 if(penMap != NULL)
181 *resultPtr++ = penMap[bestIndex];
182 else
183 *resultPtr++ = bestIndex;
185 else
187 // no matching color found, use color 0
188 // can this happen at all?
189 *resultPtr++ = 0;
192 if(mPtr != NULL)
194 // if we have a mask and the alpha value is >= 0x80 the
195 // pixel is treated as non-transparent
196 if(a >= 0x80)
197 mPtr[x/8] |= bitMask;
199 bitMask >>= 1;
200 if(bitMask == 0x00)
201 bitMask = 0x80;
205 // advance the mask pointer by one line
206 if(mPtr != NULL)
207 mPtr += RAWIDTH(width);
212 RETURN(result);
213 return result;
216 #ifdef __AROS__
217 APTR STDARGS VARARGS68K DitherImage(CONST_APTR data, Tag tag1, ...)
219 AROS_SLOWSTACKTAGS_PRE_AS(tag1, APTR)
220 retval = DitherImageA(data, AROS_SLOWSTACKTAGS_ARG(tag1));
221 AROS_SLOWSTACKTAGS_POST
223 #else
224 #if !defined(__PPC__)
225 APTR STDARGS VARARGS68K DitherImage(CONST_APTR data, ...)
227 APTR ret;
228 VA_LIST args;
230 VA_START(args, data);
231 ret = DitherImageA(data, (struct TagItem *)VA_ARG(args, IPTR));
232 VA_END(args);
234 return ret;
236 #endif
237 #endif
239 void FreeDitheredImage(APTR image, APTR mask)
241 ENTER();
243 if(image != NULL)
244 FreeVec(image);
245 if(mask != NULL)
246 FreeVec(mask);
248 LEAVE();