Files
Ange-Marie MAURIN - A2M Systèmes 3f36b98c71 feat(3d): contrat SEQUA 3D, I3DEngineAdapter et négociation des capacités
Bibliothèque sequa::3d (espace de noms sequa::three_d), sans dépendance à un moteur : interface I3DEngineAdapter, tampons et négociation des capacités, synchronisation de la scène par deltas versionnés tout ou rien (SceneState, snapshot), demandes d'image et mesures communes. NullEngineAdapter (SIMULÉ) pour les tests. Types provisoires en attendant le format du schéma.
2026-11-07 04:37:15 +01:00

75 lines
2.4 KiB
C++

// SPDX-License-Identifier: MPL-2.0
#include "sequa/3d/scene.hpp"
#include <doctest/doctest.h>
using namespace sequa::three_d;
namespace {
Transform at(float x)
{
Transform t;
t.position = {x, 0, 0};
return t;
}
} // namespace
TEST_CASE("SceneState : creation, deplacement, destruction")
{
SceneState scene;
REQUIRE_FALSE(scene.apply({1, {CreateObject{1, at(0), {}}, CreateObject{2, at(5), {}}}}));
REQUIRE_FALSE(scene.apply({2, {SetTransform{1, at(3)}, DestroyObject{2}}}));
CHECK(scene.world_version() == 2);
REQUIRE(scene.objects().size() == 1);
CHECK(scene.objects().at(1).transform == at(3));
}
TEST_CASE("SceneState : version non croissante refusee")
{
SceneState scene;
REQUIRE_FALSE(scene.apply({5, {}}));
const auto error = scene.apply({5, {}});
REQUIRE(error.has_value());
CHECK(error->code == Error::Code::invalid_argument);
CHECK(scene.apply({4, {}}).has_value());
}
TEST_CASE("SceneState : un delta invalide ne modifie rien (tout ou rien)")
{
SceneState scene;
REQUIRE_FALSE(scene.apply({1, {CreateObject{1, at(0), {}}}}));
// Le déplacement de 1 est valide, mais 99 est inconnu : rien ne doit être appliqué.
CHECK(scene.apply({2, {SetTransform{1, at(7)}, SetTransform{99, at(1)}}}).has_value());
CHECK(scene.world_version() == 1);
CHECK(scene.objects().at(1).transform == at(0));
CHECK(scene.apply({2, {CreateObject{1, at(0), {}}}}).has_value()); // doublon
CHECK(scene.apply({2, {CreateObject{invalid_object, at(0), {}}}}).has_value());
CHECK(scene.world_version() == 1);
}
TEST_CASE("SceneState : le snapshot reconstruit une scene identique")
{
SceneState scene;
Visual sphere;
sphere.primitive = Primitive::sphere;
sphere.semantic_class = 3;
REQUIRE_FALSE(scene.apply({1, {CreateObject{7, at(1), {}}, CreateObject{3, at(2), sphere}}}));
REQUIRE_FALSE(scene.apply({4, {SetCamera{Camera{at(-10), 60, 0.1f, 500}}}}));
const SceneDelta snapshot = scene.snapshot();
CHECK(snapshot.world_version == 4);
REQUIRE(snapshot.commands.size() == 3);
CHECK(std::get<CreateObject>(snapshot.commands[0]).id == 3); // ordre par id croissant
CHECK(std::holds_alternative<SetCamera>(snapshot.commands[2]));
SceneState copy;
REQUIRE_FALSE(copy.apply(snapshot));
CHECK(copy.objects() == scene.objects());
CHECK(copy.camera() == scene.camera());
}