Initial window setup

This commit is contained in:
2026-01-11 16:10:52 +01:00
commit 6b6f8b8b5f
13 changed files with 18959 additions and 0 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.so.* filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build/

16
CMakeLists.txt Normal file
View File

@@ -0,0 +1,16 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.20)
set( CMAKE_EXPORT_COMPILE_COMMANDS on)
project(Pacman)
add_executable(Pacman src/main.c)
target_link_libraries( Pacman
X11
GL
Xrandr
)
target_include_directories(Pacman
PRIVATE "libs/rgfw/"
)

0
README.md Normal file
View File

View File

@@ -0,0 +1,139 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT
#pragma once
#include <stdint.h>
// clang-format off
//
// Shared library macros
#if defined( _MSC_VER ) && defined( box2d_EXPORTS )
// build the Windows DLL
#define BOX2D_EXPORT __declspec( dllexport )
#elif defined( _MSC_VER ) && defined( BOX2D_DLL )
// using the Windows DLL
#define BOX2D_EXPORT __declspec( dllimport )
#elif defined( box2d_EXPORTS )
// building or using the shared library
#define BOX2D_EXPORT __attribute__( ( visibility( "default" ) ) )
#else
// static library
#define BOX2D_EXPORT
#endif
// C++ macros
#ifdef __cplusplus
#define B2_API extern "C" BOX2D_EXPORT
#define B2_INLINE inline
#define B2_LITERAL(T) T
#define B2_ZERO_INIT {}
#else
#define B2_API BOX2D_EXPORT
#define B2_INLINE static inline
/// Used for C literals like (b2Vec2){1.0f, 2.0f} where C++ requires b2Vec2{1.0f, 2.0f}
#define B2_LITERAL(T) (T)
#define B2_ZERO_INIT {0}
#endif
// clang-format on
/**
* @defgroup base Base
* Base functionality
* @{
*/
/// Prototype for user allocation function
/// @param size the allocation size in bytes
/// @param alignment the required alignment, guaranteed to be a power of 2
typedef void* b2AllocFcn( unsigned int size, int alignment );
/// Prototype for user free function
/// @param mem the memory previously allocated through `b2AllocFcn`
/// @param size the allocation size in bytes
typedef void b2FreeFcn( void* mem, unsigned int size );
/// Prototype for the user assert callback. Return 0 to skip the debugger break.
typedef int b2AssertFcn( const char* condition, const char* fileName, int lineNumber );
/// Prototype for user log callback. Used to log warnings.
typedef void b2LogFcn( const char* message );
/// This allows the user to override the allocation functions. These should be
/// set during application startup.
B2_API void b2SetAllocator( b2AllocFcn* allocFcn, b2FreeFcn* freeFcn );
/// @return the total bytes allocated by Box2D
B2_API int b2GetByteCount( void );
/// Override the default assert function
/// @param assertFcn a non-null assert callback
B2_API void b2SetAssertFcn( b2AssertFcn* assertFcn );
/// Override the default log function
/// @param logFcn a non-null log callback
B2_API void b2SetLogFcn( b2LogFcn* logFcn );
/// Version numbering scheme.
/// See https://semver.org/
typedef struct b2Version
{
/// Significant changes
int major;
/// Incremental changes
int minor;
/// Bug fixes
int revision;
} b2Version;
/// Get the current version of Box2D
B2_API b2Version b2GetVersion( void );
/**@}*/
//! @cond
// see https://github.com/scottt/debugbreak
#if defined( _MSC_VER )
#define B2_BREAKPOINT __debugbreak()
#elif defined( __GNUC__ ) || defined( __clang__ )
#define B2_BREAKPOINT __builtin_trap()
#else
// Unknown compiler
#include <assert.h>
#define B2_BREAKPOINT assert( 0 )
#endif
#if !defined( NDEBUG ) || defined( B2_ENABLE_ASSERT )
B2_API int b2InternalAssertFcn( const char* condition, const char* fileName, int lineNumber );
#define B2_ASSERT( condition ) \
do \
{ \
if ( !( condition ) && b2InternalAssertFcn( #condition, __FILE__, (int)__LINE__ ) ) \
B2_BREAKPOINT; \
} \
while ( 0 )
#else
#define B2_ASSERT( ... ) ( (void)0 )
#endif
/// Get the absolute number of system ticks. The value is platform specific.
B2_API uint64_t b2GetTicks( void );
/// Get the milliseconds passed from an initial tick value.
B2_API float b2GetMilliseconds( uint64_t ticks );
/// Get the milliseconds passed from an initial tick value. Resets the passed in
/// value to the current tick value.
B2_API float b2GetMillisecondsAndReset( uint64_t* ticks );
/// Yield to be used in a busy loop.
B2_API void b2Yield( void );
/// Simple djb2 hash function for determinism testing
#define B2_HASH_INIT 5381
B2_API uint32_t b2Hash( uint32_t hash, const uint8_t* data, int count );
//! @endcond

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,851 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT
#pragma once
#include "base.h"
#include "math_functions.h"
#include <stdbool.h>
typedef struct b2SimplexCache b2SimplexCache;
typedef struct b2Hull b2Hull;
/**
* @defgroup geometry Geometry
* @brief Geometry types and algorithms
*
* Definitions of circles, capsules, segments, and polygons. Various algorithms to compute hulls, mass properties, and so on.
* Functions should take the shape as the first argument to assist editor auto-complete.
* @{
*/
/// The maximum number of vertices on a convex polygon. Changing this affects performance even if you
/// don't use more vertices.
#define B2_MAX_POLYGON_VERTICES 8
/// Low level ray cast input data
typedef struct b2RayCastInput
{
/// Start point of the ray cast
b2Vec2 origin;
/// Translation of the ray cast
b2Vec2 translation;
/// The maximum fraction of the translation to consider, typically 1
float maxFraction;
} b2RayCastInput;
/// A distance proxy is used by the GJK algorithm. It encapsulates any shape.
/// You can provide between 1 and B2_MAX_POLYGON_VERTICES and a radius.
typedef struct b2ShapeProxy
{
/// The point cloud
b2Vec2 points[B2_MAX_POLYGON_VERTICES];
/// The number of points. Must be greater than 0.
int count;
/// The external radius of the point cloud. May be zero.
float radius;
} b2ShapeProxy;
/// Low level shape cast input in generic form. This allows casting an arbitrary point
/// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius.
/// A capsule is two points with a non-zero radius. A box is four points with a zero radius.
typedef struct b2ShapeCastInput
{
/// A generic shape
b2ShapeProxy proxy;
/// The translation of the shape cast
b2Vec2 translation;
/// The maximum fraction of the translation to consider, typically 1
float maxFraction;
/// Allow shape cast to encroach when initially touching. This only works if the radius is greater than zero.
bool canEncroach;
} b2ShapeCastInput;
/// Low level ray cast or shape-cast output data. Returns a zero fraction and normal in the case of initial overlap.
typedef struct b2CastOutput
{
/// The surface normal at the hit point
b2Vec2 normal;
/// The surface hit point
b2Vec2 point;
/// The fraction of the input translation at collision
float fraction;
/// The number of iterations used
int iterations;
/// Did the cast hit?
bool hit;
} b2CastOutput;
/// This holds the mass data computed for a shape.
typedef struct b2MassData
{
/// The mass of the shape, usually in kilograms.
float mass;
/// The position of the shape's centroid relative to the shape's origin.
b2Vec2 center;
/// The rotational inertia of the shape about the shape center.
float rotationalInertia;
} b2MassData;
/// A solid circle
typedef struct b2Circle
{
/// The local center
b2Vec2 center;
/// The radius
float radius;
} b2Circle;
/// A solid capsule can be viewed as two semicircles connected
/// by a rectangle.
typedef struct b2Capsule
{
/// Local center of the first semicircle
b2Vec2 center1;
/// Local center of the second semicircle
b2Vec2 center2;
/// The radius of the semicircles
float radius;
} b2Capsule;
/// A solid convex polygon. It is assumed that the interior of the polygon is to
/// the left of each edge.
/// Polygons have a maximum number of vertices equal to B2_MAX_POLYGON_VERTICES.
/// In most cases you should not need many vertices for a convex polygon.
/// @warning DO NOT fill this out manually, instead use a helper function like
/// b2MakePolygon or b2MakeBox.
typedef struct b2Polygon
{
/// The polygon vertices
b2Vec2 vertices[B2_MAX_POLYGON_VERTICES];
/// The outward normal vectors of the polygon sides
b2Vec2 normals[B2_MAX_POLYGON_VERTICES];
/// The centroid of the polygon
b2Vec2 centroid;
/// The external radius for rounded polygons
float radius;
/// The number of polygon vertices
int count;
} b2Polygon;
/// A line segment with two-sided collision.
typedef struct b2Segment
{
/// The first point
b2Vec2 point1;
/// The second point
b2Vec2 point2;
} b2Segment;
/// A line segment with one-sided collision. Only collides on the right side.
/// Several of these are generated for a chain shape.
/// ghost1 -> point1 -> point2 -> ghost2
typedef struct b2ChainSegment
{
/// The tail ghost vertex
b2Vec2 ghost1;
/// The line segment
b2Segment segment;
/// The head ghost vertex
b2Vec2 ghost2;
/// The owning chain shape index (internal usage only)
int chainId;
} b2ChainSegment;
/// Validate ray cast input data (NaN, etc)
B2_API bool b2IsValidRay( const b2RayCastInput* input );
/// Make a convex polygon from a convex hull. This will assert if the hull is not valid.
/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull
B2_API b2Polygon b2MakePolygon( const b2Hull* hull, float radius );
/// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid.
/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull
B2_API b2Polygon b2MakeOffsetPolygon( const b2Hull* hull, b2Vec2 position, b2Rot rotation );
/// Make an offset convex polygon from a convex hull. This will assert if the hull is not valid.
/// @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull
B2_API b2Polygon b2MakeOffsetRoundedPolygon( const b2Hull* hull, b2Vec2 position, b2Rot rotation, float radius );
/// Make a square polygon, bypassing the need for a convex hull.
/// @param halfWidth the half-width
B2_API b2Polygon b2MakeSquare( float halfWidth );
/// Make a box (rectangle) polygon, bypassing the need for a convex hull.
/// @param halfWidth the half-width (x-axis)
/// @param halfHeight the half-height (y-axis)
B2_API b2Polygon b2MakeBox( float halfWidth, float halfHeight );
/// Make a rounded box, bypassing the need for a convex hull.
/// @param halfWidth the half-width (x-axis)
/// @param halfHeight the half-height (y-axis)
/// @param radius the radius of the rounded extension
B2_API b2Polygon b2MakeRoundedBox( float halfWidth, float halfHeight, float radius );
/// Make an offset box, bypassing the need for a convex hull.
/// @param halfWidth the half-width (x-axis)
/// @param halfHeight the half-height (y-axis)
/// @param center the local center of the box
/// @param rotation the local rotation of the box
B2_API b2Polygon b2MakeOffsetBox( float halfWidth, float halfHeight, b2Vec2 center, b2Rot rotation );
/// Make an offset rounded box, bypassing the need for a convex hull.
/// @param halfWidth the half-width (x-axis)
/// @param halfHeight the half-height (y-axis)
/// @param center the local center of the box
/// @param rotation the local rotation of the box
/// @param radius the radius of the rounded extension
B2_API b2Polygon b2MakeOffsetRoundedBox( float halfWidth, float halfHeight, b2Vec2 center, b2Rot rotation, float radius );
/// Transform a polygon. This is useful for transferring a shape from one body to another.
B2_API b2Polygon b2TransformPolygon( b2Transform transform, const b2Polygon* polygon );
/// Compute mass properties of a circle
B2_API b2MassData b2ComputeCircleMass( const b2Circle* shape, float density );
/// Compute mass properties of a capsule
B2_API b2MassData b2ComputeCapsuleMass( const b2Capsule* shape, float density );
/// Compute mass properties of a polygon
B2_API b2MassData b2ComputePolygonMass( const b2Polygon* shape, float density );
/// Compute the bounding box of a transformed circle
B2_API b2AABB b2ComputeCircleAABB( const b2Circle* shape, b2Transform transform );
/// Compute the bounding box of a transformed capsule
B2_API b2AABB b2ComputeCapsuleAABB( const b2Capsule* shape, b2Transform transform );
/// Compute the bounding box of a transformed polygon
B2_API b2AABB b2ComputePolygonAABB( const b2Polygon* shape, b2Transform transform );
/// Compute the bounding box of a transformed line segment
B2_API b2AABB b2ComputeSegmentAABB( const b2Segment* shape, b2Transform transform );
/// Test a point for overlap with a circle in local space
B2_API bool b2PointInCircle( const b2Circle* shape, b2Vec2 point );
/// Test a point for overlap with a capsule in local space
B2_API bool b2PointInCapsule( const b2Capsule* shape, b2Vec2 point );
/// Test a point for overlap with a convex polygon in local space
B2_API bool b2PointInPolygon( const b2Polygon* shape, b2Vec2 point );
/// Ray cast versus circle shape in local space.
B2_API b2CastOutput b2RayCastCircle( const b2Circle* shape, const b2RayCastInput* input );
/// Ray cast versus capsule shape in local space.
B2_API b2CastOutput b2RayCastCapsule( const b2Capsule* shape, const b2RayCastInput* input );
/// Ray cast versus segment shape in local space. Optionally treat the segment as one-sided with hits from
/// the left side being treated as a miss.
B2_API b2CastOutput b2RayCastSegment( const b2Segment* shape, const b2RayCastInput* input, bool oneSided );
/// Ray cast versus polygon shape in local space.
B2_API b2CastOutput b2RayCastPolygon( const b2Polygon* shape, const b2RayCastInput* input );
/// Shape cast versus a circle.
B2_API b2CastOutput b2ShapeCastCircle(const b2Circle* shape, const b2ShapeCastInput* input );
/// Shape cast versus a capsule.
B2_API b2CastOutput b2ShapeCastCapsule( const b2Capsule* shape, const b2ShapeCastInput* input);
/// Shape cast versus a line segment.
B2_API b2CastOutput b2ShapeCastSegment( const b2Segment* shape, const b2ShapeCastInput* input );
/// Shape cast versus a convex polygon.
B2_API b2CastOutput b2ShapeCastPolygon( const b2Polygon* shape, const b2ShapeCastInput* input );
/// A convex hull. Used to create convex polygons.
/// @warning Do not modify these values directly, instead use b2ComputeHull()
typedef struct b2Hull
{
/// The final points of the hull
b2Vec2 points[B2_MAX_POLYGON_VERTICES];
/// The number of points
int count;
} b2Hull;
/// Compute the convex hull of a set of points. Returns an empty hull if it fails.
/// Some failure cases:
/// - all points very close together
/// - all points on a line
/// - less than 3 points
/// - more than B2_MAX_POLYGON_VERTICES points
/// This welds close points and removes collinear points.
/// @warning Do not modify a hull once it has been computed
B2_API b2Hull b2ComputeHull( const b2Vec2* points, int count );
/// This determines if a hull is valid. Checks for:
/// - convexity
/// - collinear points
/// This is expensive and should not be called at runtime.
B2_API bool b2ValidateHull( const b2Hull* hull );
/**@}*/
/**
* @defgroup distance Distance
* Functions for computing the distance between shapes.
*
* These are advanced functions you can use to perform distance calculations. There
* are functions for computing the closest points between shapes, doing linear shape casts,
* and doing rotational shape casts. The latter is called time of impact (TOI).
* @{
*/
/// Result of computing the distance between two line segments
typedef struct b2SegmentDistanceResult
{
/// The closest point on the first segment
b2Vec2 closest1;
/// The closest point on the second segment
b2Vec2 closest2;
/// The barycentric coordinate on the first segment
float fraction1;
/// The barycentric coordinate on the second segment
float fraction2;
/// The squared distance between the closest points
float distanceSquared;
} b2SegmentDistanceResult;
/// Compute the distance between two line segments, clamping at the end points if needed.
B2_API b2SegmentDistanceResult b2SegmentDistance( b2Vec2 p1, b2Vec2 q1, b2Vec2 p2, b2Vec2 q2 );
/// Used to warm start the GJK simplex. If you call this function multiple times with nearby
/// transforms this might improve performance. Otherwise you can zero initialize this.
/// The distance cache must be initialized to zero on the first call.
/// Users should generally just zero initialize this structure for each call.
typedef struct b2SimplexCache
{
/// The number of stored simplex points
uint16_t count;
/// The cached simplex indices on shape A
uint8_t indexA[3];
/// The cached simplex indices on shape B
uint8_t indexB[3];
} b2SimplexCache;
static const b2SimplexCache b2_emptySimplexCache = B2_ZERO_INIT;
/// Input for b2ShapeDistance
typedef struct b2DistanceInput
{
/// The proxy for shape A
b2ShapeProxy proxyA;
/// The proxy for shape B
b2ShapeProxy proxyB;
/// The world transform for shape A
b2Transform transformA;
/// The world transform for shape B
b2Transform transformB;
/// Should the proxy radius be considered?
bool useRadii;
} b2DistanceInput;
/// Output for b2ShapeDistance
typedef struct b2DistanceOutput
{
b2Vec2 pointA; ///< Closest point on shapeA
b2Vec2 pointB; ///< Closest point on shapeB
b2Vec2 normal; ///< Normal vector that points from A to B. Invalid if distance is zero.
float distance; ///< The final distance, zero if overlapped
int iterations; ///< Number of GJK iterations used
int simplexCount; ///< The number of simplexes stored in the simplex array
} b2DistanceOutput;
/// Simplex vertex for debugging the GJK algorithm
typedef struct b2SimplexVertex
{
b2Vec2 wA; ///< support point in proxyA
b2Vec2 wB; ///< support point in proxyB
b2Vec2 w; ///< wB - wA
float a; ///< barycentric coordinate for closest point
int indexA; ///< wA index
int indexB; ///< wB index
} b2SimplexVertex;
/// Simplex from the GJK algorithm
typedef struct b2Simplex
{
b2SimplexVertex v1, v2, v3; ///< vertices
int count; ///< number of valid vertices
} b2Simplex;
/// Compute the closest points between two shapes represented as point clouds.
/// b2SimplexCache cache is input/output. On the first call set b2SimplexCache.count to zero.
/// The underlying GJK algorithm may be debugged by passing in debug simplexes and capacity. You may pass in NULL and 0 for these.
B2_API b2DistanceOutput b2ShapeDistance( const b2DistanceInput* input, b2SimplexCache* cache, b2Simplex* simplexes,
int simplexCapacity );
/// Input parameters for b2ShapeCast
typedef struct b2ShapeCastPairInput
{
b2ShapeProxy proxyA; ///< The proxy for shape A
b2ShapeProxy proxyB; ///< The proxy for shape B
b2Transform transformA; ///< The world transform for shape A
b2Transform transformB; ///< The world transform for shape B
b2Vec2 translationB; ///< The translation of shape B
float maxFraction; ///< The fraction of the translation to consider, typically 1
bool canEncroach; ///< Allows shapes with a radius to move slightly closer if already touching
} b2ShapeCastPairInput;
/// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction.
/// Initially touching shapes are treated as a miss.
B2_API b2CastOutput b2ShapeCast( const b2ShapeCastPairInput* input );
/// Make a proxy for use in overlap, shape cast, and related functions. This is a deep copy of the points.
B2_API b2ShapeProxy b2MakeProxy( const b2Vec2* points, int count, float radius );
/// Make a proxy with a transform. This is a deep copy of the points.
B2_API b2ShapeProxy b2MakeOffsetProxy( const b2Vec2* points, int count, float radius, b2Vec2 position, b2Rot rotation );
/// This describes the motion of a body/shape for TOI computation. Shapes are defined with respect to the body origin,
/// which may not coincide with the center of mass. However, to support dynamics we must interpolate the center of mass
/// position.
typedef struct b2Sweep
{
b2Vec2 localCenter; ///< Local center of mass position
b2Vec2 c1; ///< Starting center of mass world position
b2Vec2 c2; ///< Ending center of mass world position
b2Rot q1; ///< Starting world rotation
b2Rot q2; ///< Ending world rotation
} b2Sweep;
/// Evaluate the transform sweep at a specific time.
B2_API b2Transform b2GetSweepTransform( const b2Sweep* sweep, float time );
/// Time of impact input
typedef struct b2TOIInput
{
b2ShapeProxy proxyA; ///< The proxy for shape A
b2ShapeProxy proxyB; ///< The proxy for shape B
b2Sweep sweepA; ///< The movement of shape A
b2Sweep sweepB; ///< The movement of shape B
float maxFraction; ///< Defines the sweep interval [0, maxFraction]
} b2TOIInput;
/// Describes the TOI output
typedef enum b2TOIState
{
b2_toiStateUnknown,
b2_toiStateFailed,
b2_toiStateOverlapped,
b2_toiStateHit,
b2_toiStateSeparated
} b2TOIState;
/// Time of impact output
typedef struct b2TOIOutput
{
/// The type of result
b2TOIState state;
/// The hit point
b2Vec2 point;
/// The hit normal
b2Vec2 normal;
/// The sweep time of the collision
float fraction;
} b2TOIOutput;
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
/// non-tunneling collisions. If you change the time interval, you should call this function
/// again.
B2_API b2TOIOutput b2TimeOfImpact( const b2TOIInput* input );
/**@}*/
/**
* @defgroup collision Collision
* @brief Functions for colliding pairs of shapes
* @{
*/
/// A manifold point is a contact point belonging to a contact manifold.
/// It holds details related to the geometry and dynamics of the contact points.
/// Box2D uses speculative collision so some contact points may be separated.
/// You may use the totalNormalImpulse to determine if there was an interaction during
/// the time step.
typedef struct b2ManifoldPoint
{
/// Location of the contact point in world space. Subject to precision loss at large coordinates.
/// @note Should only be used for debugging.
b2Vec2 point;
/// Location of the contact point relative to shapeA's origin in world space
/// @note When used internally to the Box2D solver, this is relative to the body center of mass.
b2Vec2 anchorA;
/// Location of the contact point relative to shapeB's origin in world space
/// @note When used internally to the Box2D solver, this is relative to the body center of mass.
b2Vec2 anchorB;
/// The separation of the contact point, negative if penetrating
float separation;
/// The impulse along the manifold normal vector.
float normalImpulse;
/// The friction impulse
float tangentImpulse;
/// The total normal impulse applied across sub-stepping and restitution. This is important
/// to identify speculative contact points that had an interaction in the time step.
/// This includes the warm starting impulse, the sub-step delta impulse, and the restitution
/// impulse.
float totalNormalImpulse;
/// Relative normal velocity pre-solve. Used for hit events. If the normal impulse is
/// zero then there was no hit. Negative means shapes are approaching.
float normalVelocity;
/// Uniquely identifies a contact point between two shapes
uint16_t id;
/// Did this contact point exist the previous step?
bool persisted;
} b2ManifoldPoint;
/// A contact manifold describes the contact points between colliding shapes.
/// @note Box2D uses speculative collision so some contact points may be separated.
typedef struct b2Manifold
{
/// The unit normal vector in world space, points from shape A to bodyB
b2Vec2 normal;
/// Angular impulse applied for rolling resistance. N * m * s = kg * m^2 / s
float rollingImpulse;
/// The manifold points, up to two are possible in 2D
b2ManifoldPoint points[2];
/// The number of contacts points, will be 0, 1, or 2
int pointCount;
} b2Manifold;
/// Compute the contact manifold between two circles
B2_API b2Manifold b2CollideCircles( const b2Circle* circleA, b2Transform xfA, const b2Circle* circleB, b2Transform xfB );
/// Compute the contact manifold between a capsule and circle
B2_API b2Manifold b2CollideCapsuleAndCircle( const b2Capsule* capsuleA, b2Transform xfA, const b2Circle* circleB,
b2Transform xfB );
/// Compute the contact manifold between an segment and a circle
B2_API b2Manifold b2CollideSegmentAndCircle( const b2Segment* segmentA, b2Transform xfA, const b2Circle* circleB,
b2Transform xfB );
/// Compute the contact manifold between a polygon and a circle
B2_API b2Manifold b2CollidePolygonAndCircle( const b2Polygon* polygonA, b2Transform xfA, const b2Circle* circleB,
b2Transform xfB );
/// Compute the contact manifold between a capsule and circle
B2_API b2Manifold b2CollideCapsules( const b2Capsule* capsuleA, b2Transform xfA, const b2Capsule* capsuleB, b2Transform xfB );
/// Compute the contact manifold between an segment and a capsule
B2_API b2Manifold b2CollideSegmentAndCapsule( const b2Segment* segmentA, b2Transform xfA, const b2Capsule* capsuleB,
b2Transform xfB );
/// Compute the contact manifold between a polygon and capsule
B2_API b2Manifold b2CollidePolygonAndCapsule( const b2Polygon* polygonA, b2Transform xfA, const b2Capsule* capsuleB,
b2Transform xfB );
/// Compute the contact manifold between two polygons
B2_API b2Manifold b2CollidePolygons( const b2Polygon* polygonA, b2Transform xfA, const b2Polygon* polygonB, b2Transform xfB );
/// Compute the contact manifold between an segment and a polygon
B2_API b2Manifold b2CollideSegmentAndPolygon( const b2Segment* segmentA, b2Transform xfA, const b2Polygon* polygonB,
b2Transform xfB );
/// Compute the contact manifold between a chain segment and a circle
B2_API b2Manifold b2CollideChainSegmentAndCircle( const b2ChainSegment* segmentA, b2Transform xfA, const b2Circle* circleB,
b2Transform xfB );
/// Compute the contact manifold between a chain segment and a capsule
B2_API b2Manifold b2CollideChainSegmentAndCapsule( const b2ChainSegment* segmentA, b2Transform xfA, const b2Capsule* capsuleB,
b2Transform xfB, b2SimplexCache* cache );
/// Compute the contact manifold between a chain segment and a rounded polygon
B2_API b2Manifold b2CollideChainSegmentAndPolygon( const b2ChainSegment* segmentA, b2Transform xfA, const b2Polygon* polygonB,
b2Transform xfB, b2SimplexCache* cache );
/**@}*/
/**
* @defgroup tree Dynamic Tree
* The dynamic tree is a binary AABB tree to organize and query large numbers of geometric objects
*
* Box2D uses the dynamic tree internally to sort collision shapes into a binary bounding volume hierarchy.
* This data structure may have uses in games for organizing other geometry data and may be used independently
* of Box2D rigid body simulation.
*
* A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
* A dynamic tree arranges data in a binary tree to accelerate
* queries such as AABB queries and ray casts. Leaf nodes are proxies
* with an AABB. These are used to hold a user collision object.
* Nodes are pooled and relocatable, so I use node indices rather than pointers.
* The dynamic tree is made available for advanced users that would like to use it to organize
* spatial game data besides rigid bodies.
* @{
*/
/// The dynamic tree structure. This should be considered private data.
/// It is placed here for performance reasons.
typedef struct b2DynamicTree
{
/// The tree nodes
struct b2TreeNode* nodes;
/// The root index
int root;
/// The number of nodes
int nodeCount;
/// The allocated node space
int nodeCapacity;
/// Node free list
int freeList;
/// Number of proxies created
int proxyCount;
/// Leaf indices for rebuild
int* leafIndices;
/// Leaf bounding boxes for rebuild
b2AABB* leafBoxes;
/// Leaf bounding box centers for rebuild
b2Vec2* leafCenters;
/// Bins for sorting during rebuild
int* binIndices;
/// Allocated space for rebuilding
int rebuildCapacity;
} b2DynamicTree;
/// These are performance results returned by dynamic tree queries.
typedef struct b2TreeStats
{
/// Number of internal nodes visited during the query
int nodeVisits;
/// Number of leaf nodes visited during the query
int leafVisits;
} b2TreeStats;
/// Constructing the tree initializes the node pool.
B2_API b2DynamicTree b2DynamicTree_Create( void );
/// Destroy the tree, freeing the node pool.
B2_API void b2DynamicTree_Destroy( b2DynamicTree* tree );
/// Create a proxy. Provide an AABB and a userData value.
B2_API int b2DynamicTree_CreateProxy( b2DynamicTree* tree, b2AABB aabb, uint64_t categoryBits, uint64_t userData );
/// Destroy a proxy. This asserts if the id is invalid.
B2_API void b2DynamicTree_DestroyProxy( b2DynamicTree* tree, int proxyId );
/// Move a proxy to a new AABB by removing and reinserting into the tree.
B2_API void b2DynamicTree_MoveProxy( b2DynamicTree* tree, int proxyId, b2AABB aabb );
/// Enlarge a proxy and enlarge ancestors as necessary.
B2_API void b2DynamicTree_EnlargeProxy( b2DynamicTree* tree, int proxyId, b2AABB aabb );
/// Modify the category bits on a proxy. This is an expensive operation.
B2_API void b2DynamicTree_SetCategoryBits( b2DynamicTree* tree, int proxyId, uint64_t categoryBits );
/// Get the category bits on a proxy.
B2_API uint64_t b2DynamicTree_GetCategoryBits( b2DynamicTree* tree, int proxyId );
/// This function receives proxies found in the AABB query.
/// @return true if the query should continue
typedef bool b2TreeQueryCallbackFcn( int proxyId, uint64_t userData, void* context );
/// Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB.
/// @return performance data
B2_API b2TreeStats b2DynamicTree_Query( const b2DynamicTree* tree, b2AABB aabb, uint64_t maskBits,
b2TreeQueryCallbackFcn* callback, void* context );
/// Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB.
/// No filtering is performed.
/// @return performance data
B2_API b2TreeStats b2DynamicTree_QueryAll( const b2DynamicTree* tree, b2AABB aabb, b2TreeQueryCallbackFcn* callback,
void* context );
/// This function receives clipped ray cast input for a proxy. The function
/// returns the new ray fraction.
/// - return a value of 0 to terminate the ray cast
/// - return a value less than input->maxFraction to clip the ray
/// - return a value of input->maxFraction to continue the ray cast without clipping
typedef float b2TreeRayCastCallbackFcn( const b2RayCastInput* input, int proxyId, uint64_t userData, void* context );
/// Ray cast against the proxies in the tree. This relies on the callback
/// to perform a exact ray cast in the case were the proxy contains a shape.
/// The callback also performs the any collision filtering. This has performance
/// roughly equal to k * log(n), where k is the number of collisions and n is the
/// number of proxies in the tree.
/// Bit-wise filtering using mask bits can greatly improve performance in some scenarios.
/// However, this filtering may be approximate, so the user should still apply filtering to results.
/// @param tree the dynamic tree to ray cast
/// @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1)
/// @param maskBits mask bit hint: `bool accept = (maskBits & node->categoryBits) != 0;`
/// @param callback a callback class that is called for each proxy that is hit by the ray
/// @param context user context that is passed to the callback
/// @return performance data
B2_API b2TreeStats b2DynamicTree_RayCast( const b2DynamicTree* tree, const b2RayCastInput* input, uint64_t maskBits,
b2TreeRayCastCallbackFcn* callback, void* context );
/// This function receives clipped ray cast input for a proxy. The function
/// returns the new ray fraction.
/// - return a value of 0 to terminate the ray cast
/// - return a value less than input->maxFraction to clip the ray
/// - return a value of input->maxFraction to continue the ray cast without clipping
typedef float b2TreeShapeCastCallbackFcn( const b2ShapeCastInput* input, int proxyId, uint64_t userData, void* context );
/// Ray cast against the proxies in the tree. This relies on the callback
/// to perform a exact ray cast in the case were the proxy contains a shape.
/// The callback also performs the any collision filtering. This has performance
/// roughly equal to k * log(n), where k is the number of collisions and n is the
/// number of proxies in the tree.
/// @param tree the dynamic tree to ray cast
/// @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
/// @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0;`
/// @param callback a callback class that is called for each proxy that is hit by the shape
/// @param context user context that is passed to the callback
/// @return performance data
B2_API b2TreeStats b2DynamicTree_ShapeCast( const b2DynamicTree* tree, const b2ShapeCastInput* input, uint64_t maskBits,
b2TreeShapeCastCallbackFcn* callback, void* context );
/// Get the height of the binary tree.
B2_API int b2DynamicTree_GetHeight( const b2DynamicTree* tree );
/// Get the ratio of the sum of the node areas to the root area.
B2_API float b2DynamicTree_GetAreaRatio( const b2DynamicTree* tree );
/// Get the bounding box that contains the entire tree
B2_API b2AABB b2DynamicTree_GetRootBounds( const b2DynamicTree* tree );
/// Get the number of proxies created
B2_API int b2DynamicTree_GetProxyCount( const b2DynamicTree* tree );
/// Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted.
B2_API int b2DynamicTree_Rebuild( b2DynamicTree* tree, bool fullBuild );
/// Get the number of bytes used by this tree
B2_API int b2DynamicTree_GetByteCount( const b2DynamicTree* tree );
/// Get proxy user data
B2_API uint64_t b2DynamicTree_GetUserData( const b2DynamicTree* tree, int proxyId );
/// Get the AABB of a proxy
B2_API b2AABB b2DynamicTree_GetAABB( const b2DynamicTree* tree, int proxyId );
/// Validate this tree. For testing.
B2_API void b2DynamicTree_Validate( const b2DynamicTree* tree );
/// Validate this tree has no enlarged AABBs. For testing.
B2_API void b2DynamicTree_ValidateNoEnlarged( const b2DynamicTree* tree );
/**@}*/
/**
* @defgroup character Character mover
* Character movement solver
* @{
*/
/// These are the collision planes returned from b2World_CollideMover
typedef struct b2PlaneResult
{
/// The collision plane between the mover and a convex shape
b2Plane plane;
// The collision point on the shape.
b2Vec2 point;
/// Did the collision register a hit? If not this plane should be ignored.
bool hit;
} b2PlaneResult;
/// These are collision planes that can be fed to b2SolvePlanes. Normally
/// this is assembled by the user from plane results in b2PlaneResult
typedef struct b2CollisionPlane
{
/// The collision plane between the mover and some shape
b2Plane plane;
/// Setting this to FLT_MAX makes the plane as rigid as possible. Lower values can
/// make the plane collision soft. Usually in meters.
float pushLimit;
/// The push on the mover determined by b2SolvePlanes. Usually in meters.
float push;
/// Indicates if b2ClipVector should clip against this plane. Should be false for soft collision.
bool clipVelocity;
} b2CollisionPlane;
/// Result returned by b2SolvePlanes
typedef struct b2PlaneSolverResult
{
/// The translation of the mover
b2Vec2 translation;
/// The number of iterations used by the plane solver. For diagnostics.
int iterationCount;
} b2PlaneSolverResult;
/// Solves the position of a mover that satisfies the given collision planes.
/// @param targetDelta the desired movement from the position used to generate the collision planes
/// @param planes the collision planes
/// @param count the number of collision planes
B2_API b2PlaneSolverResult b2SolvePlanes( b2Vec2 targetDelta, b2CollisionPlane* planes, int count );
/// Clips the velocity against the given collision planes. Planes with zero push or clipVelocity
/// set to false are skipped.
B2_API b2Vec2 b2ClipVector( b2Vec2 vector, const b2CollisionPlane* planes, int count );
/**@}*/

View File

@@ -0,0 +1,194 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT
#pragma once
#include <stdint.h>
// Note: this file should be stand-alone
/**
* @defgroup id Ids
* These ids serve as handles to internal Box2D objects.
* These should be considered opaque data and passed by value.
* Include this header if you need the id types and not the whole Box2D API.
* All ids are considered null if initialized to zero.
*
* For example in C++:
*
* @code{.cxx}
* b2WorldId worldId = {};
* @endcode
*
* Or in C:
*
* @code{.c}
* b2WorldId worldId = {0};
* @endcode
*
* These are both considered null.
*
* @warning Do not use the internals of these ids. They are subject to change. Ids should be treated as opaque objects.
* @warning You should use ids to access objects in Box2D. Do not access files within the src folder. Such usage is unsupported.
* @{
*/
/// World id references a world instance. This should be treated as an opaque handle.
typedef struct b2WorldId
{
uint16_t index1;
uint16_t generation;
} b2WorldId;
/// Body id references a body instance. This should be treated as an opaque handle.
typedef struct b2BodyId
{
int32_t index1;
uint16_t world0;
uint16_t generation;
} b2BodyId;
/// Shape id references a shape instance. This should be treated as an opaque handle.
typedef struct b2ShapeId
{
int32_t index1;
uint16_t world0;
uint16_t generation;
} b2ShapeId;
/// Chain id references a chain instances. This should be treated as an opaque handle.
typedef struct b2ChainId
{
int32_t index1;
uint16_t world0;
uint16_t generation;
} b2ChainId;
/// Joint id references a joint instance. This should be treated as an opaque handle.
typedef struct b2JointId
{
int32_t index1;
uint16_t world0;
uint16_t generation;
} b2JointId;
/// Contact id references a contact instance. This should be treated as an opaque handled.
typedef struct b2ContactId
{
int32_t index1;
uint16_t world0;
int16_t padding;
uint32_t generation;
} b2ContactId;
#ifdef __cplusplus
#define B2_NULL_ID {}
#define B2_ID_INLINE inline
#else
#define B2_NULL_ID { 0 }
#define B2_ID_INLINE static inline
#endif
/// Use these to make your identifiers null.
/// You may also use zero initialization to get null.
static const b2WorldId b2_nullWorldId = B2_NULL_ID;
static const b2BodyId b2_nullBodyId = B2_NULL_ID;
static const b2ShapeId b2_nullShapeId = B2_NULL_ID;
static const b2ChainId b2_nullChainId = B2_NULL_ID;
static const b2JointId b2_nullJointId = B2_NULL_ID;
static const b2ContactId b2_nullContactId = B2_NULL_ID;
/// Macro to determine if any id is null.
#define B2_IS_NULL( id ) ( (id).index1 == 0 )
/// Macro to determine if any id is non-null.
#define B2_IS_NON_NULL( id ) ( (id).index1 != 0 )
/// Compare two ids for equality. Doesn't work for b2WorldId. Don't mix types.
#define B2_ID_EQUALS( id1, id2 ) ( (id1).index1 == (id2).index1 && (id1).world0 == (id2).world0 && (id1).generation == (id2).generation )
/// Store a world id into a uint32_t.
B2_ID_INLINE uint32_t b2StoreWorldId( b2WorldId id )
{
return ( (uint32_t)id.index1 << 16 ) | (uint32_t)id.generation;
}
/// Load a uint32_t into a world id.
B2_ID_INLINE b2WorldId b2LoadWorldId( uint32_t x )
{
b2WorldId id = { (uint16_t)( x >> 16 ), (uint16_t)( x ) };
return id;
}
/// Store a body id into a uint64_t.
B2_ID_INLINE uint64_t b2StoreBodyId( b2BodyId id )
{
return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation;
}
/// Load a uint64_t into a body id.
B2_ID_INLINE b2BodyId b2LoadBodyId( uint64_t x )
{
b2BodyId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) };
return id;
}
/// Store a shape id into a uint64_t.
B2_ID_INLINE uint64_t b2StoreShapeId( b2ShapeId id )
{
return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation;
}
/// Load a uint64_t into a shape id.
B2_ID_INLINE b2ShapeId b2LoadShapeId( uint64_t x )
{
b2ShapeId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) };
return id;
}
/// Store a chain id into a uint64_t.
B2_ID_INLINE uint64_t b2StoreChainId( b2ChainId id )
{
return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation;
}
/// Load a uint64_t into a chain id.
B2_ID_INLINE b2ChainId b2LoadChainId( uint64_t x )
{
b2ChainId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) };
return id;
}
/// Store a joint id into a uint64_t.
B2_ID_INLINE uint64_t b2StoreJointId( b2JointId id )
{
return ( (uint64_t)id.index1 << 32 ) | ( (uint64_t)id.world0 ) << 16 | (uint64_t)id.generation;
}
/// Load a uint64_t into a joint id.
B2_ID_INLINE b2JointId b2LoadJointId( uint64_t x )
{
b2JointId id = { (int32_t)( x >> 32 ), (uint16_t)( x >> 16 ), (uint16_t)( x ) };
return id;
}
/// Store a contact id into 16 bytes
B2_ID_INLINE void b2StoreContactId( b2ContactId id, uint32_t values[3] )
{
values[0] = (uint32_t)id.index1;
values[1] = (uint32_t)id.world0;
values[2] = (uint32_t)id.generation;
}
/// Load a two uint64_t into a contact id.
B2_ID_INLINE b2ContactId b2LoadContactId( uint32_t values[3] )
{
b2ContactId id;
id.index1 = (int32_t)values[0];
id.world0 = (uint16_t)values[1];
id.padding = 0;
id.generation = (uint32_t)values[2];
return id;
}
/**@}*/

