test: cover testTileTexture
This commit is contained in:
1 parent
647ad7f254
commit
ea0e3b2ad0
1 file changed
+152
@@ -149,3 +149,155 @@ VF_TEST(theAtlasDoesNotDependOnTheOrderTilesAreGenerated) {
|
|||||||
CHECK(forwards == backwards);
|
CHECK(forwards == backwards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The opaque pass draws without blending, so an opaque tile with a hole in it
|
||||||
|
// would put a stale colour on screen rather than a hole.
|
||||||
|
VF_TEST(opaqueTilesAreFullyOpaqueInEveryPixel) {
|
||||||
|
TileSampler sampler;
|
||||||
|
int size = sampler.params().tileSize;
|
||||||
|
for (int tile = 0; tile < renderedTiles(sampler); ++tile) {
|
||||||
|
if (sampler.palette().specFor(tile).cutout) continue;
|
||||||
|
int transparent = 0;
|
||||||
|
for (int y = 0; y < size; ++y) {
|
||||||
|
for (int x = 0; x < size; ++x) {
|
||||||
|
if (sampler.pixelAt(tile, x, y).a != 255) ++transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_EQ(transparent, 0);
|
||||||
|
if (transparent != 0) {
|
||||||
|
std::printf(" tile %d (%s) has %d see-through pixels\n", tile,
|
||||||
|
sampler.palette().specFor(tile).name, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A cutout tile that is solid everywhere is not a shape, and one that is hollow
|
||||||
|
// everywhere is not a tile. Both ends have to be present in the alpha channel.
|
||||||
|
VF_TEST(cutoutTilesCarryBothHolesAndSolidPixels) {
|
||||||
|
TileSampler sampler;
|
||||||
|
int size = sampler.params().tileSize;
|
||||||
|
int cutouts = 0;
|
||||||
|
for (int tile = 0; tile < renderedTiles(sampler); ++tile) {
|
||||||
|
const TileSpec& spec = sampler.palette().specFor(tile);
|
||||||
|
if (!spec.cutout) continue;
|
||||||
|
++cutouts;
|
||||||
|
int holes = 0;
|
||||||
|
int solid = 0;
|
||||||
|
for (int y = 0; y < size; ++y) {
|
||||||
|
for (int x = 0; x < size; ++x) {
|
||||||
|
uint8_t alpha = sampler.pixelAt(tile, x, y).a;
|
||||||
|
if (alpha == 0) ++holes;
|
||||||
|
if (alpha == 255) ++solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK(holes > 0);
|
||||||
|
CHECK(solid > 0);
|
||||||
|
CHECK_EQ(holes + solid, size * size);
|
||||||
|
if (holes == 0 || solid == 0) {
|
||||||
|
std::printf(" tile %d (%s): %d holes, %d solid\n", tile, spec.name, holes, solid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK(cutouts >= 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The failure this whole wave exists to stop: a tile that renders as one flat
|
||||||
|
// plate of colour. Measured on the interior so the edge darkening cannot pass a
|
||||||
|
// flat tile off as textured.
|
||||||
|
VF_TEST(everyTileVariesAcrossItsInterior) {
|
||||||
|
TileSampler sampler;
|
||||||
|
const int minimumSpread = 12;
|
||||||
|
for (int tile = 0; tile < renderedTiles(sampler); ++tile) {
|
||||||
|
LuminanceRange range = interiorRange(sampler, tile);
|
||||||
|
CHECK(range.spread() >= minimumSpread);
|
||||||
|
if (range.spread() < minimumSpread) {
|
||||||
|
std::printf(" tile %d (%s) is flat: spread %d\n", tile,
|
||||||
|
sampler.palette().specFor(tile).name, range.spread());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Brick courses are offset by half a brick. Without the offset every joint
|
||||||
|
// lines up and a brick wall reads as a grid, so the mortar columns of one
|
||||||
|
// course must not repeat in the next.
|
||||||
|
VF_TEST(brickCoursesShiftTheirJointsBetweenRows) {
|
||||||
|
TileSampler sampler;
|
||||||
|
TileSpec synthetic = syntheticBrick();
|
||||||
|
int layouts = distinctJointLayouts(sampler, synthetic, 500);
|
||||||
|
CHECK(layouts >= 2);
|
||||||
|
if (layouts < 2) std::printf(" synthetic brick has %d joint layouts\n", layouts);
|
||||||
|
|
||||||
|
// The two courses that actually sit next to each other, spelled out.
|
||||||
|
std::vector<int> firstCourse = accentColumns(sampler, synthetic, 500, 2);
|
||||||
|
std::vector<int> secondCourse = accentColumns(sampler, synthetic, 500, 6);
|
||||||
|
CHECK(!firstCourse.empty());
|
||||||
|
CHECK(!secondCourse.empty());
|
||||||
|
CHECK(firstCourse != secondCourse);
|
||||||
|
|
||||||
|
for (int tile = 0; tile < renderedTiles(sampler); ++tile) {
|
||||||
|
const TileSpec& spec = sampler.palette().specFor(tile);
|
||||||
|
if (spec.pattern != TilePattern::Brick) continue;
|
||||||
|
int real = distinctJointLayouts(sampler, withoutGrain(spec), tile);
|
||||||
|
CHECK(real >= 2);
|
||||||
|
if (real < 2) std::printf(" tile %d (%s) has %d joint layouts\n", tile, spec.name, real);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contrast is a real knob, not a field nobody reads: raising it has to widen
|
||||||
|
// what the tile actually puts on screen.
|
||||||
|
VF_TEST(raisingContrastWidensTheLuminanceRange) {
|
||||||
|
TileTextureParams plain;
|
||||||
|
TileTextureParams punchy;
|
||||||
|
punchy.contrast = 2.0f;
|
||||||
|
TileSampler flat(plain);
|
||||||
|
TileSampler bold(punchy);
|
||||||
|
|
||||||
|
int widened = 0;
|
||||||
|
for (int tile = 0; tile < renderedTiles(flat); ++tile) {
|
||||||
|
int quiet = interiorRange(flat, tile).spread();
|
||||||
|
int loud = interiorRange(bold, tile).spread();
|
||||||
|
CHECK(loud >= quiet);
|
||||||
|
if (loud > quiet) ++widened;
|
||||||
|
}
|
||||||
|
CHECK(widened > tileCount / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The seed reaches the grain, and only the grain: the palette a sampler reports
|
||||||
|
// is the same table whatever the seed is.
|
||||||
|
VF_TEST(changingTheNoiseSeedRedrawsTheGrainButNotThePalette) {
|
||||||
|
TileTextureParams first;
|
||||||
|
TileTextureParams second;
|
||||||
|
second.noiseSeed = first.noiseSeed ^ 0x5bf03635u;
|
||||||
|
TileSampler original(first);
|
||||||
|
TileSampler reseeded(second);
|
||||||
|
|
||||||
|
int changed = 0;
|
||||||
|
for (int tile = 0; tile < renderedTiles(original); ++tile) {
|
||||||
|
if (renderTile(original, tile) != renderTile(reseeded, tile)) ++changed;
|
||||||
|
CHECK(original.palette().specFor(tile).base == reseeded.palette().specFor(tile).base);
|
||||||
|
CHECK(original.palette().specFor(tile).accent == reseeded.palette().specFor(tile).accent);
|
||||||
|
}
|
||||||
|
CHECK(changed > tileCount * 3 / 4);
|
||||||
|
|
||||||
|
TileSampler sameSeedAgain(first);
|
||||||
|
CHECK(renderAtlas(original, false) == renderAtlas(sameSeedAgain, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeTile is the path render/Atlas.cpp takes and pixelAt is the path the
|
||||||
|
// tests take. They have to be the same generator.
|
||||||
|
VF_TEST(writeTileAgreesWithPixelAtEverywhere) {
|
||||||
|
TileSampler sampler;
|
||||||
|
int size = sampler.params().tileSize;
|
||||||
|
for (int tile = 0; tile < renderedTiles(sampler); ++tile) {
|
||||||
|
std::vector<uint8_t> bytes = renderTile(sampler, tile);
|
||||||
|
for (int y = 0; y < size; ++y) {
|
||||||
|
for (int x = 0; x < size; ++x) {
|
||||||
|
TilePixel texel = sampler.pixelAt(tile, x, y);
|
||||||
|
std::size_t offset = (static_cast<std::size_t>(y) * size + x) * 4;
|
||||||
|
CHECK_EQ(bytes[offset + 0], texel.r);
|
||||||
|
CHECK_EQ(bytes[offset + 1], texel.g);
|
||||||
|
CHECK_EQ(bytes[offset + 2], texel.b);
|
||||||
|
CHECK_EQ(bytes[offset + 3], texel.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user