
//---------------------------------------------------------------------------

// This software is Copyright (c) 2015 Embarcadero Technologies, Inc. 
// You may only use this software if you are an authorized licensee
// of an Embarcadero developer tools product. 
// This software is considered a Redistributable as defined under
// the software license agreement that comes with the Embarcadero Products
// and is subject to that software license agreement. 

//---------------------------------------------------------------------------
unit Test;

interface

//class Test;
//struct Settings;
//
//typedef Test* TestCreateFcn();
//
//#define	RAND_LIMIT	32767
//#define DRAW_STRING_NEW_LINE 16
//
///// Random number in range [-1,1]
//inline float32 RandomFloat()
//{
//	float32 r = (float32)(std::rand() & (RAND_LIMIT));
//	r /= RAND_LIMIT;
//	r = 2.0f * r - 1.0f;
//	return r;
//}
//
///// Random floating point number in range [lo, hi]
//inline float32 RandomFloat(float32 lo, float32 hi)
//{
//	float32 r = (float32)(std::rand() & (RAND_LIMIT));
//	r /= RAND_LIMIT;
//	r = (hi - lo) * r + lo;
//	return r;
//}
//
///// Test settings.  Some can be controlled in the GUI. 
//struct Settings
//{
//	Settings()
//	{
//		hz = 60.0f;
//		velocityIterations = 8;
//		positionIterations = 3;
//		drawShapes = true;
//		drawJoints = true;
//		drawAABBs = false;
//		drawContactPoints = false;
//		drawContactNormals = false;
//		drawContactImpulse = false;
//		drawFrictionImpulse = false;
//		drawCOMs = false;
//		drawStats = false;
//		drawProfile = false;
//		enableWarmStarting = true;
//		enableContinuous = true;
//		enableSubStepping = false;
//		enableSleep = true;
//		pause = false;
//		singleStep = false;
//	}
//
//	float32 hz;
//	int32 velocityIterations;
//	int32 positionIterations;
//	bool drawShapes;
//	bool drawJoints;
//	bool drawAABBs;
//	bool drawContactPoints;
//	bool drawContactNormals;
//	bool drawContactImpulse;
//	bool drawFrictionImpulse;
//	bool drawCOMs;
//	bool drawStats;
//	bool drawProfile;
//	bool enableWarmStarting;
//	bool enableContinuous;
//	bool enableSubStepping;
//	bool enableSleep;
//	bool pause;
//	bool singleStep;
//};

type
  PSettings = ^TSettings;
  TSettings = record
    hz: single;
    velocityIterations: Int32;
    positionIterations: Int32;
    drawShapes: Boolean;
    drawJoints: Boolean;
    drawAABBs: Boolean;
    drawContactPoints: Boolean;
    drawContactNormals: Boolean;
    drawContactImpulse: Boolean;
    drawFrictionImpulse: Boolean;
    drawCOMs: Boolean;
    drawStats: Boolean;
    drawProfile: Boolean;
    enableWarmStarting: Boolean;
    enableContinuous: Boolean;
    enableSubStepping: Boolean;
    enableSleep: Boolean;
    pause: Boolean;
    singleStep: Boolean;
  end;

//struct TestEntry
//{
//	const char *name;
//	TestCreateFcn *createFcn;
//};

//  TTest = class;
  PTest = ^TTest;
  TTest = record

  end;
//
//  TTestCreateFunction = function(): TTest;
//
  PTestEntry = ^TTestEntry;
  TTestEntry = record
    Name: string;
    //CreateFunction: TTestCreateFunction;
  end;