View File

@@ -0,0 +1,776 @@
// SPDX-FileCopyrightText: 2023 Erin Catto
// SPDX-License-Identifier: MIT
#pragma once
#include "base.h"
#include <float.h>
#include <math.h>
#include <stdbool.h>
/**
* @defgroup math Math
* @brief Vector math types and functions
* @{
*/
/// 2D vector
/// This can be used to represent a point or free vector
typedef struct b2Vec2
{
/// coordinates
float x, y;
} b2Vec2;
/// Cosine and sine pair
/// This uses a custom implementation designed for cross-platform determinism
typedef struct b2CosSin
{
/// cosine and sine
float cosine;
float sine;
} b2CosSin;
/// 2D rotation
/// This is similar to using a complex number for rotation
typedef struct b2Rot
{
/// cosine and sine
float c, s;
} b2Rot;
/// A 2D rigid transform
typedef struct b2Transform
{
b2Vec2 p;
b2Rot q;
} b2Transform;
/// A 2-by-2 Matrix
typedef struct b2Mat22
{
/// columns
b2Vec2 cx, cy;
} b2Mat22;
/// Axis-aligned bounding box
typedef struct b2AABB
{
b2Vec2 lowerBound;
b2Vec2 upperBound;
} b2AABB;
/// separation = dot(normal, point) - offset
typedef struct b2Plane
{
b2Vec2 normal;
float offset;
} b2Plane;
/**@}*/
/**
* @addtogroup math
* @{
*/
/// https://en.wikipedia.org/wiki/Pi
#define B2_PI 3.14159265359f
static const b2Vec2 b2Vec2_zero = { 0.0f, 0.0f };
static const b2Rot b2Rot_identity = { 1.0f, 0.0f };
static const b2Transform b2Transform_identity = { { 0.0f, 0.0f }, { 1.0f, 0.0f } };
static const b2Mat22 b2Mat22_zero = { { 0.0f, 0.0f }, { 0.0f, 0.0f } };
/// Is this a valid number? Not NaN or infinity.
B2_API bool b2IsValidFloat( float a );
/// Is this a valid vector? Not NaN or infinity.
B2_API bool b2IsValidVec2( b2Vec2 v );
/// Is this a valid rotation? Not NaN or infinity. Is normalized.
B2_API bool b2IsValidRotation( b2Rot q );
/// Is this a valid transform? Not NaN or infinity. Rotation is normalized.
B2_API bool b2IsValidTransform( b2Transform t );
/// Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound.
B2_API bool b2IsValidAABB( b2AABB aabb );
/// Is this a valid plane? Normal is a unit vector. Not Nan or infinity.
B2_API bool b2IsValidPlane( b2Plane a );
/// @return the minimum of two integers
B2_INLINE int b2MinInt( int a, int b )
{
return a < b ? a : b;
}
/// @return the maximum of two integers
B2_INLINE int b2MaxInt( int a, int b )
{
return a > b ? a : b;
}
/// @return the absolute value of an integer
B2_INLINE int b2AbsInt( int a )
{
return a < 0 ? -a : a;
}
/// @return an integer clamped between a lower and upper bound
B2_INLINE int b2ClampInt( int a, int lower, int upper )
{
return a < lower ? lower : ( a > upper ? upper : a );
}
/// @return the minimum of two floats
B2_INLINE float b2MinFloat( float a, float b )
{
return a < b ? a : b;
}
/// @return the maximum of two floats
B2_INLINE float b2MaxFloat( float a, float b )
{
return a > b ? a : b;
}
/// @return the absolute value of a float
B2_INLINE float b2AbsFloat( float a )
{
return a < 0 ? -a : a;
}
/// @return a float clamped between a lower and upper bound
B2_INLINE float b2ClampFloat( float a, float lower, float upper )
{
return a < lower ? lower : ( a > upper ? upper : a );
}
/// Compute an approximate arctangent in the range [-pi, pi]
/// This is hand coded for cross-platform determinism. The atan2f
/// function in the standard library is not cross-platform deterministic.
/// Accurate to around 0.0023 degrees
B2_API float b2Atan2( float y, float x );
/// Compute the cosine and sine of an angle in radians. Implemented
/// for cross-platform determinism.
B2_API b2CosSin b2ComputeCosSin( float radians );
/// Vector dot product
B2_INLINE float b2Dot( b2Vec2 a, b2Vec2 b )
{
return a.x * b.x + a.y * b.y;
}
/// Vector cross product. In 2D this yields a scalar.
B2_INLINE float b2Cross( b2Vec2 a, b2Vec2 b )
{
return a.x * b.y - a.y * b.x;
}
/// Perform the cross product on a vector and a scalar. In 2D this produces a vector.
B2_INLINE b2Vec2 b2CrossVS( b2Vec2 v, float s )
{
return B2_LITERAL( b2Vec2 ){ s * v.y, -s * v.x };
}
/// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
B2_INLINE b2Vec2 b2CrossSV( float s, b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ -s * v.y, s * v.x };
}
/// Get a left pointing perpendicular vector. Equivalent to b2CrossSV(1.0f, v)
B2_INLINE b2Vec2 b2LeftPerp( b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ -v.y, v.x };
}
/// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1.0f)
B2_INLINE b2Vec2 b2RightPerp( b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ v.y, -v.x };
}
/// Vector addition
B2_INLINE b2Vec2 b2Add( b2Vec2 a, b2Vec2 b )
{
return B2_LITERAL( b2Vec2 ){ a.x + b.x, a.y + b.y };
}
/// Vector subtraction
B2_INLINE b2Vec2 b2Sub( b2Vec2 a, b2Vec2 b )
{
return B2_LITERAL( b2Vec2 ){ a.x - b.x, a.y - b.y };
}
/// Vector negation
B2_INLINE b2Vec2 b2Neg( b2Vec2 a )
{
return B2_LITERAL( b2Vec2 ){ -a.x, -a.y };
}
/// Vector linear interpolation
/// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
B2_INLINE b2Vec2 b2Lerp( b2Vec2 a, b2Vec2 b, float t )
{
return B2_LITERAL( b2Vec2 ){ ( 1.0f - t ) * a.x + t * b.x, ( 1.0f - t ) * a.y + t * b.y };
}
/// Component-wise multiplication
B2_INLINE b2Vec2 b2Mul( b2Vec2 a, b2Vec2 b )
{
return B2_LITERAL( b2Vec2 ){ a.x * b.x, a.y * b.y };
}
/// Multiply a scalar and vector
B2_INLINE b2Vec2 b2MulSV( float s, b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ s * v.x, s * v.y };
}
/// a + s * b
B2_INLINE b2Vec2 b2MulAdd( b2Vec2 a, float s, b2Vec2 b )
{
return B2_LITERAL( b2Vec2 ){ a.x + s * b.x, a.y + s * b.y };
}
/// a - s * b
B2_INLINE b2Vec2 b2MulSub( b2Vec2 a, float s, b2Vec2 b )
{
return B2_LITERAL( b2Vec2 ){ a.x - s * b.x, a.y - s * b.y };
}
/// Component-wise absolute vector
B2_INLINE b2Vec2 b2Abs( b2Vec2 a )
{
b2Vec2 b;
b.x = b2AbsFloat( a.x );
b.y = b2AbsFloat( a.y );
return b;
}
/// Component-wise minimum vector
B2_INLINE b2Vec2 b2Min( b2Vec2 a, b2Vec2 b )
{
b2Vec2 c;
c.x = b2MinFloat( a.x, b.x );
c.y = b2MinFloat( a.y, b.y );
return c;
}
/// Component-wise maximum vector
B2_INLINE b2Vec2 b2Max( b2Vec2 a, b2Vec2 b )
{
b2Vec2 c;
c.x = b2MaxFloat( a.x, b.x );
c.y = b2MaxFloat( a.y, b.y );
return c;
}
/// Component-wise clamp vector v into the range [a, b]
B2_INLINE b2Vec2 b2Clamp( b2Vec2 v, b2Vec2 a, b2Vec2 b )
{
b2Vec2 c;
c.x = b2ClampFloat( v.x, a.x, b.x );
c.y = b2ClampFloat( v.y, a.y, b.y );
return c;
}
/// Get the length of this vector (the norm)
B2_INLINE float b2Length( b2Vec2 v )
{
return sqrtf( v.x * v.x + v.y * v.y );
}
/// Get the distance between two points
B2_INLINE float b2Distance( b2Vec2 a, b2Vec2 b )
{
float dx = b.x - a.x;
float dy = b.y - a.y;
return sqrtf( dx * dx + dy * dy );
}
/// Convert a vector into a unit vector if possible, otherwise returns the zero vector.
/// todo MSVC is not inlining this function in several places per warning 4710
B2_INLINE b2Vec2 b2Normalize( b2Vec2 v )
{
float length = sqrtf( v.x * v.x + v.y * v.y );
if ( length < FLT_EPSILON )
{
return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f };
}
float invLength = 1.0f / length;
b2Vec2 n = { invLength * v.x, invLength * v.y };
return n;
}
/// Determines if the provided vector is normalized (norm(a) == 1).
B2_INLINE bool b2IsNormalized( b2Vec2 a )
{
float aa = b2Dot( a, a );
return b2AbsFloat( 1.0f - aa ) < 100.0f * FLT_EPSILON;
}
/// Convert a vector into a unit vector if possible, otherwise returns the zero vector. Also
/// outputs the length.
B2_INLINE b2Vec2 b2GetLengthAndNormalize( float* length, b2Vec2 v )
{
*length = sqrtf( v.x * v.x + v.y * v.y );
if ( *length < FLT_EPSILON )
{
return B2_LITERAL( b2Vec2 ){ 0.0f, 0.0f };
}
float invLength = 1.0f / *length;
b2Vec2 n = { invLength * v.x, invLength * v.y };
return n;
}
/// Normalize rotation
B2_INLINE b2Rot b2NormalizeRot( b2Rot q )
{
float mag = sqrtf( q.s * q.s + q.c * q.c );
float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
b2Rot qn = { q.c * invMag, q.s * invMag };
return qn;
}
/// Integrate rotation from angular velocity
/// @param q1 initial rotation
/// @param deltaAngle the angular displacement in radians
B2_INLINE b2Rot b2IntegrateRotation( b2Rot q1, float deltaAngle )
{
// dc/dt = -omega * sin(t)
// ds/dt = omega * cos(t)
// c2 = c1 - omega * h * s1
// s2 = s1 + omega * h * c1
b2Rot q2 = { q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c };
float mag = sqrtf( q2.s * q2.s + q2.c * q2.c );
float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
b2Rot qn = { q2.c * invMag, q2.s * invMag };
return qn;
}
/// Get the length squared of this vector
B2_INLINE float b2LengthSquared( b2Vec2 v )
{
return v.x * v.x + v.y * v.y;
}
/// Get the distance squared between points
B2_INLINE float b2DistanceSquared( b2Vec2 a, b2Vec2 b )
{
b2Vec2 c = { b.x - a.x, b.y - a.y };
return c.x * c.x + c.y * c.y;
}
/// Make a rotation using an angle in radians
B2_INLINE b2Rot b2MakeRot( float radians )
{
b2CosSin cs = b2ComputeCosSin( radians );
return B2_LITERAL( b2Rot ){ cs.cosine, cs.sine };
}
/// Make a rotation using a unit vector
B2_INLINE b2Rot b2MakeRotFromUnitVector( b2Vec2 unitVector )
{
B2_ASSERT( b2IsNormalized( unitVector ) );
return B2_LITERAL( b2Rot ){ unitVector.x, unitVector.y };
}
/// Compute the rotation between two unit vectors
B2_API b2Rot b2ComputeRotationBetweenUnitVectors( b2Vec2 v1, b2Vec2 v2 );
/// Is this rotation normalized?
B2_INLINE bool b2IsNormalizedRot( b2Rot q )
{
// larger tolerance due to failure on mingw 32-bit
float qq = q.s * q.s + q.c * q.c;
return 1.0f - 0.0006f < qq && qq < 1.0f + 0.0006f;
}
/// Get the inverse of a rotation
B2_INLINE b2Rot b2InvertRot( b2Rot a )
{
return B2_LITERAL( b2Rot ){
.c = a.c,
.s = -a.s,
};
}
/// Normalized linear interpolation
/// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
/// https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
B2_INLINE b2Rot b2NLerp( b2Rot q1, b2Rot q2, float t )
{
float omt = 1.0f - t;
b2Rot q = {
omt * q1.c + t * q2.c,
omt * q1.s + t * q2.s,
};
float mag = sqrtf( q.s * q.s + q.c * q.c );
float invMag = mag > 0.0f ? 1.0f / mag : 0.0f;
b2Rot qn = { q.c * invMag, q.s * invMag };
return qn;
}
/// Compute the angular velocity necessary to rotate between two rotations over a give time
/// @param q1 initial rotation
/// @param q2 final rotation
/// @param inv_h inverse time step
B2_INLINE float b2ComputeAngularVelocity( b2Rot q1, b2Rot q2, float inv_h )
{
// ds/dt = omega * cos(t)
// dc/dt = -omega * sin(t)
// s2 = s1 + omega * h * c1
// c2 = c1 - omega * h * s1
// omega * h * s1 = c1 - c2
// omega * h * c1 = s2 - s1
// omega * h = (c1 - c2) * s1 + (s2 - s1) * c1;
// omega * h = s1 * c1 - c2 * s1 + s2 * c1 - s1 * c1
// omega * h = s2 * c1 - c2 * s1 = sin(a2 - a1) ~= a2 - a1 for small delta
float omega = inv_h * ( q2.s * q1.c - q2.c * q1.s );
return omega;
}
/// Get the angle in radians in the range [-pi, pi]
B2_INLINE float b2Rot_GetAngle( b2Rot q )
{
return b2Atan2( q.s, q.c );
}
/// Get the x-axis
B2_INLINE b2Vec2 b2Rot_GetXAxis( b2Rot q )
{
b2Vec2 v = { q.c, q.s };
return v;
}
/// Get the y-axis
B2_INLINE b2Vec2 b2Rot_GetYAxis( b2Rot q )
{
b2Vec2 v = { -q.s, q.c };
return v;
}
/// Multiply two rotations: q * r
B2_INLINE b2Rot b2MulRot( b2Rot q, b2Rot r )
{
// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
// [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
// s(q + r) = qs * rc + qc * rs
// c(q + r) = qc * rc - qs * rs
b2Rot qr;
qr.s = q.s * r.c + q.c * r.s;
qr.c = q.c * r.c - q.s * r.s;
return qr;
}
/// Transpose multiply two rotations: inv(a) * b
/// This rotates a vector local in frame b into a vector local in frame a
B2_INLINE b2Rot b2InvMulRot( b2Rot a, b2Rot b )
{
// [ ac as] * [bc -bs] = [ac*bc+qs*bs -ac*bs+as*bc]
// [-as ac] [bs bc] [-as*bc+ac*bs as*bs+ac*bc]
// s(a - b) = ac * bs - as * bc
// c(a - b) = ac * bc + as * bs
b2Rot r;
r.s = a.c * b.s - a.s * b.c;
r.c = a.c * b.c + a.s * b.s;
return r;
}
/// Relative angle between a and b
B2_INLINE float b2RelativeAngle( b2Rot a, b2Rot b )
{
// sin(b - a) = bs * ac - bc * as
// cos(b - a) = bc * ac + bs * as
float s = a.c * b.s - a.s * b.c;
float c = a.c * b.c + a.s * b.s;
return b2Atan2( s, c );
}
/// Convert any angle into the range [-pi, pi]
B2_INLINE float b2UnwindAngle( float radians )
{
// Assuming this is deterministic
return remainderf( radians, 2.0f * B2_PI );
}
/// Rotate a vector
B2_INLINE b2Vec2 b2RotateVector( b2Rot q, b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y };
}
/// Inverse rotate a vector
B2_INLINE b2Vec2 b2InvRotateVector( b2Rot q, b2Vec2 v )
{
return B2_LITERAL( b2Vec2 ){ q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y };
}
/// Transform a point (e.g. local space to world space)
B2_INLINE b2Vec2 b2TransformPoint( b2Transform t, const b2Vec2 p )
{
float x = ( t.q.c * p.x - t.q.s * p.y ) + t.p.x;
float y = ( t.q.s * p.x + t.q.c * p.y ) + t.p.y;
return B2_LITERAL( b2Vec2 ){ x, y };
}
/// Inverse transform a point (e.g. world space to local space)
B2_INLINE b2Vec2 b2InvTransformPoint( b2Transform t, const b2Vec2 p )
{
float vx = p.x - t.p.x;
float vy = p.y - t.p.y;
return B2_LITERAL( b2Vec2 ){ t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy };
}
/// Multiply two transforms. If the result is applied to a point p local to frame B,
/// the transform would first convert p to a point local to frame A, then into a point
/// in the world frame.
/// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
/// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
B2_INLINE b2Transform b2MulTransforms( b2Transform A, b2Transform B )
{
b2Transform C;
C.q = b2MulRot( A.q, B.q );
C.p = b2Add( b2RotateVector( A.q, B.p ), A.p );
return C;
}
/// Creates a transform that converts a local point in frame B to a local point in frame A.
/// v2 = A.q' * (B.q * v1 + B.p - A.p)
/// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
B2_INLINE b2Transform b2InvMulTransforms( b2Transform A, b2Transform B )
{
b2Transform C;
C.q = b2InvMulRot( A.q, B.q );
C.p = b2InvRotateVector( A.q, b2Sub( B.p, A.p ) );
return C;
}
/// Multiply a 2-by-2 matrix times a 2D vector
B2_INLINE b2Vec2 b2MulMV( b2Mat22 A, b2Vec2 v )
{
b2Vec2 u = {
A.cx.x * v.x + A.cy.x * v.y,
A.cx.y * v.x + A.cy.y * v.y,
};
return u;
}
/// Get the inverse of a 2-by-2 matrix
B2_INLINE b2Mat22 b2GetInverse22( b2Mat22 A )
{
float a = A.cx.x, b = A.cy.x, c = A.cx.y, d = A.cy.y;
float det = a * d - b * c;
if ( det != 0.0f )
{
det = 1.0f / det;
}
b2Mat22 B = {
{ det * d, -det * c },
{ -det * b, det * a },
};
return B;
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
B2_INLINE b2Vec2 b2Solve22( b2Mat22 A, b2Vec2 b )
{
float a11 = A.cx.x, a12 = A.cy.x, a21 = A.cx.y, a22 = A.cy.y;
float det = a11 * a22 - a12 * a21;
if ( det != 0.0f )
{
det = 1.0f / det;
}
b2Vec2 x = { det * ( a22 * b.x - a12 * b.y ), det * ( a11 * b.y - a21 * b.x ) };
return x;
}
/// Does a fully contain b
B2_INLINE bool b2AABB_Contains( b2AABB a, b2AABB b )
{
bool s = true;
s = s && a.lowerBound.x <= b.lowerBound.x;
s = s && a.lowerBound.y <= b.lowerBound.y;
s = s && b.upperBound.x <= a.upperBound.x;
s = s && b.upperBound.y <= a.upperBound.y;
return s;
}
/// Get the center of the AABB.
B2_INLINE b2Vec2 b2AABB_Center( b2AABB a )
{
b2Vec2 b = { 0.5f * ( a.lowerBound.x + a.upperBound.x ), 0.5f * ( a.lowerBound.y + a.upperBound.y ) };
return b;
}
/// Get the extents of the AABB (half-widths).
B2_INLINE b2Vec2 b2AABB_Extents( b2AABB a )
{
b2Vec2 b = { 0.5f * ( a.upperBound.x - a.lowerBound.x ), 0.5f * ( a.upperBound.y - a.lowerBound.y ) };
return b;
}
/// Union of two AABBs
B2_INLINE b2AABB b2AABB_Union( b2AABB a, b2AABB b )
{
b2AABB c;
c.lowerBound.x = b2MinFloat( a.lowerBound.x, b.lowerBound.x );
c.lowerBound.y = b2MinFloat( a.lowerBound.y, b.lowerBound.y );
c.upperBound.x = b2MaxFloat( a.upperBound.x, b.upperBound.x );
c.upperBound.y = b2MaxFloat( a.upperBound.y, b.upperBound.y );
return c;
}
/// Do a and b overlap
B2_INLINE bool b2AABB_Overlaps( b2AABB a, b2AABB b )
{
return !( b.lowerBound.x > a.upperBound.x || b.lowerBound.y > a.upperBound.y || a.lowerBound.x > b.upperBound.x ||
a.lowerBound.y > b.upperBound.y );
}
/// Compute the bounding box of an array of circles
B2_INLINE b2AABB b2MakeAABB( const b2Vec2* points, int count, float radius )
{
B2_ASSERT( count > 0 );
b2AABB a = { points[0], points[0] };
for ( int i = 1; i < count; ++i )
{
a.lowerBound = b2Min( a.lowerBound, points[i] );
a.upperBound = b2Max( a.upperBound, points[i] );
}
b2Vec2 r = { radius, radius };
a.lowerBound = b2Sub( a.lowerBound, r );
a.upperBound = b2Add( a.upperBound, r );
return a;
}
/// Signed separation of a point from a plane
B2_INLINE float b2PlaneSeparation( b2Plane plane, b2Vec2 point )
{
return b2Dot( plane.normal, point ) - plane.offset;
}
/// One-dimensional mass-spring-damper simulation. Returns the new velocity given the position and time step.
/// You can then compute the new position using:
/// position += timeStep * newVelocity
/// This drives towards a zero position. By using implicit integration we get a stable solution
/// that doesn't require transcendental functions.
B2_INLINE float b2SpringDamper( float hertz, float dampingRatio, float position, float velocity, float timeStep )
{
float omega = 2.0f * B2_PI * hertz;
float omegaH = omega * timeStep;
return ( velocity - omega * omegaH * position ) / ( 1.0f + 2.0f * dampingRatio * omegaH + omegaH * omegaH );
}
/// Box2D bases all length units on meters, but you may need different units for your game.
/// You can set this value to use different units. This should be done at application startup
/// and only modified once. Default value is 1.
/// For example, if your game uses pixels for units you can use pixels for all length values
/// sent to Box2D. There should be no extra cost. However, Box2D has some internal tolerances
/// and thresholds that have been tuned for meters. By calling this function, Box2D is able
/// to adjust those tolerances and thresholds to improve accuracy.
/// A good rule of thumb is to pass the height of your player character to this function. So
/// if your player character is 32 pixels high, then pass 32 to this function. Then you may
/// confidently use pixels for all the length values sent to Box2D. All length values returned
/// from Box2D will also be pixels because Box2D does not do any scaling internally.
/// However, you are now on the hook for coming up with good values for gravity, density, and
/// forces.
/// @warning This must be modified before any calls to Box2D
B2_API void b2SetLengthUnitsPerMeter( float lengthUnits );
/// Get the current length units per meter.
B2_API float b2GetLengthUnitsPerMeter( void );
/**@}*/
/**
* @defgroup math_cpp C++ Math
* @brief Math operator overloads for C++
*
* See math_functions.h for details.
* @{
*/
#ifdef __cplusplus
/// Unary add one vector to another
inline void operator+=( b2Vec2& a, b2Vec2 b )
{
a.x += b.x;
a.y += b.y;
}
/// Unary subtract one vector from another
inline void operator-=( b2Vec2& a, b2Vec2 b )
{
a.x -= b.x;
a.y -= b.y;
}
/// Unary multiply a vector by a scalar
inline void operator*=( b2Vec2& a, float b )
{
a.x *= b;
a.y *= b;
}
/// Unary negate a vector
inline b2Vec2 operator-( b2Vec2 a )
{
return { -a.x, -a.y };
}
/// Binary vector addition
inline b2Vec2 operator+( b2Vec2 a, b2Vec2 b )
{
return { a.x + b.x, a.y + b.y };
}
/// Binary vector subtraction
inline b2Vec2 operator-( b2Vec2 a, b2Vec2 b )
{
return { a.x - b.x, a.y - b.y };
}
/// Binary scalar and vector multiplication
inline b2Vec2 operator*( float a, b2Vec2 b )
{
return { a * b.x, a * b.y };
}
/// Binary scalar and vector multiplication
inline b2Vec2 operator*( b2Vec2 a, float b )
{
return { a.x * b, a.y * b };
}
/// Binary vector equality
inline bool operator==( b2Vec2 a, b2Vec2 b )
{
return a.x == b.x && a.y == b.y;
}
/// Binary vector inequality
inline bool operator!=( b2Vec2 a, b2Vec2 b )
{
return a.x != b.x || a.y != b.y;
}
#endif
/**@}*/

File diff suppressed because it is too large Load Diff

BIN
libs/box2d/libbox2d.so.3.2.0 LFS Executable file

Binary file not shown.

14231
libs/rgfw/RGFW.h Normal file

File diff suppressed because it is too large Load Diff

35
src/main.c Normal file
View File

@@ -0,0 +1,35 @@
#define RGFW_IMPLEMENTATION
#define RGFW_OPENGL
#include "RGFW.h"
#include <stdio.h>
void keyfunc (RGFW_window* win, RGFW_key key, u8 keychar, RGFW_keymod keymod, RGFW_bool repeat, RGFW_bool pressed){
RGFW_UNUSED(repeat);
if (key == RGFW_escape && pressed){
RGFW_window_setShouldClose(win, 1);
}
}
int main (int argc, char **argv){
RGFW_window* win = RGFW_createWindow("PACMAN CLONE", 0,0, 800, 600, RGFW_windowCenter | RGFW_windowNoResize | RGFW_windowOpenGL);
RGFW_setKeyCallback(keyfunc);
while ( RGFW_window_shouldClose(win) == RGFW_FALSE){
RGFW_event event;
RGFW_pollEvents();
}
RGFW_window_close(win);
return 0;
}