Line data Source code
1 0 : /*
2 :
3 : OOPixMapChannelOperations.m
4 :
5 :
6 : Copyright (C) 2010-2013 Jens Ayton
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : #include "OOPixMapChannelOperations.h"
29 : #import "OOCPUInfo.h"
30 :
31 :
32 : static void ExtractChannel_4(OOPixMap *ioPixMap, uint8_t channelIndex);
33 : static void ToRGBA_1(OOPixMap srcPx, OOPixMap dstPx);
34 : static void ToRGBA_2(OOPixMap srcPx, OOPixMap dstPx);
35 : static void ModulateUniform_4(OOPixMap pixMap, uint16_t f0, uint16_t f1, uint16_t f2, uint16_t f3);
36 : static void ModulatePixMap_4(OOPixMap mainPx, OOPixMap otherPx);
37 : static void AddPixMap_4(OOPixMap mainPx, OOPixMap otherPx);
38 :
39 :
40 0 : BOOL OOExtractPixMapChannel(OOPixMap *ioPixMap, uint8_t channelIndex, BOOL compactWhenDone)
41 : {
42 : if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap) || ioPixMap->format != kOOPixMapRGBA || channelIndex > 3))
43 : {
44 : return NO;
45 : }
46 :
47 : ExtractChannel_4(ioPixMap, channelIndex);
48 :
49 : ioPixMap->format = kOOPixMapGrayscale;
50 : ioPixMap->rowBytes = ioPixMap->width;
51 :
52 : if (compactWhenDone)
53 : {
54 : OOCompactPixMap(ioPixMap);
55 : }
56 :
57 : return YES;
58 : }
59 :
60 :
61 0 : static void ExtractChannel_4(OOPixMap *ioPixMap, uint8_t channelIndex)
62 : {
63 : NSCParameterAssert(ioPixMap != NULL);
64 :
65 : uint32_t *src;
66 : uint8_t *dst;
67 : uint_fast8_t shift;
68 : uint_fast32_t xCount, y;
69 :
70 : dst = ioPixMap->pixels;
71 : shift = 8 * channelIndex;
72 :
73 : for (y = 0; y < ioPixMap->height; y++)
74 : {
75 : src = (uint32_t *)((char *)ioPixMap->pixels + y * ioPixMap->rowBytes);
76 : xCount = ioPixMap->width;
77 :
78 : do
79 : {
80 : *dst++ = (*src++ >> shift) & 0xFF;
81 : }
82 : while (--xCount);
83 : }
84 : }
85 :
86 :
87 0 : BOOL OOPixMapToRGBA(OOPixMap *ioPixMap)
88 : {
89 : if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap))) return NO;
90 : if (ioPixMap->format == kOOPixMapRGBA) return YES;
91 :
92 : OOPixMap temp = OOAllocatePixMap(ioPixMap->width, ioPixMap->height, 4, 0, 0);
93 : if (EXPECT_NOT(OOIsNullPixMap(temp))) return NO;
94 :
95 : BOOL OK = NO;
96 : switch (ioPixMap->format)
97 : {
98 : case kOOPixMapGrayscale:
99 : ToRGBA_1(*ioPixMap, temp);
100 : OK = YES;
101 : break;
102 :
103 : case kOOPixMapGrayscaleAlpha:
104 : ToRGBA_2(*ioPixMap, temp);
105 : OK = YES;
106 : break;
107 :
108 : case kOOPixMapRGBA:
109 : case kOOPixMapInvalidFormat:
110 : OK = NO;
111 : break;
112 : // No default, because -Wswitch-enum is our friend.
113 : }
114 :
115 : if (OK)
116 : {
117 : free(ioPixMap->pixels);
118 : *ioPixMap = temp;
119 : }
120 : else
121 : {
122 : free(temp.pixels);
123 : }
124 :
125 : return OK;
126 : }
127 :
128 :
129 0 : static void ToRGBA_1(OOPixMap srcPx, OOPixMap dstPx)
130 : {
131 : NSCParameterAssert(OOPixMapBytesPerPixel(srcPx) == 1 && dstPx.format == kOOPixMapRGBA && srcPx.width == dstPx.width && srcPx.height == dstPx.height);
132 :
133 : uint8_t *src;
134 : uint32_t *dst;
135 : uint_fast32_t xCount, y;
136 :
137 : dst = dstPx.pixels;
138 :
139 : for (y = 0; y < srcPx.height; y++)
140 : {
141 : src = (uint8_t *)((char *)srcPx.pixels + y * srcPx.rowBytes);
142 : xCount = srcPx.width;
143 :
144 : do
145 : {
146 : *dst++ = (*src++ * 0x00010101) | 0xFF000000;
147 : }
148 : while (--xCount);
149 : }
150 : }
151 :
152 :
153 0 : static void ToRGBA_2(OOPixMap srcPx, OOPixMap dstPx)
154 : {
155 : NSCParameterAssert(OOPixMapBytesPerPixel(srcPx) == 2 && dstPx.format == kOOPixMapRGBA && srcPx.width == dstPx.width && srcPx.height == dstPx.height);
156 :
157 : uint16_t *src;
158 : uint_fast32_t px;
159 : uint32_t *dst;
160 : uint_fast32_t xCount, y;
161 :
162 : dst = dstPx.pixels;
163 :
164 : for (y = 0; y < srcPx.height; y++)
165 : {
166 : src = (uint16_t *)((char *)srcPx.pixels + y * srcPx.rowBytes);
167 : xCount = srcPx.width;
168 :
169 : do
170 : {
171 : px = *src++;
172 : #if OOLITE_BIG_ENDIAN
173 : *dst++ = (((px & 0xFF00) >> 8) * 0x00010101) | ((px & 0x00FF) << 24);
174 : #elif OOLITE_LITTLE_ENDIAN
175 : *dst++ = ((px & 0x00FF) * 0x00010101) | ((px & 0xFF00) << 16);
176 : #else
177 : #error Unknown byte order.
178 : #endif
179 : }
180 : while (--xCount);
181 : }
182 : }
183 :
184 :
185 0 : BOOL OOPixMapModulateUniform(OOPixMap *ioPixMap, float f0, float f1, float f2, float f3)
186 : {
187 : if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap))) return NO;
188 : if (EXPECT_NOT(!OOPixMapToRGBA(ioPixMap))) return NO;
189 :
190 : ModulateUniform_4(*ioPixMap, f0 * 256.0f, f1 * 256.0f, f2 * 256.0f, f3 * 256.0f);
191 :
192 : return YES;
193 : }
194 :
195 :
196 0 : static void ModulateUniform_4(OOPixMap pixMap, uint16_t f3, uint16_t f2, uint16_t f1, uint16_t f0)
197 : {
198 : NSCParameterAssert(OOPixMapBytesPerPixel(pixMap) == 4);
199 :
200 : uint32_t *curr;
201 : uint_fast32_t px;
202 : uint_fast32_t p0, p1, p2, p3;
203 : uint_fast32_t xCount, y;
204 :
205 : for (y = 0; y < pixMap.height; y++)
206 : {
207 : curr = (uint32_t *)((char *)pixMap.pixels + y * pixMap.rowBytes);
208 : xCount = pixMap.width;
209 :
210 : do
211 : {
212 : px = *curr;
213 :
214 : /* Principle of operation:
215 : Each pixel component is in the range 0..0xFF.
216 : Each constant factor component is in the range 0..0x100.
217 : Multiplying them therefore gives us a result in the range
218 : 0x0000..0xFF00. The bottom byte is discarded by shifting
219 : and masking.
220 : */
221 :
222 : p0 = px & 0xFF000000;
223 : p0 = ((p0 >> 8) * f0) & 0xFF000000;
224 :
225 : p1 = px & 0x00FF0000;
226 : p1 = ((p1 * f1) >> 8) & 0x00FF0000;
227 :
228 : p2 = px & 0x0000FF00;
229 : p2 = ((p2 * f2) >> 8) & 0x0000FF00;
230 :
231 : p3 = px & 0x000000FF;
232 : p3 = ((p3 * f3) >> 8) & 0x000000FF;
233 :
234 : px = p0 | p1 | p2 | p3;
235 : *curr++ = px;
236 : }
237 : while (--xCount);
238 : }
239 : }
240 :
241 :
242 0 : BOOL OOPixMapModulatePixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
243 : {
244 : if (EXPECT_NOT(ioDstPixMap == NULL || !OOIsValidPixMap(*ioDstPixMap))) return NO;
245 : if (EXPECT_NOT(!OOIsValidPixMap(otherPixMap) || otherPixMap.format != kOOPixMapRGBA)) return NO;
246 : if (EXPECT_NOT(!OOPixMapToRGBA(ioDstPixMap))) return NO;
247 : if (EXPECT_NOT(ioDstPixMap->width != otherPixMap.width || ioDstPixMap->height != otherPixMap.height)) return NO;
248 :
249 : ModulatePixMap_4(*ioDstPixMap, otherPixMap);
250 :
251 : return YES;
252 : }
253 :
254 :
255 0 : static void ModulatePixMap_4(OOPixMap mainPx, OOPixMap otherPx)
256 : {
257 : uint32_t *dst, *other;
258 : uint_fast32_t px;
259 : uint_fast16_t m0, m1, m2, m3;
260 : uint_fast16_t o0, o1, o2, o3;
261 : uint_fast32_t xCount, y;
262 :
263 : for (y = 0; y < mainPx.height; y++)
264 : {
265 : dst = (uint32_t *)((char *)mainPx.pixels + y * mainPx.rowBytes);
266 : other = (uint32_t *)((char *)otherPx.pixels + y * otherPx.rowBytes);
267 : xCount = mainPx.width;
268 :
269 : do
270 : {
271 : px = *dst;
272 : m0 = (px >> 24) & 0xFF;
273 : m1 = (px >> 16) & 0xFF;
274 : m2 = (px >> 8) & 0xFF;
275 : m3 = px & 0xFF;
276 :
277 : px = *other;
278 : o0 = (px >> 24) & 0xFF;
279 : o1 = (px >> 16) & 0xFF;
280 : o2 = (px >> 8) & 0xFF;
281 : o3 = px & 0xFF;
282 :
283 : /* Unlike in ModulateUniform(), neither side here goes to 256, so
284 : we have to divide by 255 rather than shifting. However, the
285 : compiler should be able to optimize this to a multiplication
286 : by a magic number.
287 : */
288 : m0 = (m0 * o0) / 255;
289 : m1 = (m1 * o1) / 255;
290 : m2 = (m2 * o2) / 255;
291 : m3 = (m3 * o3) / 255;
292 :
293 : *dst++ = ((uint_fast32_t)m0 << 24) | ((uint_fast32_t)m1 << 16) | (m2 << 8) | m3;
294 : other++;
295 : }
296 : while (--xCount);
297 : }
298 : }
299 :
300 :
301 0 : BOOL OOPixMapAddPixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
302 : {
303 : if (EXPECT_NOT(ioDstPixMap == NULL || !OOIsValidPixMap(*ioDstPixMap))) return NO;
304 : if (EXPECT_NOT(!OOIsValidPixMap(otherPixMap) || otherPixMap.format != kOOPixMapRGBA)) return NO;
305 : if (EXPECT_NOT(!OOPixMapToRGBA(ioDstPixMap))) return NO;
306 : if (EXPECT_NOT(ioDstPixMap->width != otherPixMap.width || ioDstPixMap->height != otherPixMap.height)) return NO;
307 :
308 : AddPixMap_4(*ioDstPixMap, otherPixMap);
309 :
310 : return YES;
311 : }
312 :
313 :
314 0 : static void AddPixMap_4(OOPixMap mainPx, OOPixMap otherPx)
315 : {
316 : uint32_t *dst, *other;
317 : uint_fast32_t px;
318 : uint_fast32_t m02, m13;
319 : uint_fast32_t o02, o13;
320 : uint_fast32_t xCount, y;
321 :
322 : for (y = 0; y < mainPx.height; y++)
323 : {
324 : dst = (uint32_t *)((char *)mainPx.pixels + y * mainPx.rowBytes);
325 : other = (uint32_t *)((char *)otherPx.pixels + y * otherPx.rowBytes);
326 : xCount = mainPx.width;
327 :
328 : do
329 : {
330 : px = *dst;
331 : m02 = (px & 0xFF00FF00) >> 8;
332 : m13 = px & 0x00FF00FF;
333 :
334 : px = *other;
335 : o02 = (px & 0xFF00FF00) >> 8;
336 : o13 = px & 0x00FF00FF;
337 :
338 : /* Saturated adds, two components at a time.
339 : By masking out the overflow bits of each component,
340 : multiplying them by 0xFF and shifting right one byte, we get a
341 : mask that's oxFF for components that overflowed and 0x00 for
342 : components that did not, without any conditionals.
343 : */
344 : m02 += o02;
345 : m02 |= ((m02 & 0x01000100) * 0xFF) >> 8;
346 : m13 += o13;
347 : m13 |= ((m13 & 0x01000100) * 0xFF) >> 8;
348 :
349 : *dst++ = ((m02 << 8) & 0xFF00FF00) | (m13 & 0x00FF00FF);
350 : other++;
351 : }
352 : while (--xCount);
353 : }
354 : }
355 :
|