Util: Add basic mImage blit with no blending

This commit is contained in:
Vicki Pfau 2023-04-03 01:50:16 -07:00
parent 5b18089e85
commit cfd5572fb6
3 changed files with 336 additions and 0 deletions

View File

@ -101,11 +101,14 @@ void mImageDestroy(struct mImage*);
bool mImageSave(const struct mImage*, const char* path, const char* format);
bool mImageSaveVF(const struct mImage*, struct VFile* vf, const char* format);
uint32_t mImageGetPixel(const struct mImage* image, unsigned x, unsigned y);
uint32_t mImageGetPixelRaw(const struct mImage* image, unsigned x, unsigned y);
void mImageSetPixel(struct mImage* image, unsigned x, unsigned y, uint32_t color);
void mImageSetPixelRaw(struct mImage* image, unsigned x, unsigned y, uint32_t color);
void mImageBlit(struct mImage* image, const struct mImage* source, int x, int y);
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to);
#ifndef PYCPARSE

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba-util/image.h>
#include <mgba-util/geometry.h>
#include <mgba-util/image/png-io.h>
#include <mgba-util/vfs.h>
@ -317,6 +318,56 @@ void mImageSetPixel(struct mImage* image, unsigned x, unsigned y, uint32_t color
mImageSetPixelRaw(image, x, y, mColorConvert(color, mCOLOR_ARGB8, image->format));
}
void mImageBlit(struct mImage* image, const struct mImage* source, int x, int y) {
struct mRectangle dstRect = {
.x = 0,
.y = 0,
.width = image->width,
.height = image->height
};
struct mRectangle srcRect = {
.x = x,
.y = y,
.width = source->width,
.height = source->height
};
if (!mRectangleIntersection(&srcRect, &dstRect)) {
return;
}
int srcStartX;
int srcStartY;
int dstStartX;
int dstStartY;
if (x < 0) {
dstStartX = 0;
srcStartX = -x;
} else {
srcStartX = 0;
dstStartX = srcRect.x;
}
if (y < 0) {
dstStartY = 0;
srcStartY = -y;
} else {
srcStartY = 0;
dstStartY = srcRect.y;
}
for (y = 0; y < srcRect.height; ++y) {
uintptr_t srcPixel = (uintptr_t) PIXEL(source, srcStartX, srcStartY + y);
uintptr_t dstPixel = (uintptr_t) PIXEL(image, dstStartX, dstStartY + y);
for (x = 0; x < srcRect.width; ++x, srcPixel += source->depth, dstPixel += image->depth) {
uint32_t color;
GET_PIXEL(color, srcPixel, source->depth);
color = mColorConvert(color, source->format, image->format);
PUT_PIXEL(color, dstPixel, image->depth);
}
}
}
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to) {
if (from == to) {
return color;

View File

@ -703,6 +703,287 @@ M_TEST_DEFINE(convert2x2) {
}
}
M_TEST_DEFINE(blitBoundaries) {
static const uint32_t spriteBuffer[4] = {
0xFF000F00, 0xFF000F01,
0xFF000F10, 0xFF000F11
};
static const uint32_t canvasBuffer[9] = {
0xFF000000, 0xFF000000, 0xFF000000,
0xFF000000, 0xFF000000, 0xFF000000,
0xFF000000, 0xFF000000, 0xFF000000
};
struct mImage* sprite = mImageCreateFromConstBuffer(2, 2, 2, mCOLOR_XRGB8, spriteBuffer);
struct mImage* canvas;
#define COMPARE(AA, BA, CA, AB, BB, CB, AC, BC, CC) \
assert_int_equal(mImageGetPixel(canvas, 0, 0), 0xFF000000 | (AA)); \
assert_int_equal(mImageGetPixel(canvas, 1, 0), 0xFF000000 | (BA)); \
assert_int_equal(mImageGetPixel(canvas, 2, 0), 0xFF000000 | (CA)); \
assert_int_equal(mImageGetPixel(canvas, 0, 1), 0xFF000000 | (AB)); \
assert_int_equal(mImageGetPixel(canvas, 1, 1), 0xFF000000 | (BB)); \
assert_int_equal(mImageGetPixel(canvas, 2, 1), 0xFF000000 | (CB)); \
assert_int_equal(mImageGetPixel(canvas, 0, 2), 0xFF000000 | (AC)); \
assert_int_equal(mImageGetPixel(canvas, 1, 2), 0xFF000000 | (BC)); \
assert_int_equal(mImageGetPixel(canvas, 2, 2), 0xFF000000 | (CC))
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, -2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, -1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, -1);
COMPARE(0xF11, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, -1);
COMPARE(0xF10, 0xF11, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, -1);
COMPARE(0x000, 0xF10, 0xF11,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, -1);
COMPARE(0x000, 0x000, 0xF10,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, -1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, 0);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, 0);
COMPARE(0xF01, 0x000, 0x000,
0xF11, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, 0);
COMPARE(0xF00, 0xF01, 0x000,
0xF10, 0xF11, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, 0);
COMPARE(0x000, 0xF00, 0xF01,
0x000, 0xF10, 0xF11,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, 0);
COMPARE(0x000, 0x000, 0xF00,
0x000, 0x000, 0xF10,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, 0);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, 1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, 1);
COMPARE(0x000, 0x000, 0x000,
0xF01, 0x000, 0x000,
0xF11, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, 1);
COMPARE(0x000, 0x000, 0x000,
0xF00, 0xF01, 0x000,
0xF10, 0xF11, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, 1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0xF00, 0xF01,
0x000, 0xF10, 0xF11);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, 1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0xF00,
0x000, 0x000, 0xF10);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, 1);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0xF01, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0xF00, 0xF01, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0xF00, 0xF01);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0xF00);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, 2);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -2, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, -1, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 0, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 1, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 2, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer);
mImageBlit(canvas, sprite, 3, 3);
COMPARE(0x000, 0x000, 0x000,
0x000, 0x000, 0x000,
0x000, 0x000, 0x000);
mImageDestroy(canvas);
#undef COMPARE
mImageDestroy(sprite);
}
M_TEST_SUITE_DEFINE(Image,
cmocka_unit_test(zeroDim),
cmocka_unit_test(pitchRead),
@ -721,4 +1002,5 @@ M_TEST_SUITE_DEFINE(Image,
cmocka_unit_test(convert2x1),
cmocka_unit_test(convert1x2),
cmocka_unit_test(convert2x2),
cmocka_unit_test(blitBoundaries),
)