//
//extern TestEntry g_testEntries[];
//// This is called when a joint in the world is implicitly destroyed
//// because an attached body is destroyed.  This gives us a chance to
//// nullify the mouse joint. 
//class DestructionListener : public b2DestructionListener
//{
//public:
//	void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); }
//	void SayGoodbye(b2Joint* joint);
//
//	Test* test;
//};
//
//const int32 k_maxContactPoints = 2048;
//
//struct ContactPoint
//{
//	b2Fixture* fixtureA;
//	b2Fixture* fixtureB;
//	b2Vec2 normal;
//	b2Vec2 position;
//	b2PointState state;
//	float32 normalImpulse;
//	float32 tangentImpulse;
//	float32 separation;
//};
//
//class Test : public b2ContactListener
//{
//public:
//
//	Test();
//	virtual ~Test();
//
//	void DrawTitle(const char *string);
//	virtual void Step(Settings* settings);
//	virtual void Keyboard(int key) { B2_NOT_USED(key); }
//	virtual void KeyboardUp(int key) { B2_NOT_USED(key); }
//	void ShiftMouseDown(const b2Vec2& p);
//	virtual void MouseDown(const b2Vec2& p);
//	virtual void MouseUp(const b2Vec2& p);
//	void MouseMove(const b2Vec2& p);
//	void LaunchBomb();
//	void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity);
//
//	void SpawnBomb(const b2Vec2& worldPt);
//	void CompleteBombSpawn(const b2Vec2& p);
//
//	// Let derived tests know that a joint was destroyed. 
//	virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); }
//
//	// Callbacks for derived classes. 
//	virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
//	virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
//	virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
//	virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
//	{
//		B2_NOT_USED(contact);
//		B2_NOT_USED(impulse);
//	}
//
//	void ShiftOrigin(const b2Vec2& newOrigin);
//
//protected:
//	friend class DestructionListener;
//	friend class BoundaryListener;
//	friend class ContactListener;
//
//	b2Body* m_groundBody;
//	b2AABB m_worldAABB;
//	ContactPoint m_points[k_maxContactPoints];
//	int32 m_pointCount;
//	DestructionListener m_destructionListener;
//	int32 m_textLine;
//	b2World* m_world;
//	b2Body* m_bomb;
//	b2MouseJoint* m_mouseJoint;
//	b2Vec2 m_bombSpawnPoint;
//	bool m_bombSpawning;
//	b2Vec2 m_mouseWorld;
//	int32 m_stepCount;
//
//	b2Profile m_maxProfile;
//	b2Profile m_totalProfile;
//};


implementation

