mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-07-06 17:30:22 +00:00
Merge pull request #241 from mkilgore/paint-fill-fix
Fix PAINT when border color is not supplied (QB64Official/qb64#38)
This commit is contained in:
commit
4799c9b7d0
|
@ -13503,128 +13503,98 @@ void sub_paint(float x, float y, qbs *fillstr, uint32 bordercol, qbs *background
|
|||
done = (uint8 *)calloc(i, 1);
|
||||
}
|
||||
|
||||
// return if first point is the bordercolor
|
||||
if (qbg_active_page_offset[iy * qbg_width + ix] == bordercol)
|
||||
// The original color of the starting location
|
||||
uint32_t startingColor = qbg_active_page_offset[iy * qbg_width + ix];
|
||||
|
||||
bool borderColorProvided = passed & 4;
|
||||
|
||||
// Exit early if we're already at the border color
|
||||
if (borderColorProvided && qbg_active_page_offset[iy * qbg_width + ix] == bordercol)
|
||||
return;
|
||||
|
||||
// create first node
|
||||
a_x[0] = ix;
|
||||
a_y[0] = iy;
|
||||
a_t[0] = 15;
|
||||
// types:
|
||||
//&1=check left
|
||||
//&2=check right
|
||||
//&4=check above
|
||||
//&8=check below
|
||||
|
||||
a_n = 1;
|
||||
qbg_active_page_offset[iy * qbg_width + ix] = tile[ix % sx][iy % sy];
|
||||
done[iy * qbg_width + ix] = 1;
|
||||
|
||||
nextpass:
|
||||
b_n = 0;
|
||||
for (i = 0; i < a_n; i++) {
|
||||
t = a_t[i];
|
||||
ix = a_x[i];
|
||||
iy = a_y[i];
|
||||
// Each index maps to a direction, in the order:
|
||||
// Left, Right, Up, Down
|
||||
int32_t xdelta[4] = { -1, 1, 0, 0 };
|
||||
int32_t ydelta[4] = { 0, 0, -1, 1 };
|
||||
|
||||
// left
|
||||
if (t & 1) {
|
||||
x2 = ix - 1;
|
||||
y2 = iy;
|
||||
if (x2 >= qbg_view_x1) {
|
||||
offset = y2 * qbg_width + x2;
|
||||
if (!done[offset]) {
|
||||
done[offset] = 1;
|
||||
if (qbg_active_page_offset[offset] != bordercol) {
|
||||
qbg_active_page_offset[offset] = tile[x2 % sx][y2 % sy];
|
||||
b_t[b_n] = 13;
|
||||
b_x[b_n] = x2;
|
||||
b_y[b_n] = y2;
|
||||
b_n++; // add new node
|
||||
// The bits indicate the directions that should be checked for the next
|
||||
// pixel, we ignore the direction we came from.
|
||||
uint32_t dirCheckMap[4] = {
|
||||
1 | 4 | 8, // Left, Up, Down
|
||||
2 | 4 | 8, // Right, Up, Down
|
||||
1 | 2 | 4, // Left, Right, Up
|
||||
1 | 2 | 8, // Left, Right, Down
|
||||
};
|
||||
|
||||
while (true) {
|
||||
b_n = 0;
|
||||
for (i = 0; i < a_n; i++) {
|
||||
t = a_t[i];
|
||||
ix = a_x[i];
|
||||
iy = a_y[i];
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
if ((t & (1 << k)) == 0)
|
||||
continue;
|
||||
|
||||
x2 = ix + xdelta[k];
|
||||
y2 = iy + ydelta[k];
|
||||
|
||||
// Verify dimensions are within bounds
|
||||
if (x2 >= qbg_view_x1 && x2 <= qbg_view_x2 && y2 >= qbg_view_y1 && y2 <= qbg_view_y2) {
|
||||
offset = y2 * qbg_width + x2;
|
||||
|
||||
// Check that we haven't done this pixel yet
|
||||
if (!done[offset]) {
|
||||
done[offset] = 1;
|
||||
|
||||
// We either check that we didn't hit the border color
|
||||
// (if provided), or that we're still the starting
|
||||
// color.
|
||||
if ((borderColorProvided && qbg_active_page_offset[offset] != bordercol)
|
||||
|| (!borderColorProvided && qbg_active_page_offset[offset] == startingColor)) {
|
||||
|
||||
qbg_active_page_offset[offset] = tile[x2 % sx][y2 % sy];
|
||||
b_t[b_n] = dirCheckMap[k];
|
||||
b_x[b_n] = x2;
|
||||
b_y[b_n] = y2;
|
||||
b_n++; // add new node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// right
|
||||
if (t & 2) {
|
||||
x2 = ix + 1;
|
||||
y2 = iy;
|
||||
if (x2 <= qbg_view_x2) {
|
||||
offset = y2 * qbg_width + x2;
|
||||
if (!done[offset]) {
|
||||
done[offset] = 1;
|
||||
if (qbg_active_page_offset[offset] != bordercol) {
|
||||
qbg_active_page_offset[offset] = tile[x2 % sx][y2 % sy];
|
||||
b_t[b_n] = 14;
|
||||
b_x[b_n] = x2;
|
||||
b_y[b_n] = y2;
|
||||
b_n++; // add new node
|
||||
}
|
||||
}
|
||||
}
|
||||
// no new nodes?
|
||||
if (b_n == 0) {
|
||||
memset(done, 0, write_page->width * write_page->height); // cleanup
|
||||
return; // finished!
|
||||
}
|
||||
|
||||
// above
|
||||
if (t & 4) {
|
||||
x2 = ix;
|
||||
y2 = iy - 1;
|
||||
if (y2 >= qbg_view_y1) {
|
||||
offset = y2 * qbg_width + x2;
|
||||
if (!done[offset]) {
|
||||
done[offset] = 1;
|
||||
if (qbg_active_page_offset[offset] != bordercol) {
|
||||
qbg_active_page_offset[offset] = tile[x2 % sx][y2 % sy];
|
||||
b_t[b_n] = 7;
|
||||
b_x[b_n] = x2;
|
||||
b_y[b_n] = y2;
|
||||
b_n++; // add new node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swap a & b arrays
|
||||
sp = a_x;
|
||||
a_x = b_x;
|
||||
b_x = sp;
|
||||
|
||||
// below
|
||||
if (t & 8) {
|
||||
x2 = ix;
|
||||
y2 = iy + 1;
|
||||
if (y2 <= qbg_view_y2) {
|
||||
offset = y2 * qbg_width + x2;
|
||||
if (!done[offset]) {
|
||||
done[offset] = 1;
|
||||
if (qbg_active_page_offset[offset] != bordercol) {
|
||||
qbg_active_page_offset[offset] = tile[x2 % sx][y2 % sy];
|
||||
b_t[b_n] = 11;
|
||||
b_x[b_n] = x2;
|
||||
b_y[b_n] = y2;
|
||||
b_n++; // add new node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sp = a_y;
|
||||
a_y = b_y;
|
||||
b_y = sp;
|
||||
|
||||
} // i
|
||||
cp = a_t;
|
||||
a_t = b_t;
|
||||
b_t = cp;
|
||||
|
||||
// no new nodes?
|
||||
if (b_n == 0) {
|
||||
memset(done, 0, write_page->width * write_page->height); // cleanup
|
||||
return; // finished!
|
||||
a_n = b_n;
|
||||
}
|
||||
|
||||
// swap a & b arrays
|
||||
sp = a_x;
|
||||
a_x = b_x;
|
||||
b_x = sp;
|
||||
sp = a_y;
|
||||
a_y = b_y;
|
||||
b_y = sp;
|
||||
cp = a_t;
|
||||
a_t = b_t;
|
||||
b_t = cp;
|
||||
a_n = b_n;
|
||||
|
||||
goto nextpass;
|
||||
}
|
||||
|
||||
void sub_circle(double x, double y, double r, uint32 col, double start, double end, double aspect, int32 passed) {
|
||||
|
|
|
@ -107,7 +107,7 @@ do
|
|||
|
||||
pushd . > /dev/null
|
||||
cd "./tests/compile_tests/$category"
|
||||
testResult=$("../../../$EXE" 2>&1)
|
||||
testResult=$("../../../$EXE" "../../../$RESULTS_DIR" "$category-$testName" 2>&1)
|
||||
ERR=$?
|
||||
popd > /dev/null
|
||||
|
||||
|
|
19
tests/compile_tests/paint/tile_border_black_bg.bas
Normal file
19
tests/compile_tests/paint/tile_border_black_bg.bas
Normal file
|
@ -0,0 +1,19 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, white border color.
|
||||
' background is black, circle is white.
|
||||
'
|
||||
' Result should fill the entire circle with pattern
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
Circle (64, 25), 25, 7
|
||||
Paint (64, 25), TILE$, 7
|
||||
|
||||
AssertImage test1&, "tile_border_black_bg.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_border_black_bg.bmp
Normal file
BIN
tests/compile_tests/paint/tile_border_black_bg.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
1
tests/compile_tests/paint/tile_border_black_bg.output
Normal file
1
tests/compile_tests/paint/tile_border_black_bg.output
Normal file
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
23
tests/compile_tests/paint/tile_border_black_nocolor.bas
Normal file
23
tests/compile_tests/paint/tile_border_black_nocolor.bas
Normal file
|
@ -0,0 +1,23 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, black border color.
|
||||
' background is colored white, circle is black.
|
||||
'
|
||||
' Result should no change anything, as the inside
|
||||
' of the circle matches the border color.
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
' Make the entire image white
|
||||
Line (0, 0)-(127, 49), 7, BF
|
||||
|
||||
Circle (64, 25), 25, 0
|
||||
Paint (64, 25), TILE$, 7
|
||||
|
||||
AssertImage test1&, "tile_border_black_nocolor.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_border_black_nocolor.bmp
Normal file
BIN
tests/compile_tests/paint/tile_border_black_nocolor.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
28
tests/compile_tests/paint/tile_border_white_bg.bas
Normal file
28
tests/compile_tests/paint/tile_border_white_bg.bas
Normal file
|
@ -0,0 +1,28 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, black border color.
|
||||
' background is colored white, circle is black.
|
||||
'
|
||||
' Note the starting location for Paint is neither
|
||||
' white or black, the starting color should not
|
||||
' matter when using a border color.
|
||||
'
|
||||
' Result should fill the entire circle with pattern
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
' Make the entire image white
|
||||
Line (0, 0)-(127, 49), 7, BF
|
||||
|
||||
Circle (64, 25), 25, 0
|
||||
Pset (64, 25), 15 ' Set the starting location a third color
|
||||
|
||||
Paint (64, 25), TILE$, 0
|
||||
|
||||
AssertImage test1&, "tile_border_white_bg.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_border_white_bg.bmp
Normal file
BIN
tests/compile_tests/paint/tile_border_white_bg.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
1
tests/compile_tests/paint/tile_border_white_bg.output
Normal file
1
tests/compile_tests/paint/tile_border_white_bg.output
Normal file
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
23
tests/compile_tests/paint/tile_border_white_nocolor.bas
Normal file
23
tests/compile_tests/paint/tile_border_white_nocolor.bas
Normal file
|
@ -0,0 +1,23 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, white border color.
|
||||
' background is colored white, circle is black.
|
||||
'
|
||||
' Result should no change anything, as the inside
|
||||
' of the circle matches the border color.
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
' Make the entire image white
|
||||
Line (0, 0)-(127, 49), 7, BF
|
||||
|
||||
Circle (64, 25), 25, 0
|
||||
Paint (64, 25), TILE$, 7
|
||||
|
||||
AssertImage test1&, "tile_border_white_nocolor.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_border_white_nocolor.bmp
Normal file
BIN
tests/compile_tests/paint/tile_border_white_nocolor.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
19
tests/compile_tests/paint/tile_noborder_black_bg.bas
Normal file
19
tests/compile_tests/paint/tile_noborder_black_bg.bas
Normal file
|
@ -0,0 +1,19 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, no border color.
|
||||
' background is left black.
|
||||
'
|
||||
' Result should fill the entire circle with pattern
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
Circle (64, 25), 25, 7
|
||||
Paint (64, 25), TILE$
|
||||
|
||||
AssertImage test1&, "tile_noborder_black_bg.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_noborder_black_bg.bmp
Normal file
BIN
tests/compile_tests/paint/tile_noborder_black_bg.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
1
tests/compile_tests/paint/tile_noborder_black_bg.output
Normal file
1
tests/compile_tests/paint/tile_noborder_black_bg.output
Normal file
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
22
tests/compile_tests/paint/tile_noborder_white_bg.bas
Normal file
22
tests/compile_tests/paint/tile_noborder_white_bg.bas
Normal file
|
@ -0,0 +1,22 @@
|
|||
$Console:Only
|
||||
ChDir _StartDir$
|
||||
|
||||
TILE$ = MKL$(&HAAFFBB55)
|
||||
|
||||
' Paint with tiling, no border color.
|
||||
' background is colored white, circle is black.
|
||||
'
|
||||
' Result should fill the entire circle with pattern
|
||||
test1& = _NewImage(128, 50, 9)
|
||||
_Dest test1&
|
||||
|
||||
' Make the entire image white
|
||||
Line (0, 0)-(127, 49), 7, BF
|
||||
|
||||
Circle (64, 25), 25, 0
|
||||
Paint (64, 25), TILE$
|
||||
|
||||
AssertImage test1&, "tile_noborder_white_bg.bmp"
|
||||
System
|
||||
|
||||
'$include:'../utilities/imageassert.bm'
|
BIN
tests/compile_tests/paint/tile_noborder_white_bg.bmp
Normal file
BIN
tests/compile_tests/paint/tile_noborder_white_bg.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
1
tests/compile_tests/paint/tile_noborder_white_bg.output
Normal file
1
tests/compile_tests/paint/tile_noborder_white_bg.output
Normal file
|
@ -0,0 +1 @@
|
|||
Success, images are identical!
|
111
tests/compile_tests/utilities/imageassert.bm
Normal file
111
tests/compile_tests/utilities/imageassert.bm
Normal file
|
@ -0,0 +1,111 @@
|
|||
|
||||
'
|
||||
' Asserts that a created image, 'originalActualImage', is identical to the provide expected image, 'expectedFileName'
|
||||
'
|
||||
' The created image is converted to 32-bit and saved to the results folder.
|
||||
' We then load the expected image as a 32-bit image, compare file sizes,
|
||||
' width/height, and each pixel.
|
||||
'
|
||||
SUB AssertImage(originalActualImage As Long, expectedFileName As String)
|
||||
Dim actualImage As Long
|
||||
Dim ResultsDir As String, TestPrefix As String
|
||||
|
||||
ResultsDir = Command$(1)
|
||||
TestPrefix = Command$(2)
|
||||
|
||||
' Make sure the test result will be seen
|
||||
_Dest _Console
|
||||
|
||||
' Convert to 32-bit for comparisons
|
||||
actualImage = _NewImage(_Width(originalActualImage), _Height(originalActualImage), 32)
|
||||
_PUTIMAGE , originalActualImage, actualImage
|
||||
|
||||
'First save the result
|
||||
SaveImage actualImage, ResultsDir + "/" + TestPrefix + "_result.bmp"
|
||||
|
||||
'Compare both images, print whether they are identical
|
||||
Dim expectedImage As Long
|
||||
expectedImage = _LOADIMAGE(expectedFileName, 32)
|
||||
|
||||
If _Width(actualImage) <> _Width(expectedImage) Then
|
||||
Print "Failure! Image width differs, actual:"; _Width(actualImage);", Expected:"; _Width(expectedImage)
|
||||
GoTo freeImages
|
||||
End If
|
||||
|
||||
If _Height(actualImage) <> _Height(expectedImage) Then
|
||||
Print "Failure! Image height differs, actual:"; _Height(actualImage);", Expected:"; _Height(expectedImage)
|
||||
GoTo freeImages
|
||||
End If
|
||||
|
||||
Dim actual As _Mem, expected As _Mem
|
||||
|
||||
actual = _MEMIMAGE(actualImage)
|
||||
expected = _MEMIMAGE(expectedImage)
|
||||
|
||||
IF actual.SIZE <> expected.SIZE THEN
|
||||
Print "Failure! Image sizes differ, Actual:"; actual.SIZE; ", Expected:"; expected.SIZE
|
||||
GoTo freeImages
|
||||
END IF
|
||||
|
||||
w& = _Width(expectedImage)
|
||||
h& = _Height(expectedImage)
|
||||
|
||||
For x& = 0 to w& - 1
|
||||
For y& = 0 to h& - 1
|
||||
pixelOffset = (y& * w& + x&) * 4
|
||||
|
||||
actualPixel& = _MemGet(actual, actual.OFFSET + pixelOffset, LONG)
|
||||
expectedPixel& = _MemGet(expected, expected.OFFSET + pixelOffset, LONG)
|
||||
|
||||
If actualPixel& <> expectedPixel& Then
|
||||
Print "Failure! Image pixels at ("; x&; ","; y&; ") differ, actual: 0x"; HEX$(actualPixel&);", expected: 0x"; HEX$(expectedPixel&)
|
||||
GoTo freeImages
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
|
||||
PRINT "Success, images are identical!"
|
||||
|
||||
freeImages:
|
||||
_MEMFREE actual
|
||||
_MEMFREE expected
|
||||
_FreeImage actualImage
|
||||
END SUB
|
||||
|
||||
' From the QB64-PE Wiki: https://qb64phoenix.com/qb64wiki/index.php/SAVEIMAGE
|
||||
Sub SaveImage (image As Long, filename As String)
|
||||
bytesperpixel& = _PixelSize(image&)
|
||||
If bytesperpixel& = 0 Then Print "Text modes unsupported!": End
|
||||
If bytesperpixel& = 1 Then bpp& = 8 Else bpp& = 24
|
||||
x& = _Width(image&)
|
||||
y& = _Height(image&)
|
||||
b$ = "BM????QB64????" + MKL$(40) + MKL$(x&) + MKL$(y&) + MKI$(1) + MKI$(bpp&) + MKL$(0) + "????" + String$(16, 0) 'partial BMP header info(???? to be filled later)
|
||||
If bytesperpixel& = 1 Then
|
||||
For c& = 0 To 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
|
||||
cv& = _PaletteColor(c&, image&) ' color attribute to read.
|
||||
b$ = b$ + Chr$(_Blue32(cv&)) + Chr$(_Green32(cv&)) + Chr$(_Red32(cv&)) + Chr$(0) 'spacer byte
|
||||
Next
|
||||
End If
|
||||
Mid$(b$, 11, 4) = MKL$(Len(b$)) ' image pixel data offset(BMP header)
|
||||
lastsource& = _Source
|
||||
_Source image&
|
||||
If ((x& * 3) Mod 4) Then padder$ = String$(4 - ((x& * 3) Mod 4), 0)
|
||||
For py& = y& - 1 To 0 Step -1 ' read JPG image pixel color data
|
||||
r$ = ""
|
||||
For px& = 0 To x& - 1
|
||||
c& = Point(px&, py&) 'POINT 32 bit values are large LONG values
|
||||
If bytesperpixel& = 1 Then r$ = r$ + Chr$(c&) Else r$ = r$ + Left$(MKL$(c&), 3)
|
||||
Next px&
|
||||
d$ = d$ + r$ + padder$
|
||||
Next py&
|
||||
_Source lastsource&
|
||||
Mid$(b$, 35, 4) = MKL$(Len(d$)) ' image size(BMP header)
|
||||
b$ = b$ + d$ ' total file data bytes to create file
|
||||
Mid$(b$, 3, 4) = MKL$(Len(b$)) ' size of data file(BMP header)
|
||||
If LCase$(Right$(filename$, 4)) <> ".bmp" Then ext$ = ".bmp"
|
||||
f& = FreeFile
|
||||
Open filename$ + ext$ For Output As #f&: Close #f& ' erases an existing file
|
||||
Open filename$ + ext$ For Binary As #f&
|
||||
Put #f&, , b$
|
||||
Close #f&
|
||||
End Sub
|
Loading…
Reference in a new issue