iPhoneTestEntries.mm
*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//
// File modified for cocos2d integration
// http://www.cocos2d-iphone.org
//
#include "iPhoneTest.h"
//#include "GLES-Render.h"
#include "AddPair.h"
#include "ApplyForce.h"
#include "BodyTypes.h"
#include "Breakable.h"
#include "Bridge.h"
#include "BulletTest.h"
#include "Cantilever.h"
#include "Car.h"
#include "ContinuousTest.h"
#include "Chain.h"
#include "CharacterCollision.h"
#include "CollisionFiltering.h"
#include "CollisionProcessing.h"
#include "CompoundShapes.h"
#include "Confined.h"
#include "DistanceTest.h"
#include "Dominos.h"
#include "DynamicTreeTest.h"
#include "EdgeShapes.h"
#include "EdgeTest.h"
#include "Gears.h"
#include "OneSidedPlatform.h"
#include "Pinball.h"
#include "PolyCollision.h"
#include "PolyShapes.h"
#include "Prismatic.h"
#include "Pulleys.h"
#include "Pyramid.h"
#include "RayCast.h"
#include "Revolute.h"
//#include "Rope.h"
#include "RopeJoint.h"
#include "SensorTest.h"
#include "ShapeEditing.h"
#include "SliderCrank.h"
#include "SphereStack.h"
#include "TheoJansen.h"
#include "Tiles.h"
#include "TimeOfImpact.h"
#include "VaryingFriction.h"
#include "VaryingRestitution.h"
#include "VerticalStack.h"
#include "Web.h"
TestEntry g_testEntries[] =
{
{"Gears", Gears::Create},
{"Character Collision",CharacterCollision::Create},
{"Edge Test",EdgeTest::Create},
{"Body Types",BodyTypes::Create},
{"Shape Editing",ShapeEditing::Create},
{"Tiles", Tiles::Create},
{"Car", Car::Create},
{"Apply Force",ApplyForce::Create},
{"Prismatic",Prismatic::Create},
{"Vertical Stack",VerticalStack::Create},
{"SphereStack",SphereStack::Create},
{"Revolute", Revolute::Create},
{"Pulleys", Pulleys::Create},
{"Polygon Shapes",PolyShapes::Create},
//{"Rope", Rope::Create},
{"Web", Web::Create},
{"RopeJoint",RopeJoint::Create},
{"One-Sided Platform",OneSidedPlatform::Create},
{"Pinball", Pinball::Create},
{"Bullet Test",BulletTest::Create},
{"Continuous Test",ContinuousTest::Create},
{"Time of Impact",TimeOfImpact::Create},
{"Ray-Cast", RayCast::Create},
{"Confined", Confined::Create},
{"Pyramid", Pyramid::Create},
{"Varying Restitution",VaryingRestitution::Create},
{"Theo Jansen's Walker",TheoJansen::Create},
{"Edge Shapes",EdgeShapes::Create},
{"PolyCollision",PolyCollision::Create},
{"Cantilever",Cantilever::Create},
{"Bridge", Bridge::Create},
{"Breakable",Breakable::Create},
{"Chain", Chain::Create},
{"Collision Filtering",CollisionFiltering::Create},
{"Collision Processing",CollisionProcessing::Create},
{"Compound Shapes",CompoundShapes::Create},
{"Distance Test",DistanceTest::Create},
{"Dominos", Dominos::Create},
{"Dynamic Tree",DynamicTreeTest::Create},
{"Sensor Test",SensorTest::Create},
{"Slider Crank",SliderCrank::Create},
{"Varying Friction",VaryingFriction::Create},
{"Add Pair Stress Test",AddPair::Create},
// {NULL, NULL}
};
int g_totalEntries = sizeof(g_testEntries) /sizeof(g_testEntries[0]);
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//
// File modified for cocos2d integration
// http://www.cocos2d-iphone.org
//
#ifndef TEST_H
#define TEST_H
#import <UIKit/UIKit.h>
#include <Box2D/Box2D.h>
#include "GLES-Render.h"
#include <cstdlib>
class Test;
struct Settings;
typedef Test* TestCreateFcn();
#define RAND_LIMIT 32767
/// Random number in range [-1,1]
inline float32 RandomFloat()
{
float32 r = (float32)(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)(rand() & (RAND_LIMIT));
r /= RAND_LIMIT;
r = (hi - lo) * r + lo;
return r;
}
/// Test settings. Some can be controlled in the GUI.
/// Test settings. Some can be controlled in the GUI.
struct Settings
{
Settings() :
viewCenter(0.0f,20.0f),
hz(60.0f),
velocityIterations(8),
positionIterations(3),
drawShapes(1),
drawJoints(1),
drawAABBs(0),
drawPairs(0),
drawContactPoints(0),
drawContactNormals(0),
drawContactForces(0),
drawFrictionForces(0),
drawCOMs(0),
drawStats(0),
drawProfile(0),
enableWarmStarting(1),
enableContinuous(1),
enableSubStepping(0),
pause(0),
singleStep(0)
{}
b2Vec2 viewCenter;
float32 hz;
int32 velocityIterations;
int32 positionIterations;
int32 drawShapes;
int32 drawJoints;
int32 drawAABBs;
int32 drawPairs;
int32 drawContactPoints;
int32 drawContactNormals;
int32 drawContactForces;
int32 drawFrictionForces;
int32 drawCOMs;
int32 drawStats;
int32 drawProfile;
int32 enableWarmStarting;
int32 enableContinuous;
int32 enableSubStepping;
int32 pause;
int32 singleStep;
};
struct TestEntry
{
const char *name;
TestCreateFcn *createFcn;
};
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;
};
class Test : publicb2ContactListener
{
public:
Test();
virtual ~Test();
void SetGravity(float x,float y);// iPhone specific
void SetTextLine(int32 line) {m_textLine = line; }
void DrawTitle(int x,int y, const char *string);
virtual void Step(Settings* settings);
virtual void Keyboard(unsigned char key) {B2_NOT_USED(key); }
void ShiftMouseDown(constb2Vec2& p);
virtualbool MouseDown(constb2Vec2& p); // cocos2d modifications
virtual void MouseUp(const b2Vec2& p);
void MouseMove(constb2Vec2& p);
void LaunchBomb();
void LaunchBomb(constb2Vec2& position, const b2Vec2& velocity);
void SpawnBomb(constb2Vec2& worldPt);
void CompleteBombSpawn(constb2Vec2& 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(const b2Contact* contact,const b2ContactImpulse* impulse)
{
B2_NOT_USED(contact);
B2_NOT_USED(impulse);
}
b2World* m_world;// cocos2d specific
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;
GLESDebugDraw m_debugDraw;
int32 m_textLine;
b2Body* m_bomb;
b2MouseJoint* m_mouseJoint;
b2Vec2 m_bombSpawnPoint;
bool m_bombSpawning;
b2Vec2 m_mouseWorld;
int32 m_stepCount;
};
#endif
iPhoneTest.mm
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//
// File modified for cocos2d integration
// http://www.cocos2d-iphone.org
//
#include "iPhoneTest.h"
#include "GLES-Render.h"
#include <cstdio>
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 = newb2World(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(&m_debugDraw);
m_bombSpawning = false;
m_stepCount = 0;
b2BodyDef bodyDef;
m_groundBody = m_world->CreateBody(&bodyDef);
}
Test::~Test()
{
// By deleting the world, we delete the bomb, mouse joint, etc.
deletem_world;
m_world = NULL;
}
void Test::SetGravity(float x, float y)
{
float tVectorLength=sqrtf(x*x+y*y);
float newGravityX=9.81f*x/tVectorLength;
float newGravityY=9.81f*y/tVectorLength;
m_world->SetGravity(b2Vec2(newGravityX,newGravityY));
}
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];
++m_pointCount;
}
}
void Test::DrawTitle(int x,int y, const char *string)
{
m_debugDraw.DrawString(x, y, string);
}
class QueryCallback : publicb2QueryCallback
{
public:
QueryCallback(constb2Vec2& 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.
returnfalse;
}
}
// Continue the query.
returntrue;
}
b2Vec2 m_point;
b2Fixture* m_fixture;
};
bool Test::MouseDown(constb2Vec2& p)
{
m_mouseWorld = p;
if (m_mouseJoint !=NULL)
{
returnfalse;
}
// 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);
returntrue;
}
return false;
}
void Test::SpawnBomb(constb2Vec2& worldPt)
{
m_bombSpawnPoint = worldPt;
m_bombSpawning = true;
}
void Test::CompleteBombSpawn(constb2Vec2& 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(constb2Vec2& p)
{
m_mouseWorld = p;
if (m_mouseJoint !=NULL)
{
return;
}
SpawnBomb(p);
}
void Test::MouseUp(constb2Vec2& p)
{
if (m_mouseJoint)
{
m_world->DestroyJoint(m_mouseJoint);
m_mouseJoint =NULL;
}
if (m_bombSpawning)
{
CompleteBombSpawn(p);
}
}
void Test::MouseMove(constb2Vec2& 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(constb2Vec2& 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;
}
m_debugDraw.DrawString(5,m_textLine, "****PAUSED****");
m_textLine +=15;
}
uint32 flags = 0;
flags += settings->drawShapes* b2Draw::e_shapeBit;
flags += settings->drawJoints* b2Draw::e_jointBit;
flags += settings->drawAABBs* b2Draw::e_aabbBit;
flags += settings->drawPairs* b2Draw::e_pairBit;
flags += settings->drawCOMs* b2Draw::e_centerOfMassBit;
m_debugDraw.SetFlags(flags);
m_world->SetWarmStarting(settings->enableWarmStarting >0);
m_world->SetContinuousPhysics(settings->enableContinuous >0);
m_pointCount = 0;
m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
// m_world->DrawDebugData();
if (timeStep > 0.0f)
{
++m_stepCount;
}
if (settings->drawStats)
{
m_debugDraw.DrawString(5,m_textLine, "bodies/contacts/joints/proxies = %d/%d/%d",
m_world->GetBodyCount(),m_world->GetContactCount(),m_world->GetJointCount(),m_world->GetProxyCount());
m_textLine +=15;
}
if (m_mouseJoint)
{
// b2Body* body = m_mouseJoint->GetBodyB();
// b2Vec2 p1 = body->GetWorldPoint(m_mouseJoint->m_localAnchor);
// b2Vec2 p2 = m_mouseJoint->m_target;
//
// glPointSize(4.0f);
// glColor3f(0.0f, 1.0f, 0.0f);
// glBegin(GL_POINTS);
// glVertex2f(p1.x, p1.y);
// glVertex2f(p2.x, p2.y);
// glEnd();
// glPointSize(1.0f);
//
// glColor3f(0.8f, 0.8f, 0.8f);
// glBegin(GL_LINES);
// glVertex2f(p1.x, p1.y);
// glVertex2f(p2.x, p2.y);
// glEnd();
}
if (m_bombSpawning)
{
// glPointSize(4.0f);
// glColor3f(0.0f, 0.0f, 1.0f);
// glBegin(GL_POINTS);
// glColor3f(0.0f, 0.0f, 1.0f);
// glVertex2f(m_bombSpawnPoint.x, m_bombSpawnPoint.y);
// glEnd();
//
// glColor3f(0.8f, 0.8f, 0.8f);
// glBegin(GL_LINES);
// glVertex2f(m_mouseWorld.x, m_mouseWorld.y);
// glVertex2f(m_bombSpawnPoint.x, m_bombSpawnPoint.y);
// glEnd();
}
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
m_debugDraw.DrawPoint(point->position,10.0f, b2Color(0.3f,0.95f, 0.3f));
}
elseif (point->state == b2_persistState)
{
// Persist
m_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;
m_debugDraw.DrawSegment(p1, p2,b2Color(0.4f, 0.9f,0.4f));
}
elseif (settings->drawContactForces ==1)
{
//b2Vec2 p1 = point->position;
//b2Vec2 p2 = p1 + k_forceScale * point->normalForce * point->normal;
//DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
}
if (settings->drawFrictionForces ==1)
{
//b2Vec2 tangent = b2Cross(point->normal, 1.0f);
//b2Vec2 p1 = point->position;
//b2Vec2 p2 = p1 + k_forceScale * point->tangentForce * tangent;
//DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
}
}
}
}