127 lines
4.4 KiB
C++
127 lines
4.4 KiB
C++
#include "graphics/VirtualTextureBlend.h"
|
|
|
|
#include "image/ImageData.h"
|
|
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include <cmath>
|
|
#include <memory>
|
|
|
|
using eve::graphics::VirtualTextureBlend;
|
|
using eve::graphics::VirtualTextureBlendConfig;
|
|
using eve::graphics::VirtualTextureBlendLayer;
|
|
using eve::graphics::VirtualTexturePageId;
|
|
using eve::image::ImageData;
|
|
|
|
namespace {
|
|
|
|
std::shared_ptr<ImageData> solid(float r, float g, float b, float a = 1.f) {
|
|
auto image = std::make_shared<ImageData>(4, 4, "RGBA8");
|
|
for (int y = 0; y < 4; ++y)
|
|
for (int x = 0; x < 4; ++x) image->setPixel(x, y, {r, g, b, a});
|
|
return image;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("graphics.virtual_texture.validates_contract") {
|
|
VirtualTextureBlendConfig invalid{};
|
|
invalid.tileSize = 2;
|
|
auto rejected = VirtualTextureBlend::create(invalid);
|
|
CHECK(!rejected.ok());
|
|
|
|
VirtualTextureBlendConfig valid{};
|
|
valid.width = 8;
|
|
valid.height = 8;
|
|
valid.tileSize = 4;
|
|
valid.borderSize = 1;
|
|
auto created = VirtualTextureBlend::create(valid);
|
|
REQUIRE(created.ok());
|
|
auto noLayers = created.value()->requestAlbedoPage(0, 0, 0);
|
|
CHECK(!noLayers.ok());
|
|
}
|
|
|
|
TEST_CASE("graphics.virtual_texture.height_blends_and_normalizes_normals") {
|
|
VirtualTextureBlendConfig config{8, 8, 4, 1, 8};
|
|
auto created = VirtualTextureBlend::create(config);
|
|
REQUIRE(created.ok());
|
|
auto blend = std::move(created).value();
|
|
|
|
VirtualTextureBlendLayer red{};
|
|
red.albedo = solid(1.f, 0.f, 0.f, 0.2f);
|
|
red.normal = solid(1.f, 0.5f, 0.5f);
|
|
red.constantWeight = 1.f;
|
|
red.heightContrast = 1.f;
|
|
REQUIRE(blend->addLayer(red).ok());
|
|
|
|
VirtualTextureBlendLayer blue{};
|
|
blue.albedo = solid(0.f, 0.f, 1.f, 0.8f);
|
|
blue.normal = solid(0.5f, 1.f, 0.5f);
|
|
blue.constantWeight = 1.f;
|
|
blue.heightContrast = 1.f;
|
|
REQUIRE(blend->addLayer(blue).ok());
|
|
|
|
auto albedo = blend->requestAlbedoPage(0, 0, 0);
|
|
REQUIRE(albedo.ok());
|
|
const auto color = albedo.value()->getPixel(2, 2);
|
|
CHECK(color.b > 0.95f);
|
|
CHECK(color.r < 0.05f);
|
|
|
|
auto normal = blend->requestNormalPage(0, 0, 0);
|
|
REQUIRE(normal.ok());
|
|
const auto encoded = normal.value()->getPixel(2, 2);
|
|
const float nx = encoded.r * 2.f - 1.f;
|
|
const float ny = encoded.g * 2.f - 1.f;
|
|
const float nz = encoded.b * 2.f - 1.f;
|
|
CHECK(std::abs(std::sqrt(nx * nx + ny * ny + nz * nz) - 1.f) < 0.03f);
|
|
}
|
|
|
|
TEST_CASE("graphics.virtual_texture_pages_have_borders_and_lru_receipts_survive") {
|
|
VirtualTextureBlendConfig config{12, 4, 4, 1, 1};
|
|
auto created = VirtualTextureBlend::create(config);
|
|
REQUIRE(created.ok());
|
|
auto blend = std::move(created).value();
|
|
VirtualTextureBlendLayer layer{};
|
|
layer.albedo = solid(0.25f, 0.5f, 0.75f);
|
|
REQUIRE(blend->addLayer(layer).ok());
|
|
|
|
auto first = blend->requestAlbedoPage(0, 0, 0);
|
|
REQUIRE(first.ok());
|
|
CHECK_EQ(first.value()->getWidth(), 6);
|
|
REQUIRE(blend->requestAlbedoPage(1, 0, 0).ok());
|
|
CHECK_EQ(blend->stats().pageEvictions, 1u);
|
|
CHECK(first.value()->getPixel(0, 0).g > 0.48f);
|
|
|
|
auto baked = blend->bakeAlbedo();
|
|
REQUIRE(baked.ok());
|
|
CHECK_EQ(baked.value()->getWidth(), 12);
|
|
CHECK_EQ(baked.value()->getHeight(), 4);
|
|
}
|
|
|
|
TEST_CASE("graphics.virtual_texture_builds_atomic_resident_set_with_fallback") {
|
|
VirtualTextureBlendConfig config{8, 8, 4, 1, 2};
|
|
auto created = VirtualTextureBlend::create(config);
|
|
REQUIRE(created.ok());
|
|
auto blend = std::move(created).value();
|
|
VirtualTextureBlendLayer layer{};
|
|
layer.albedo = solid(0.2f, 0.4f, 0.8f);
|
|
REQUIRE(blend->addLayer(layer).ok());
|
|
|
|
auto duplicate = blend->buildResidentSet({{0, 0}, {0, 0}});
|
|
CHECK(!duplicate.ok());
|
|
auto tooMany = blend->buildResidentSet({{0, 0}, {1, 0}, {0, 1}});
|
|
CHECK(!tooMany.ok());
|
|
|
|
auto built = blend->buildResidentSet({VirtualTexturePageId{1, 0}});
|
|
REQUIRE(built.ok());
|
|
const auto& set = built.value();
|
|
CHECK_EQ(set.pageExtent, 6);
|
|
CHECK_EQ(set.residentPages, 1u);
|
|
CHECK_EQ(set.pageTable->getWidth(), 2);
|
|
CHECK_EQ(set.pageTable->getHeight(), 2);
|
|
CHECK(set.pageTable->getPixel(0, 0).b < 0.05f);
|
|
CHECK(set.pageTable->getPixel(1, 0).b > 0.95f);
|
|
CHECK(set.albedoAtlas->getPixel(0, 0).b > 0.75f);
|
|
CHECK(set.normalAtlas->getPixel(0, 0).b > 0.95f);
|
|
}
|