128 lines
4.2 KiB
C++
128 lines
4.2 KiB
C++
// 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 <cstdio>
|
|
#include <set>
|
|
|
|
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<long> hits;
|
|
std::set<long> hidden;
|
|
|
|
void Add(SpherePack * sphere) { hits.insert(long(reinterpret_cast<intptr_t>(sphere->GetUserData()))); }
|
|
|
|
void VisibilityCallback(const Frustum &, SpherePack * sphere, ViewState state) override
|
|
{
|
|
if (state == VS_OUTSIDE)
|
|
hidden.insert(long(reinterpret_cast<intptr_t>(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<void *>(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<long>{1, 2}));
|
|
}
|
|
{
|
|
Collector c;
|
|
factory.PointTest2d(Vector3d(100.0f, 10.0f, 0.0f), &c);
|
|
CHECK((c.hits == std::set<long>{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<long>{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<long>{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<long>{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<long>{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;
|
|
}
|