mirror of https://github.com/mgba-emu/mgba.git
Util: Add mPainterDrawLine
This commit is contained in:
parent
4ca8ffe3f4
commit
ba49175697
|
@ -136,6 +136,7 @@ void mImageCompositeWithAlpha(struct mImage* image, const struct mImage* source,
|
||||||
|
|
||||||
void mPainterInit(struct mPainter*, struct mImage* backing);
|
void mPainterInit(struct mPainter*, struct mImage* backing);
|
||||||
void mPainterDrawRectangle(struct mPainter*, int x, int y, int width, int height);
|
void mPainterDrawRectangle(struct mPainter*, int x, int y, int width, int height);
|
||||||
|
void mPainterDrawLine(struct mPainter*, int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to);
|
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to);
|
||||||
uint32_t mImageColorConvert(uint32_t color, const struct mImage* from, enum mColorFormat to);
|
uint32_t mImageColorConvert(uint32_t color, const struct mImage* from, enum mColorFormat to);
|
||||||
|
|
|
@ -614,6 +614,75 @@ void mPainterDrawRectangle(struct mPainter* painter, int x, int y, int width, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mPainterDrawLine(struct mPainter* painter, int x1, int y1, int x2, int y2) {
|
||||||
|
if (!painter->strokeWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int dx = x2 - x1;
|
||||||
|
int dy = y2 - y1;
|
||||||
|
int x, y;
|
||||||
|
int xi = 1;
|
||||||
|
int yi = 1;
|
||||||
|
int residual;
|
||||||
|
|
||||||
|
int mx = dx;
|
||||||
|
int my = dy;
|
||||||
|
if (mx < 0) {
|
||||||
|
mx = -mx;
|
||||||
|
}
|
||||||
|
if (my < 0) {
|
||||||
|
my = -my;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dx < 0) {
|
||||||
|
xi = -1;
|
||||||
|
dx = -dx;
|
||||||
|
}
|
||||||
|
if (dy < 0) {
|
||||||
|
yi = -1;
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
uint32_t color = painter->strokeColor;
|
||||||
|
|
||||||
|
if (mx > my) {
|
||||||
|
residual = 2 * dy - dx;
|
||||||
|
y = y1;
|
||||||
|
for (x = x1; x != x2 + xi; x += xi) {
|
||||||
|
for (i = 0; i < painter->strokeWidth; ++i) {
|
||||||
|
if (painter->blend) {
|
||||||
|
color = mColorMixARGB8(painter->strokeColor, mImageGetPixel(painter->backing, x, y - painter->strokeWidth / 2 + i));
|
||||||
|
}
|
||||||
|
mImageSetPixel(painter->backing, x, y - painter->strokeWidth / 2 + i, color);
|
||||||
|
}
|
||||||
|
if (residual > 0) {
|
||||||
|
y += yi;
|
||||||
|
residual -= 2 * dx;
|
||||||
|
}
|
||||||
|
residual += 2 * dy;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
residual = 2 * dx - dy;
|
||||||
|
x = x1;
|
||||||
|
for (y = y1; y != y2 + yi; y += yi) {
|
||||||
|
for (i = 0; i < painter->strokeWidth; ++i) {
|
||||||
|
if (painter->blend) {
|
||||||
|
color = mColorMixARGB8(painter->strokeColor, mImageGetPixel(painter->backing, x - painter->strokeWidth / 2 + i, y));
|
||||||
|
}
|
||||||
|
mImageSetPixel(painter->backing, x - painter->strokeWidth / 2 + i, y, color);
|
||||||
|
}
|
||||||
|
if (residual > 0) {
|
||||||
|
x += xi;
|
||||||
|
residual -= 2 * dy;
|
||||||
|
}
|
||||||
|
residual += 2 * dx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Draw endcaps for widths >2
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to) {
|
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to) {
|
||||||
if (from == to) {
|
if (from == to) {
|
||||||
return color;
|
return color;
|
||||||
|
|
|
@ -1628,6 +1628,227 @@ M_TEST_DEFINE(painterDrawRectangle) {
|
||||||
mImageDestroy(image);
|
mImageDestroy(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(painterDrawLineOctants) {
|
||||||
|
struct mImage* image;
|
||||||
|
struct mPainter painter;
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 2, 2);
|
||||||
|
COMPARE3X(0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0x00,
|
||||||
|
0x00, 0x00, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 2, 2, 0, 0);
|
||||||
|
COMPARE3X(0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0x00,
|
||||||
|
0x00, 0x00, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 2, 0, 0, 2);
|
||||||
|
COMPARE3X(0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0xFF, 0x00,
|
||||||
|
0xFF, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 2, 2, 0);
|
||||||
|
COMPARE3X(0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0xFF, 0x00,
|
||||||
|
0xFF, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 2, 1);
|
||||||
|
COMPARE3X(0xFF, 0xFF, 0x00,
|
||||||
|
0x00, 0x00, 0xFF,
|
||||||
|
0x00, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 2, 1, 0, 0);
|
||||||
|
COMPARE3X(0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0xFF,
|
||||||
|
0x00, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 1, 2);
|
||||||
|
COMPARE3X(0xFF, 0x00, 0x00,
|
||||||
|
0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 1, 2, 0, 0);
|
||||||
|
COMPARE3X(0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0x00,
|
||||||
|
0x00, 0xFF, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(painterDrawLineWidth) {
|
||||||
|
struct mImage* image;
|
||||||
|
struct mPainter painter;
|
||||||
|
|
||||||
|
image = mImageCreate(4, 4, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 2;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 3, 3);
|
||||||
|
COMPARE4X(0xFF, 0x00, 0x00, 0x00,
|
||||||
|
0xFF, 0xFF, 0x00, 0x00,
|
||||||
|
0x00, 0xFF, 0xFF, 0x00,
|
||||||
|
0x00, 0x00, 0xFF, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(4, 4, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 3;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 3, 3);
|
||||||
|
COMPARE4X(0xFF, 0xFF, 0x00, 0x00,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x00,
|
||||||
|
0x00, 0xFF, 0xFF, 0xFF,
|
||||||
|
0x00, 0x00, 0xFF, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(4, 4, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 2;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 3, 0, 0, 3);
|
||||||
|
COMPARE4X(0x00, 0x00, 0xFF, 0xFF,
|
||||||
|
0x00, 0xFF, 0xFF, 0x00,
|
||||||
|
0xFF, 0xFF, 0x00, 0x00,
|
||||||
|
0xFF, 0x00, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(4, 4, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 3;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 3, 0, 0, 3);
|
||||||
|
COMPARE4X(0x00, 0x00, 0xFF, 0xFF,
|
||||||
|
0x00, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x00,
|
||||||
|
0xFF, 0xFF, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 2;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 1, 0, 1, 2);
|
||||||
|
COMPARE3X(0xFF, 0xFF, 0x00,
|
||||||
|
0xFF, 0xFF, 0x00,
|
||||||
|
0xFF, 0xFF, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 3;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 1, 0, 1, 2);
|
||||||
|
COMPARE3X(0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 2;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 1, 2, 1);
|
||||||
|
COMPARE3X(0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF,
|
||||||
|
0x00, 0x00, 0x00);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_XRGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 3;
|
||||||
|
painter.strokeColor = 0xFF0000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 1, 2, 1);
|
||||||
|
COMPARE3X(0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(painterDrawLineBlend) {
|
||||||
|
struct mImage* image;
|
||||||
|
struct mPainter painter;
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_ARGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = false;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0x400000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 2, 2);
|
||||||
|
painter.strokeColor = 0x4000FF00;
|
||||||
|
mPainterDrawLine(&painter, 0, 2, 2, 0);
|
||||||
|
COMPARE3(0x400000FF, 0x00000000, 0x4000FF00,
|
||||||
|
0x00000000, 0x4000FF00, 0x00000000,
|
||||||
|
0x4000FF00, 0x00000000, 0x400000FF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
|
||||||
|
image = mImageCreate(3, 3, mCOLOR_ARGB8);
|
||||||
|
mPainterInit(&painter, image);
|
||||||
|
painter.blend = true;
|
||||||
|
painter.strokeWidth = 1;
|
||||||
|
painter.strokeColor = 0x400000FF;
|
||||||
|
mPainterDrawLine(&painter, 0, 0, 2, 2);
|
||||||
|
painter.strokeColor = 0x4000FF00;
|
||||||
|
mPainterDrawLine(&painter, 0, 2, 2, 0);
|
||||||
|
COMPARE3(0x400000FF, 0x00000000, 0x4000FF00,
|
||||||
|
0x00000000, 0x6F00916D, 0x00000000,
|
||||||
|
0x4000FF00, 0x00000000, 0x400000FF);
|
||||||
|
mImageDestroy(image);
|
||||||
|
}
|
||||||
|
|
||||||
#undef COMPARE3X
|
#undef COMPARE3X
|
||||||
#undef COMPARE3
|
#undef COMPARE3
|
||||||
#undef COMPARE4X
|
#undef COMPARE4X
|
||||||
|
@ -1663,4 +1884,7 @@ M_TEST_SUITE_DEFINE(Image,
|
||||||
cmocka_unit_test(painterStrokeRectangleWidth),
|
cmocka_unit_test(painterStrokeRectangleWidth),
|
||||||
cmocka_unit_test(painterStrokeRectangleBlend),
|
cmocka_unit_test(painterStrokeRectangleBlend),
|
||||||
cmocka_unit_test(painterDrawRectangle),
|
cmocka_unit_test(painterDrawRectangle),
|
||||||
|
cmocka_unit_test(painterDrawLineOctants),
|
||||||
|
cmocka_unit_test(painterDrawLineWidth),
|
||||||
|
cmocka_unit_test(painterDrawLineBlend),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue