mirror of
https://github.com/birth1mark/orbis8.git
synced 2026-10-29 01:00:32 +01:00
2837 lines
81 KiB
C++
2837 lines
81 KiB
C++
#include <string>
|
|
#include <vector>
|
|
#include <tuple>
|
|
|
|
#include "doctest.h"
|
|
#include "../source/graphics.h"
|
|
#include "../source/fontdata.h"
|
|
#include "../source/PicoRam.h"
|
|
|
|
#include "testHelpers.h"
|
|
|
|
TEST_CASE("graphics class behaves as expected") {
|
|
//general setup
|
|
std::string fontdata = get_font_data();
|
|
PicoRam picoRam;
|
|
picoRam.Reset();
|
|
Graphics* graphics = new Graphics(fontdata, &picoRam);
|
|
graphics->cls();
|
|
|
|
SUBCASE("Constructor sets default clip") {
|
|
CHECK(picoRam.drawState.clip_xb == 0);
|
|
CHECK(picoRam.drawState.clip_yb == 0);
|
|
CHECK(picoRam.drawState.clip_xe == 128);
|
|
CHECK(picoRam.drawState.clip_ye == 128);
|
|
}
|
|
SUBCASE("Constructor sets default color") {
|
|
CHECK(picoRam.drawState.color == 6);
|
|
}
|
|
SUBCASE("Constructor sets default draw color palette") {
|
|
//colors mapped to themselves
|
|
for (uint8_t c = 0; c < 16; c++) {
|
|
CHECK(graphics->getDrawPalMappedColor(c) == c);
|
|
}
|
|
}
|
|
SUBCASE("Constructor sets default draw transparency palette") {
|
|
//color 0 defaults to transparent
|
|
CHECK(graphics->isColorTransparent(0) == true);
|
|
|
|
//all other colors not transparent
|
|
for (uint8_t c = 1; c < 16; c++) {
|
|
CHECK(graphics->isColorTransparent(c) == false);
|
|
}
|
|
}
|
|
SUBCASE("Constructor sets default screen palette") {
|
|
//colors mapped to themselves
|
|
for (uint8_t c = 0; c < 16; c++) {
|
|
CHECK(graphics->getScreenPalMappedColor(c) == c);
|
|
}
|
|
}
|
|
SUBCASE("cls() clears the pico 8 framebuffer to color, defaults to black") {
|
|
const uint8_t testColor = 4;
|
|
graphics->cls(testColor);
|
|
bool isAllColor = true;
|
|
for(int x = 0; x < 128; x++){
|
|
for(int y = 0; y < 128; y++){
|
|
isAllColor &= graphics->pget(x, y) == testColor;
|
|
}
|
|
}
|
|
CHECK(isAllColor);
|
|
}
|
|
SUBCASE("cls() defaults to black") {
|
|
bool isAllColor = true;
|
|
graphics->cls();
|
|
for(int x = 0; x < 128; x++){
|
|
for(int y = 0; y < 128; y++){
|
|
isAllColor &= graphics->pget(x, y) == 0;
|
|
}
|
|
}
|
|
CHECK(isAllColor);
|
|
}
|
|
SUBCASE("cls() resets cursor") {
|
|
picoRam.drawState.text_x = 42;
|
|
picoRam.drawState.text_y = 99;
|
|
graphics->cls();
|
|
graphics->cursor();
|
|
|
|
CHECK_EQ(picoRam.drawState.text_x, 0);
|
|
CHECK_EQ(picoRam.drawState.text_y, 0);
|
|
}
|
|
SUBCASE("cls() resets clip") {
|
|
picoRam.drawState.clip_xb = 10;
|
|
picoRam.drawState.clip_yb = 12;
|
|
picoRam.drawState.clip_xe = 100;
|
|
picoRam.drawState.clip_ye = 102;
|
|
graphics->cls();
|
|
|
|
CHECK_EQ(picoRam.drawState.clip_xb, 0);
|
|
CHECK_EQ(picoRam.drawState.clip_yb, 0);
|
|
CHECK_EQ(picoRam.drawState.clip_xe, 128);
|
|
CHECK_EQ(picoRam.drawState.clip_ye, 128);
|
|
}
|
|
SUBCASE("pset() sets color at coord") {
|
|
const uint8_t testColor = 15;
|
|
graphics->pset(72, 31, testColor);
|
|
|
|
CHECK(graphics->pget(72, 31) == testColor);
|
|
}
|
|
SUBCASE("pset() with no color uses pen color") {
|
|
graphics->pset(121, 6);
|
|
|
|
CHECK(graphics->pget(121, 6) == picoRam.drawState.color);
|
|
}
|
|
SUBCASE("color({color}) sets color in ram") {
|
|
graphics->color(12);
|
|
|
|
CHECK(picoRam.drawState.color == 12);
|
|
}
|
|
SUBCASE("color() resets color to 6") {
|
|
picoRam.drawState.color = 12;
|
|
|
|
graphics->color();
|
|
|
|
CHECK(picoRam.drawState.color == 6);
|
|
}
|
|
SUBCASE("color() returns previous") {
|
|
auto prev = picoRam.drawState.color = 13;
|
|
|
|
graphics->color(12);
|
|
|
|
CHECK(prev == 13);
|
|
}
|
|
SUBCASE("line() clears line state") {
|
|
picoRam.drawState.line_x = 10;
|
|
picoRam.drawState.line_y = 30;
|
|
picoRam.drawState.lineInvalid = false;
|
|
|
|
graphics->line();
|
|
|
|
CHECK(
|
|
(picoRam.drawState.line_x == 0 &&
|
|
picoRam.drawState.line_y == 0 &&
|
|
picoRam.drawState.lineInvalid == true) == true);
|
|
}
|
|
SUBCASE("line({arg}) sets color and clears line") {
|
|
picoRam.drawState.line_x = 10;
|
|
picoRam.drawState.line_y = 30;
|
|
picoRam.drawState.lineInvalid = false;
|
|
picoRam.drawState.color = 2;
|
|
|
|
graphics->line(14);
|
|
|
|
CHECK(
|
|
(picoRam.drawState.line_x == 0 &&
|
|
picoRam.drawState.line_y == 0 &&
|
|
picoRam.drawState.lineInvalid == true &&
|
|
picoRam.drawState.color == 14) == true);
|
|
}
|
|
SUBCASE("line({x}, {y}) without valid line state does nothing") {
|
|
graphics->cls();
|
|
graphics->line();
|
|
graphics->line(10, 11);
|
|
|
|
bool isAllColor = true;
|
|
for(int x = 0; x < 128; x++){
|
|
for(int y = 0; y < 128; y++){
|
|
isAllColor &= graphics->pget(0, 0) == 0;
|
|
}
|
|
}
|
|
|
|
CHECK(
|
|
(picoRam.drawState.line_x == 0 &&
|
|
picoRam.drawState.line_y == 0 &&
|
|
picoRam.drawState.lineInvalid == true &&
|
|
isAllColor) == true);
|
|
}
|
|
SUBCASE("line({x}, {y}) with valid line state updates state") {
|
|
graphics->cls();
|
|
picoRam.drawState.line_x = 10;
|
|
picoRam.drawState.line_y = 10;
|
|
picoRam.drawState.lineInvalid = false;
|
|
graphics->line(13, 13);
|
|
|
|
CHECK(
|
|
(picoRam.drawState.line_x == 13 &&
|
|
picoRam.drawState.line_y == 13 &&
|
|
picoRam.drawState.lineInvalid == false) == true);
|
|
}
|
|
SUBCASE("line({x}, {y}) draws (45 degree down-right)") {
|
|
graphics->cls();
|
|
picoRam.drawState.color = 2;
|
|
picoRam.drawState.line_x = 10;
|
|
picoRam.drawState.line_y = 10;
|
|
picoRam.drawState.lineInvalid = false;
|
|
graphics->line(12, 12);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{10, 10, 2},
|
|
{11, 11, 2},
|
|
{12, 12, 2}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x}, {y}, {c}) draws (vertical down, even x value)") {
|
|
graphics->cls();
|
|
picoRam.drawState.line_x = 20;
|
|
picoRam.drawState.line_y = 20;
|
|
picoRam.drawState.lineInvalid = false;
|
|
graphics->line(20, 24, 13);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 13},
|
|
{20, 21, 13},
|
|
{20, 22, 13},
|
|
{20, 23, 13},
|
|
{20, 24, 13}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x}, {y}, {c}) draws (vertical up, odd x value)") {
|
|
graphics->cls();
|
|
picoRam.drawState.line_x = 21;
|
|
picoRam.drawState.line_y = 24;
|
|
picoRam.drawState.lineInvalid = false;
|
|
graphics->line(21, 20, 3);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{21, 20, 3},
|
|
{21, 21, 3},
|
|
{21, 22, 3},
|
|
{21, 23, 3},
|
|
{21, 24, 3}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}) draws (45 degree left)") {
|
|
graphics->cls();
|
|
picoRam.drawState.color = 10;
|
|
graphics->line(20, 20, 18, 22);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 10},
|
|
{19, 21, 10},
|
|
{18, 22, 10}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}, {c}) draws (horizontal left)") {
|
|
graphics->cls();
|
|
graphics->line(20, 20, 18, 20, 4);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 4},
|
|
{19, 20, 4},
|
|
{18, 20, 4}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}, {c}) draws (45 degree up left)") {
|
|
graphics->cls();
|
|
graphics->line(20, 20, 18, 18, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 5},
|
|
{19, 19, 5},
|
|
{18, 18, 5}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}, {c}) draws (vertical up)") {
|
|
graphics->cls();
|
|
graphics->line(20, 20, 20, 18, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 5},
|
|
{20, 19, 5},
|
|
{20, 18, 5}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}, {c}) draws (45 degree up right)") {
|
|
graphics->cls();
|
|
graphics->line(20, 20, 22, 18, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 5},
|
|
{21, 19, 5},
|
|
{22, 18, 5}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("line({x1}, {y1}, {x2}, {y2}, {c}) draws (horizontal right)") {
|
|
graphics->cls();
|
|
graphics->line(20, 20, 22, 20, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{20, 20, 5},
|
|
{21, 20, 5},
|
|
{22, 20, 5}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("overdrawn line() still draws (horizontal)") {
|
|
graphics->cls();
|
|
graphics->line(-10, 1, 138, 1, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 1, 5},
|
|
{1, 1, 5},
|
|
{2, 1, 5}//etc
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("overdrawn line() still draws (vertical)") {
|
|
graphics->cls();
|
|
graphics->line(1, -10, 1, 138, 5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{1, 0, 5},
|
|
{1, 1, 5},
|
|
{1, 2, 5}//etc
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
|
|
SUBCASE("circ({ox}, {oy}) uses pen color and radius of 4") {
|
|
graphics->cls();
|
|
graphics->circ(40, 40);
|
|
|
|
//quarter circle from 12 oclock to 3 oclock
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{39, 36, 6},
|
|
{40, 36, 6},
|
|
{41, 36, 6},
|
|
{42, 37, 6},
|
|
{43, 37, 6},
|
|
{43, 38, 6},
|
|
{44, 39, 6},
|
|
{44, 40, 6}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circ({ox}, {oy}, {r}) uses pen color") {
|
|
graphics->cls();
|
|
graphics->color(14);
|
|
graphics->circ(40, 40, 1);
|
|
|
|
//radius of 1 draws 4 points around center
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 39, 14},
|
|
{41, 40, 14},
|
|
{40, 41, 14},
|
|
{39, 40, 14},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circ({ox}, {oy}, {r}, {c}) draws correctly") {
|
|
graphics->cls();
|
|
graphics->circ(40, 40, 2, 13);
|
|
|
|
//radius of 2 draws this circle
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{38, 39, 13},
|
|
{38, 40, 13},
|
|
{38, 41, 13},
|
|
{39, 38, 13},
|
|
{39, 42, 13},
|
|
{40, 38, 13},
|
|
{40, 42, 13},
|
|
{41, 38, 13},
|
|
{41, 42, 13},
|
|
{42, 39, 13},
|
|
{42, 40, 13},
|
|
{42, 41, 13},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circ({ox}, {oy}, {r}, {c}) radius of 0 draws 1 point") {
|
|
graphics->cls();
|
|
graphics->circ(40, 40, 0, 13);
|
|
|
|
//radius of 2 draws this circle
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 13},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
//circfill (same as circ tests, but also test center point)
|
|
SUBCASE("circfill({ox}, {oy}) uses pen color and radius of 4") {
|
|
graphics->cls();
|
|
graphics->circfill(40, 40);
|
|
|
|
//quarter circle from 12 oclock to 3 oclock
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{39, 36, 6},
|
|
{40, 36, 6},
|
|
{41, 36, 6},
|
|
{42, 37, 6},
|
|
{43, 37, 6},
|
|
{43, 38, 6},
|
|
{44, 39, 6},
|
|
{44, 40, 6},
|
|
{40, 40, 6},//center point
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circfill({ox}, {oy}, {r}) uses pen color") {
|
|
graphics->cls();
|
|
graphics->color(14);
|
|
graphics->circfill(40, 40, 1);
|
|
|
|
//radius of 1 draws 4 points around center, plus the center
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 39, 14},
|
|
{41, 40, 14},
|
|
{40, 41, 14},
|
|
{39, 40, 14},
|
|
{40, 40, 14},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circfill({ox}, {oy}, {r}, {c}) draws correctly") {
|
|
graphics->cls();
|
|
graphics->circfill(40, 40, 2, 13);
|
|
|
|
//radius of 2 draws this circle
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{38, 39, 13},
|
|
{38, 40, 13},
|
|
{38, 41, 13},
|
|
{39, 38, 13},
|
|
{39, 42, 13},
|
|
{40, 38, 13},
|
|
{40, 42, 13},
|
|
{41, 38, 13},
|
|
{41, 42, 13},
|
|
{42, 39, 13},
|
|
{42, 40, 13},
|
|
{42, 41, 13},
|
|
{40, 40, 13},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circfill({ox}, {oy}, {r}, {c}) radius of 0 draws 1 point") {
|
|
graphics->cls();
|
|
graphics->circfill(40, 40, 0, 13);
|
|
|
|
//radius of 0 draws a point
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 13},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("circfill({ox}, {oy}, {r}, {c}) with inverted mode fills outside circle") {
|
|
graphics->cls(8);
|
|
picoRam.drawState.colorSettingFlag = 0x02; // Enable inverted fill mode
|
|
graphics->circfill(40, 40, 2, 13);
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Inside circle should be background color (8)
|
|
{40, 40, 8},
|
|
{39, 40, 8},
|
|
{40, 39, 8},
|
|
{41, 40, 8},
|
|
{40, 41, 8},
|
|
// Outside circle should be filled color (13)
|
|
{40, 37, 13},
|
|
{40, 43, 13},
|
|
{37, 40, 13},
|
|
{43, 40, 13},
|
|
|
|
{0, 0, 13},
|
|
{127, 127, 13},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("oval({x0}, {x1}, {y0}, {y1}, {c}) draws an ellipse") {
|
|
graphics->cls();
|
|
graphics->oval(40, 40, 45, 42, 13);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40,41,13},
|
|
{41,40,13},
|
|
{41,42,13},
|
|
{42,40,13},
|
|
{42,42,13},
|
|
{43,40,13},
|
|
{43,42,13},
|
|
{44,41,13}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("oval({x0}, {x1}, {y0}, {y1}, {c}) with zeroes doesn't infinite loop") {
|
|
graphics->cls();
|
|
graphics->oval(40, 40, 40, 40, 13);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("ovalfill({x0}, {x1}, {y0}, {y1}, {c}) fills an ellipse") {
|
|
graphics->cls();
|
|
graphics->ovalfill(40, 40, 45, 42, 13);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40,41,13},
|
|
{41,40,13},
|
|
{41,41,13},
|
|
{41,42,13},
|
|
{42,40,13},
|
|
{42,41,13},
|
|
{42,42,13},
|
|
{43,40,13},
|
|
{43,41,13},
|
|
{43,42,13},
|
|
{44,41,13}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("ovalfill({x0}, {x1}, {y0}, {y1}, {c}) with zeroes doesn't infinite loop") {
|
|
graphics->cls();
|
|
graphics->ovalfill(40, 40, 40, 40, 13);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rect({x1}, {y1}, {x2}, {y2}) uses pen color") {
|
|
graphics->cls();
|
|
graphics->color(15);
|
|
graphics->rect(40, 40, 43, 42);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 15},
|
|
{40, 41, 15},
|
|
{40, 42, 15},
|
|
{41, 40, 15},
|
|
{41, 42, 15},
|
|
{42, 40, 15},
|
|
{42, 42, 15},
|
|
{43, 40, 15},
|
|
{43, 41, 15},
|
|
{43, 42, 15}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rect({x1}, {y1}, {x2}, {y2}) offscreen x draws nothing") {
|
|
graphics->cls();
|
|
graphics->color(15);
|
|
graphics->rect(-50, 40, -40, 42);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 40, 0},
|
|
{0, 41, 0},
|
|
{0, 42, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rect({x1}, {y1}, {x2}, {y2}) offscreen y draws nothing") {
|
|
graphics->cls();
|
|
graphics->color(15);
|
|
graphics->rect(40, -50, 43, -40);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 0, 0},
|
|
{41, 0, 0},
|
|
{42, 0, 0},
|
|
{43, 0, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rect({x1}, {y1}, {x2}, {y2}, {c}) swapped coords work, color used") {
|
|
graphics->cls();
|
|
graphics->rect(42, 43, 40, 40, 1);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 1},
|
|
{40, 41, 1},
|
|
{40, 42, 1},
|
|
{40, 43, 1},
|
|
{41, 40, 1},
|
|
{41, 43, 1},
|
|
{42, 40, 1},
|
|
{42, 41, 1},
|
|
{42, 42, 1},
|
|
{42, 43, 1}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rectfill({x1}, {y1}, {x2}, {y2}) uses pen color, fills rect") {
|
|
graphics->cls();
|
|
graphics->color(10);
|
|
graphics->rectfill(40, 40, 43, 43);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 10},
|
|
{40, 41, 10},
|
|
{40, 42, 10},
|
|
{40, 43, 10},
|
|
{41, 40, 10},
|
|
{41, 41, 10},
|
|
{41, 42, 10},
|
|
{41, 43, 10},
|
|
{42, 40, 10},
|
|
{42, 41, 10},
|
|
{42, 42, 10},
|
|
{42, 43, 10},
|
|
{43, 40, 10},
|
|
{43, 41, 10},
|
|
{43, 42, 10},
|
|
{43, 43, 10}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rectfill({x1}, {y1}, {x2}, {y2}, {c}) swapped coords work, color used") {
|
|
graphics->cls();
|
|
graphics->rectfill(42, 43, 40, 40, 2);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 2},
|
|
{40, 41, 2},
|
|
{40, 42, 2},
|
|
{40, 43, 2},
|
|
{41, 40, 2},
|
|
{41, 41, 2},
|
|
{41, 42, 2},
|
|
{41, 43, 2},
|
|
{42, 40, 2},
|
|
{42, 41, 2},
|
|
{42, 42, 2},
|
|
{42, 43, 2}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
|
|
SUBCASE("spr(...) draws to screen at location") {
|
|
graphics->cls();
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
graphics->sset(i % 8, i / 8, i%2 == 0 ? i : 0 );
|
|
}
|
|
|
|
graphics->spr(0, 101, 33, 1.0, 1.0, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{103, 33, 2},
|
|
{105, 33, 4},
|
|
{107, 33, 6},
|
|
{101, 34, 8},
|
|
{103, 34, 10},
|
|
{105, 34, 12},
|
|
{107, 34, 14},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws more than 1 horizontal sprite") {
|
|
graphics->cls();
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
graphics->sset(i, 0, i);
|
|
}
|
|
|
|
graphics->spr(0, 35, 100, 1.5, 1.0, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{35, 100, 0},
|
|
{36, 100, 1},
|
|
{37, 100, 2},
|
|
{38, 100, 3},
|
|
{39, 100, 4},
|
|
{40, 100, 5},
|
|
{41, 100, 6},
|
|
{42, 100, 7},
|
|
{43, 100, 8},
|
|
{44, 100, 9},
|
|
{45, 100, 10},
|
|
{46, 100, 11},
|
|
{47, 100, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws more than 1 vertical sprite") {
|
|
graphics->cls();
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
graphics->sset(0, i, i);
|
|
}
|
|
|
|
graphics->spr(0, 35, 100, 1.0, 1.25, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{35, 100, 0},
|
|
{35, 101, 1},
|
|
{35, 102, 2},
|
|
{35, 103, 3},
|
|
{35, 104, 4},
|
|
{35, 105, 5},
|
|
{35, 106, 6},
|
|
{35, 107, 7},
|
|
{35, 108, 8},
|
|
{35, 109, 9},
|
|
{35, 100, 0}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws flipped Horizontal") {
|
|
graphics->cls();
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
graphics->sset(i, 0, i);
|
|
}
|
|
|
|
graphics->spr(0, 35, 100, 1.0, 1.0, true, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{34, 100, 0},
|
|
{35, 100, 7},
|
|
{36, 100, 6},
|
|
{37, 100, 5},
|
|
{38, 100, 4},
|
|
{39, 100, 3},
|
|
{40, 100, 2},
|
|
{41, 100, 1},
|
|
{42, 100, 0},
|
|
{43, 100, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws flipped vertical") {
|
|
graphics->cls();
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
graphics->sset(0, i, i);
|
|
}
|
|
|
|
graphics->spr(0, 35, 100, 1.0, 1.0, false, true);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{35, 99, 0},
|
|
{35, 100, 7},
|
|
{35, 101, 6},
|
|
{35, 102, 5},
|
|
{35, 103, 4},
|
|
{35, 104, 3},
|
|
{35, 105, 2},
|
|
{35, 106, 1},
|
|
{35, 107, 0},
|
|
{35, 108, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws to screen at odd numbered location") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->spr(0, 51, 11, 1, 1, false, false);
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{50, 10, 0},
|
|
{51, 11, 0},
|
|
{52, 12, 1},
|
|
{53, 13, 2},
|
|
{54, 14, 3},
|
|
{55, 15, 4},
|
|
{56, 16, 5},
|
|
{57, 17, 6},
|
|
{58, 18, 7},
|
|
{59, 19, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws doesn't repeat sprites if spritesheet width is exceeded") {
|
|
graphics->cls();
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 128; x++) {
|
|
graphics->sset(x, y, (x+y)%15+1);
|
|
}
|
|
}
|
|
|
|
//sprite 6, but a width and height of 16 pixels goes off the edge.
|
|
//it should end instead of wrapping
|
|
graphics->spr(6, 0, 40, 16, 16, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{81, 40, 0},
|
|
{81, 41, 0},
|
|
{81, 42, 0},
|
|
{81, 43, 0},
|
|
{81, 44, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("spr(...) draws last sprite (sprite 255)") {
|
|
graphics->cls();
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 128; x++) {
|
|
graphics->sset(x, y, (x+y)%15+1);
|
|
}
|
|
}
|
|
|
|
graphics->spr(255, 0, 120, 1, 1, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 120, 1},
|
|
{0, 121, 2},
|
|
{0, 122, 3},
|
|
{0, 123, 4},
|
|
{0, 124, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws to screen at odd numbered location") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(0, 0, 8, 8, 51, 11, 8, 8, false, false);
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{50, 10, 0},
|
|
{51, 11, 0},
|
|
{52, 12, 1},
|
|
{53, 13, 2},
|
|
{54, 14, 3},
|
|
{55, 15, 4},
|
|
{56, 16, 5},
|
|
{57, 17, 6},
|
|
{58, 18, 7},
|
|
{59, 19, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws from odd numbered sprite sheet location") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(1, 1, 4, 4, 51, 11, 4, 4, false, false);
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{51, 10, 0},
|
|
{51, 11, 1},
|
|
{51, 12, 1},
|
|
{51, 13, 1},
|
|
{51, 14, 1},
|
|
{52, 11, 2},
|
|
{52, 12, 2},
|
|
{52, 13, 2},
|
|
{52, 14, 2},
|
|
{53, 11, 3},
|
|
{53, 12, 3},
|
|
{53, 13, 3},
|
|
{53, 14, 3},
|
|
{54, 11, 4},
|
|
{54, 12, 4},
|
|
{54, 13, 4},
|
|
{54, 14, 4},
|
|
{55, 11, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws from odd numbered sprite sheet location flipped horizontally") {
|
|
//bug discovered in high stakes
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(1, 1, 4, 4, 0, 15, 4, 4, true, false);
|
|
|
|
//check sprite in columns
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 14, 0},
|
|
{0, 15, 4},
|
|
{0, 16, 4},
|
|
{0, 17, 4},
|
|
{0, 18, 4},
|
|
{1, 15, 3},
|
|
{1, 16, 3},
|
|
{1, 17, 3},
|
|
{1, 18, 3},
|
|
{2, 15, 2},
|
|
{2, 16, 2},
|
|
{2, 17, 2},
|
|
{2, 18, 2},
|
|
{3, 15, 1},
|
|
{3, 16, 1},
|
|
{3, 17, 1},
|
|
{3, 18, 1},
|
|
{4, 15, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws non-square to screen at location") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(3, 2, 3, 4, 100, 50, 3, 4, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 50, 3},
|
|
{100, 51, 3},
|
|
{100, 52, 3},
|
|
{100, 53, 3},
|
|
{101, 50, 4},
|
|
{101, 51, 4},
|
|
{101, 52, 4},
|
|
{101, 53, 4},
|
|
{102, 50, 5},
|
|
{102, 51, 5},
|
|
{102, 52, 5},
|
|
{102, 53, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) negative screen dimensions flip image") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(3, 2, 3, 4, 100, 50, 3, -4, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 46, 3},
|
|
{100, 47, 3},
|
|
{100, 48, 3},
|
|
{100, 49, 3},
|
|
{101, 46, 4},
|
|
{101, 47, 4},
|
|
{101, 48, 4},
|
|
{101, 49, 4},
|
|
{102, 46, 5},
|
|
{102, 47, 5},
|
|
{102, 48, 5},
|
|
{102, 49, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws doesn't repeat sprites if spritesheet width is exceeded") {
|
|
graphics->cls();
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 128; x++) {
|
|
graphics->sset(x, y, (x+y)%15+1);
|
|
}
|
|
}
|
|
|
|
//sprite 6, but a width and height of 16 pixels goes off the edge.
|
|
//it should end instead of wrapping
|
|
graphics->sspr(48, 0, 128, 32, 100, 50, 3, -4, false, false);
|
|
graphics->spr(6, 0, 40, 16, 16, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{81, 40, 0},
|
|
{81, 41, 0},
|
|
{81, 42, 0},
|
|
{81, 43, 0},
|
|
{81, 44, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("sspr(...) draws last sprite (sprite 255)") {
|
|
graphics->cls();
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 128; x++) {
|
|
graphics->sset(x, y, (x+y)%15+1);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(120, 120, 3, 4, 100, 50, 6, 8, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 50, 1},
|
|
{100, 51, 1},
|
|
{100, 52, 2},
|
|
{100, 53, 2},
|
|
{101, 50, 1},
|
|
{101, 51, 1},
|
|
{101, 52, 2},
|
|
{101, 53, 2},
|
|
{102, 50, 2},
|
|
{102, 51, 2},
|
|
{102, 52, 3},
|
|
{102, 53, 3},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
/*//TODO: come back and make SSPR stretch exactly how pico 8 does
|
|
SUBCASE("sspr(...) draws unevenly stretched sprite") {
|
|
graphics->cls();
|
|
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->sspr(3,1,3,1,100,50,5,1,false,false);
|
|
|
|
debugScreen(graphics);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 50, 3},
|
|
{101, 50, 3},
|
|
{102, 50, 4},
|
|
{103, 50, 5},
|
|
{104, 50, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
*/
|
|
SUBCASE("fget for sprite with none set")
|
|
{
|
|
auto result = graphics->fget(0);
|
|
|
|
CHECK_EQ(result, 0);
|
|
}
|
|
SUBCASE("fget for sprite with flags set")
|
|
{
|
|
uint8_t flags = 47;
|
|
picoRam.spriteFlags[4] = flags;
|
|
auto result = graphics->fget(4);
|
|
|
|
CHECK_EQ(result, flags);
|
|
}
|
|
SUBCASE("fget for sprite and flag number with flags set")
|
|
{
|
|
//118 in binary: 0111 0110
|
|
uint8_t flags = 118;
|
|
picoRam.spriteFlags[12] = flags;
|
|
auto result0 = graphics->fget(12, 0);
|
|
auto result1 = graphics->fget(12, 1);
|
|
auto result2 = graphics->fget(12, 2);
|
|
auto result3 = graphics->fget(12, 3);
|
|
auto result4 = graphics->fget(12, 4);
|
|
auto result5 = graphics->fget(12, 5);
|
|
auto result6 = graphics->fget(12, 6);
|
|
auto result7 = graphics->fget(12, 7);
|
|
|
|
bool offBitsCorrect = result0 == false && result3 == false && result7 == false;
|
|
bool onBitsCorrect = result1 == true && result2 == true && result4 == true
|
|
&& result5 == true && result6 == true;
|
|
|
|
CHECK(offBitsCorrect);
|
|
CHECK(onBitsCorrect);
|
|
}
|
|
SUBCASE("fset sets value in ram")
|
|
{
|
|
uint8_t flags = 65;
|
|
graphics->fset(31, flags);
|
|
auto result = picoRam.spriteFlags[31];
|
|
|
|
CHECK_EQ(result, flags);
|
|
}
|
|
SUBCASE("fset for single flag sets value in ram")
|
|
{
|
|
//fifth bit and second bit 0010 0100 == 36 in decimal
|
|
graphics->fset(17, 5, true);
|
|
graphics->fset(17, 2, true);
|
|
|
|
auto result = picoRam.spriteFlags[17];
|
|
|
|
CHECK_EQ(result, 36);
|
|
}
|
|
SUBCASE("sget defaults to 0 when nothing on sprite sheet")
|
|
{
|
|
auto result = graphics->sget(14, 41);
|
|
|
|
CHECK_EQ(result, 0);
|
|
}
|
|
SUBCASE("sget returns correct value for even x pixel")
|
|
{
|
|
int x = 40;
|
|
int y = 10;
|
|
int combinedIdx = y * 64 + (x / 2);
|
|
picoRam.spriteSheetData[combinedIdx] = 137; //10001001
|
|
auto result = graphics->sget(x, y);
|
|
|
|
CHECK_EQ(result, 9);
|
|
}
|
|
SUBCASE("sget returns correct value for odd x pixel")
|
|
{
|
|
int x = 41;
|
|
int y = 11;
|
|
int combinedIdx = y * 64 + (x / 2);
|
|
picoRam.spriteSheetData[combinedIdx] = 200; //11001000
|
|
auto result = graphics->sget(x, y);
|
|
|
|
CHECK_EQ(result, 12);
|
|
}
|
|
SUBCASE("sget returns 0 when out of bounds") {
|
|
graphics->cls();
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 128; x++) {
|
|
graphics->sset(x, y, (x+y)%15+1);
|
|
}
|
|
}
|
|
|
|
auto result = graphics->sget(128, 128);
|
|
|
|
CHECK_EQ(result, 0);
|
|
}
|
|
SUBCASE("sset sets value in ram for even x pixel")
|
|
{
|
|
uint8_t x = 60;
|
|
uint8_t y = 23;
|
|
graphics->sset(x, y, 14); //14 = 1110
|
|
|
|
int combinedIdx = y * 64 + (x / 2);
|
|
auto result = picoRam.spriteSheetData[combinedIdx];
|
|
|
|
CHECK_EQ(result, 14);
|
|
}
|
|
SUBCASE("sset sets value in ram for odd x pixel")
|
|
{
|
|
uint8_t x = 61;
|
|
uint8_t y = 23;
|
|
graphics->sset(x, y, 12); //12 = 1100
|
|
|
|
int combinedIdx = y * 64 + (x / 2);
|
|
auto result = picoRam.spriteSheetData[combinedIdx];
|
|
|
|
CHECK_EQ(result, 192);
|
|
}
|
|
SUBCASE("sset does nothing for out of bounds pixel")
|
|
{
|
|
uint8_t x = 128;
|
|
uint8_t y = 0;
|
|
graphics->sset(x, y, 14); //14 = 1110
|
|
|
|
int combinedIdx = y * 64 + (x / 2);
|
|
auto result = picoRam.spriteSheetData[combinedIdx];
|
|
|
|
CHECK_EQ(result, 0);
|
|
}
|
|
SUBCASE("camera({x}, {y}) sets values in memory")
|
|
{
|
|
uint8_t x = 33;
|
|
uint8_t y = 120;
|
|
graphics->camera(x, y);
|
|
|
|
CHECK_EQ(picoRam.drawState.camera_x, x);
|
|
CHECK_EQ(picoRam.drawState.camera_y, y);
|
|
}
|
|
SUBCASE("camera() sets values in memory to 0")
|
|
{
|
|
picoRam.drawState.camera_x = 33;
|
|
picoRam.drawState.camera_y = 120;
|
|
graphics->camera();
|
|
|
|
CHECK_EQ(picoRam.drawState.camera_x, 0);
|
|
CHECK_EQ(picoRam.drawState.camera_y, 0);
|
|
}
|
|
SUBCASE("camera({x}, {y}) returns previous values")
|
|
{
|
|
uint8_t x = 33;
|
|
uint8_t y = 120;
|
|
graphics->camera(x, y);
|
|
auto prev = graphics->camera(120, 31);
|
|
|
|
CHECK_EQ(std::get<0>(prev), x);
|
|
CHECK_EQ(std::get<1>(prev), y);
|
|
}
|
|
SUBCASE("camera values applies to pget")
|
|
{
|
|
uint8_t col = 13;
|
|
picoRam.drawState.camera_x = -44;
|
|
picoRam.drawState.camera_y = -3;
|
|
graphics->pset(14, 32, 13);
|
|
|
|
auto result = graphics->pget(14, 32);
|
|
|
|
CHECK_EQ(result, col);
|
|
}
|
|
SUBCASE("camera values applies to pset")
|
|
{
|
|
uint8_t col = 13;
|
|
picoRam.drawState.camera_x = -44;
|
|
picoRam.drawState.camera_y = -3;
|
|
graphics->pset(14, 32, 13);
|
|
graphics->camera();
|
|
|
|
auto result = graphics->pget(58, 35);
|
|
|
|
CHECK_EQ(result, col);
|
|
}
|
|
SUBCASE("camera values apply to line")
|
|
{
|
|
graphics->cls();
|
|
graphics->camera(-10, -10);
|
|
graphics->line(20, 20, 18, 22, 10);
|
|
graphics->camera();
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{30, 30, 10},
|
|
{29, 31, 10},
|
|
{28, 32, 10}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to circ")
|
|
{
|
|
graphics->cls();
|
|
graphics->camera(-20, -20);
|
|
graphics->circ(40, 40, 1, 14);
|
|
graphics->camera();
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{60, 59, 14},
|
|
{61, 60, 14},
|
|
{60, 61, 14},
|
|
{59, 60, 14},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to circfill")
|
|
{
|
|
graphics->cls();
|
|
graphics->camera(-30, -30);
|
|
graphics->circfill(40, 40, 1, 3);
|
|
graphics->camera();
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{70, 70, 3},
|
|
{70, 69, 3},
|
|
{71, 70, 3},
|
|
{70, 71, 3},
|
|
{69, 70, 3},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to rect")
|
|
{
|
|
graphics->cls();
|
|
graphics->camera(-50, -50);
|
|
graphics->rect(-10, -10, -8, -8, 4);
|
|
graphics->camera();
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 4},
|
|
{41, 40, 4},
|
|
{42, 40, 4},
|
|
{40, 41, 4},
|
|
{40, 42, 4},
|
|
{40, 42, 4},
|
|
{41, 42, 4},
|
|
{42, 42, 4},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to rectfill")
|
|
{
|
|
graphics->cls();
|
|
graphics->camera(-100, -100);
|
|
graphics->rectfill(0, 0, 1, 1, 3);
|
|
graphics->camera();
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 100, 3},
|
|
{100, 101, 3},
|
|
{101, 100, 3},
|
|
{101, 101, 3},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to spr")
|
|
{
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->cls();
|
|
graphics->camera(-100, -100);
|
|
graphics->spr(0, 10, 10, 1, 1, false, false);
|
|
graphics->camera();
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{109, 109, 0},
|
|
{110, 110, 0},
|
|
{111, 111, 1},
|
|
{112, 112, 2},
|
|
{113, 113, 3},
|
|
{114, 114, 4},
|
|
{115, 115, 5},
|
|
{116, 116, 6},
|
|
{117, 117, 7},
|
|
{118, 118, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("camera values apply to sspr")
|
|
{
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->cls();
|
|
graphics->camera(-100, -100);
|
|
graphics->sspr(0, 0, 8, 8, 10, 10, 8, 8, false, false);
|
|
graphics->camera();
|
|
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{109, 109, 0},
|
|
{110, 110, 0},
|
|
{111, 111, 1},
|
|
{112, 112, 2},
|
|
{113, 113, 3},
|
|
{114, 114, 4},
|
|
{115, 115, 5},
|
|
{116, 116, 6},
|
|
{117, 117, 7},
|
|
{118, 118, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip() resets clip memory to entire screen")
|
|
{
|
|
picoRam.drawState.clip_xb = 28;
|
|
picoRam.drawState.clip_xe = 28;
|
|
picoRam.drawState.clip_yb = 50;
|
|
picoRam.drawState.clip_ye = 50;
|
|
|
|
graphics->clip();
|
|
|
|
CHECK_EQ(picoRam.drawState.clip_xb, 0);
|
|
CHECK_EQ(picoRam.drawState.clip_xe, 128);
|
|
CHECK_EQ(picoRam.drawState.clip_yb, 0);
|
|
CHECK_EQ(picoRam.drawState.clip_ye, 128);
|
|
}
|
|
SUBCASE("clip({x}, {y}, {w}, {h}) sets clip in memory")
|
|
{
|
|
graphics->clip(50, 75, 25, 25);
|
|
|
|
CHECK_EQ(picoRam.drawState.clip_xb, 50);
|
|
CHECK_EQ(picoRam.drawState.clip_xe, 75);
|
|
CHECK_EQ(picoRam.drawState.clip_yb, 75);
|
|
CHECK_EQ(picoRam.drawState.clip_ye, 100);
|
|
}
|
|
SUBCASE("clip() returns prev value")
|
|
{
|
|
picoRam.drawState.clip_xb = 28;
|
|
picoRam.drawState.clip_xe = 29;
|
|
picoRam.drawState.clip_yb = 50;
|
|
picoRam.drawState.clip_ye = 51;
|
|
|
|
auto prev = graphics->clip();
|
|
|
|
CHECK_EQ(std::get<0>(prev), 28);
|
|
CHECK_EQ(std::get<1>(prev), 29);
|
|
CHECK_EQ(std::get<2>(prev), 50);
|
|
CHECK_EQ(std::get<3>(prev), 51);
|
|
}
|
|
SUBCASE("clip values applies to pset")
|
|
{
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->pset(32, 32, 13);
|
|
|
|
auto result = graphics->pget(32, 32);
|
|
|
|
CHECK_EQ(result, 0);
|
|
}
|
|
SUBCASE("clip values apply to diagonal line")
|
|
{
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->line(98, 98, 102, 102, 10);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{98, 98, 0},
|
|
{99, 99, 0},
|
|
{100, 100, 10},
|
|
{101, 101, 10},
|
|
{102, 102, 10},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to horizontal line")
|
|
{
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->line(98, 102, 102, 102, 10);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{98, 102, 0},
|
|
{99, 102, 0},
|
|
{100, 102, 10},
|
|
{101, 102, 10},
|
|
{102, 102, 10},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to vertical line")
|
|
{
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->line(102, 98, 102, 102, 10);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{102, 98, 0},
|
|
{102, 99, 0},
|
|
{102, 100, 10},
|
|
{102, 101, 10},
|
|
{102, 102, 10},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to circ") {
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->circ(100, 100, 1, 14);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{100, 99, 0},
|
|
{101, 100, 14},
|
|
{100, 101, 14},
|
|
{99, 100, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to circfill") {
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->circfill(105, 99, 1, 3);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{105, 100, 3},
|
|
{106, 99, 0},
|
|
{105, 98, 0},
|
|
{104, 99, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to rect") {
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->rect(98, 98, 101, 101, 4);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{98, 98, 0},
|
|
{98, 99, 0},
|
|
{98, 100, 0},
|
|
{98, 101, 0},
|
|
{99, 98, 0},
|
|
{100, 98, 0},
|
|
{101, 98, 0},
|
|
{101, 99, 0},
|
|
{101, 100, 4},
|
|
{101, 101, 4},
|
|
{100, 101, 4},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to rectfill") {
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->rectfill(99, 99, 100, 102, 3);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{99, 99, 0},
|
|
{99, 100, 0},
|
|
{99, 101, 0},
|
|
{99, 102, 0},
|
|
{100, 99, 0},
|
|
{100, 100, 3},
|
|
{100, 101, 3},
|
|
{100, 102, 3},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to spr") {
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->cls();
|
|
graphics->clip(111, 111, 17, 17);
|
|
graphics->spr(0, 110, 110, 1, 1, false, false);
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{109, 109, 0},
|
|
{110, 110, 0},
|
|
{111, 111, 1},
|
|
{112, 112, 2},
|
|
{113, 113, 3},
|
|
{114, 114, 4},
|
|
{115, 115, 5},
|
|
{116, 116, 6},
|
|
{117, 117, 7},
|
|
{118, 118, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("clip values apply to sspr") {
|
|
for(uint8_t i = 0; i < 16; i++) {
|
|
for(uint8_t j = 0; j < 16; j++) {
|
|
graphics->sset(i, j, i);
|
|
}
|
|
}
|
|
|
|
graphics->cls();
|
|
graphics->clip(100, 100, 28, 28);
|
|
graphics->sspr(1, 1, 2, 2, 96, 96, 8, 8, false, false);
|
|
|
|
|
|
//diagonal across sprite
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{96, 96, 0},
|
|
{97, 97, 0},
|
|
{98, 98, 0},
|
|
{99, 99, 0},
|
|
{100, 100, 2},
|
|
{101, 101, 2},
|
|
{102, 102, 2},
|
|
{103, 103, 2},
|
|
{104, 104, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("mget from upper half of map data (non-shared)"){
|
|
int x = 78;
|
|
int y = 17;
|
|
int idx = y * 128 + x;
|
|
picoRam.mapData[idx] = 242;
|
|
|
|
auto result = graphics->mget(x, y);
|
|
|
|
CHECK_EQ(242, result);
|
|
}
|
|
SUBCASE("mget from lower half of map data (shared)"){
|
|
int x = 121;
|
|
int y = 57;
|
|
int idx = y * 128 + x;
|
|
picoRam.spriteSheetData[idx] = 71;
|
|
|
|
auto result = graphics->mget(x, y);
|
|
|
|
CHECK_EQ(71, result);
|
|
}
|
|
SUBCASE("mget out of bounds returns 0"){
|
|
for(int y = 0; y < 64; y++){
|
|
for(int x = 0; x < 128; x++){
|
|
graphics->mset(x,y,1);
|
|
}
|
|
}
|
|
auto result1 = graphics->mget(-1, 16);
|
|
auto result2 = graphics->mget(128, 16);
|
|
auto result3 = graphics->mget(10, -1);
|
|
auto result4 = graphics->mget(10, 64);
|
|
|
|
CHECK_EQ(0, result1);
|
|
CHECK_EQ(0, result2);
|
|
CHECK_EQ(0, result3);
|
|
CHECK_EQ(0, result4);
|
|
}
|
|
SUBCASE("mset from upper half of map data (non-shared)"){
|
|
int x = 13;
|
|
int y = 7;
|
|
int idx = y * 128 + x;
|
|
graphics->mset(x, y, 177);
|
|
|
|
auto result = picoRam.mapData[idx];
|
|
|
|
CHECK_EQ(177, result);
|
|
}
|
|
SUBCASE("mset from lower half of map data (shared)"){
|
|
int x = 12;
|
|
int y = 63;
|
|
int idx = y * 128 + x;
|
|
graphics->mset(x, y, 251);
|
|
|
|
auto result = picoRam.spriteSheetData[idx];
|
|
|
|
CHECK_EQ(251, result);
|
|
}
|
|
SUBCASE("mset out of bounds does nothing"){
|
|
graphics->mset(-1, 16, 1);
|
|
graphics->mset(128, 16, 1);
|
|
graphics->mset(10, -1, 1);
|
|
graphics->mset(10, 64, 1);
|
|
graphics->mset(128, 64, 1);
|
|
|
|
auto result1 = graphics->mget(-1, 16);
|
|
auto result2 = graphics->mget(128, 16);
|
|
auto result3 = graphics->mget(10, -1);
|
|
auto result4 = graphics->mget(10, 64);
|
|
auto result5 = graphics->mget(128, 64);
|
|
|
|
CHECK_EQ(0, result1);
|
|
CHECK_EQ(0, result2);
|
|
CHECK_EQ(0, result3);
|
|
CHECK_EQ(0, result4);
|
|
CHECK_EQ(0, result5);
|
|
}
|
|
SUBCASE("mset out of bounds of big map doesn't crash"){
|
|
picoRam.data[0x5f56] = 0x80;
|
|
const int cely = 128;
|
|
const int celx = 128; //128 is out of bounds, but the index is inbounds
|
|
const int mapW = 128;
|
|
const int idx = cely * mapW + celx;
|
|
|
|
auto resultBefore = picoRam.userData[idx];
|
|
|
|
graphics->mset(celx, cely, resultBefore + 1);
|
|
|
|
auto resultAfter = picoRam.userData[idx];
|
|
|
|
CHECK_EQ(resultBefore, resultAfter);
|
|
}
|
|
SUBCASE("map with no layer argument draws map cell sprite"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, 5);
|
|
}
|
|
for(int x = 0; x < 128; x++) {
|
|
for (int y = 0; y < 32; y++) {
|
|
graphics->mset(x, y, 1);
|
|
}
|
|
}
|
|
|
|
graphics->map(0,0,0,0,2,2);
|
|
|
|
//diagonal across screen- 2x2 cells, 16x16 pixels
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 0, 5},
|
|
{1, 1, 5},
|
|
{2, 2, 5},
|
|
{3, 3, 5},
|
|
{15, 15, 5},
|
|
{16, 16, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("map with unfilled layer argument doesn't draw"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, 5);
|
|
}
|
|
for(int x = 0; x < 128; x++) {
|
|
for (int y = 0; y < 32; y++) {
|
|
graphics->mset(x, y, 1);
|
|
}
|
|
}
|
|
|
|
graphics->map(0,0,0,0,2,2,5);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 0, 0},
|
|
{1, 1, 0},
|
|
{2, 2, 0},
|
|
{3, 3, 0},
|
|
{15, 15, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("map with filled layer argument doesn't draw"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, 5);
|
|
}
|
|
for(int x = 0; x < 128; x++) {
|
|
for (int y = 0; y < 32; y++) {
|
|
graphics->mset(x, y, 1);
|
|
}
|
|
}
|
|
uint8_t layer = 3;
|
|
graphics->fset(1, layer);
|
|
|
|
graphics->map(0,0,0,0,2,2,layer);
|
|
|
|
//diagonal across screen- 2x2 cells, 16x16 pixels
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 0, 5},
|
|
{1, 1, 5},
|
|
{2, 2, 5},
|
|
{3, 3, 5},
|
|
{15, 15, 5},
|
|
{16, 16, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}) remaps draw color") {
|
|
graphics->pal(14, 5, 0);
|
|
|
|
auto result = graphics->getDrawPalMappedColor(14);
|
|
|
|
CHECK_EQ(5, result);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, {p}) remaps screen color") {
|
|
graphics->pal(13, 4, 1);
|
|
|
|
auto result = graphics->getScreenPalMappedColor(13);
|
|
|
|
CHECK_EQ(4, result);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, 0) returns previous") {
|
|
graphics->pal(14, 2, 0);
|
|
auto result = graphics->pal(14, 8, 0);
|
|
|
|
CHECK_EQ(2, result);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, 1) returns previous") {
|
|
graphics->pal(13, 4, 1);
|
|
auto result = graphics->pal(13, 6, 1);
|
|
|
|
CHECK_EQ(4, result);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, {p}) 17 remapped to 1") {
|
|
graphics->pal(13, 17, 1);
|
|
|
|
auto result = graphics->getScreenPalMappedColor(13);
|
|
|
|
CHECK_EQ(1, result);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, {p}) extended palette allowed") {
|
|
graphics->pal(7, 143, 1);
|
|
|
|
auto result = graphics->getScreenPalMappedColor(7);
|
|
|
|
CHECK_EQ(143, result);
|
|
}
|
|
SUBCASE("palt({c}, {t}) sets transparency value for color") {
|
|
graphics->palt(2, true);
|
|
|
|
CHECK(graphics->isColorTransparent(2) == true);
|
|
}
|
|
SUBCASE("palt({c}, {t}) sets transparency value for color") {
|
|
graphics->palt(4, true);
|
|
|
|
CHECK(graphics->isColorTransparent(4) == true);
|
|
|
|
graphics->palt(4, false);
|
|
|
|
CHECK(graphics->isColorTransparent(4) == false);
|
|
}
|
|
SUBCASE("palt({c}, {t}) can set color 0 to opaque") {
|
|
CHECK(graphics->isColorTransparent(0) == true);
|
|
|
|
graphics->palt(0, false);
|
|
|
|
CHECK(graphics->isColorTransparent(0) == false);
|
|
}
|
|
SUBCASE("pal() resets all palette changes") {
|
|
graphics->pal(14, 5, 0);
|
|
graphics->pal(13, 4, 1);
|
|
graphics->palt(15, true);
|
|
|
|
graphics->pal();
|
|
|
|
bool isDefault = true;
|
|
|
|
for (uint8_t c = 0; c < 16; c++) {
|
|
isDefault &= graphics->getDrawPalMappedColor(c) == c;
|
|
isDefault &= graphics->isColorTransparent(c) == (c == 0);
|
|
isDefault &= graphics->getScreenPalMappedColor(c) == c;
|
|
}
|
|
|
|
CHECK(isDefault);
|
|
}
|
|
SUBCASE("pal(0) resets draw palette only") {
|
|
graphics->pal(14, 5, 0);
|
|
graphics->pal(13, 4, 1);
|
|
graphics->palt(15, true);
|
|
|
|
graphics->pal(0);
|
|
|
|
CHECK_EQ(14, graphics->getDrawPalMappedColor(14));
|
|
CHECK_EQ(4, graphics->getScreenPalMappedColor(13));
|
|
}
|
|
SUBCASE("pal(1) resets screen palette only") {
|
|
graphics->pal(14, 5, 0);
|
|
graphics->pal(13, 4, 1);
|
|
graphics->palt(15, true);
|
|
|
|
graphics->pal(1);
|
|
|
|
CHECK_EQ(5, graphics->getDrawPalMappedColor(14));
|
|
CHECK_EQ(13, graphics->getScreenPalMappedColor(13));
|
|
}
|
|
SUBCASE("pal changes sprite colors"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, 5);
|
|
}
|
|
graphics->pal(5, 2, 0);
|
|
graphics->spr(1, 0, 0, 1.0, 1.0, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 0, 2},
|
|
{1, 1, 2},
|
|
{2, 2, 2},
|
|
{3, 3, 2},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("palt changes sprite transparency"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, 5);
|
|
}
|
|
graphics->palt(5, true);
|
|
graphics->spr(1, 0, 0, 1.0, 1.0, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0, 0, 0},
|
|
{1, 1, 0},
|
|
{2, 2, 0},
|
|
{3, 3, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, {p}) doesn't change default transparency") {
|
|
graphics->pal(0, 0, 0);
|
|
|
|
CHECK(graphics->isColorTransparent(0) == true);
|
|
}
|
|
SUBCASE("pal({c0}, {c1}, {p}) doesn't change transparency") {
|
|
graphics->palt(4, true);
|
|
graphics->pal(4, 7, 0);
|
|
|
|
CHECK(graphics->isColorTransparent(4) == true);
|
|
}
|
|
SUBCASE("cursor({x}, {y}) sets cursor loc in memory"){
|
|
graphics->cursor(4, 13);
|
|
|
|
CHECK_EQ(picoRam.drawState.text_x, 4);
|
|
CHECK_EQ(picoRam.drawState.text_y, 13);
|
|
}
|
|
SUBCASE("cursor({x}, {y}, {c}) sets cursor loc in memory and color"){
|
|
graphics->cursor(42, 99, 3);
|
|
|
|
CHECK_EQ(picoRam.drawState.text_x, 42);
|
|
CHECK_EQ(picoRam.drawState.text_y, 99);
|
|
CHECK_EQ(picoRam.drawState.color, 3);
|
|
}
|
|
SUBCASE("cursor() resets cursor but not color"){
|
|
graphics->cursor(42, 99, 3);
|
|
graphics->cursor();
|
|
|
|
CHECK_EQ(picoRam.drawState.text_x, 0);
|
|
CHECK_EQ(picoRam.drawState.text_y, 0);
|
|
CHECK_EQ(picoRam.drawState.color, 3);
|
|
}
|
|
SUBCASE("cursor() returns previous values")
|
|
{
|
|
uint8_t x = 33;
|
|
uint8_t y = 120;
|
|
graphics->cursor(x, y);
|
|
auto prev = graphics->cursor(11, 31);
|
|
|
|
CHECK_EQ(std::get<0>(prev), x);
|
|
CHECK_EQ(std::get<1>(prev), y);
|
|
}
|
|
SUBCASE("tline draws sprites from map"){
|
|
for(int i = 0; i < 128; i++) {
|
|
for (int j = 0; j < 32; j++)
|
|
graphics->sset(i, j, i%16);
|
|
}
|
|
for(int x = 0; x < 128; x++) {
|
|
for (int y = 0; y < 32; y++) {
|
|
graphics->mset(x, y, (x + y) % 16);
|
|
}
|
|
}
|
|
|
|
graphics->tline(27, 34, 34, 41, 3, 4);
|
|
|
|
//diagonal across screen- 2x2 cells, 16x16 pixels
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{27,34,8},
|
|
{28,35,9},
|
|
{29,36,10},
|
|
{30,37,11},
|
|
{31,38,12},
|
|
{32,39,13},
|
|
{33,40,14},
|
|
{34,41,15}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("fillp(pat) sets values in memory"){
|
|
//0011001111001100 - 2x2 checkerboard
|
|
graphics->fillp(0x33cc);
|
|
|
|
CHECK_EQ(picoRam.drawState.fillPattern[0], 0xcc);
|
|
CHECK_EQ(picoRam.drawState.fillPattern[1], 0x33);
|
|
CHECK_EQ(picoRam.drawState.fillPatternTransparencyBit, 0);
|
|
|
|
CHECK_EQ(picoRam.data[0x5f31], 0xcc);
|
|
CHECK_EQ(picoRam.data[0x5f32], 0x33);
|
|
CHECK_EQ(picoRam.data[0x5f33], 0);
|
|
}
|
|
SUBCASE("fillp(pat) returns previous"){
|
|
graphics->fillp(0x33cc);
|
|
|
|
auto prev = graphics->fillp(0x44dd);
|
|
|
|
CHECK_EQ(prev.bits(), 0x33cc0000);
|
|
}
|
|
SUBCASE("fill pattern affects rectfill"){
|
|
//0b0101101001011010 - 1x1 checkerboard
|
|
graphics->fillp(0x5A5A);
|
|
graphics->cls(8);
|
|
|
|
graphics->rectfill(0, 0, 4, 4, 10);
|
|
|
|
//black and yellow 4x4 checkerboard, with pink elsewhere
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{ 0, 0,10},
|
|
{ 1, 0, 0},
|
|
{ 2, 0,10},
|
|
{ 3, 0, 0},
|
|
{ 4, 0,10},
|
|
{ 5, 0, 8},
|
|
{ 0, 1, 0},
|
|
{ 1, 1,10},
|
|
{ 2, 1, 0},
|
|
{ 3, 1,10},
|
|
{ 4, 1, 0},
|
|
{ 5, 1, 8},
|
|
{ 0, 2,10},
|
|
{ 1, 2, 0},
|
|
{ 2, 2,10},
|
|
{ 3, 2, 0},
|
|
{ 4, 2,10},
|
|
{ 5, 2, 8},
|
|
{ 0, 3, 0},
|
|
{ 1, 3,10},
|
|
{ 2, 3, 0},
|
|
{ 3, 3,10},
|
|
{ 4, 3, 0},
|
|
{ 5, 3, 8},
|
|
{ 0, 4,10},
|
|
{ 1, 4, 0},
|
|
{ 2, 4,10},
|
|
{ 3, 4, 0},
|
|
{ 4, 4,10},
|
|
{ 5, 4, 8},
|
|
{ 0, 5, 8},
|
|
{ 1, 5, 8},
|
|
{ 2, 5, 8},
|
|
{ 3, 5, 8},
|
|
{ 4, 5, 8},
|
|
{ 5, 5, 8},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("fill pattern with transparency"){
|
|
//0b0101101001011010.1 - 1x1 checkerboard with transparency
|
|
graphics->fillp(23130.5);
|
|
graphics->cls(3);
|
|
|
|
graphics->rectfill(0, 0, 2, 2, 11);
|
|
|
|
//3x3 checkerboard, with alt set to transparent
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{ 0, 0,11},
|
|
{ 1, 0, 3},
|
|
{ 2, 0,11},
|
|
{ 3, 0, 3},
|
|
{ 0, 1, 3},
|
|
{ 1, 1,11},
|
|
{ 2, 1, 3},
|
|
{ 3, 1, 3},
|
|
{ 0, 2,11},
|
|
{ 1, 2, 3},
|
|
{ 2, 2,11},
|
|
{ 3, 2, 3},
|
|
{ 0, 3, 3},
|
|
{ 1, 3, 3},
|
|
{ 2, 3, 3},
|
|
{ 3, 3, 3}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("fill pattern oriented correctly"){
|
|
//311 = 0b0000000100110111
|
|
//0000
|
|
//0001
|
|
//0011
|
|
//0111
|
|
graphics->cls(0);
|
|
graphics->fillp(311);
|
|
|
|
//e8: light pink alt color, pink normal color
|
|
graphics->rectfill(0, 0, 3, 3, 0xe8);
|
|
|
|
//black and yellow 4x4 checkerboard, with pink elsewhere
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{ 0, 0, 8},
|
|
{ 1, 0, 8},
|
|
{ 2, 0, 8},
|
|
{ 3, 0, 8},
|
|
{ 4, 0, 0},
|
|
{ 0, 1, 8},
|
|
{ 1, 1, 8},
|
|
{ 2, 1, 8},
|
|
{ 3, 1,14},
|
|
{ 4, 1, 0},
|
|
{ 0, 2, 8},
|
|
{ 1, 2, 8},
|
|
{ 2, 2,14},
|
|
{ 3, 2,14},
|
|
{ 4, 2, 0},
|
|
{ 0, 3, 8},
|
|
{ 1, 3,14},
|
|
{ 2, 3,14},
|
|
{ 3, 3,14},
|
|
{ 4, 3, 0},
|
|
{ 0, 4, 0},
|
|
{ 1, 4, 0},
|
|
{ 2, 4, 0},
|
|
{ 3, 4, 0},
|
|
{ 4, 4, 0}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
//TODO: allow this shorthand to work
|
|
/*
|
|
SUBCASE("fill pattern shorthand works"){
|
|
graphics->cls(0);
|
|
picoRam.drawState.colorSettingFlag = 1;
|
|
//0x104e.abcd
|
|
graphics->rectfill(0, 0, 3, 3, 0x104eabcd);
|
|
|
|
CHECK_EQ(picoRam.drawState.fillPattern[0], 0xcd);
|
|
CHECK_EQ(picoRam.drawState.fillPattern[1], 0xab);
|
|
CHECK_EQ(picoRam.drawState.fillPatternTransparencyBit, 0);
|
|
|
|
//black and yellow 4x4 checkerboard, with pink elsewhere
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{ 0, 0, 4},
|
|
{ 1, 0,14},
|
|
{ 2, 0, 4},
|
|
{ 3, 0,14},
|
|
{ 4, 0, 0},
|
|
{ 0, 1, 4},
|
|
{ 1, 1,14},
|
|
{ 2, 1, 4},
|
|
{ 3, 1, 4},
|
|
{ 4, 1, 0},
|
|
{ 0, 2, 4},
|
|
{ 1, 2, 4},
|
|
{ 2, 2,14},
|
|
{ 3, 2,14},
|
|
{ 4, 2, 0},
|
|
{ 0, 3, 4},
|
|
{ 1, 3, 4},
|
|
{ 2, 3,14},
|
|
{ 3, 3, 4},
|
|
{ 4, 3, 0},
|
|
{ 0, 4, 0},
|
|
{ 1, 4, 0},
|
|
{ 2, 4, 0},
|
|
{ 3, 4, 0},
|
|
{ 4, 4, 0}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
*/
|
|
SUBCASE("Remap spritesheet to screen (after drawing character to screen)"){
|
|
graphics->cls();
|
|
|
|
//emulate print("zo",8,0)
|
|
picoRam.drawState.drawPaletteMap[7] = 6;
|
|
graphics->drawCharacter(122, 8, 0, 6, 0);
|
|
graphics->drawCharacter(111, 12, 0, 6, 0);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0x60;
|
|
|
|
graphics->spr(1, 0, 64, 1.0, 1.0, false, false);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{0,64,6},
|
|
{1,64,6},
|
|
{2,64,6},
|
|
{3,64,0},
|
|
{4,64,0},
|
|
{5,64,6},
|
|
{6,64,6},
|
|
{7,64,0},
|
|
{8,64,0},
|
|
{0,65,0},
|
|
{1,65,0},
|
|
{2,65,6},
|
|
{3,65,0},
|
|
{4,65,6},
|
|
{5,65,0},
|
|
{6,65,6},
|
|
{7,65,0},
|
|
{8,65,0},
|
|
{0,66,0},
|
|
{1,66,6},
|
|
{2,66,0},
|
|
{3,66,0},
|
|
{4,66,6},
|
|
{5,66,0},
|
|
{6,66,6},
|
|
{7,66,0},
|
|
{8,66,0},
|
|
{0,67,6},
|
|
{1,67,0},
|
|
{2,67,0},
|
|
{3,67,0},
|
|
{4,67,6},
|
|
{5,67,0},
|
|
{6,67,6},
|
|
{7,67,0},
|
|
{8,67,0},
|
|
{0,68,6},
|
|
{1,68,6},
|
|
{2,68,6},
|
|
{3,68,0},
|
|
{4,68,6},
|
|
{5,68,6}
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("Remap screen to spritesheet"){
|
|
graphics->cls();
|
|
graphics->sset(125,125,4);
|
|
graphics->sset(126,126,5);
|
|
graphics->sset(127,127,6);
|
|
graphics->sset(128,128,13);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0x00;
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{124,124,0},
|
|
{125,124,0},
|
|
{126,124,0},
|
|
{127,124,0},
|
|
{128,124,0},
|
|
{124,125,0},
|
|
{125,125,4},
|
|
{126,125,0},
|
|
{127,125,0},
|
|
{128,125,0},
|
|
{124,126,0},
|
|
{125,126,0},
|
|
{126,126,5},
|
|
{127,126,0},
|
|
{128,126,0},
|
|
{124,127,0},
|
|
{125,127,0},
|
|
{126,127,0},
|
|
{127,127,6},
|
|
{128,127,0},
|
|
{124,128,0},
|
|
{125,128,0},
|
|
{126,128,0},
|
|
{127,128,0},
|
|
{128,128,0}
|
|
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("change map width"){
|
|
picoRam.data[0x5f57] = 4;
|
|
|
|
for(int y = 0; y < 8; y++){
|
|
for(int x = 0; x < 32; x++) {
|
|
graphics->sset(x,y,(x/8) + 1);
|
|
}
|
|
}
|
|
|
|
graphics->mset(0, 0, 1);
|
|
graphics->mset(0, 1, 2);
|
|
graphics->mset(1, 0, 2);
|
|
graphics->mset(1, 1, 1);
|
|
|
|
graphics->mset(2, 2046, 2);
|
|
graphics->mset(2, 2047, 3);
|
|
graphics->mset(3, 2046, 3);
|
|
graphics->mset(3, 2047, 2);
|
|
|
|
graphics->cls();
|
|
|
|
graphics->map(0, 0, 0, 0, 4, 8);
|
|
graphics->map(0, 2040, 64, 64, 4, 8);
|
|
|
|
CHECK_EQ(picoRam.hwState.widthOfTheMap, 4);
|
|
CHECK_EQ(graphics->mget(0,0), 1);
|
|
CHECK_EQ(graphics->mget(3,2047), 2);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{6,6,2},
|
|
{14,6,3},
|
|
{6,14,3},
|
|
{14,14,2},
|
|
|
|
{82,118,3},
|
|
{90,118,4},
|
|
{82,126,4},
|
|
{90,126,3},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("use extended ram for big map"){
|
|
picoRam.data[0x5f56] = 0x80;
|
|
|
|
for(int y = 0; y < 8; y++){
|
|
for(int x = 64; x < 96; x++) {
|
|
graphics->sset(x,y,(x/8) + 1);
|
|
}
|
|
}
|
|
|
|
graphics->mset(0, 0, 8);
|
|
graphics->mset(0, 1, 9);
|
|
graphics->mset(1, 0, 9);
|
|
graphics->mset(1, 1, 8);
|
|
|
|
graphics->mset(126, 254, 9);
|
|
graphics->mset(126, 255, 10);
|
|
graphics->mset(127, 254, 10);
|
|
graphics->mset(127, 255, 9);
|
|
|
|
graphics->cls();
|
|
|
|
graphics->map(0, 0, 8, 8, 2, 2);
|
|
graphics->map(126, 254, 112, 112, 2, 2);
|
|
|
|
CHECK_EQ(picoRam.hwState.mapMemMapping, 0x80);
|
|
CHECK_EQ(graphics->mget(0,0), 8);
|
|
CHECK_EQ(picoRam.data[0x8000], 8);
|
|
CHECK_EQ(picoRam.userData[0], 8);
|
|
CHECK_EQ(graphics->mget(127,255), 9);
|
|
CHECK_EQ(picoRam.data[0xFFFF], 9);
|
|
CHECK_EQ(picoRam.userData[0x7FFF], 9);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{12,12,9},
|
|
{20,12,10},
|
|
{12,20,10},
|
|
{20,20,9},
|
|
|
|
{116,116,10},
|
|
{124,116,11},
|
|
{116,124,11},
|
|
{124,124,10},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("use only part of extended ram for big map"){
|
|
picoRam.data[0x5f56] = 0xb6;
|
|
//18944 total map bytes, 148 lines (using default 128 width)
|
|
|
|
for(int y = 0; y < 8; y++){
|
|
for(int x = 64; x < 96; x++) {
|
|
graphics->sset(x,y,(x/8) + 3);
|
|
}
|
|
}
|
|
|
|
graphics->mset(0, 0, 8);
|
|
graphics->mset(0, 1, 9);
|
|
graphics->mset(1, 0, 9);
|
|
graphics->mset(1, 1, 8);
|
|
|
|
graphics->mset(126, 146, 9);
|
|
graphics->mset(126, 147, 10);
|
|
graphics->mset(127, 146, 10);
|
|
graphics->mset(127, 147, 9);
|
|
|
|
graphics->cls();
|
|
|
|
graphics->map(0, 0, 8, 8, 2, 2);
|
|
graphics->map(126, 146, 112, 112, 2, 2);
|
|
|
|
CHECK_EQ(picoRam.hwState.mapMemMapping, 0xb6);
|
|
CHECK_EQ(picoRam.data[0x5f56], 0xb6);
|
|
CHECK_EQ(graphics->mget(0,0), 8);
|
|
CHECK_EQ(picoRam.data[0xb600], 8);
|
|
CHECK_EQ(graphics->mget(127,147), 9);
|
|
CHECK_EQ(picoRam.data[0xFFFF], 9);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{12,12,11},
|
|
{20,12,12},
|
|
{12,20,12},
|
|
{20,20,11},
|
|
|
|
{116,116,12},
|
|
{124,116,13},
|
|
{116,124,13},
|
|
{124,124,12},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("map width set to 256 functions as expected"){
|
|
picoRam.data[0x5f56] = 0x80;
|
|
picoRam.data[0x5f57] = 0;
|
|
|
|
for(int y = 0; y < 8; y++){
|
|
for(int x = 64; x < 96; x++) {
|
|
graphics->sset(x,y,(x/8) + 1);
|
|
}
|
|
}
|
|
|
|
graphics->mset(0, 0, 8);
|
|
graphics->mset(0, 1, 9);
|
|
graphics->mset(1, 0, 9);
|
|
graphics->mset(1, 1, 8);
|
|
|
|
graphics->mset(254, 126, 9);
|
|
graphics->mset(255, 0126, 10);
|
|
graphics->mset(254, 127, 10);
|
|
graphics->mset(255, 127, 9);
|
|
|
|
graphics->cls();
|
|
|
|
graphics->map(0, 0, 8, 8, 2, 2);
|
|
graphics->map(254, 126, 112, 112, 2, 2);
|
|
|
|
CHECK_EQ(picoRam.hwState.widthOfTheMap, 0);
|
|
CHECK_EQ(graphics->mget(0,0), 8);
|
|
CHECK_EQ(picoRam.data[0x8000], 8);
|
|
CHECK_EQ(picoRam.userData[0], 8);
|
|
CHECK_EQ(graphics->mget(255, 127), 9);
|
|
CHECK_EQ(picoRam.data[0xFFFF], 9);
|
|
CHECK_EQ(picoRam.userData[0x7FFF], 9);
|
|
}
|
|
SUBCASE("drawCharacter with forced width and height for wide character"){
|
|
graphics->cls();
|
|
|
|
//emulate print("\^x0\^y1▤a",10,10,9)
|
|
picoRam.drawState.drawPaletteMap[7] = 9;
|
|
graphics->drawCharacter(152, 10, 10, 9, 0, 0, 0, 1);
|
|
//the a should be invisible (0 width)
|
|
graphics->drawCharacter(65, 10, 10, 9, 0, 0, 0, 1);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{9,10,0},
|
|
{10,10,9},
|
|
{11,10,9},
|
|
{12,10,9},
|
|
{13,10,9},
|
|
{14,10,0},
|
|
{9,11,0},
|
|
{10,11,0},
|
|
{11,11,0},
|
|
{12,11,0},
|
|
{13,11,0},
|
|
{14,11,0},
|
|
{9,12,0},
|
|
{10,12,0},
|
|
{11,12,0},
|
|
{12,12,0},
|
|
{13,12,0},
|
|
{14,12,0},
|
|
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("drawCharacter with forced width and height for normal character"){
|
|
graphics->cls();
|
|
|
|
//emulate print("\^x3\^y3a",10,10,9)
|
|
picoRam.drawState.drawPaletteMap[7] = 9;
|
|
graphics->drawCharacter(97, 10, 10, 9, 0, 0, 3, 3);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{9,10,0},
|
|
{10,10,9},
|
|
{11,10,9},
|
|
{12,10,9},
|
|
{13,10,0},
|
|
{14,10,0},
|
|
{9,11,0},
|
|
{10,11,9},
|
|
{11,11,0},
|
|
{12,11,9},
|
|
{13,11,0},
|
|
{14,11,0},
|
|
{9,12,0},
|
|
{10,12,9},
|
|
{11,12,9},
|
|
{12,12,9},
|
|
{13,12,0},
|
|
{14,12,0},
|
|
{9,14,0},
|
|
{10,14,0},
|
|
{11,14,0},
|
|
{12,14,0},
|
|
{13,14,0},
|
|
{14,14,0},
|
|
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect with no radius draws a rect") {
|
|
graphics->cls();
|
|
graphics->rrect(40, 40, 3, 3, 0, 15);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 15},
|
|
{40, 41, 15},
|
|
{40, 42, 15},
|
|
{40, 43, 0},
|
|
{41, 40, 15},
|
|
{41, 41, 0},
|
|
{41, 42, 15},
|
|
{42, 40, 15},
|
|
{42, 41, 15},
|
|
{42, 42, 15},
|
|
{42, 43, 0},
|
|
{43, 40, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrectfill with no radius draws a rect") {
|
|
graphics->cls();
|
|
graphics->rrectfill(40, 40, 3, 3, 0, 15);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
{40, 40, 15},
|
|
{40, 41, 15},
|
|
{40, 42, 15},
|
|
{40, 43, 0},
|
|
{41, 40, 15},
|
|
{41, 41, 15},
|
|
{41, 42, 15},
|
|
{42, 40, 15},
|
|
{42, 41, 15},
|
|
{42, 42, 15},
|
|
{42, 43, 0},
|
|
{43, 40, 0},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect with radius 1 produces some output") {
|
|
graphics->cls();
|
|
graphics->rrect(10, 10, 6, 6, 1, 8);
|
|
|
|
// Just check that some pixels are drawn (not testing exact pattern)
|
|
bool hasPixels = false;
|
|
for (int y = 10; y < 16; y++) {
|
|
for (int x = 10; x < 16; x++) {
|
|
if (graphics->pget(x, y) == 8) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrectfill with radius 1 draws stepped corners") {
|
|
graphics->cls();
|
|
graphics->rrectfill(10, 10, 6, 6, 1, 8);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Row 0: cut 0 (full width)
|
|
{10, 10, 8}, {11, 10, 8}, {12, 10, 8}, {13, 10, 8}, {14, 10, 8}, {15, 10, 8},
|
|
// Row 1-4: full width
|
|
{10, 11, 8}, {11, 11, 8}, {12, 11, 8}, {13, 11, 8}, {14, 11, 8}, {15, 11, 8},
|
|
{10, 12, 8}, {11, 12, 8}, {12, 12, 8}, {13, 12, 8}, {14, 12, 8}, {15, 12, 8},
|
|
{10, 13, 8}, {11, 13, 8}, {12, 13, 8}, {13, 13, 8}, {14, 13, 8}, {15, 13, 8},
|
|
{10, 14, 8}, {11, 14, 8}, {12, 14, 8}, {13, 14, 8}, {14, 14, 8}, {15, 14, 8},
|
|
// Row 5: cut 0 (full width)
|
|
{10, 15, 8}, {11, 15, 8}, {12, 15, 8}, {13, 15, 8}, {14, 15, 8}, {15, 15, 8},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect with radius 2 produces some output") {
|
|
graphics->cls();
|
|
graphics->rrect(20, 20, 8, 8, 2, 7);
|
|
|
|
// Just check that some pixels are drawn
|
|
bool hasPixels = false;
|
|
for (int y = 20; y < 28; y++) {
|
|
for (int x = 20; x < 28; x++) {
|
|
if (graphics->pget(x, y) == 7) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrectfill with radius 2 draws stepped corners") {
|
|
graphics->cls();
|
|
graphics->rrectfill(20, 20, 8, 8, 2, 7);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Row 0: cut 1 from each side
|
|
{21, 20, 7}, {22, 20, 7}, {23, 20, 7}, {24, 20, 7}, {25, 20, 7}, {26, 20, 7},
|
|
// Row 1: cut 0 (full width)
|
|
{20, 21, 7}, {21, 21, 7}, {22, 21, 7}, {23, 21, 7}, {24, 21, 7}, {25, 21, 7}, {26, 21, 7}, {27, 21, 7},
|
|
// Middle rows: full width
|
|
{20, 22, 7}, {21, 22, 7}, {22, 22, 7}, {23, 22, 7}, {24, 22, 7}, {25, 22, 7}, {26, 22, 7}, {27, 22, 7},
|
|
{20, 23, 7}, {21, 23, 7}, {22, 23, 7}, {23, 23, 7}, {24, 23, 7}, {25, 23, 7}, {26, 23, 7}, {27, 23, 7},
|
|
{20, 24, 7}, {21, 24, 7}, {22, 24, 7}, {23, 24, 7}, {24, 24, 7}, {25, 24, 7}, {26, 24, 7}, {27, 24, 7},
|
|
{20, 25, 7}, {21, 25, 7}, {22, 25, 7}, {23, 25, 7}, {24, 25, 7}, {25, 25, 7}, {26, 25, 7}, {27, 25, 7},
|
|
// Row 6: cut 1 from each side
|
|
{21, 26, 7}, {22, 26, 7}, {23, 26, 7}, {24, 26, 7}, {25, 26, 7}, {26, 26, 7},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect with large radius produces output") {
|
|
graphics->cls();
|
|
graphics->rrect(10, 10, 16, 16, 6, 12);
|
|
|
|
// Just check that some pixels are drawn
|
|
bool hasPixels = false;
|
|
for (int y = 10; y < 26; y++) {
|
|
for (int x = 10; x < 26; x++) {
|
|
if (graphics->pget(x, y) == 12) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrectfill with large radius uses lookup tables") {
|
|
graphics->cls();
|
|
graphics->rrectfill(10, 10, 16, 16, 6, 12);
|
|
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Test key points based on r=6 pattern: {5,3,2,1,1,0}
|
|
// Row 0: cut 5 from each side -> width 6
|
|
{15, 10, 12}, {16, 10, 12}, {17, 10, 12}, {18, 10, 12}, {19, 10, 12}, {20, 10, 12},
|
|
// Row 1: cut 3 from each side -> width 10
|
|
{13, 11, 12}, {14, 11, 12}, {15, 11, 12}, {16, 11, 12}, {17, 11, 12},
|
|
{18, 11, 12}, {19, 11, 12}, {20, 11, 12}, {21, 11, 12}, {22, 11, 12},
|
|
// Row 5: cut 0 -> full width (16 pixels)
|
|
{10, 15, 12}, {11, 15, 12}, {12, 15, 12}, {13, 15, 12}, {14, 15, 12}, {15, 15, 12},
|
|
{16, 15, 12}, {17, 15, 12}, {18, 15, 12}, {19, 15, 12}, {20, 15, 12}, {21, 15, 12},
|
|
{22, 15, 12}, {23, 15, 12}, {24, 15, 12}, {25, 15, 12},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect radius clamped to max allowed") {
|
|
graphics->cls();
|
|
graphics->rrect(30, 30, 10, 8, 10, 5); // radius 10 should be clamped to 4 (8/2)
|
|
|
|
// Should behave like radius 4: pattern {3,2,1,0}
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Row 0: cut 3 from each side -> start at x=33, end at x=36
|
|
{33, 30, 5}, {34, 30, 5}, {35, 30, 5}, {36, 30, 5},
|
|
// Row 1: cut 2 from each side -> start at x=32, end at x=37
|
|
{32, 31, 5}, {37, 31, 5},
|
|
// Row 2: cut 1 from each side -> start at x=31, end at x=38
|
|
{31, 32, 5}, {38, 32, 5},
|
|
// Row 3: cut 0 -> full width
|
|
{30, 33, 5}, {39, 33, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrectfill radius clamped to max allowed") {
|
|
graphics->cls();
|
|
graphics->rrectfill(30, 30, 10, 8, 10, 5); // radius 10 should be clamped to 4 (8/2)
|
|
|
|
// Should behave like radius 4: pattern {3,2,1,0}
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Row 0: cut 3 from each side -> width 4
|
|
{33, 30, 5}, {34, 30, 5}, {35, 30, 5}, {36, 30, 5},
|
|
// Row 1: cut 2 from each side -> width 6
|
|
{32, 31, 5}, {33, 31, 5}, {34, 31, 5}, {35, 31, 5}, {36, 31, 5}, {37, 31, 5},
|
|
// Row 3: cut 0 -> full width (10 pixels)
|
|
{30, 33, 5}, {31, 33, 5}, {32, 33, 5}, {33, 33, 5}, {34, 33, 5},
|
|
{35, 33, 5}, {36, 33, 5}, {37, 33, 5}, {38, 33, 5}, {39, 33, 5},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("rrect basic functionality") {
|
|
graphics->cls();
|
|
graphics->rrect(50, 50, 10, 10, 2, 9);
|
|
|
|
// Just check that some pixels are drawn
|
|
bool hasPixels = false;
|
|
for (int y = 50; y < 60; y++) {
|
|
for (int x = 50; x < 60; x++) {
|
|
if (graphics->pget(x, y) == 9) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrectfill basic functionality") {
|
|
graphics->cls();
|
|
graphics->rrectfill(50, 50, 10, 10, 2, 9);
|
|
|
|
// Just check that some pixels are drawn
|
|
bool hasPixels = false;
|
|
for (int y = 50; y < 60; y++) {
|
|
for (int x = 50; x < 60; x++) {
|
|
if (graphics->pget(x, y) == 9) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrect basic clipping test") {
|
|
graphics->cls();
|
|
graphics->clip(50, 50, 20, 20); // large clip area
|
|
graphics->rrect(55, 55, 10, 10, 2, 11);
|
|
|
|
// Just check that some pixels are drawn
|
|
bool hasPixels = false;
|
|
for (int y = 55; y < 65; y++) {
|
|
for (int x = 55; x < 65; x++) {
|
|
if (graphics->pget(x, y) == 11) {
|
|
hasPixels = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CHECK(hasPixels);
|
|
}
|
|
SUBCASE("rrectfill respects clipping") {
|
|
graphics->cls();
|
|
graphics->clip(12, 12, 4, 4); // clip to small area
|
|
graphics->rrectfill(10, 10, 8, 8, 1, 11);
|
|
|
|
// Only pixels within clip area (12-15, 12-15) should be drawn
|
|
std::vector<coloredPoint> expectedPoints = {
|
|
// Check that pixels outside clip are not drawn
|
|
{10, 10, 0}, {11, 10, 0},
|
|
{10, 11, 0}, {11, 11, 0},
|
|
// Check that pixels inside clip are drawn (filled)
|
|
{12, 12, 11}, {13, 12, 11}, {14, 12, 11}, {15, 12, 11},
|
|
{12, 13, 11}, {13, 13, 11}, {14, 13, 11}, {15, 13, 11},
|
|
{12, 14, 11}, {13, 14, 11}, {14, 14, 11}, {15, 14, 11},
|
|
{12, 15, 11}, {13, 15, 11}, {14, 15, 11}, {15, 15, 11},
|
|
};
|
|
|
|
checkPoints(graphics, expectedPoints);
|
|
}
|
|
SUBCASE("Memory mapping for sprite sheet buffer") {
|
|
picoRam.hwState.spriteSheetMemMapping = 0x00;
|
|
uint8_t* buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.spriteSheetData);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0x60;
|
|
buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.screenBuffer);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0x80;
|
|
buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0xA0;
|
|
buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x2000);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0xC0;
|
|
buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x4000);
|
|
|
|
picoRam.hwState.spriteSheetMemMapping = 0xE0;
|
|
buffer = graphics->GetP8SpriteSheetBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x6000);
|
|
}
|
|
SUBCASE("Memory mapping for frame buffer") {
|
|
picoRam.hwState.screenDataMemMapping = 0x00;
|
|
uint8_t* buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.spriteSheetData);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0x60;
|
|
buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.screenBuffer);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0x80;
|
|
buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0xA0;
|
|
buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x2000);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0xC0;
|
|
buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x4000);
|
|
|
|
picoRam.hwState.screenDataMemMapping = 0xE0;
|
|
buffer = graphics->GetP8FrameBuffer();
|
|
CHECK_EQ(buffer, picoRam.userData + 0x6000);
|
|
}
|
|
SUBCASE("Sprite rendering with upper memory mapping") {
|
|
picoRam.hwState.spriteSheetMemMapping = 0xC0;
|
|
|
|
uint8_t* spriteBuffer = graphics->GetP8SpriteSheetBuffer();
|
|
|
|
for (int y = 0; y < 8; y++) {
|
|
for (int byteX = 0; byteX < 4; byteX++) { // 4 bytes = 8 pixels wide
|
|
int byteIdx = y * 64 + byteX; // 64 bytes per row
|
|
spriteBuffer[byteIdx] = 0x55; // Pattern: 5,5 (both pixels are color 5)
|
|
}
|
|
}
|
|
|
|
graphics->cls();
|
|
graphics->spr(0, 10, 10, 1.0, 1.0, false, false);
|
|
|
|
CHECK_EQ(graphics->pget(10, 10), 5); // top-left should be color 5
|
|
CHECK_EQ(graphics->pget(11, 10), 5); // next pixel should be color 5
|
|
CHECK_EQ(graphics->pget(10, 11), 5); // below should be color 5
|
|
CHECK_EQ(graphics->pget(17, 17), 5); // bottom-right should be color 5
|
|
}
|
|
SUBCASE("Sprite transparency with upper memory mapping") {
|
|
//map sprite sheet to upper memory
|
|
picoRam.hwState.spriteSheetMemMapping = 0xC0;
|
|
|
|
graphics->palt();
|
|
|
|
//create a sprite with alternating pixels
|
|
for (int y = 0; y < 8; y++) {
|
|
for (int x = 0; x < 8; x++) {
|
|
//left pixel is opaque (5), right pixel is transparent (0)
|
|
uint8_t color = x % 2 == 0 ? 5 : 0;
|
|
graphics->sset(x, y, color);
|
|
}
|
|
}
|
|
|
|
graphics->cls(2);
|
|
graphics->spr(0, 10, 10, 1.0, 1.0, false, false);
|
|
|
|
// Even X positions should be opaque (color 5)
|
|
CHECK_EQ(graphics->pget(10, 10), 5);
|
|
CHECK_EQ(graphics->pget(12, 10), 5);
|
|
CHECK_EQ(graphics->pget(14, 10), 5);
|
|
|
|
// Odd X positions should be background color (color 2)
|
|
CHECK_EQ(graphics->pget(11, 10), 2);
|
|
CHECK_EQ(graphics->pget(13, 10), 2);
|
|
CHECK_EQ(graphics->pget(15, 10), 2);
|
|
}
|
|
|
|
|
|
//general teardown
|
|
delete graphics;
|
|
} |