From 3c2ef81536aebcf14d19db74628f0157b8a29d59 Mon Sep 17 00:00:00 2001 From: shenlei Date: Wed, 30 Sep 2026 12:24:24 +0900 Subject: [PATCH] SphereLib: mark the verbatim sphere tree PORTED with a query test Co-Authored-By: Claude Opus 5.5 --- audit/history.jsonl | 3 + audit/port-map/SphereLib/frustum.cpp.json | 32 +++ audit/port-map/SphereLib/sphere.cpp.json | 56 +++++ audit/port-map/SphereLib/spherepack.cpp.json | 224 +++++++++++++++++++ src/port/CMakeLists.txt | 4 + tests/port/port_spherelib_test.cpp | 127 +++++++++++ 6 files changed, 446 insertions(+) create mode 100644 audit/port-map/SphereLib/frustum.cpp.json create mode 100644 audit/port-map/SphereLib/sphere.cpp.json create mode 100644 audit/port-map/SphereLib/spherepack.cpp.json create mode 100644 tests/port/port_spherelib_test.cpp diff --git a/audit/history.jsonl b/audit/history.jsonl index 71b4a3e6..2c974860 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -573,3 +573,6 @@ {"date": "2026-09-30T03:07:37+00:00", "unit": "MilesLib/*", "action": "MilesLib platform port: 40250 SoundBase/SoundData/SoundInstance2D/3D/Stream/SoundManager*/Type copied verbatim (only includes + one unused QPC local differ) over an AIL_* software mixer (MilesAil.cpp: 2D balance pan, 3D inverse distance min 1/max 200 + listener pan, threaded stream decode, loop counts, decompress_ASI/ADPCM to float WAV); host NativeAudioEngine drains MtMilesMix; CSoundManager Create/Destroy in PythonBoot (IsNoSoundCard), listener+Update from PythonApplicationCamera, Save/RestoreVolume on window focus, CSoundData::SetPackMode in PackInitialize; old AudioCommands/SoundInstance bridge deleted; 142/142 PORTED", "evidence": "port_miles_test ok (2D/3D/stream fades/DataToInstance); ctest all pass except pre-existing flaky login_flow; desktop live client MT_AUDIO_TRACE peaks 1.17/0.70 at login and ~0.02 in game; Android device not attached, NEEDS device run"} {"date": "2026-09-30T03:19:50+00:00", "unit": "SpeedTreeLib/SpeedTreeWrapper.cpp", "action": "CSpeedTreeRT stand-in reads the .spt collision block (12000: 12002 sphere, 12003 cylinder) and the composite texcoord block (10000: 10002 leaf maps, 10003 frond, 10004 billboard) instead of a fixed trunk cylinder and hand-picked leaf rects; GetCollisionObjectCount/GetCollisionObject DIVERGENT -> PORTED; SetupLeafBuffers note updated (earlier 'no per-leaf-map texcoords' conclusion was wrong, the rects are in section 10000)", "evidence": "port_speedtree_test ok; token layout checked over 118 .spt extracted from the 40250 packs; fake-server Yongan view (camera 4500/3/0): tree crown now drawn from its own leaf-map cells, the wrong fruit/autumn cell is gone"} {"date": "2026-09-30T03:19:50+00:00", "unit": "SpeedTreeLib/SpeedGrassRT.cpp", "action": "SpeedGrassRT/SpeedGrassWrapper/BoundaryShapeManager N_A: compiled (USE_SPEEDGRASS) but no caller outside those files", "evidence": "LC_ALL=C grep over ClientVS22/source for CSpeedGrassRT/CSpeedGrassWrapper/CBoundaryShapeManager"} +{"date": "2026-09-30T03:23:35+00:00", "unit": "SphereLib/spherepack.cpp", "action": "all functions PORTED: src/port/SphereLib is the 40250 source verbatim", "evidence": "diff vs ClientVS22/source/SphereLib (cp949->utf8, CR stripped, #include lines dropped) = 0 lines; tests/port/port_spherelib_test.cpp range/point/ray/frustum queries"} +{"date": "2026-09-30T03:23:35+00:00", "unit": "SphereLib/sphere.cpp", "action": "all functions PORTED: src/port/SphereLib is the 40250 source verbatim", "evidence": "diff vs ClientVS22/source/SphereLib (cp949->utf8, CR stripped, #include lines dropped) = 0 lines; tests/port/port_spherelib_test.cpp range/point/ray/frustum queries"} +{"date": "2026-09-30T03:23:35+00:00", "unit": "SphereLib/frustum.cpp", "action": "all functions PORTED: src/port/SphereLib is the 40250 source verbatim", "evidence": "diff vs ClientVS22/source/SphereLib (cp949->utf8, CR stripped, #include lines dropped) = 0 lines; tests/port/port_spherelib_test.cpp range/point/ray/frustum queries"} diff --git a/audit/port-map/SphereLib/frustum.cpp.json b/audit/port-map/SphereLib/frustum.cpp.json new file mode 100644 index 00000000..69e4521c --- /dev/null +++ b/audit/port-map/SphereLib/frustum.cpp.json @@ -0,0 +1,32 @@ +{ + "reference": "SphereLib/frustum.cpp", + "reference_sha256": "933ef6a97dc79510d19d83f239f7537fafd314f84cc7cd5b3392bae998cfe32c", + "priority": "P4", + "contracts": [], + "functions": { + "Frustum::ViewVolumeTest": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/frustum.cpp:Frustum::ViewVolumeTest" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Frustum::BuildViewFrustum": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/frustum.cpp:Frustum::BuildViewFrustum" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Frustum::BuildViewFrustum2": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/frustum.cpp:Frustum::BuildViewFrustum2" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + } + } +} diff --git a/audit/port-map/SphereLib/sphere.cpp.json b/audit/port-map/SphereLib/sphere.cpp.json new file mode 100644 index 00000000..7b0b937f --- /dev/null +++ b/audit/port-map/SphereLib/sphere.cpp.json @@ -0,0 +1,56 @@ +{ + "reference": "SphereLib/sphere.cpp", + "reference_sha256": "969dfc33be25be2568bba32a12491ac848724362bdc4a143878b2430f37121b7", + "priority": "P4", + "contracts": [], + "functions": { + "Vector3d::IsInStaticRange": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Vector3d::IsInStaticRange" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Sphere::Set": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Sphere::Set" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Sphere::RayIntersection": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Sphere::RayIntersection" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Sphere::RayIntersectionInFront": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Sphere::RayIntersectionInFront" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Sphere::Report": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Sphere::Report" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "Sphere::Compute": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/sphere.cpp:Sphere::Compute" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + } + } +} diff --git a/audit/port-map/SphereLib/spherepack.cpp.json b/audit/port-map/SphereLib/spherepack.cpp.json new file mode 100644 index 00000000..c52b0d6b --- /dev/null +++ b/audit/port-map/SphereLib/spherepack.cpp.json @@ -0,0 +1,224 @@ +{ + "reference": "SphereLib/spherepack.cpp", + "reference_sha256": "e9fcd5e6c27f9106a85d3948856d67845fec48efd102b3044f0d227935097122", + "priority": "P4", + "contracts": [], + "functions": { + "SpherePackFactory::SpherePackFactory": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::SpherePackFactory" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::~SpherePackFactory": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::~SpherePackFactory" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::Process": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::Process" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::AddSphere_": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::AddSphere_" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::AddIntegrate": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::AddIntegrate" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::AddRecompute": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::AddRecompute" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::Render": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::Render" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::Render": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::Render" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::Recompute": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::Recompute" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::LostChild": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::LostChild" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::Remove": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::Remove" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::GetColor": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::GetColor" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::Integrate": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::Integrate" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::FrustumTest": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::FrustumTest" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::VisibilityTest": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::VisibilityTest" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::RayTrace": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::RayTrace" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::RangeTest": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::RangeTest" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::PointTest2d": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::PointTest2d" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::RangeTest": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::RangeTest" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::PointTest2d": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::PointTest2d" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::RangeTestCallback": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::RangeTestCallback" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::PointTest2dCallback": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::PointTest2dCallback" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::RayTrace": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::RayTrace" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::RayTraceCallback": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::RayTraceCallback" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::Reset": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::Reset" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePack::Reset": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePack::Reset" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + }, + "SpherePackFactory::VisibilityCallback": { + "status": "PORTED", + "impl": [ + "src/port/SphereLib/spherepack.cpp:SpherePackFactory::VisibilityCallback" + ], + "test": "tests/port/port_spherelib_test.cpp", + "note": "verbatim 40250 source (0 diff lines outside #include); used by CCullingManager and CScreen frustum" + } + } +} diff --git a/src/port/CMakeLists.txt b/src/port/CMakeLists.txt index 24cbc467..1c8021d6 100644 --- a/src/port/CMakeLists.txt +++ b/src/port/CMakeLists.txt @@ -205,6 +205,10 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) target_link_libraries(port_speedtree_test PRIVATE port_platform) add_test(NAME port.speedtree COMMAND $) + add_executable(port_spherelib_test ${PROJECT_SOURCE_DIR}/tests/port/port_spherelib_test.cpp) + target_link_libraries(port_spherelib_test PRIVATE port_platform) + add_test(NAME port.spherelib COMMAND $) + # 批次 2V1: Packet.h struct sizes against the classic wire layouts. add_executable(port_packet_test ${PROJECT_SOURCE_DIR}/tests/port/port_packet_test.cpp ${PROJECT_SOURCE_DIR}/tests/port/port_packet_test_wire.cpp) diff --git a/tests/port/port_spherelib_test.cpp b/tests/port/port_spherelib_test.cpp new file mode 100644 index 00000000..aa8345ea --- /dev/null +++ b/tests/port/port_spherelib_test.cpp @@ -0,0 +1,127 @@ +// SphereLib: the 40250 sphere tree (verbatim src/port/SphereLib) that CCullingManager builds with the same +// factory parameters. Checks the range, 2D point, ray and frustum queries CCullingManager makes and the +// Frustum plane test on its own. +#include "SphereLib/StdAfx.h" +#include "SphereLib/spherepack.h" + +#include +#include + +static int g_failures = 0; +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK(%s)\n", __FILE__, __LINE__, #cond); \ + ++g_failures; \ + } \ + } while (0) + +namespace +{ + +// Collects the user data of the leaves a query reports, like CCullingManager's callbacks. +struct Collector : SpherePackCallback +{ + std::set hits; + std::set hidden; + + void Add(SpherePack * sphere) { hits.insert(long(reinterpret_cast(sphere->GetUserData()))); } + + void VisibilityCallback(const Frustum &, SpherePack * sphere, ViewState state) override + { + if (state == VS_OUTSIDE) + hidden.insert(long(reinterpret_cast(sphere->GetUserData()))); + else + Add(sphere); + } + void RayTraceCallback(const Vector3d &, const Vector3d &, float, const Vector3d &, SpherePack * sphere) override { Add(sphere); } + void RangeTestCallback(const Vector3d &, float, SpherePack * sphere, ViewState) override { Add(sphere); } + void PointTest2dCallback(const Vector3d &, SpherePack * sphere, ViewState) override { Add(sphere); } +}; + +void * Tag(long v) { return reinterpret_cast(intptr_t(v)); } + +void TestFrustumPlanes() +{ + // Identity view-projection: the D3D clip box x,y in [-1,1], z in [0,1]. + D3DXMATRIX m; + D3DXMatrixIdentity(&m); + Frustum f; + f.BuildViewFrustum(m); + CHECK(f.ViewVolumeTest(Vector3d(0.0f, 0.0f, 0.5f), 0.1f) == VS_INSIDE); + CHECK(f.ViewVolumeTest(Vector3d(1.0f, 0.0f, 0.5f), 0.1f) == VS_PARTIAL); + CHECK(f.ViewVolumeTest(Vector3d(5.0f, 0.0f, 0.5f), 0.1f) == VS_OUTSIDE); + CHECK(f.ViewVolumeTest(Vector3d(0.0f, 0.0f, -1.0f), 0.1f) == VS_OUTSIDE); +} + +void TestFactoryQueries() +{ + SpherePackFactory factory(10000, 6400, 1600, 400); // CCullingManager::CCullingManager + SpherePack * a = factory.AddSphere_(Vector3d(0.0f, 0.0f, 0.0f), 50.0f, Tag(1), false); + SpherePack * b = factory.AddSphere_(Vector3d(100.0f, 0.0f, 0.0f), 50.0f, Tag(2), false); + factory.AddSphere_(Vector3d(20000.0f, 0.0f, 0.0f), 50.0f, Tag(3), false); + factory.Process(); + + { + Collector c; + factory.RangeTest(Vector3d(0.0f, 0.0f, 0.0f), 500.0f, &c); + CHECK((c.hits == std::set{1, 2})); + } + { + Collector c; + factory.PointTest2d(Vector3d(100.0f, 10.0f, 0.0f), &c); + CHECK((c.hits == std::set{2})); + } + { + // The second argument is the ray (direction times length), as CCullingManager::FindRay passes it. + Collector c; + factory.RayTrace(Vector3d(-1000.0f, 0.0f, 0.0f), Vector3d(2000.0f, 0.0f, 0.0f), &c); + CHECK((c.hits == std::set{1, 2})); + Collector shortRay; + factory.RayTrace(Vector3d(-1000.0f, 0.0f, 0.0f), Vector3d(1000.0f, 0.0f, 0.0f), &shortRay); + CHECK((shortRay.hits == std::set{1})); + } + { + // Clip box [-1000,1000] x [-1000,1000] x [-500,500] in world space. + D3DXMATRIX m; + D3DXMatrixIdentity(&m); + m._11 = m._22 = m._33 = 0.001f; + m._43 = 0.5f; + Frustum f; + f.BuildViewFrustum(m); + Collector c; + factory.FrustumTest(f, &c); + CHECK((c.hits == std::set{1, 2})); + CHECK(c.hidden.count(3) == 1); + } + + // A moved sphere is found at its new position once the factory re-integrates it. + b->NewPos(Vector3d(20000.0f, 100.0f, 0.0f)); + factory.Process(); + { + Collector c; + factory.RangeTest(Vector3d(20000.0f, 0.0f, 0.0f), 500.0f, &c); + CHECK((c.hits == std::set{2, 3})); + } + + factory.Remove(a); + factory.Process(); + { + Collector c; + factory.RangeTest(Vector3d(0.0f, 0.0f, 0.0f), 500.0f, &c); + CHECK(c.hits.empty()); + } +} + +} // namespace + +int main() +{ + TestFrustumPlanes(); + TestFactoryQueries(); + if (g_failures) + std::fprintf(stderr, "port_spherelib_test: %d failure(s)\n", g_failures); + else + std::puts("port_spherelib_test: ok"); + return g_failures ? 1 : 0; +}