MBED port of the Physacs library

README.md

Committer:
jstephens78
Date:
19 months ago
Revision:
1:ebc0214989c0
Parent:
0:e39efa4f4f58

File content as of revision 1:ebc0214989c0:

<img src="https://github.com/victorfisac/Physac/blob/master/icon/physac_256x256.png">

# Physac-MBED
This is a port of the Physac physics library to the MBED platform.

## Resource Usage
The following outlines are based on defaults settings described under
[##Modifications], and can be used to gauge resource demands of using Physac-MBED:
 - Each `PhysicsBody` requires 172 bytes of memory. Unless calling PhysicsShatter,
   these are always generated by user.
 - Each `PhysicsManifold` requires 56 bytes. These are generated internally during
   collisions to represent how the PhysicsBodys are interacting.

## Modifications
The original Physac library was altered in the following ways to get running and
to reduce footprint:
 - `PHYSAC_MAX_BODIES` was set to 16
 - `PHYSAC_MAX_MANIFOLDS` was set to 96
 - `PHYSAC_MAX_VERTICES` was set to 4
 - `PHYSAC_CIRCLE_VERTICES` was set to 12

Physac-MBED can represent only collision shapes which are triangles, rectangles,
or circles in its out-of-the-box configuration.

## Using Physac
A simple demo using Physac-MBED to simulate objects and render them to a uLCD
display:
```c++
#include "mbed.h"
#include "uLCD_4DGL.h"

#define PHYSAC_NO_THREADS
#define PHYSAC_STANDALONE
#define PHYSAC_IMPLEMENTATION
#define _STDBOOL_H
#include "physac.h"

uLCD_4DGL uLCD(p9,p10,p30);

int main(void)
{
    uLCD.baudrate(BAUD_3000000);
    wait(.05);

    int screenWidth = 128;
    int screenHeight = 128;
    PhysicsBody floor = CreatePhysicsBodyRectangle((Vector2) {
        screenWidth/2, screenHeight - 4
    }, screenWidth - 2, 4, 100);
    floor->enabled = false;             // make object static

    // Defines which objects to create in the demo, and their initial properties
    //  { x, y, density, rot, v_x, v_y }
    const size_t objs_n = 5;
    size_t objs_rect_n = 4;
    float objs_init[objs_n][6] = {
        { 48,   0,   10,   PHYSAC_PI / 4,  0,     0 },
        { 48,   64,  10,   0,              0,     0 },
        { 92,   0,   10,   0,              0,     0 },
        { 80,   48,  10,   PHYSAC_PI / 4,  0,     0 },
        { 256,  0,   30,  0,              -.75,  -.5 },
    };
    PhysicsBody objs[objs_n];

    // Create demo objects
    for (int i = 0; i < objs_n; i++) {
        if (i < objs_rect_n) {
            objs[i] = CreatePhysicsBodyRectangle((Vector2) {
                objs_init[i][0], objs_init[i][1]
            }, 24, 24, objs_init[i][2]);
        } else {
            objs[i] = CreatePhysicsBodyCircle((Vector2) {
                objs_init[i][0], objs_init[i][1]
            }, 12, objs_init[i][2]);
        }
        SetPhysicsBodyRotation(objs[i], objs_init[i][3]);
        objs[i]->velocity.x = objs_init[i][4];
        objs[i]->velocity.y = objs_init[i][5];
    }

    // Simulation Loop
    Timer timer;
    timer.start();

    // Time per step in ms
    deltaTime = 2.5;

    while (true) {
        float dt = timer.read() * 1000;
        timer.reset();

        // In this demo, rendering takes orders of magnitudes longer than
        // physics takes to compute. So we run several steps per frame.
        for (int i = 0; i < 8; i++) {
            PhysicsStep();
        }
        float phys_time = timer.read() * 1000;

        // Draw physics bodies
        uLCD.cls();
        int bodiesCount = GetPhysicsBodiesCount();
        for (int i = 0; i < bodiesCount; i++) {
            PhysicsBody body = GetPhysicsBody(i);

            if (body != NULL) {
                int vertexCount = GetPhysicsShapeVerticesCount(i);
                for (int j = 0; j < vertexCount; j++) {
                    // Get physics bodies shape vertices to draw lines
                    // Note: GetPhysicsShapeVertex() already calculates rotation transformations
                    Vector2 vertexA = GetPhysicsShapeVertex(body, j);

                    int jj = (((j + 1) < vertexCount) ? (j + 1) : 0);   // Get next vertex or first to close the shape
                    Vector2 vertexB = GetPhysicsShapeVertex(body, jj);

                    uLCD.line(vertexA.x, vertexA.y, vertexB.x, vertexB.y, GREEN);     // Draw a line between two vertex positions
                }
            }
        }
        float render_time = timer.read()*1000 - phys_time;

        printf("[%2.2f] Phys: %4.4f Render: %4.4f\r\n",
                  dt,
                  phys_time,
                  render_time);
    }

    ClosePhysics();       // Unitialize physics
}
```

### Use in multi-file projects:
**Note**: the `PHYSAC_IMPLEMENTATION` macro will cause the definitions of all
the internal functions of Physac to be included. This should **only be done once,
from .cpp file**. For example:
```c++
// myheader.h
#define PHYSAC_NO_THREADS
#define PHYSAC_STANDALONE
#define _STDBOOL_H
#include "physac.h"     // this includes only the declarations

------

// myfile.cpp
#include "myheader.h"

#define PHYSAC_IMPLEMENTATION
#include "physac.h"     // this includes the definitions
```

## Future work
Possible future improvements to this port:

 1. Re-work allocation scheme so users can pre-allocate arrays of bodies and
    manifolds

 2. Implement a partial collision reporting scheme.
 
    Presently in `PhysicsStep()`, all bodies are iterated, a manifold is generated
    for every collision, and *then* manifolds are iteratively resolved. This is
    necessary for "correct" resolution of collisions in sequence with velocity,
    but this requires a lot of working memory.
    
    A possible trade-off would be to iterate bodies only until a certain number
    of manifolds are generated, then updating those bodies. This would reduce the
    resource demands for large scenes, at the expense of accuracy.


# Physac

Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop to simluate physics.
A physics step contains the following phases: get collision information, apply dynamics, collision solving and position correction. It uses a very simple struct for physic bodies with a position vector to be used in any 3D rendering API.

The header file includes some tweakable define values to fit the results that the user wants with a minimal bad results. Most of those values are commented with a little explanation about their uses.

Physac API
-----

The PhysicsBody struct contains all dynamics information and collision shape. The user should use the following structure components:
```c
typedef struct *PhysicsBody {
    unsigned int id;
    bool enabled;                   // Enabled dynamics state (collisions are calculated anyway)
    Vector2 position;               // Physics body shape pivot
    Vector2 velocity;               // Current linear velocity applied to position
    Vector2 force;                  // Current linear force (reset to 0 every step)
    float angularVelocity;          // Current angular velocity applied to orient
    float torque;                   // Current angular force (reset to 0 every step)
    float orient;                   // Rotation in radians
    float staticFriction;           // Friction when the body has no movement (0 to 1)
    float dynamicFriction;          // Friction when the body has movement (0 to 1)
    float restitution;              // Restitution coefficient of the body (0 to 1)
    bool useGravity;                // Apply gravity force to dynamics
    bool isGrounded;                // Physics grounded on other body state
    bool freezeOrient;              // Physics rotation constraint
    PhysicsShape shape;             // Physics body shape information (type, radius, vertices, normals)
} *PhysicsBody;
```

The header contains a few customizable define values. I set the values that gived me the best results.
```c
#define     PHYSAC_MAX_BODIES               64
#define     PHYSAC_MAX_MANIFOLDS            4096
#define     PHYSAC_MAX_VERTICES             24
#define     PHYSAC_CIRCLE_VERTICES          24

#define     PHYSAC_COLLISION_ITERATIONS     100
#define     PHYSAC_PENETRATION_ALLOWANCE    0.05f
#define     PHYSAC_PENETRATION_CORRECTION   0.4f
```

Physac contains defines for memory management functions (malloc, free) to bring the user the opportunity to implement its own memory functions:

```c
#define     PHYSAC_MALLOC(size)             malloc(size)
#define     PHYSAC_FREE(ptr)                free(ptr)
```

The Physac API functions availables for the user are the following:

```c
// Initializes physics values, pointers and creates physics loop thread
void InitPhysics(void);

// Returns true if physics thread is currently enabled
bool IsPhysicsEnabled(void);

// Sets physics global gravity force
void SetPhysicsGravity(float x, float y);

// Creates a new circle physics body with generic parameters
PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density);

// Creates a new rectangle physics body with generic parameters
PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density);

// Creates a new polygon physics body with generic parameters
PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density);

// Adds a force to a physics body
void PhysicsAddForce(PhysicsBody body, Vector2 force);

// Adds a angular force to a physics body
void PhysicsAddTorque(PhysicsBody body, float amount);

// Shatters a polygon shape physics body to little physics bodies with explosion force
void PhysicsShatter(PhysicsBody body, Vector2 position, float force);

// Returns the current amount of created physics bodies
int GetPhysicsBodiesCount(void);

// Returns a physics body of the bodies pool at a specific index
PhysicsBody GetPhysicsBody(int index);

// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON)
int GetPhysicsShapeType(int index);

// Returns the amount of vertices of a physics body shape
int GetPhysicsShapeVerticesCount(int index);

// Returns transformed position of a body shape (body position + vertex transformed position)
Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex);

// Sets physics body shape transform based on radians parameter
void SetPhysicsBodyRotation(PhysicsBody body, float radians);

// Unitializes and destroy a physics body
void DestroyPhysicsBody(PhysicsBody body);

// Unitializes physics pointers and closes physics loop thread
void ClosePhysics(void);
```
_Note: InitPhysics() needs to be called at program start and ClosePhysics() before the program ends. Closing and initializing Physac during the program flow doesn't affect or produces any error (useful as a 'reset' to destroy any created body by user in runtime)._

Dependencies
-----

Physac uses the following C libraries for memory management, math operations and some debug features:

   *  stdlib.h - Memory allocation [malloc(), free(), srand(), rand()].
   *  stdio.h  - Message logging (only if PHYSAC_DEBUG is defined) [printf()].
   *  math.h   - Math operations functions [cos(), sin(), fabs(), sqrtf()].