Files
lace/3-mid/physics/implement/box2d/source/c/box2d-space.cpp
2023-12-31 21:18:19 +11:00

460 lines
9.5 KiB
C++

#include "box2d-space.h"
#include "box2d-conversions.h"
#include <box2d/box2d.h>
#include "box2d-object-private.h"
#include <stdio.h>
///////////////
/// Conversions
//
b2World*
to_World (Space* From)
{
return (b2World*) From;
}
Space*
to_Space (b2World* From)
{
return (Space*) From;
}
///////////////
/// C++ Support
//
/// Raycasts
//
class my_raycast_Callback : public b2RayCastCallback
{
public:
b2Fixture* Nearest;
float
ReportFixture (b2Fixture* fixture,
const b2Vec2& point,
const b2Vec2& normal,
float fraction)
{
Nearest = fixture;
return fraction;
}
};
/// Collisions
//
const int32 k_maxContactPoints = 4 * 2048;
struct ContactPoint
{
b2Fixture* fixtureA;
b2Fixture* fixtureB;
b2Vec2 normal;
b2Vec2 position;
b2PointState state;
float normalImpulse;
float tangentImpulse;
float separation;
};
class contact_Listener : public b2ContactListener
{
public:
contact_Listener();
virtual ~contact_Listener();
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);
}
ContactPoint m_points[k_maxContactPoints];
int32 m_pointCount;
};
contact_Listener::
contact_Listener()
{
m_pointCount = 0;
}
contact_Listener::
~contact_Listener()
{
}
void
contact_Listener::
PreSolve (b2Contact* contact,
const b2Manifold* oldManifold)
{
if (m_pointCount == k_maxContactPoints)
return;
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);
ContactPoint* cp = m_points + m_pointCount;
cp->fixtureA = fixtureA;
cp->fixtureB = fixtureB;
cp->position.SetZero();
for (int32 i = 0; i < manifold->pointCount; ++i)
{
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];
}
if (manifold->pointCount > 1)
cp->position *= (1.0 / float (manifold->pointCount)); // Calculate middle site.
++m_pointCount;
}
///////////////
/// C Interface
//
extern "C"
{
int
b2d_space_contact_Count (Space* Self)
{
b2World* the_World = to_World (Self);
contact_Listener* the_contact_Listener = dynamic_cast <contact_Listener*> (the_World->GetContactManager().m_contactListener);
return the_contact_Listener->m_pointCount;
}
b2d_Contact
b2d_space_Contact (Space* Self, int contact_Id)
{
b2World* the_World = to_World (Self);
contact_Listener* the_contact_Listener = dynamic_cast <contact_Listener*> (the_World->GetContactManager().m_contactListener);
ContactPoint* point = the_contact_Listener->m_points + contact_Id;
b2Body* body1 = point->fixtureA->GetBody();
b2Body* body2 = point->fixtureB->GetBody();
b2d_Contact the_Contact;
the_Contact.Object_A = (Object*) (body1->GetUserData().pointer);
the_Contact.Object_B = (Object*) (body2->GetUserData().pointer);
the_Contact.Site.x = point->position.x;
the_Contact.Site.y = point->position.y;
the_Contact.Site.z = 0.0;
return the_Contact;
}
struct Space*
b2d_new_Space ()
{
b2World* Self = new b2World (b2Vec2 (0.0, -9.8));
Self->SetContactListener (new contact_Listener());
return to_Space (Self);
}
void
b2d_free_Space (struct Space* Self)
{
b2World* the_World = to_World (Self);
delete the_World->GetContactManager().m_contactListener;
delete the_World;
}
void
b2d_Space_Gravity_is (Space* Self,
Vector_3* Now)
{
b2World* the_World = to_World (Self);
the_World->SetGravity (b2Vec2 (Now->x, Now->y));
}
void
b2d_Space_evolve (Space* Self,
float By)
{
b2World* the_World = to_World (Self);
contact_Listener* the_contact_Listener = dynamic_cast <contact_Listener*> (the_World->GetContactManager().m_contactListener);
the_contact_Listener->m_pointCount = 0;
the_World->Step (By, 6, 2);
}
void
b2d_Space_add_Object (Space* Self,
Object* the_Object)
{
b2World* the_World = (b2World*) Self;
the_Object->body = the_World->CreateBody (&the_Object->bodyDef);
the_Object->body->SetUserData (the_Object);
the_Object->body->CreateFixture (&the_Object->fixtureDef);
}
void
b2d_Space_rid_Object (Space* Self,
Object* the_Object)
{
((b2World*)Self)->DestroyBody (the_Object->body);
the_Object->body = 0;
}
void
b2d_Space_add_Joint (Space* Self,
Joint* the_Joint)
{
b2World* the_World = (b2World*) Self;
b2JointDef* jointDef = (b2JointDef*) the_Joint;
Object* Object_A = (Object*) jointDef->bodyA;
Object* Object_B = (Object*) jointDef->bodyB;
jointDef->bodyA = Object_A->body;
jointDef->bodyB = Object_B->body;
if (jointDef->type == e_revoluteJoint)
{
b2RevoluteJointDef* revolute_Def = static_cast <b2RevoluteJointDef*> (jointDef);
b2RevoluteJoint* the_Joint;
the_Joint = (b2RevoluteJoint*) the_World->CreateJoint (revolute_Def);
jointDef->userData.pointer = (uintptr_t) dynamic_cast <b2Joint*> (the_Joint);
}
else
{
printf ("TODO: b2d_Space_add_Joint");
}
}
void
b2d_Space_rid_Joint (Space* Self, Joint* the_Joint)
{
b2World* the_World = (b2World*) Self;
b2JointDef* the_Joint_Def = (b2JointDef*) the_Joint;
b2Joint* b2d_Joint = (b2Joint*) the_Joint_Def->userData.pointer;
Object* Object_A = (Object*) the_Joint_Def->bodyA->GetUserData().pointer;
Object* Object_B = (Object*) the_Joint_Def->bodyB->GetUserData().pointer;
the_World->DestroyJoint (b2d_Joint);
the_Joint_Def->bodyA = (b2Body*) Object_A;
the_Joint_Def->bodyB = (b2Body*) Object_B;
}
void*
b2d_b2Joint_user_Data (b2Joint* the_Joint)
{
return (void*) the_Joint->GetUserData().pointer;
}
/// Joint Cursor
//
joint_Cursor
b2d_Space_first_Joint (Space* Self)
{
b2World* the_World = (b2World*) Self;
return {the_World->GetJointList()};
}
void
b2d_Space_next_Joint (joint_Cursor* Cursor)
{
Cursor->Joint = Cursor->Joint->GetNext();
}
b2Joint*
b2d_Space_joint_Element (joint_Cursor* Cursor)
{
return Cursor->Joint;
}
/// Raycasts
//
b2d_ray_Collision
b2d_Space_cast_Ray (Space* Self, Vector_3* From,
Vector_3* To)
{
b2World* the_World = (b2World*) Self;
my_raycast_Callback the_Callback;
the_Callback.Nearest = 0;
the_World->RayCast (&the_Callback,
b2Vec2 (From->x, From->y),
b2Vec2 (To ->x, To ->y));
b2d_ray_Collision the_Collision;
if (the_Callback.Nearest == 0)
the_Collision.near_Object = 0;
else
the_Collision.near_Object = (Object*) (the_Callback.Nearest->GetBody()->GetUserData().pointer);
the_Collision.hit_Fraction = 0.0;
the_Collision.Normal_world = Vector_3 (0.0, 0.0, 0.0);
the_Collision.Site_world = Vector_3 (0.0, 0.0, 0.0);
return the_Collision;
}
/// Pointcasts
//
class QueryCallback : public b2QueryCallback
{
public:
QueryCallback (const b2Vec2& point)
{
m_point = point;
m_fixture = NULL;
}
bool
ReportFixture (b2Fixture* fixture) override
{
b2Body* body = fixture->GetBody();
bool inside = fixture->TestPoint (m_point);
if (inside)
{
m_fixture = fixture;
return false; // We are done, terminate the query.
}
return true; // Continue the query.
}
b2Vec2 m_point;
b2Fixture* m_fixture;
};
b2d_point_Collision
b2d_Space_cast_Point (Space* Self,
Vector_3* Point)
{
b2d_point_Collision Result;
b2World* the_World = (b2World *)Self;
const b2Vec2 p = b2Vec2 (Point->x,
Point->y);
// Make a small box.
//
b2AABB aabb;
b2Vec2 d;
d.Set (0.001f, 0.001f);
aabb.lowerBound = p - d;
aabb.upperBound = p + d;
printf ("\n");
printf ("b2d_Space_cast_Point ~ p = %f %f\n", p.x, p.y);
// Query the world for overlapping shapes.
//
QueryCallback Callback (p);
the_World->QueryAABB (&Callback, aabb);
if (Callback.m_fixture)
{
Result.near_Object = (Object*) Callback.m_fixture->GetBody()->GetUserData().pointer;
}
else
{
Result.near_Object = NULL;
}
Result.Site_world = *Point;
return Result;
}
} // extern "C"