1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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 // -------------------------------------------------------------------------*/
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
)
31 if (g
== NULL
|| outRaw
== NULL
)
32 return SJME_ERROR_NULL_ARGUMENTS
;
34 if (outRawOff
< 0 || outRawLen
< 0 || (outRawOff
+ outRawLen
) < 0 ||
36 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
38 /* Determine number of pixels to actually draw. */
39 limit
= inNumPixels
* g
->bytesPerPixel
;
42 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
44 if (outRawLen
< limit
)
48 p
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
49 for (i
= 0; i
< limit
; i
+= 4)
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
)
67 if (g
== NULL
|| outRaw
== NULL
)
68 return SJME_ERROR_NULL_ARGUMENTS
;
70 if (outRawOff
< 0 || outRawLen
< 0 || (outRawOff
+ outRawLen
) < 0 ||
72 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
74 /* Determine number of pixels to actually draw. */
75 limit
= inNumPixels
* g
->bytesPerPixel
;
78 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
80 if (outRawLen
< limit
)
84 p
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
85 for (i
= 0; i
< limit
; i
+= 2)
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
)
103 if (g
== NULL
|| outRaw
== NULL
)
104 return SJME_ERROR_NULL_ARGUMENTS
;
106 if (outRawOff
< 0 || outRawLen
< 0 || (outRawOff
+ outRawLen
) < 0 ||
108 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
110 /* Determine number of pixels to actually draw. */
111 limit
= inNumPixels
* g
->bytesPerPixel
;
114 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
116 if (outRawLen
< limit
)
120 p
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
121 for (i
= 0; i
< limit
; i
+= 1)
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
)
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
;
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;
187 sa
= ((src
[i
] | srcMask
) >> 24) & 0xFF;
188 sr
= ((src
[i
]) >> 16) & 0xFF;
189 sg
= ((src
[i
]) >> 8) & 0xFF;
193 iA
= sjme_fixed_fraction(255 - sa
, 255);
195 /* Extract components. */
196 da
= sjme_fixed_fraction(da
, 255);
197 dr
= sjme_fixed_fraction(dr
, 255);
198 dg
= sjme_fixed_fraction(dg
, 255);
199 db
= sjme_fixed_fraction(db
, 255);
201 sa
= sjme_fixed_fraction(sa
, 255);
202 sr
= sjme_fixed_fraction(sr
, 255);
203 sg
= sjme_fixed_fraction(sg
, 255);
204 sb
= sjme_fixed_fraction(sb
, 255);
206 /* A(dest) = A(src) + A(dest) - (A(src) * A(dest)) */
207 ca
= sa
+ da
- sjme_fixed_mul(sa
, da
);
209 /* R(dest) = (R(src) * A(src)) + (R(dest) * (1 - A(src))) */
210 cr
= sjme_fixed_mul(sr
, sa
) + sjme_fixed_mul(dr
, iA
);
212 /* G(dest) = (G(src) * A(src)) + (G(dest) * (1 - A(src))) */
213 cg
= sjme_fixed_mul(sg
, sa
) + sjme_fixed_mul(dg
, iA
);
215 /* B(dest) = (B(src) * A(src)) + (B(dest) * (1 - A(src))) */
216 cb
= sjme_fixed_mul(sb
, sa
) + sjme_fixed_mul(db
, iA
);
218 /* Return the original factor. */
219 ca
= sjme_fixed_mul(ca
, tff
);
220 cr
= sjme_fixed_mul(cr
, tff
);
221 cg
= sjme_fixed_mul(cg
, tff
);
222 cb
= sjme_fixed_mul(cb
, tff
);
225 ca
= sjme_fixed_int(ca
) & 0xFF;
226 cr
= sjme_fixed_int(cr
) & 0xFF;
227 cg
= sjme_fixed_int(cg
) & 0xFF;
228 cb
= sjme_fixed_int(cb
) & 0xFF;
229 dest
[i
] = (ca
<< 24) | (cr
<< 16) | (cg
<< 8) | cb
| destMask
;
233 return SJME_ERROR_NONE
;
236 sjme_errorCode
sjme_scritchpen_coreUtil_rawScanBytes(
237 sjme_attrInNotNull sjme_scritchui_pencil g
,
238 sjme_attrInPositiveNonZero sjme_jint inPixels
,
239 sjme_attrInPositiveNonZero sjme_jint inBytes
,
240 sjme_attrOutNotNull sjme_attrOutPositiveNonZero sjme_jint
* outBytes
,
241 sjme_attrOutNullable sjme_attrOutPositiveNonZero sjme_jint
* outLimit
)
245 if (g
== NULL
|| outBytes
== NULL
)
246 return SJME_ERROR_NULL_ARGUMENTS
;
248 if (inPixels
< 0 || (outLimit
!= NULL
&& inBytes
< 0))
249 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
251 /* Depends on the pixel format. */
253 switch (g
->pixelFormat
)
255 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888
:
256 case SJME_GFX_PIXEL_FORMAT_INT_RGB888
:
257 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888
:
258 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888
:
259 case SJME_GFX_PIXEL_FORMAT_INT_BGR888
:
260 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888
:
261 result
= inPixels
* 4;
264 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888
:
265 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888
:
266 result
= inPixels
* 3;
269 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444
:
270 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565
:
271 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555
:
272 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555
:
273 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536
:
274 result
= inPixels
* 2;
277 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256
:
281 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4
:
282 result
= (inPixels
>> 1) + (inPixels
& 1);
285 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2
:
286 result
= (inPixels
>> 2) + ((inPixels
>> 1) & 1);
289 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1
:
290 result
= (inPixels
>> 3) + ((inPixels
>> 2) & 1);
294 /* Make sure what was calculated did not overflow. */
296 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
298 /* Calculate smaller value? */
299 if (outLimit
!= NULL
)
301 /* Use the smaller of the two. */
302 if (result
< inBytes
)
310 return SJME_ERROR_NONE
;
313 sjme_errorCode
sjme_scritchpen_coreUtil_rawScanToRgb(
314 sjme_attrInNotNull sjme_scritchui_pencil g
,
315 sjme_attrInNotNullBuf(outRgbLen
) sjme_jint
* outRgb
,
316 sjme_attrInPositive sjme_jint outRgbOff
,
317 sjme_attrInPositive sjme_jint outRgbLen
,
318 sjme_attrOutNotNullBuf(inRawLen
) sjme_cpointer inRaw
,
319 sjme_attrInPositive sjme_jint inRawOff
,
320 sjme_attrInPositive sjme_jint inRawLen
)
322 sjme_errorCode error
;
323 sjme_juint destAlphaMask
;
324 sjme_jint limit
, i
, t
, mulShift
, j
;
326 const sjme_jshort
* ss
;
327 const sjme_jbyte
* sb
;
329 sjme_scritchui_pencilColor color
;
331 if (g
== NULL
|| outRgb
== NULL
|| inRaw
== NULL
)
332 return SJME_ERROR_NULL_ARGUMENTS
;
334 if (outRgbOff
< 0 || outRgbLen
< 0 || (outRgbOff
+ outRgbLen
) < 0 ||
335 inRawOff
< 0 || inRawLen
< 0 || (inRawOff
+ inRawLen
) < 0)
336 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
338 /* Destination alpha mask. */
339 destAlphaMask
= (g
->hasAlpha
? 0 : 0xFF000000);
341 /* Determine the type to use for scan reading. */
346 switch (g
->pixelFormat
)
348 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888
:
349 case SJME_GFX_PIXEL_FORMAT_INT_RGB888
:
350 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888
:
351 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888
:
352 case SJME_GFX_PIXEL_FORMAT_INT_BGR888
:
353 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888
:
354 si
= SJME_POINTER_OFFSET(inRaw
, inRawOff
);
355 limit
= inRawLen
/ 4;
358 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888
:
359 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888
:
360 sb
= SJME_POINTER_OFFSET(inRaw
, inRawOff
);
361 limit
= inRawLen
/ 3;
365 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444
:
366 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565
:
367 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555
:
368 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555
:
369 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536
:
370 ss
= SJME_POINTER_OFFSET(inRaw
, inRawOff
);
371 limit
= inRawLen
/ 2;
374 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256
:
375 sb
= SJME_POINTER_OFFSET(inRaw
, inRawOff
);
379 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4
:
380 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2
:
381 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1
:
386 return SJME_ERROR_INVALID_ARGUMENT
;
390 d
= &outRgb
[outRgbOff
];
392 /* If the output RGB is smaller than the raw input, limit to it. */
393 if (outRgbLen
< limit
)
396 /* Clear error state. */
397 error
= SJME_ERROR_NONE
;
399 /* Already in the most native format? */
400 if (g
->pixelFormat
== SJME_GFX_PIXEL_FORMAT_INT_ARGB8888
&& si
!= NULL
)
401 memmove(d
, si
, limit
* 4);
404 else if (g
->pixelFormat
== SJME_GFX_PIXEL_FORMAT_INT_RGB888
&& si
!= NULL
)
406 /* Copy and put in the mask. */
407 for (i
= 0; i
< limit
; i
++)
408 *(d
++) = *(si
++) | destAlphaMask
;
411 /* Integer mapping. */
414 for (i
= 0; i
< limit
; i
++)
418 error
|= sjme_scritchpen_corePrim_mapColorFromRaw(g
,
421 *(d
++) = color
.argb
| destAlphaMask
;
428 for (i
= 0; i
< limit
; i
++)
430 t
= *(ss
++) & 0xFFFF;
432 error
|= sjme_scritchpen_corePrim_mapColorFromRaw(g
,
435 *(d
++) = color
.argb
| destAlphaMask
;
440 else if (sb
!= NULL
&& mulShift
== 3)
442 for (i
= 0; i
< limit
; i
++)
444 t
= ((sjme_juint
)(((*(sb
++)) & 0xFF))) << 16;
445 t
|= ((sjme_juint
)(((*(sb
++)) & 0xFF))) << 8;
446 t
|= ((sjme_juint
)(((*(sb
++)) & 0xFF)));
448 error
|= sjme_scritchpen_corePrim_mapColorFromRaw(g
,
451 *(d
++) = color
.argb
| destAlphaMask
;
458 for (i
= 0; i
< limit
; i
++)
462 error
|= sjme_scritchpen_corePrim_mapColorFromRaw(g
,
465 *(d
++) = color
.argb
| destAlphaMask
;
475 /* Failed or success? */
476 if (sjme_error_is(error
))
477 return sjme_error_default(error
);
478 return SJME_ERROR_NONE
;
481 sjme_errorCode
sjme_scritchpen_coreUtil_rgbScanFill(
482 sjme_attrInNotNull sjme_scritchui_pencil g
,
483 sjme_attrOutNotNullBuf(inNumPixels
) sjme_jint
* outRgb
,
484 sjme_attrInPositiveNonZero sjme_jint outRgbOff
,
485 sjme_attrInPositiveNonZero sjme_jint inNumPixels
,
486 sjme_attrInValue sjme_jint inValue
)
491 if (g
== NULL
|| outRgb
== NULL
)
492 return SJME_ERROR_NULL_ARGUMENTS
;
494 if (outRgbOff
< 0 || inNumPixels
< 0 ||
495 (outRgbOff
+ inNumPixels
) < 0)
496 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
498 /* Fill in, which is a rather simple operation. */
499 p
= &outRgb
[outRgbOff
];
500 for (i
= 0; i
< inNumPixels
; i
++)
504 return SJME_ERROR_NONE
;
507 sjme_errorCode
sjme_scritchpen_coreUtil_rgbScanGet(
508 sjme_attrInNotNull sjme_scritchui_pencil g
,
509 sjme_attrInPositive sjme_jint x
,
510 sjme_attrInPositive sjme_jint y
,
511 sjme_attrOutNotNullBuf(inLen
) sjme_jint
* destRgb
,
512 sjme_attrInPositiveNonZero sjme_jint inNumPixels
)
514 sjme_errorCode error
;
515 sjme_jint ex
, rgbBytes
, rawScanBytes
;
518 if (g
== NULL
|| destRgb
== NULL
)
519 return SJME_ERROR_NONE
;
521 /* We cannot access a region outside the image bounds. */
522 ex
= x
+ inNumPixels
;
523 rgbBytes
= inNumPixels
* sizeof(*destRgb
);
524 if (x
< 0 || y
< 0 || inNumPixels
< 0 ||
525 ex
< 0 || ex
> g
->width
|| rgbBytes
< 0)
527 #if defined(SJME_CONFIG_DEBUG)
528 sjme_message("rgbScanGet(%p, %d, %d, %p, %d) != [%d, %d]",
529 g
, x
, y
, destRgb
, inNumPixels
,
530 g
->width
, g
->height
);
532 return SJME_ERROR_SCAN_OUT_OF_BOUNDS
;
535 /* How much data is to be read? */
536 rawScanBytes
= (inNumPixels
* g
->bitsPerPixel
) / 8;
537 if (rawScanBytes
< 0)
539 #if defined(SJME_CONFIG_DEBUG)
540 sjme_message("rgbScanGet(%p, %d, %d, %p, %d) != [%d, %d]",
541 g
, x
, y
, destRgb
, inNumPixels
,
542 g
->width
, g
->height
);
544 return SJME_ERROR_SCAN_OUT_OF_BOUNDS
;
548 rawScan
= sjme_alloca(rawScanBytes
);
550 return sjme_error_outOfMemory(NULL
, rawScanBytes
);
553 memset(rawScan
, 0, rawScanBytes
);
555 /* Load in from image directly. */
556 if (sjme_error_is(error
= g
->prim
.rawScanGet(g
,
557 x
, y
, rawScan
, rawScanBytes
, inNumPixels
)))
558 return sjme_error_default(error
);
561 return g
->util
->rawScanToRgb(g
,
562 destRgb
, 0, inNumPixels
,
563 rawScan
, 0, rawScanBytes
);
566 sjme_errorCode
sjme_scritchpen_coreUtil_rgbScanPut(
567 sjme_attrInNotNull sjme_scritchui_pencil g
,
568 sjme_attrInPositive sjme_jint x
,
569 sjme_attrInPositive sjme_jint y
,
570 sjme_attrInNotNullBuf(inLen
) const sjme_jint
* srcRgb
,
571 sjme_attrInPositiveNonZero sjme_jint inNumPixels
,
572 sjme_attrInValue sjme_jboolean srcAlpha
,
573 sjme_attrInValue sjme_jboolean mulAlpha
,
574 sjme_attrInRange(0, 255) sjme_jint mulAlphaValue
)
576 sjme_errorCode error
;
577 sjme_jint ex
, rawScanBytes
, rgbBytes
;
581 if (g
== NULL
|| srcRgb
== NULL
)
582 return SJME_ERROR_NONE
;
584 /* We cannot access a region outside the image bounds. */
585 ex
= x
+ inNumPixels
;
586 rgbBytes
= inNumPixels
* sizeof(*destRgb
);
587 if (x
< 0 || y
< 0 || inNumPixels
< 0 ||
588 ex
< 0 || ex
> g
->width
|| rgbBytes
< 0 ||
589 (mulAlpha
&& (mulAlphaValue
< 0 || mulAlphaValue
> 255)))
591 #if defined(SJME_CONFIG_DEBUG)
592 sjme_message("rgbScanPut(%p, %d, %d, %p, %d, %d, %d, %d) != [%d, %d]",
593 g
, x
, y
, srcRgb
, inNumPixels
, srcAlpha
, mulAlpha
, mulAlphaValue
,
594 g
->width
, g
->height
);
596 return SJME_ERROR_SCAN_OUT_OF_BOUNDS
;
599 /* How much data is to be written? */
600 rawScanBytes
= (inNumPixels
* g
->bitsPerPixel
) / 8;
601 if (rawScanBytes
< 0)
603 #if defined(SJME_CONFIG_DEBUG)
604 sjme_message("rgbScanPut(%p, %d, %d, %p, %d, %d, %d, %d) != [%d, %d]",
605 g
, x
, y
, srcRgb
, inNumPixels
, srcAlpha
, mulAlpha
, mulAlphaValue
,
606 g
->width
, g
->height
);
608 return SJME_ERROR_SCAN_OUT_OF_BOUNDS
;
611 /* Do we need to alpha blend? */
612 if (srcAlpha
|| mulAlpha
)
614 /* Allocate dest RGB data. */
615 destRgb
= sjme_alloca(rgbBytes
);
617 return sjme_error_outOfMemory(NULL
, rgbBytes
);
620 memset(destRgb
, 0, rgbBytes
);
622 /* Load in RGB data from image, which might be lossy. */
623 if (sjme_error_is(error
= g
->util
->rgbScanGet(g
,
624 x
, y
, destRgb
, inNumPixels
)))
625 return sjme_error_default(error
);
627 /* Perform blending. */
628 if (sjme_error_is(error
= g
->util
->blendRGBInto(g
,
629 g
->hasAlpha
, srcAlpha
,
630 mulAlpha
, mulAlphaValue
,
631 destRgb
, srcRgb
, inNumPixels
)))
632 return sjme_error_default(error
);
634 /* The destination becomes the new source. */
638 /* Allocate raw scan data. */
639 rawScan
= sjme_alloca(rawScanBytes
);
641 return sjme_error_outOfMemory(NULL
, rawScanBytes
);
644 memset(rawScan
, 0, rawScanBytes
);
646 /* Map from RGB to raw pixels. */
647 if (sjme_error_is(error
= g
->util
->rgbToRawScan(g
,
648 rawScan
, 0, rawScanBytes
,
649 srcRgb
, 0, inNumPixels
)))
650 return sjme_error_default(error
);
652 /* Write direct image data. */
653 return g
->prim
.rawScanPutPure(g
,
655 rawScan
, rawScanBytes
, inNumPixels
);
658 sjme_errorCode
sjme_scritchpen_coreUtil_rgbToRawScan(
659 sjme_attrInNotNull sjme_scritchui_pencil g
,
660 sjme_attrOutNotNullBuf(rawLen
) void* outRaw
,
661 sjme_attrInPositive sjme_jint outRawOff
,
662 sjme_attrInPositive sjme_jint outRawLen
,
663 sjme_attrInNotNullBuf(rgbLen
) const sjme_jint
* inRgb
,
664 sjme_attrInPositive sjme_jint inRgbOff
,
665 sjme_attrInPositive sjme_jint inRgbLen
)
667 sjme_errorCode error
;
668 sjme_jint limit
, i
, t
, mulShift
, j
;
673 sjme_scritchui_pencilColor color
;
675 if (g
== NULL
|| inRgb
== NULL
|| outRaw
== NULL
)
676 return SJME_ERROR_NULL_ARGUMENTS
;
678 if (inRgbOff
< 0 || inRgbLen
< 0 || (inRgbOff
+ inRgbLen
) < 0 ||
679 outRawOff
< 0 || outRawLen
< 0 || (outRawOff
+ outRawLen
) < 0)
680 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
682 /* Determine the type to use for scan reading. */
687 switch (g
->pixelFormat
)
689 case SJME_GFX_PIXEL_FORMAT_INT_ARGB8888
:
690 case SJME_GFX_PIXEL_FORMAT_INT_RGB888
:
691 case SJME_GFX_PIXEL_FORMAT_INT_BGRA8888
:
692 case SJME_GFX_PIXEL_FORMAT_INT_BGRX8888
:
693 case SJME_GFX_PIXEL_FORMAT_INT_BGR888
:
694 case SJME_GFX_PIXEL_FORMAT_INT_RGBX8888
:
695 di
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
696 limit
= outRawLen
/ 4;
699 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888
:
700 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888
:
701 db
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
702 limit
= outRawLen
/ 3;
706 case SJME_GFX_PIXEL_FORMAT_SHORT_ARGB4444
:
707 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB565
:
708 case SJME_GFX_PIXEL_FORMAT_SHORT_RGB555
:
709 case SJME_GFX_PIXEL_FORMAT_SHORT_ABGR1555
:
710 case SJME_GFX_PIXEL_FORMAT_SHORT_INDEXED65536
:
711 ds
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
712 limit
= outRawLen
/ 2;
715 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256
:
716 db
= SJME_POINTER_OFFSET(outRaw
, outRawOff
);
720 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4
:
721 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2
:
722 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1
:
727 return SJME_ERROR_INVALID_ARGUMENT
;
731 s
= &inRgb
[inRgbOff
];
733 /* If the output RGB is smaller than the raw input, limit to it. */
734 if (inRgbLen
< limit
)
737 /* Clear error state. */
738 error
= SJME_ERROR_NONE
;
740 /* Already in the most native format? */
741 if (g
->pixelFormat
== SJME_GFX_PIXEL_FORMAT_INT_ARGB8888
&& di
!= NULL
)
742 memmove(di
, s
, limit
* 4);
745 else if (g
->pixelFormat
== SJME_GFX_PIXEL_FORMAT_INT_RGB888
&& di
!= NULL
)
747 /* Copy and put in the mask. */
748 for (i
= 0; i
< limit
; i
++)
752 /* Integer mapping. */
755 for (i
= 0; i
< limit
; i
++)
759 error
|= sjme_scritchpen_corePrim_mapColorFromRGB(g
,
769 for (i
= 0; i
< limit
; i
++)
773 error
|= sjme_scritchpen_corePrim_mapColorFromRGB(g
,
776 *(ds
++) = color
.v
& 0xFFFF;
781 else if (db
!= NULL
&& mulShift
== 3)
783 for (i
= 0; i
< limit
; i
++)
787 error
|= sjme_scritchpen_corePrim_mapColorFromRGB(g
,
790 *(db
++) = (color
.v
>> 16) & 0xFF;
791 *(db
++) = (color
.v
>> 8) & 0xFF;
792 *(db
++) = (color
.v
) & 0xFF;
799 for (i
= 0; i
< limit
; i
++)
803 error
|= sjme_scritchpen_corePrim_mapColorFromRGB(g
,
806 *(db
++) = color
.v
& 0xFF;
816 /* Failed or success? */
817 if (sjme_error_is(error
))
818 return sjme_error_default(error
);
819 return SJME_ERROR_NONE
;