//
//void DestructionListener::SayGoodbye(b2Joint* joint)
//{
//	if (test->m_mouseJoint == joint)
//	{
//		test->m_mouseJoint = NULL;
//	}
//	else
//	{
//		test->JointDestroyed(joint);
//	}
//}
//
//Test::Test()
//{
//	b2Vec2 gravity;
//	gravity. Set(0.0f, -10.0f);
//	m_world = new b2World(gravity);
//	m_bomb = NULL;
//	m_textLine = 30;
//	m_mouseJoint = NULL;
//	m_pointCount = 0;
//
//	m_destructionListener.test = this;
//	m_world->SetDestructionListener(&m_destructionListener);
//	m_world->SetContactListener(this);
//	m_world->SetDebugDraw(&g_debugDraw);
//
//	m_bombSpawning = false;
//
//	m_stepCount = 0;
//
//	b2BodyDef bodyDef;
//	m_groundBody = m_world->CreateBody(&bodyDef);
//
//	memset(&m_maxProfile, 0, sizeof(b2Profile));
//	memset(&m_totalProfile, 0, sizeof(b2Profile));
//}
//
//Test::~Test()
//{
//	// By deleting the world, we delete the bomb, mouse joint, etc. 
//	delete m_world;
//	m_world = NULL;
//}
//
//void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
//{
//	const b2Manifold* manifold = contact->GetManifold();
//
//	if (manifold->pointCount == 0)
//	{
//		return;
//	}
//
//	b2Fixture* fixtureA = contact->GetFixtureA();
//	b2Fixture* fixtureB = contact->GetFixtureB();
//
//	b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints];
//	b2GetPointStates(state1, state2, oldManifold, manifold);
//
//	b2WorldManifold worldManifold;
//	contact->GetWorldManifold(&worldManifold);
//
//	for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i)
//	{
//		ContactPoint* cp = m_points + m_pointCount;
//		cp->fixtureA = fixtureA;
//		cp->fixtureB = fixtureB;
//		cp->position = worldManifold.points[i];
//		cp->normal = worldManifold.normal;
//		cp->state = state2[i];
//		cp->normalImpulse = manifold->points[i].normalImpulse;
//		cp->tangentImpulse = manifold->points[i].tangentImpulse;
//		cp->separation = worldManifold.separations[i];
//		++m_pointCount;
//	}
//}
//
//void Test::DrawTitle(const char *string)
//{
//    g_debugDraw. DrawString(5, DRAW_STRING_NEW_LINE, string);
//    m_textLine = 3 * DRAW_STRING_NEW_LINE;
//}
//
//class QueryCallback : public b2QueryCallback
//{
//public:
//	QueryCallback(const b2Vec2& point)
//	{
//		m_point = point;
//		m_fixture = NULL;
//	}
//
//	bool ReportFixture(b2Fixture* fixture)
//	{
//		b2Body* body = fixture->GetBody();
//		if (body->GetType() == b2_dynamicBody)
//		{
//			bool inside = fixture->TestPoint(m_point);
//			if (inside)
//			{
//				m_fixture = fixture;
//
//				// We are done, terminate the query. 
//				return false;
//			}
//		}
//
//		// Continue the query. 
//		return true;
//	}
//
//	b2Vec2 m_point;
//	b2Fixture* m_fixture;
//};
//
//void Test::MouseDown(const b2Vec2& p)
//{
//	m_mouseWorld = p;
//
//	if (m_mouseJoint ! = NULL)
//	{
//		return;
//	}
//
//	// Make a small box. 
//	b2AABB aabb;
//	b2Vec2 d;
//	d.Set(0.001f, 0.001f);
//	aabb.lowerBound = p - d;
//	aabb.upperBound = p + d;
//
//	// Query the world for overlapping shapes. 
//	QueryCallback callback(p);
//	m_world->QueryAABB(&callback, aabb);
//
//	if (callback.m_fixture)
//	{
//		b2Body* body = callback.m_fixture->GetBody();
//		b2MouseJointDef md;
//		md.bodyA = m_groundBody;
//		md.bodyB = body;
//		md.target = p;
//		md.maxForce = 1000.0f * body->GetMass();
//		m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
//		body->SetAwake(true);
//	}
//}
//
//void Test::SpawnBomb(const b2Vec2& worldPt)
//{
//	m_bombSpawnPoint = worldPt;
//	m_bombSpawning = true;
//}
//
//void Test::CompleteBombSpawn(const b2Vec2& p)
//{
//	if (m_bombSpawning == false)
//	{
//		return;
//	}
//
//	const float multiplier = 30.0f;
//	b2Vec2 vel = m_bombSpawnPoint - p;
//	vel *= multiplier;
//	LaunchBomb(m_bombSpawnPoint,vel);
//	m_bombSpawning = false;
//}
//
//void Test::ShiftMouseDown(const b2Vec2& p)
//{
//	m_mouseWorld = p;
//
//	if (m_mouseJoint ! = NULL)
//	{
//		return;
//	}
//
//	SpawnBomb(p);
//}
//
//void Test::MouseUp(const b2Vec2& p)
//{
//	if (m_mouseJoint)
//	{
//		m_world->DestroyJoint(m_mouseJoint);
//		m_mouseJoint = NULL;
//	}
//
//	if (m_bombSpawning)
//	{
//		CompleteBombSpawn(p);
//	}
//}
//
//void Test::MouseMove(const b2Vec2& p)
//{
//	m_mouseWorld = p;
//
//	if (m_mouseJoint)
//	{
//		m_mouseJoint->SetTarget(p);
//	}
//}
//
//void Test::LaunchBomb()
//{
//	b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f);
//	b2Vec2 v = -5.0f * p;
//	LaunchBomb(p, v);
//}
//
//void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity)
//{
//	if (m_bomb)
//	{
//		m_world->DestroyBody(m_bomb);
//		m_bomb = NULL;
//	}
//
//	b2BodyDef bd;
//	bd.type = b2_dynamicBody;
//	bd.position = position;
//	bd.bullet = true;
//	m_bomb = m_world->CreateBody(&bd);
//	m_bomb->SetLinearVelocity(velocity);
//
//	b2CircleShape circle;
//	circle.m_radius = 0.3f;
//
//	b2FixtureDef fd;
//	fd.shape = &circle;
//	fd.density = 20.0f;
//	fd.restitution = 0.0f;
//
//	b2Vec2 minV = position - b2Vec2(0.3f,0.3f);
//	b2Vec2 maxV = position + b2Vec2(0.3f,0.3f);
//
//	b2AABB aabb;
//	aabb.lowerBound = minV;
//	aabb.upperBound = maxV;
//
//	m_bomb->CreateFixture(&fd);
//}
//
//void Test::Step(Settings* settings)
//{
//	float32 timeStep = settings->hz > 0.0f ?  1.0f / settings->hz : float32(0.0f);
//
//	if (settings->pause)
//	{
//		if (settings->singleStep)
//		{
//			settings->singleStep = 0;
//		}
//		else
//		{
//			timeStep = 0.0f;
//		}
//
//		g_debugDraw. DrawString(5, m_textLine, "****PAUSED****");
//		m_textLine += DRAW_STRING_NEW_LINE;
//	}
//
//	uint32 flags = 0;
//	flags += settings->drawShapes			* b2Draw::e_shapeBit;
//	flags += settings->drawJoints			* b2Draw::e_jointBit;
//	flags += settings->drawAABBs			* b2Draw::e_aabbBit;
//	flags += settings->drawCOMs				* b2Draw::e_centerOfMassBit;
//	g_debugDraw. SetFlags(flags);
//
//	m_world->SetAllowSleeping(settings->enableSleep);
//	m_world->SetWarmStarting(settings->enableWarmStarting);
//	m_world->SetContinuousPhysics(settings->enableContinuous);
//	m_world->SetSubStepping(settings->enableSubStepping);
//
//	m_pointCount = 0;
//
//	m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
//
//	m_world->DrawDebugData();
//    g_debugDraw. Flush();
//
//	if (timeStep > 0.0f)
//	{
//		++m_stepCount;
//	}
//
//	if (settings->drawStats)
//	{
//		int32 bodyCount = m_world->GetBodyCount();
//		int32 contactCount = m_world->GetContactCount();
//		int32 jointCount = m_world->GetJointCount();
//		g_debugDraw. DrawString(5, m_textLine, "bodies/contacts/joints = %d/%d/%d", bodyCount, contactCount, jointCount);
//		m_textLine += DRAW_STRING_NEW_LINE;
//
//		int32 proxyCount = m_world->GetProxyCount();
//		int32 height = m_world->GetTreeHeight();
//		int32 balance = m_world->GetTreeBalance();
//		float32 quality = m_world->GetTreeQuality();
//		g_debugDraw. DrawString(5, m_textLine, "proxies/height/balance/quality = %d/%d/%d/%g", proxyCount, height, balance, quality);
//		m_textLine += DRAW_STRING_NEW_LINE;
//	}
//
//	// Track maximum profile times
//	{
//		const b2Profile& p = m_world->GetProfile();
//		m_maxProfile.step = b2Max(m_maxProfile.step, p.step);
//		m_maxProfile.collide = b2Max(m_maxProfile.collide, p.collide);
//		m_maxProfile.solve = b2Max(m_maxProfile.solve, p.solve);
//		m_maxProfile.solveInit = b2Max(m_maxProfile.solveInit, p.solveInit);
//		m_maxProfile.solveVelocity = b2Max(m_maxProfile.solveVelocity, p.solveVelocity);
//		m_maxProfile.solvePosition = b2Max(m_maxProfile.solvePosition, p.solvePosition);
//		m_maxProfile.solveTOI = b2Max(m_maxProfile.solveTOI, p.solveTOI);
//		m_maxProfile.broadphase = b2Max(m_maxProfile.broadphase, p.broadphase);
//
//		m_totalProfile.step += p.step;
//		m_totalProfile.collide += p.collide;
//		m_totalProfile.solve += p.solve;
//		m_totalProfile.solveInit += p.solveInit;
//		m_totalProfile.solveVelocity += p.solveVelocity;
//		m_totalProfile.solvePosition += p.solvePosition;
//		m_totalProfile.solveTOI += p.solveTOI;
//		m_totalProfile.broadphase += p.broadphase;
//	}
//
//	if (settings->drawProfile)
//	{
//		const b2Profile& p = m_world->GetProfile();
//
//		b2Profile aveProfile;
//		memset(&aveProfile, 0, sizeof(b2Profile));
//		if (m_stepCount > 0)
//		{
//			float32 scale = 1.0f / m_stepCount;
//			aveProfile.step = scale * m_totalProfile.step;
//			aveProfile.collide = scale * m_totalProfile.collide;
//			aveProfile.solve = scale * m_totalProfile.solve;
//			aveProfile.solveInit = scale * m_totalProfile.solveInit;
//			aveProfile.solveVelocity = scale * m_totalProfile.solveVelocity;
//			aveProfile.solvePosition = scale * m_totalProfile.solvePosition;
//			aveProfile.solveTOI = scale * m_totalProfile.solveTOI;
//			aveProfile.broadphase = scale * m_totalProfile.broadphase;
//		}
//
//		g_debugDraw. DrawString(5, m_textLine, "step [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.step, aveProfile.step, m_maxProfile.step);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "collide [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.collide, aveProfile.collide, m_maxProfile.collide);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "solve [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solve, aveProfile.solve, m_maxProfile.solve);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "solve init [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveInit, aveProfile.solveInit, m_maxProfile.solveInit);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "solve velocity [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveVelocity, aveProfile.solveVelocity, m_maxProfile.solveVelocity);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "solve position [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solvePosition, aveProfile.solvePosition, m_maxProfile.solvePosition);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "solveTOI [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveTOI, aveProfile.solveTOI, m_maxProfile.solveTOI);
//		m_textLine += DRAW_STRING_NEW_LINE;
//		g_debugDraw. DrawString(5, m_textLine, "broad-phase [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.broadphase, aveProfile.broadphase, m_maxProfile.broadphase);
//		m_textLine += DRAW_STRING_NEW_LINE;
//	}
//
//	if (m_mouseJoint)
//	{
//		b2Vec2 p1 = m_mouseJoint->GetAnchorB();
//		b2Vec2 p2 = m_mouseJoint->GetTarget();
//
//		b2Color c;
//		c.Set(0.0f, 1.0f, 0.0f);
//		g_debugDraw. DrawPoint(p1, 4.0f, c);
//		g_debugDraw. DrawPoint(p2, 4.0f, c);
//
//		c.Set(0.8f, 0.8f, 0.8f);
//		g_debugDraw. DrawSegment(p1, p2, c);
//	}
//
//	if (m_bombSpawning)
//	{
//		b2Color c;
//		c.Set(0.0f, 0.0f, 1.0f);
//		g_debugDraw. DrawPoint(m_bombSpawnPoint, 4.0f, c);
//
//		c.Set(0.8f, 0.8f, 0.8f);
//		g_debugDraw. DrawSegment(m_mouseWorld, m_bombSpawnPoint, c);
//	}
//
//	if (settings->drawContactPoints)
//	{
//		const float32 k_impulseScale = 0.1f;
//		const float32 k_axisScale = 0.3f;
//
//		for (int32 i = 0; i < m_pointCount; ++i)
//		{
//			ContactPoint* point = m_points + i;
//
//			if (point->state == b2_addState)
//			{
//				// Add
//				g_debugDraw. DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f));
//			}
//			else if (point->state == b2_persistState)
//			{
//				// Persist
//				g_debugDraw. DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f));
//			}
//
//			if (settings->drawContactNormals == 1)
//			{
//				b2Vec2 p1 = point->position;
//				b2Vec2 p2 = p1 + k_axisScale * point->normal;
//				g_debugDraw. DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f));
//			}
//			else if (settings->drawContactImpulse == 1)
//			{
//				b2Vec2 p1 = point->position;
//				b2Vec2 p2 = p1 + k_impulseScale * point->normalImpulse * point->normal;
//				g_debugDraw. DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
//			}
//
//			if (settings->drawFrictionImpulse == 1)
//			{
//				b2Vec2 tangent = b2Cross(point->normal, 1.0f);
//				b2Vec2 p1 = point->position;
//				b2Vec2 p2 = p1 + k_impulseScale * point->tangentImpulse * tangent;
//				g_debugDraw. DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
//			}
//		}
//	}
//}
//
//void Test::ShiftOrigin(const b2Vec2& newOrigin)
//{
//	m_world->ShiftOrigin(newOrigin);
//}


end.