Add some tolerance for alpha values.
[SquirrelJME.git] / nanocoat / lib / scritchui / scritchPencilRasterScan.c
blob9b4faa8b16ab764e7383c29514c607c717a4817e
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
10 #include <string.h>
12 #include "sjme/util.h"
13 #include "lib/scritchui/scritchui.h"
14 #include "lib/scritchui/scritchuiPencil.h"
15 #include "lib/scritchui/scritchuiTypes.h"
16 #include "lib/scritchui/core/coreRaster.h"
17 #include "sjme/debug.h"
18 #include "sjme/fixed.h"
20 sjme_errorCode sjme_scritchpen_corePrim_rawScanFillInt(
21 sjme_attrInNotNull sjme_scritchui_pencil g,
22 sjme_attrOutNotNullBuf(rawLen) void* outRaw,
23 sjme_attrInPositive sjme_jint outRawOff,
24 sjme_attrInPositive sjme_jint outRawLen,
25 sjme_attrInValue sjme_jint rawPixel,
26 sjme_attrInPositiveNonZero sjme_jint inNumPixels)
28 sjme_jint limit, i;
29 sjme_jint* p;
31 if (g == NULL || outRaw == NULL)
32 return SJME_ERROR_NULL_ARGUMENTS;
34 if (outRawOff < 0 || outRawLen < 0 || (outRawOff + outRawLen) < 0 ||
35 (inNumPixels < 0))
36 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
38 /* Determine number of pixels to actually draw. */
39 limit = inNumPixels * g->bytesPerPixel;
41 if (limit < 0)
42 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
44 if (outRawLen < limit)
45 limit = outRawLen;
47 /* Fill in. */
48 p = SJME_POINTER_OFFSET(outRaw, outRawOff);
49 for (i = 0; i < limit; i += 4)
50 *(p++) = rawPixel;
52 /* Success! */
53 return SJME_ERROR_NONE;
56 sjme_errorCode sjme_scritchpen_corePrim_rawScanFillShort(
57 sjme_attrInNotNull sjme_scritchui_pencil g,
58 sjme_attrOutNotNullBuf(rawLen) void* outRaw,
59 sjme_attrInPositive sjme_jint outRawOff,
60 sjme_attrInPositive sjme_jint outRawLen,
61 sjme_attrInValue sjme_jint rawPixel,
62 sjme_attrInPositiveNonZero sjme_jint inNumPixels)
64 sjme_jint limit, i;
65 sjme_jshort* p;
67 if (g == NULL || outRaw == NULL)
68 return SJME_ERROR_NULL_ARGUMENTS;
70 if (outRawOff < 0 || outRawLen < 0 || (outRawOff + outRawLen) < 0 ||
71 (inNumPixels < 0))
72 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
74 /* Determine number of pixels to actually draw. */
75 limit = inNumPixels * g->bytesPerPixel;
77 if (limit < 0)
78 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
80 if (outRawLen < limit)
81 limit = outRawLen;
83 /* Fill in. */
84 p = SJME_POINTER_OFFSET(outRaw, outRawOff);
85 for (i = 0; i < limit; i += 2)
86 *(p++) = rawPixel;
88 /* Success! */
89 return SJME_ERROR_NONE;
92 sjme_errorCode sjme_scritchpen_corePrim_rawScanFillByte(
93 sjme_attrInNotNull sjme_scritchui_pencil g,
94 sjme_attrOutNotNullBuf(rawLen) void* outRaw,
95 sjme_attrInPositive sjme_jint outRawOff,
96 sjme_attrInPositive sjme_jint outRawLen,
97 sjme_attrInValue sjme_jint rawPixel,
98 sjme_attrInPositiveNonZero sjme_jint inNumPixels)
100 sjme_jint limit, i;
101 sjme_jbyte* p;
103 if (g == NULL || outRaw == NULL)
104 return SJME_ERROR_NULL_ARGUMENTS;
106 if (outRawOff < 0 || outRawLen < 0 || (outRawOff + outRawLen) < 0 ||
107 (inNumPixels < 0))
108 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
110 /* Determine number of pixels to actually draw. */
111 limit = inNumPixels * g->bytesPerPixel;
113 if (limit < 0)
114 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
116 if (outRawLen < limit)
117 limit = outRawLen;
119 /* Fill in. */
120 p = SJME_POINTER_OFFSET(outRaw, outRawOff);
121 for (i = 0; i < limit; i += 1)
122 *(p++) = rawPixel;
124 /* Success! */
125 return SJME_ERROR_NONE;
128 sjme_errorCode sjme_scritchpen_corePrim_rawScanGetNoDest(
129 sjme_attrInNotNull sjme_scritchui_pencil g,
130 sjme_attrInPositive sjme_jint x,
131 sjme_attrInPositive sjme_jint y,
132 sjme_attrOutNotNullBuf(inLen) void* outData,
133 sjme_attrInPositiveNonZero sjme_jint inDataLen,
134 sjme_attrInPositiveNonZero sjme_jint inNumPixels)
136 if (g == NULL || outData == NULL)
137 return SJME_ERROR_NULL_ARGUMENTS;
139 if (inDataLen < 0 || inNumPixels < 0)
140 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
142 /* Just set everything to the first default value. */
143 memset(outData, 0, inDataLen);
145 /* Do nothing, there is no reading function. */
146 return SJME_ERROR_NONE;
149 sjme_errorCode sjme_scritchpen_coreUtil_blendRGBInto(
150 sjme_attrInNotNull sjme_scritchui_pencil g,
151 sjme_attrInValue sjme_jboolean destAlpha,
152 sjme_attrInValue sjme_jboolean srcAlpha,
153 sjme_attrInValue sjme_jboolean mulAlpha,
154 sjme_attrInRange(0, 255) sjme_jint mulAlphaValue,
155 sjme_attrInNotNullBuf(numPixels) sjme_jint* dest,
156 sjme_attrInNotNullBuf(numPixels) const sjme_jint* src,
157 sjme_attrInPositive sjme_jint numPixels)
159 sjme_jint i;
160 sjme_fixed sa, sr, sg, sb, da, dr, dg, db, iA, ca, cr, cg, cb, tff;
161 sjme_juint srcMask, destMask;
163 if (g == NULL || dest == NULL || src == NULL)
164 return SJME_ERROR_NULL_ARGUMENTS;
166 if (numPixels < 0)
167 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
169 /* Source and dest mask, if alpha is applicable. */
170 destMask = (destAlpha ? 0 : UINT32_C(0xFF000000));
171 srcMask = (srcAlpha ? 0 : UINT32_C(0xFF000000));
173 /* Blend each pixel individually. */
174 /* R(dest) = (R(src) * A(src)) + (R(dest) * (1 - A(src))) */
175 /* G(dest) = (G(src) * A(src)) + (G(dest) * (1 - A(src))) */
176 /* B(dest) = (B(src) * A(src)) + (B(dest) * (1 - A(src))) */
177 /* A(dest) = A(src) + A(dest) - (A(src) * A(dest)) */
178 tff = sjme_fixed_hi(255);
179 for (i = 0; i < numPixels; i++)
181 /* Extract as integers first. */
182 da = ((dest[i] | destMask) >> 24) & 0xFF;
183 dr = ((dest[i]) >> 16) & 0xFF;
184 dg = ((dest[i]) >> 8) & 0xFF;
185 db = dest[i] & 0xFF;
187 sa = ((src[i] | srcMask) >> 24) & 0xFF;
188 sr = ((src[i]) >> 16) & 0xFF;
189 sg = ((src[i]) >> 8) & 0xFF;
190 sb = src[i] & 0xFF;
192 /* Extract components. */
193 da = sjme_fixed_fraction(da, 255);
194 dr = sjme_fixed_fraction(dr, 255);
195 dg = sjme_fixed_fraction(dg, 255);
196 db = sjme_fixed_fraction(db, 255);
198 sa = sjme_fixed_fraction(sa, 255);
199 sr = sjme_fixed_fraction(sr, 255);
200 sg = sjme_fixed_fraction(sg, 255);
201 sb = sjme_fixed_fraction(sb, 255);
203 iA = sjme_fixed_hi(1) - sa;
205 /* A(dest) = A(src) + A(dest) - (A(src) * A(dest)) */
206 ca = sa + da - sjme_fixed_mul(sa, da);
208 /* R(dest) = (R(src) * A(src)) + (R(dest) * (1 - A(src))) */
209 cr = sjme_fixed_mul(sr, sa) + sjme_fixed_mul(dr, iA);
211 /* G(dest) = (G(src) * A(src)) + (G(dest) * (1 - A(src))) */
212 cg = sjme_fixed_mul(sg, sa) + sjme_fixed_mul(dg, iA);
214 /* B(dest) = (B(src) * A(src)) + (B(dest) * (1 - A(src))) */
215 cb = sjme_fixed_mul(sb, sa) + sjme_fixed_mul(db, iA);
217 /* Return the original factor. */
218 ca = sjme_fixed_ceil(sjme_fixed_mul(ca, tff));
219 cr = sjme_fixed_ceil(sjme_fixed_mul(cr, tff));
220 cg = sjme_fixed_ceil(sjme_fixed_mul(cg, tff));
221 cb = sjme_fixed_ceil(sjme_fixed_mul(cb, tff));
223 /* Recompose. */
224 ca = sjme_fixed_int(ca) & 0xFF;
225 cr = sjme_fixed_int(cr) & 0xFF;
226 cg = sjme_fixed_int(cg) & 0xFF;
227 cb = sjme_fixed_int(cb) & 0xFF;
228 dest[i] = (ca << 24) | (cr << 16) | (cg << 8) | cb | destMask;
231 /* Success! */
232 return SJME_ERROR_NONE;
235 sjme_errorCode sjme_scritchpen_coreUtil_rawScanBytes(
236 sjme_attrInNotNull sjme_scritchui_pencil g,
237 sjme_attrInPositiveNonZero sjme_jint inPixels,
238 sjme_attrInPositiveNonZero sjme_jint inBytes,
239 sjme_attrOutNotNull sjme_attrOutPositiveNonZero sjme_jint* outBytes,
240 sjme_attrOutNullable sjme_attrOutPositiveNonZero sjme_jint* outLimit)
242 sjme_jint result;
244 if (g == NULL || outBytes == NULL)
245 return SJME_ERROR_NULL_ARGUMENTS;
247 if (inPixels < 0 || (outLimit != NULL && inBytes < 0))
248 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
250 /* Depends on the pixel format. */
251 result = -1;
252 switch (g->pixelFormat)
254 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888:
255 case SJME_GFX_PIXEL_FORMAT_INT_RGB888:
256 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888:
257 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888:
258 case SJME_GFX_PIXEL_FORMAT_INT_BGR888:
259 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888:
260 result = inPixels * 4;
261 break;
263 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888:
264 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888:
265 result = inPixels * 3;
266 break;
268 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444:
269 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565:
270 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555:
271 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555:
272 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536:
273 result = inPixels * 2;
274 break;
276 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
277 result = inPixels;
278 break;
280 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
281 result = (inPixels >> 1) + (inPixels & 1);
282 break;
284 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
285 result = (inPixels >> 2) + ((inPixels >> 1) & 1);
286 break;
288 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
289 result = (inPixels >> 3) + ((inPixels >> 2) & 1);
290 break;
293 /* Make sure what was calculated did not overflow. */
294 if (result < 0)
295 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
297 /* Calculate smaller value? */
298 if (outLimit != NULL)
300 /* Use the smaller of the two. */
301 if (result < inBytes)
302 *outLimit = inBytes;
303 else
304 *outLimit = result;
307 /* Success! */
308 *outBytes = result;
309 return SJME_ERROR_NONE;
312 sjme_errorCode sjme_scritchpen_coreUtil_rawScanToRgb(
313 sjme_attrInNotNull sjme_scritchui_pencil g,
314 sjme_attrInNotNullBuf(outRgbLen) sjme_jint* outRgb,
315 sjme_attrInPositive sjme_jint outRgbOff,
316 sjme_attrInPositive sjme_jint outRgbLen,
317 sjme_attrOutNotNullBuf(inRawLen) const void* inRaw,
318 sjme_attrInPositive sjme_jint inRawOff,
319 sjme_attrInPositive sjme_jint inRawLen)
321 sjme_errorCode error;
322 sjme_juint destAlphaMask;
323 sjme_jint limit, i, t, mulShift, j;
324 const sjme_jint* si;
325 const sjme_jshort* ss;
326 const sjme_jbyte* sb;
327 sjme_jint* d;
328 sjme_scritchui_pencilColor color;
330 if (g == NULL || outRgb == NULL || inRaw == NULL)
331 return SJME_ERROR_NULL_ARGUMENTS;
333 if (outRgbOff < 0 || outRgbLen < 0 || (outRgbOff + outRgbLen) < 0 ||
334 inRawOff < 0 || inRawLen < 0 || (inRawOff + inRawLen) < 0)
335 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
337 /* Destination alpha mask. */
338 destAlphaMask = (g->hasAlpha ? 0 : 0xFF000000);
340 /* Determine the type to use for scan reading. */
341 si = NULL;
342 ss = NULL;
343 sb = NULL;
344 mulShift = 1;
345 switch (g->pixelFormat)
347 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888:
348 case SJME_GFX_PIXEL_FORMAT_INT_RGB888:
349 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888:
350 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888:
351 case SJME_GFX_PIXEL_FORMAT_INT_BGR888:
352 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888:
353 si = SJME_POINTER_OFFSET(inRaw, inRawOff);
354 limit = inRawLen / 4;
355 break;
357 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888:
358 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888:
359 sb = SJME_POINTER_OFFSET(inRaw, inRawOff);
360 limit = inRawLen / 3;
361 mulShift = 3;
362 break;
364 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444:
365 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565:
366 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555:
367 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555:
368 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536:
369 ss = SJME_POINTER_OFFSET(inRaw, inRawOff);
370 limit = inRawLen / 2;
371 break;
373 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
374 sb = SJME_POINTER_OFFSET(inRaw, inRawOff);
375 limit = inRawLen;
376 break;
378 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
379 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
380 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
381 sjme_todo("Impl?");
382 break;
384 default:
385 return SJME_ERROR_INVALID_ARGUMENT;
388 /* Writing where? */
389 d = &outRgb[outRgbOff];
391 /* If the output RGB is smaller than the raw input, limit to it. */
392 if (outRgbLen < limit)
393 limit = outRgbLen;
395 /* Clear error state. */
396 error = SJME_ERROR_NONE;
398 /* Already in the most native format? */
399 if (g->pixelFormat == SJME_GFX_PIXEL_FORMAT_INT_ARGB8888 && si != NULL)
400 memmove(d, si, limit * 4);
402 /* Almost there. */
403 else if (g->pixelFormat == SJME_GFX_PIXEL_FORMAT_INT_RGB888 && si != NULL)
405 /* Copy and put in the mask. */
406 for (i = 0; i < limit; i++)
407 *(d++) = *(si++) | destAlphaMask;
410 /* Integer mapping. */
411 else if (si != NULL)
413 for (i = 0; i < limit; i++)
415 t = *(si++);
417 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
418 t, &color);
420 *(d++) = color.argb | destAlphaMask;
424 /* Short mapping. */
425 else if (ss != NULL)
427 for (i = 0; i < limit; i++)
429 t = *(ss++) & 0xFFFF;
431 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
432 t, &color);
434 *(d++) = color.argb | destAlphaMask;
438 /* Triple byte? */
439 else if (sb != NULL && mulShift == 3)
441 for (i = 0; i < limit; i++)
443 t = ((sjme_juint)(((*(sb++)) & 0xFF))) << 16;
444 t |= ((sjme_juint)(((*(sb++)) & 0xFF))) << 8;
445 t |= ((sjme_juint)(((*(sb++)) & 0xFF)));
447 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
448 t, &color);
450 *(d++) = color.argb | destAlphaMask;
454 /* Byte mapping. */
455 else if (sb != NULL)
457 for (i = 0; i < limit; i++)
459 t = *(sb++) & 0xFF;
461 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
462 t, &color);
464 *(d++) = color.argb | destAlphaMask;
468 /* Unknown. */
469 else
471 sjme_todo("Impl?");
474 /* Failed or success? */
475 if (sjme_error_is(error))
476 return sjme_error_default(error);
477 return SJME_ERROR_NONE;
480 sjme_errorCode sjme_scritchpen_coreUtil_rgbScanFill(
481 sjme_attrInNotNull sjme_scritchui_pencil g,
482 sjme_attrOutNotNullBuf(inNumPixels) sjme_jint* outRgb,
483 sjme_attrInPositiveNonZero sjme_jint outRgbOff,
484 sjme_attrInPositiveNonZero sjme_jint inNumPixels,
485 sjme_attrInValue sjme_jint inValue)
487 sjme_jint i;
488 sjme_jint* p;
490 if (g == NULL || outRgb == NULL)
491 return SJME_ERROR_NULL_ARGUMENTS;
493 if (outRgbOff < 0 || inNumPixels < 0 ||
494 (outRgbOff + inNumPixels) < 0)
495 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
497 /* Fill in, which is a rather simple operation. */
498 p = &outRgb[outRgbOff];
499 for (i = 0; i < inNumPixels; i++)
500 *(p++) = inValue;
502 /* Success! */
503 return SJME_ERROR_NONE;
506 sjme_errorCode sjme_scritchpen_coreUtil_rgbScanGet(
507 sjme_attrInNotNull sjme_scritchui_pencil g,
508 sjme_attrInPositive sjme_jint x,
509 sjme_attrInPositive sjme_jint y,
510 sjme_attrOutNotNullBuf(inLen) sjme_jint* destRgb,
511 sjme_attrInPositiveNonZero sjme_jint inNumPixels)
513 sjme_errorCode error;
514 sjme_jint ex, rgbBytes, rawScanBytes;
515 void* rawScan;
517 if (g == NULL || destRgb == NULL)
518 return SJME_ERROR_NONE;
520 /* We cannot access a region outside the image bounds. */
521 ex = x + inNumPixels;
522 rgbBytes = inNumPixels * sizeof(*destRgb);
523 if (x < 0 || y < 0 || inNumPixels < 0 ||
524 ex < 0 || ex > g->width || rgbBytes < 0)
525 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
527 /* How much data is to be read? */
528 rawScanBytes = (inNumPixels * g->bitsPerPixel) / 8;
529 if (rawScanBytes < 0)
530 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
532 /* Allocate. */
533 rawScan = sjme_alloca(rawScanBytes);
534 if (rawScan == NULL)
535 return SJME_ERROR_OUT_OF_MEMORY;
537 /* Clear. */
538 memset(rawScan, 0, rawScanBytes);
540 /* Load in from image directly. */
541 if (sjme_error_is(error = g->prim.rawScanGet(g,
542 x, y, rawScan, rawScanBytes, inNumPixels)))
543 return sjme_error_default(error);
545 /* Map to RGB. */
546 return g->util->rawScanToRgb(g,
547 destRgb, 0, inNumPixels,
548 rawScan, 0, rawScanBytes);
551 sjme_errorCode sjme_scritchpen_coreUtil_rgbScanPut(
552 sjme_attrInNotNull sjme_scritchui_pencil g,
553 sjme_attrInPositive sjme_jint x,
554 sjme_attrInPositive sjme_jint y,
555 sjme_attrInNotNullBuf(inLen) const sjme_jint* srcRgb,
556 sjme_attrInPositiveNonZero sjme_jint inNumPixels,
557 sjme_attrInValue sjme_jboolean srcAlpha,
558 sjme_attrInValue sjme_jboolean mulAlpha,
559 sjme_attrInRange(0, 255) sjme_jint mulAlphaValue)
561 sjme_errorCode error;
562 sjme_jint ex, rawScanBytes, rgbBytes;
563 void* rawScan;
564 sjme_jint* destRgb;
566 if (g == NULL || srcRgb == NULL)
567 return SJME_ERROR_NONE;
569 /* We cannot access a region outside the image bounds. */
570 ex = x + inNumPixels;
571 rgbBytes = inNumPixels * sizeof(*destRgb);
572 if (x < 0 || y < 0 || inNumPixels < 0 ||
573 ex < 0 || ex > g->width || rgbBytes < 0 ||
574 (mulAlpha && (mulAlphaValue < 0 || mulAlphaValue > 255)))
575 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
577 /* How much data is to be written? */
578 rawScanBytes = (inNumPixels * g->bitsPerPixel) / 8;
579 if (rawScanBytes < 0)
580 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
582 /* Do we need to alpha blend? */
583 if (srcAlpha || mulAlpha)
585 /* Allocate dest RGB data. */
586 destRgb = sjme_alloca(rgbBytes);
587 if (destRgb == NULL)
588 return SJME_ERROR_OUT_OF_MEMORY;
590 /* Clear. */
591 memset(destRgb, 0, rgbBytes);
593 /* Load in RGB data from image, which might be lossy. */
594 if (sjme_error_is(error = g->util->rgbScanGet(g,
595 x, y, destRgb, inNumPixels)))
596 return sjme_error_default(error);
598 /* Perform blending. */
599 if (sjme_error_is(error = g->util->blendRGBInto(g,
600 g->hasAlpha, srcAlpha,
601 mulAlpha, mulAlphaValue,
602 destRgb, srcRgb, inNumPixels)))
603 return sjme_error_default(error);
605 /* The destination becomes the new source. */
606 srcRgb = destRgb;
609 /* Allocate raw scan data. */
610 rawScan = sjme_alloca(rawScanBytes);
611 if (rawScan == NULL)
612 return SJME_ERROR_OUT_OF_MEMORY;
614 /* Clear. */
615 memset(rawScan, 0, rawScanBytes);
617 /* Map from RGB to raw pixels. */
618 if (sjme_error_is(error = g->util->rgbToRawScan(g,
619 rawScan, 0, rawScanBytes,
620 srcRgb, 0, inNumPixels)))
621 return sjme_error_default(error);
623 /* Write direct image data. */
624 return g->prim.rawScanPutPure(g,
625 x, y,
626 rawScan, rawScanBytes, inNumPixels);
629 sjme_errorCode sjme_scritchpen_coreUtil_rgbToRawScan(
630 sjme_attrInNotNull sjme_scritchui_pencil g,
631 sjme_attrOutNotNullBuf(rawLen) void* outRaw,
632 sjme_attrInPositive sjme_jint outRawOff,
633 sjme_attrInPositive sjme_jint outRawLen,
634 sjme_attrInNotNullBuf(rgbLen) const sjme_jint* inRgb,
635 sjme_attrInPositive sjme_jint inRgbOff,
636 sjme_attrInPositive sjme_jint inRgbLen)
638 sjme_errorCode error;
639 sjme_jint limit, i, t, mulShift, j;
640 sjme_jint* di;
641 sjme_jshort* ds;
642 sjme_jbyte* db;
643 const sjme_jint* s;
644 sjme_scritchui_pencilColor color;
646 if (g == NULL || inRgb == NULL || outRaw == NULL)
647 return SJME_ERROR_NULL_ARGUMENTS;
649 if (inRgbOff < 0 || inRgbLen < 0 || (inRgbOff + inRgbLen) < 0 ||
650 outRawOff < 0 || outRawLen < 0 || (outRawOff + outRawLen) < 0)
651 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
653 /* Determine the type to use for scan reading. */
654 di = NULL;
655 ds = NULL;
656 db = NULL;
657 mulShift = 1;
658 switch (g->pixelFormat)
660 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888:
661 case SJME_GFX_PIXEL_FORMAT_INT_RGB888:
662 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888:
663 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888:
664 case SJME_GFX_PIXEL_FORMAT_INT_BGR888:
665 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888:
666 di = SJME_POINTER_OFFSET(outRaw, outRawOff);
667 limit = outRawLen / 4;
668 break;
670 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888:
671 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888:
672 db = SJME_POINTER_OFFSET(outRaw, outRawOff);
673 limit = outRawLen / 3;
674 mulShift = 3;
675 break;
677 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444:
678 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565:
679 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555:
680 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555:
681 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536:
682 ds = SJME_POINTER_OFFSET(outRaw, outRawOff);
683 limit = outRawLen / 2;
684 break;
686 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
687 db = SJME_POINTER_OFFSET(outRaw, outRawOff);
688 limit = outRawLen;
689 break;
691 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
692 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
693 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
694 sjme_todo("Impl?");
695 break;
697 default:
698 return SJME_ERROR_INVALID_ARGUMENT;
701 /* Reading what? */
702 s = &inRgb[inRgbOff];
704 /* If the output RGB is smaller than the raw input, limit to it. */
705 if (inRgbLen < limit)
706 limit = inRgbLen;
708 /* Clear error state. */
709 error = SJME_ERROR_NONE;
711 /* Already in the most native format? */
712 if (g->pixelFormat == SJME_GFX_PIXEL_FORMAT_INT_ARGB8888 && di != NULL)
713 memmove(di, s, limit * 4);
715 /* Almost there. */
716 else if (g->pixelFormat == SJME_GFX_PIXEL_FORMAT_INT_RGB888 && di != NULL)
718 /* Copy and put in the mask. */
719 for (i = 0; i < limit; i++)
720 *(di++) = *(s++);
723 /* Integer mapping. */
724 else if (di != NULL)
726 for (i = 0; i < limit; i++)
728 t = *(s++);
730 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
731 t, &color);
733 *(di++) = color.v;
737 /* Short mapping. */
738 else if (ds != NULL)
740 for (i = 0; i < limit; i++)
742 t = *(s++);
744 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
745 t, &color);
747 *(ds++) = color.v & 0xFFFF;
751 /* Triple byte? */
752 else if (db != NULL && mulShift == 3)
754 for (i = 0; i < limit; i++)
756 t = *(s++);
758 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
759 t, &color);
761 *(db++) = (color.v >> 16) & 0xFF;
762 *(db++) = (color.v >> 8) & 0xFF;
763 *(db++) = (color.v) & 0xFF;
767 /* Byte mapping. */
768 else if (db != NULL)
770 for (i = 0; i < limit; i++)
772 t = *(s++);
774 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
775 t, &color);
777 *(db++) = color.v & 0xFF;
781 /* Unknown. */
782 else
784 sjme_todo("Impl?");
787 /* Failed or success? */
788 if (sjme_error_is(error))
789 return sjme_error_default(error);
790 return SJME_ERROR_NONE;