Add blank classes for DoJa graphics3d.
[SquirrelJME.git] / nanocoat / lib / scritchui / scritchPencilRasterScan.c
blob8e96121f611071e78f83d27cddda35e5354f3aa3
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 /* Inverse alpha. */
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);
224 /* Recompose. */
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;
232 /* Success! */
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)
243 sjme_jint result;
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. */
252 result = -1;
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;
262 break;
264 case SJME_GFX_PIXEL_FORMAT_BYTE3_RGB888:
265 case SJME_GFX_PIXEL_FORMAT_BYTE3_BGR888:
266 result = inPixels * 3;
267 break;
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;
275 break;
277 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
278 result = inPixels;
279 break;
281 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
282 result = (inPixels >> 1) + (inPixels & 1);
283 break;
285 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
286 result = (inPixels >> 2) + ((inPixels >> 1) & 1);
287 break;
289 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
290 result = (inPixels >> 3) + ((inPixels >> 2) & 1);
291 break;
294 /* Make sure what was calculated did not overflow. */
295 if (result < 0)
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)
303 *outLimit = inBytes;
304 else
305 *outLimit = result;
308 /* Success! */
309 *outBytes = result;
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;
325 const sjme_jint* si;
326 const sjme_jshort* ss;
327 const sjme_jbyte* sb;
328 sjme_jint* d;
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. */
342 si = NULL;
343 ss = NULL;
344 sb = NULL;
345 mulShift = 1;
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;
356 break;
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;
362 mulShift = 3;
363 break;
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;
372 break;
374 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
375 sb = SJME_POINTER_OFFSET(inRaw, inRawOff);
376 limit = inRawLen;
377 break;
379 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
380 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
381 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
382 sjme_todo("Impl?");
383 break;
385 default:
386 return SJME_ERROR_INVALID_ARGUMENT;
389 /* Writing where? */
390 d = &outRgb[outRgbOff];
392 /* If the output RGB is smaller than the raw input, limit to it. */
393 if (outRgbLen < limit)
394 limit = outRgbLen;
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);
403 /* Almost there. */
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. */
412 else if (si != NULL)
414 for (i = 0; i < limit; i++)
416 t = *(si++);
418 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
419 t, &color);
421 *(d++) = color.argb | destAlphaMask;
425 /* Short mapping. */
426 else if (ss != NULL)
428 for (i = 0; i < limit; i++)
430 t = *(ss++) & 0xFFFF;
432 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
433 t, &color);
435 *(d++) = color.argb | destAlphaMask;
439 /* Triple byte? */
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,
449 t, &color);
451 *(d++) = color.argb | destAlphaMask;
455 /* Byte mapping. */
456 else if (sb != NULL)
458 for (i = 0; i < limit; i++)
460 t = *(sb++) & 0xFF;
462 error |= sjme_scritchpen_corePrim_mapColorFromRaw(g,
463 t, &color);
465 *(d++) = color.argb | destAlphaMask;
469 /* Unknown. */
470 else
472 sjme_todo("Impl?");
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)
488 sjme_jint i;
489 sjme_jint* p;
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++)
501 *(p++) = inValue;
503 /* Success! */
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;
516 void* rawScan;
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);
531 #endif
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);
543 #endif
544 return SJME_ERROR_SCAN_OUT_OF_BOUNDS;
547 /* Allocate. */
548 rawScan = sjme_alloca(rawScanBytes);
549 if (rawScan == NULL)
550 return sjme_error_outOfMemory(NULL, rawScanBytes);
552 /* Clear. */
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);
560 /* Map to RGB. */
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;
578 void* rawScan;
579 sjme_jint* destRgb;
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);
595 #endif
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);
607 #endif
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);
616 if (destRgb == NULL)
617 return sjme_error_outOfMemory(NULL, rgbBytes);
619 /* Clear. */
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. */
635 srcRgb = destRgb;
638 /* Allocate raw scan data. */
639 rawScan = sjme_alloca(rawScanBytes);
640 if (rawScan == NULL)
641 return sjme_error_outOfMemory(NULL, rawScanBytes);
643 /* Clear. */
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,
654 x, y,
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;
669 sjme_jint* di;
670 sjme_jshort* ds;
671 sjme_jbyte* db;
672 const sjme_jint* s;
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. */
683 di = NULL;
684 ds = NULL;
685 db = NULL;
686 mulShift = 1;
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;
697 break;
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;
703 mulShift = 3;
704 break;
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;
713 break;
715 case SJME_GFX_PIXEL_FORMAT_BYTE_INDEXED256:
716 db = SJME_POINTER_OFFSET(outRaw, outRawOff);
717 limit = outRawLen;
718 break;
720 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED4:
721 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED2:
722 case SJME_GFX_PIXEL_FORMAT_PACKED_INDEXED1:
723 sjme_todo("Impl?");
724 break;
726 default:
727 return SJME_ERROR_INVALID_ARGUMENT;
730 /* Reading what? */
731 s = &inRgb[inRgbOff];
733 /* If the output RGB is smaller than the raw input, limit to it. */
734 if (inRgbLen < limit)
735 limit = inRgbLen;
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);
744 /* Almost there. */
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++)
749 *(di++) = *(s++);
752 /* Integer mapping. */
753 else if (di != NULL)
755 for (i = 0; i < limit; i++)
757 t = *(s++);
759 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
760 t, &color);
762 *(di++) = color.v;
766 /* Short mapping. */
767 else if (ds != NULL)
769 for (i = 0; i < limit; i++)
771 t = *(s++);
773 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
774 t, &color);
776 *(ds++) = color.v & 0xFFFF;
780 /* Triple byte? */
781 else if (db != NULL && mulShift == 3)
783 for (i = 0; i < limit; i++)
785 t = *(s++);
787 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
788 t, &color);
790 *(db++) = (color.v >> 16) & 0xFF;
791 *(db++) = (color.v >> 8) & 0xFF;
792 *(db++) = (color.v) & 0xFF;
796 /* Byte mapping. */
797 else if (db != NULL)
799 for (i = 0; i < limit; i++)
801 t = *(s++);
803 error |= sjme_scritchpen_corePrim_mapColorFromRGB(g,
804 t, &color);
806 *(db++) = color.v & 0xFF;
810 /* Unknown. */
811 else
813 sjme_todo("Impl?");
816 /* Failed or success? */
817 if (sjme_error_is(error))
818 return sjme_error_default(error);
819 return SJME_ERROR_NONE;