Skip to content

Commit bdb42bf

Browse files
authored
Order blit params (#160)
* Add basic tests for blit * Sort params in hagl_blit_xyxy()
1 parent 3f8032f commit bdb42bf

3 files changed

Lines changed: 210 additions & 5 deletions

File tree

include/hagl/blit.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
MIT License
55
6-
Copyright (c) 2018-2023 Mika Tuupola
6+
Copyright (c) 2018-2026 Mika Tuupola
77
88
Permission is hereby granted, free of charge, to any person obtaining a copy
99
of this software and associated documentation files (the "Software"), to deal
@@ -106,7 +106,11 @@ static void inline hagl_blit_xyxy(
106106
void const *surface, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
107107
hagl_bitmap_t *source
108108
) {
109-
hagl_blit_xywh(surface, x0, y0, abs(x1 - x0) + 1, abs(y1 - y0) + 1, source);
109+
uint16_t min_x = (x0 < x1) ? x0 : x1;
110+
uint16_t min_y = (y0 < y1) ? y0 : y1;
111+
uint16_t max_x = (x0 > x1) ? x0 : x1;
112+
uint16_t max_y = (y0 > y1) ? y0 : y1;
113+
hagl_blit_xywh(surface, min_x, min_y, max_x - min_x + 1, max_y - min_y + 1, source);
110114
};
111115

112116
#ifdef __cplusplus

tests/Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ SRCS = \
1515
../src/hagl_triangle.c \
1616
../src/hagl_circle.c \
1717
../src/hagl_ellipse.c \
18+
../src/hagl_blit.c \
1819
../src/rgb565.c
1920

20-
all: test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip
21+
all: test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip test_blit
2122

2223
test_fill_polygon: test_fill_polygon.c $(SRCS)
2324
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@@ -55,7 +56,10 @@ test_fill_ellipse: test_fill_ellipse.c $(SRCS)
5556
test_clip: test_clip.c $(SRCS)
5657
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
5758

58-
test: test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip
59+
test_blit: test_blit.c $(SRCS)
60+
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
61+
62+
test: test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip test_blit
5963
./test_fill_polygon
6064
./test_polygon
6165
./test_fill_rectangle
@@ -68,8 +72,9 @@ test: test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pix
6872
./test_ellipse
6973
./test_fill_ellipse
7074
./test_clip
75+
./test_blit
7176

7277
clean:
73-
rm -f test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip
78+
rm -f test_fill_polygon test_polygon test_fill_rectangle test_rectangle test_pixel test_line test_hline test_vline test_circle test_ellipse test_fill_ellipse test_clip test_blit
7479

7580
.PHONY: all test clean

tests/test_blit.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
3+
MIT License
4+
5+
Copyright (c) 2026 Mika Tuupola
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
-cut-
26+
27+
This file is part of the HAGL graphics library:
28+
https://github.com/tuupola/hagl
29+
30+
SPDX-License-Identifier: MIT
31+
32+
*/
33+
34+
#include <string.h>
35+
36+
#include "crc32.h"
37+
#include "greatest.h"
38+
#include "hagl/bitmap.h"
39+
#include "hagl/blit.h"
40+
#include "hagl/pixel.h"
41+
42+
#define TEST_WIDTH 320
43+
#define TEST_HEIGHT 240
44+
#define TEST_DEPTH 16
45+
46+
#define SOURCE_WIDTH 4
47+
#define SOURCE_HEIGHT 4
48+
49+
static hagl_bitmap_t bitmap;
50+
static uint8_t buffer[TEST_WIDTH * TEST_HEIGHT * (TEST_DEPTH / 8)];
51+
52+
static hagl_bitmap_t source;
53+
static uint8_t src_buffer[SOURCE_WIDTH * SOURCE_HEIGHT * (TEST_DEPTH / 8)];
54+
55+
static uint32_t count_pixels(hagl_bitmap_t *bitmap, hagl_color_t color) {
56+
uint32_t count = 0;
57+
for (int16_t y = 0; y < bitmap->height; y++) {
58+
for (int16_t x = 0; x < bitmap->width; x++) {
59+
if (hagl_get_pixel(bitmap, x, y) == color) {
60+
count++;
61+
}
62+
}
63+
}
64+
return count;
65+
}
66+
67+
static void setup_callback(void *data) {
68+
memset(buffer, 0, sizeof(buffer));
69+
hagl_bitmap_init(&bitmap, TEST_WIDTH, TEST_HEIGHT, TEST_DEPTH, buffer);
70+
71+
/* Fill source bitmap with all-white pixels. */
72+
memset(src_buffer, 0xFF, sizeof(src_buffer));
73+
hagl_bitmap_init(&source, SOURCE_WIDTH, SOURCE_HEIGHT, TEST_DEPTH, src_buffer);
74+
}
75+
76+
/*
77+
* Basic blit of a 4x4 source at (10,10):
78+
*
79+
* (10,10)--(13,10)
80+
* | |
81+
* (10,13)--(13,13)
82+
*/
83+
TEST test_blit_xy(void) {
84+
hagl_blit_xy(&bitmap, 10, 10, &source);
85+
86+
/* On target: four corners */
87+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 10, 10));
88+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 13, 10));
89+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 10, 13));
90+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 13, 13));
91+
92+
/* On target: interior pixel */
93+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 11, 11));
94+
95+
/* Outside: one pixel beyond each edge */
96+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 9, 10));
97+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 14, 10));
98+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 10, 9));
99+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 10, 14));
100+
101+
/* Total: 4x4 = 16 pixels */
102+
ASSERT_EQ(16, count_pixels(&bitmap, 0xFFFF));
103+
104+
PASS();
105+
}
106+
107+
/*
108+
* Scale blit of a 4x4 source into an 8x8 region at (20,20):
109+
*
110+
* (20,20)-------(27,20)
111+
* | |
112+
* (20,27)-------(27,27)
113+
*/
114+
TEST test_blit_xywh(void) {
115+
hagl_blit_xywh(&bitmap, 20, 20, 8, 8, &source);
116+
117+
/* On target: four corners of the scaled region */
118+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 20, 20));
119+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 27, 20));
120+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 20, 27));
121+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 27, 27));
122+
123+
/* On target: center pixel */
124+
ASSERT_EQ(0xFFFF, hagl_get_pixel(&bitmap, 23, 23));
125+
126+
/* Outside: one pixel beyond each edge */
127+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 19, 20));
128+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 28, 20));
129+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 20, 19));
130+
ASSERT_EQ(0x0000, hagl_get_pixel(&bitmap, 20, 28));
131+
132+
/* Total: 8x8 = 64 pixels */
133+
ASSERT_EQ(64, count_pixels(&bitmap, 0xFFFF));
134+
135+
PASS();
136+
}
137+
138+
/*
139+
* Verify xyxy produces the same result as xywh:
140+
*
141+
* xyxy: hagl_blit_xyxy(&bitmap, 20, 20, 27, 27, &source)
142+
* xywh: hagl_blit_xywh(&bitmap, 20, 20, 8, 8, &source)
143+
*/
144+
TEST test_blit_xyxy_match_xywh(void) {
145+
/* Draw with _xyxy. */
146+
hagl_blit_xyxy(&bitmap, 20, 20, 27, 27, &source);
147+
148+
uint32_t crc_xyxy = crc32(bitmap.buffer, bitmap.size);
149+
150+
/* Clear and draw the same area with _xywh. */
151+
memset(bitmap.buffer, 0, bitmap.size);
152+
hagl_blit_xywh(&bitmap, 20, 20, 8, 8, &source);
153+
154+
uint32_t crc_xywh = crc32(bitmap.buffer, bitmap.size);
155+
156+
ASSERT_EQ(crc_xywh, crc_xyxy);
157+
PASS();
158+
}
159+
160+
/*
161+
* Verify xyxy handles reversed endpoints (x0 > x1, y0 > y1):
162+
*
163+
* xyxy reversed: hagl_blit_xyxy(&bitmap, 27, 27, 20, 20, &source)
164+
* xyxy normal: hagl_blit_xyxy(&bitmap, 20, 20, 27, 27, &source)
165+
*/
166+
TEST test_blit_xyxy_reversed(void) {
167+
/* Draw with reversed endpoints. */
168+
hagl_blit_xyxy(&bitmap, 27, 27, 20, 20, &source);
169+
170+
uint32_t crc_reversed = crc32(bitmap.buffer, bitmap.size);
171+
172+
/* Clear and draw with normal order. */
173+
memset(bitmap.buffer, 0, bitmap.size);
174+
hagl_blit_xyxy(&bitmap, 20, 20, 27, 27, &source);
175+
176+
uint32_t crc_normal = crc32(bitmap.buffer, bitmap.size);
177+
178+
ASSERT_EQ(crc_normal, crc_reversed);
179+
PASS();
180+
}
181+
182+
SUITE(blit_suite) {
183+
SET_SETUP(setup_callback, NULL);
184+
RUN_TEST(test_blit_xy);
185+
RUN_TEST(test_blit_xywh);
186+
RUN_TEST(test_blit_xyxy_match_xywh);
187+
RUN_TEST(test_blit_xyxy_reversed);
188+
}
189+
190+
GREATEST_MAIN_DEFS();
191+
192+
int main(int argc, char **argv) {
193+
GREATEST_MAIN_BEGIN();
194+
RUN_SUITE(blit_suite);
195+
GREATEST_MAIN_END();
196+
}

0 commit comments

Comments
 (0)