feat: add runtime particle field updates

This commit is contained in:
OpenAI Codex
2026-09-03 18:26:13 +08:00
parent 7af12e7d62
commit 45502a53f4
12 changed files with 346 additions and 15 deletions

View File

@@ -241,6 +241,73 @@ TEST(Source, RasterArrayGpuReuseConsumesNewRevision) {
EXPECT_FALSE(particle::fieldIdentityChanged(assignedAfterReuse, wantedNewT0));
}
TEST(Source, RasterArrayRuntimeFieldWindowAdvancesWithoutReplacingTheSource) {
SourceTest test;
const auto eastMetadata = fixtureBytes("uniform-east", "metadata.json");
const auto eastField = fixtureBytes("uniform-east", "field.f32");
const auto northMetadata = fixtureBytes("uniform-north", "metadata.json");
const auto northField = fixtureBytes("uniform-north", "field.f32");
test.fileSource->sourceResponse = [&](const Resource& resource) -> Response {
Response response;
if (resource.url == "east-metadata") {
response.data = std::make_unique<std::string>(eastMetadata);
} else if (resource.url == "east-field") {
response.data = std::make_unique<std::string>(eastField);
} else if (resource.url == "north-metadata") {
response.data = std::make_unique<std::string>(northMetadata);
} else if (resource.url == "north-field") {
response.data = std::make_unique<std::string>(northField);
} else {
ADD_FAILURE() << "Unexpected RasterArray resource: " << resource.url;
}
return response;
};
style::RasterArraySource source{
"source", "uniform-east", "east-metadata", "east-field", "uniform-north", "north-metadata", "north-field"};
source.setObserver(&test.styleObserver);
bool initialLoad = true;
uint32_t sourceChangedCount = 0;
test.styleObserver.sourceChanged = [&](Source&) {
++sourceChangedCount;
if (initialLoad) {
initialLoad = false;
test.end();
}
};
source.loadDescription(*test.fileSource);
test.run();
ASSERT_TRUE(source.impl().field);
ASSERT_TRUE(source.impl().nextField);
const auto initialT0Generation = source.impl().field->generation;
const auto initialT1Generation = source.impl().nextField->generation;
const auto vortex = particle::OfflineFixtureParticleAdapter::load("vortex", initialT1Generation + 1);
const auto nodata = particle::OfflineFixtureParticleAdapter::load("nodata", vortex.generation + 1);
EXPECT_EQ(source.updateRuntimeFieldWindow(vortex), style::RasterArrayRuntimeFieldUpdateResult::Applied);
EXPECT_EQ(source.impl().field->fixtureID, "uniform-north");
EXPECT_EQ(source.impl().field->generation, initialT1Generation);
EXPECT_EQ(source.impl().nextField->fixtureID, "vortex");
EXPECT_EQ(source.impl().nextField->generation, vortex.generation);
EXPECT_EQ(sourceChangedCount, 2u);
EXPECT_EQ(source.updateRuntimeFieldWindow(vortex), style::RasterArrayRuntimeFieldUpdateResult::Noop);
auto invalid = nodata;
invalid.velocity.clear();
EXPECT_EQ(source.updateRuntimeFieldWindow(invalid),
style::RasterArrayRuntimeFieldUpdateResult::RejectedInvalidSnapshot);
EXPECT_EQ(source.impl().field->fixtureID, "uniform-north");
EXPECT_EQ(source.impl().nextField->fixtureID, "vortex");
EXPECT_EQ(source.updateRuntimeFieldWindow(nodata), style::RasterArrayRuntimeFieldUpdateResult::Applied);
EXPECT_EQ(source.impl().field->fixtureID, "vortex");
EXPECT_EQ(source.impl().nextField->fixtureID, "nodata");
EXPECT_EQ(sourceChangedCount, 3u);
EXPECT_NE(source.impl().field->generation, initialT0Generation);
}
TEST(Source, RasterArrayTimeWindowKeepsIndependentCompatibleSnapshots) {
const auto east = particle::OfflineFixtureParticleAdapter::load("uniform-east", 11);
const auto north = particle::OfflineFixtureParticleAdapter::load("uniform-north", 12);