mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
Create bindings for box2d
Currently missing lib binaries
This commit is contained in:
21
vendor/box2d/LICENSE
vendored
Normal file
21
vendor/box2d/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Erin Catto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
32
vendor/box2d/README.md
vendored
Normal file
32
vendor/box2d/README.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||

|
||||
|
||||
# Status
|
||||
[](https://github.com/erincatto/box2c/actions)
|
||||
|
||||
# Box2D v3.0 Notes
|
||||
This repository is beta and ready for testing. It should build on recent versions of clang and gcc. However, you will need the latest Visual Studio version for C11 atomics to compile (17.8.3+).
|
||||
|
||||
AVX2 CPU support is assumed. You can turn this off in the CMake options and use SSE2 instead.
|
||||
|
||||
# Box2D
|
||||
Box2D is a 2D physics engine for games.
|
||||
|
||||
## Contributing
|
||||
Please do not submit pull requests with new features or core library changes. Instead, please file an issue first for discussion. For bugs, I prefer detailed bug reports over pull requests.
|
||||
|
||||
# Giving Feedback
|
||||
Please visit the discussions tab, file an issue, or start a chat on discord.
|
||||
|
||||
## Community
|
||||
- [Discord](https://discord.gg/NKYgCBP)
|
||||
|
||||
## License
|
||||
Box2D is developed by Erin Catto, and uses the [MIT license](https://en.wikipedia.org/wiki/MIT_License).
|
||||
|
||||
## Sponsorship
|
||||
Support development of Box2D through [Github Sponsors](https://github.com/sponsors/erincatto)
|
||||
|
||||
## Ports, wrappers, and Bindings
|
||||
- https://github.com/odin-lang/Odin/tree/master/vendor/box2d
|
||||
- https://github.com/EnokViking/Box2DBeef
|
||||
- https://github.com/HolyBlackCat/box2cpp
|
||||
1202
vendor/box2d/box2d.odin
vendored
Normal file
1202
vendor/box2d/box2d.odin
vendored
Normal file
File diff suppressed because it is too large
Load Diff
757
vendor/box2d/collision.odin
vendored
Normal file
757
vendor/box2d/collision.odin
vendored
Normal file
@@ -0,0 +1,757 @@
|
||||
package vendor_box2d
|
||||
|
||||
foreign import lib {
|
||||
"box2d.lib", // dummy
|
||||
}
|
||||
|
||||
import "core:c"
|
||||
|
||||
|
||||
// The maximum number of vertices on a convex polygon. Changing this affects performance even if you
|
||||
// don't use more vertices.
|
||||
maxPolygonVertices :: 8
|
||||
|
||||
// Low level ray-cast input data
|
||||
RayCastInput :: struct {
|
||||
// Start point of the ray cast
|
||||
origin: Vec2,
|
||||
|
||||
// Translation of the ray cast
|
||||
translation: Vec2,
|
||||
|
||||
// The maximum fraction of the translation to consider, typically 1
|
||||
maxFraction: f32,
|
||||
}
|
||||
|
||||
// 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.
|
||||
ShapeCastInput :: struct {
|
||||
// A point cloud to cast
|
||||
points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
|
||||
|
||||
// The number of points
|
||||
count: i32,
|
||||
|
||||
// The radius around the point cloud
|
||||
radius: f32,
|
||||
|
||||
// The translation of the shape cast
|
||||
translation: Vec2,
|
||||
|
||||
// The maximum fraction of the translation to consider, typically 1
|
||||
maxFraction: f32,
|
||||
}
|
||||
|
||||
// Low level ray-cast or shape-cast output data
|
||||
CastOutput :: struct {
|
||||
// The surface normal at the hit point
|
||||
normal: Vec2,
|
||||
|
||||
// The surface hit point
|
||||
point: Vec2,
|
||||
|
||||
// The fraction of the input translation at collision
|
||||
fraction: f32,
|
||||
|
||||
// The number of iterations used
|
||||
iterations: i32,
|
||||
|
||||
// Did the cast hit?
|
||||
hit: bool,
|
||||
}
|
||||
|
||||
// This holds the mass data computed for a shape.
|
||||
MassData :: struct {
|
||||
// The mass of the shape, usually in kilograms.
|
||||
mass: f32,
|
||||
|
||||
// The position of the shape's centroid relative to the shape's origin.
|
||||
center: Vec2,
|
||||
|
||||
// The rotational inertia of the shape about the local origin.
|
||||
rotationalInertia: f32,
|
||||
}
|
||||
|
||||
// A solid circle
|
||||
Circle :: struct {
|
||||
// The local center
|
||||
center: Vec2,
|
||||
|
||||
// The radius
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
// A solid capsule can be viewed as two semicircles connected
|
||||
// by a rectangle.
|
||||
Capsule :: struct {
|
||||
// Local center of the first semicircle
|
||||
center1: Vec2,
|
||||
|
||||
// Local center of the second semicircle
|
||||
center2: Vec2,
|
||||
|
||||
// The radius of the semicircles
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
// 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 maxPolygonVertices.
|
||||
// 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.
|
||||
Polygon :: struct {
|
||||
// The polygon vertices
|
||||
vertices: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
|
||||
|
||||
// The outward normal vectors of the polygon sides
|
||||
normals: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
|
||||
|
||||
// The centroid of the polygon
|
||||
centroid: Vec2,
|
||||
|
||||
// The external radius for rounded polygons
|
||||
radius: f32,
|
||||
|
||||
// The number of polygon vertices
|
||||
count: i32,
|
||||
}
|
||||
|
||||
// A line segment with two-sided collision.
|
||||
Segment :: struct {
|
||||
// The first point
|
||||
point1: Vec2,
|
||||
|
||||
// The second point
|
||||
point2: Vec2,
|
||||
}
|
||||
|
||||
// A smooth 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
|
||||
SmoothSegment :: struct {
|
||||
// The tail ghost vertex
|
||||
ghost1: Vec2,
|
||||
|
||||
// The line segment
|
||||
segment: Segment,
|
||||
|
||||
// The head ghost vertex
|
||||
ghost2: Vec2,
|
||||
|
||||
// The owning chain shape index (internal usage only)
|
||||
chainId: i32,
|
||||
}
|
||||
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// Validate ray cast input data (NaN, etc)
|
||||
IsValidRay :: proc(#by_ptr input: RayCastInput) -> bool ---
|
||||
|
||||
// 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
|
||||
MakePolygon :: proc(#by_ptr hull: Hull, radius: f32) -> Polygon ---
|
||||
|
||||
// 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
|
||||
MakeOffsetPolygon :: proc(#by_ptr hull: Hull, radius: f32, transform: Transform) -> Polygon ---
|
||||
|
||||
// Make a square polygon, bypassing the need for a convex hull.
|
||||
MakeSquare :: proc(h: f32) -> Polygon ---
|
||||
|
||||
// Make a box (rectangle) polygon, bypassing the need for a convex hull.
|
||||
MakeBox :: proc(hx, hy: f32) -> Polygon ---
|
||||
|
||||
// Make a rounded box, bypassing the need for a convex hull.
|
||||
MakeRoundedBox :: proc(hx, hy: f32, radius: f32) -> Polygon ---
|
||||
|
||||
// Make an offset box, bypassing the need for a convex hull.
|
||||
MakeOffsetBox :: proc(hx, hy: f32, center: Vec2, angle: f32) -> Polygon ---
|
||||
|
||||
// Transform a polygon. This is useful for transferring a shape from one body to another.
|
||||
TransformPolygon :: proc(transform: Transform, #by_ptr polygon: Polygon) -> Polygon ---
|
||||
|
||||
// Compute mass properties of a circle
|
||||
ComputeCircleMass :: proc(#by_ptr shape: Circle, density: f32) -> MassData ---
|
||||
|
||||
// Compute mass properties of a capsule
|
||||
ComputeCapsuleMass :: proc(#by_ptr shape: Capsule, density: f32) -> MassData ---
|
||||
|
||||
// Compute mass properties of a polygon
|
||||
ComputePolygonMass :: proc(#by_ptr shape: Polygon, density: f32) -> MassData ---
|
||||
|
||||
// Compute the bounding box of a transformed circle
|
||||
ComputeCircleAABB :: proc(#by_ptr shape: Circle, transform: Transform) -> AABB ---
|
||||
|
||||
// Compute the bounding box of a transformed capsule
|
||||
ComputeCapsuleAABB :: proc(#by_ptr shape: Capsule, transform: Transform) -> AABB ---
|
||||
|
||||
// Compute the bounding box of a transformed polygon
|
||||
ComputePolygonAABB :: proc(#by_ptr shape: Polygon, transform: Transform) -> AABB ---
|
||||
|
||||
// Compute the bounding box of a transformed line segment
|
||||
ComputeSegmentAABB :: proc(#by_ptr shape: Segment, transform: Transform) -> AABB ---
|
||||
|
||||
// Test a point for overlap with a circle in local space
|
||||
PointInCircle :: proc(point: Vec2, #by_ptr shape: Circle) -> bool ---
|
||||
|
||||
// Test a point for overlap with a capsule in local space
|
||||
PointInCapsule :: proc(point: Vec2, #by_ptr shape: Capsule) -> bool ---
|
||||
|
||||
// Test a point for overlap with a convex polygon in local space
|
||||
PointInPolygon :: proc(point: Vec2, #by_ptr shape: Polygon) -> bool ---
|
||||
|
||||
// Ray cast versus circle in shape local space. Initial overlap is treated as a miss.
|
||||
RayCastCircle :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Circle) -> CastOutput ---
|
||||
|
||||
// Ray cast versus capsule in shape local space. Initial overlap is treated as a miss.
|
||||
RayCastCapsule :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Capsule) -> CastOutput ---
|
||||
|
||||
// Ray cast versus segment in shape local space. Optionally treat the segment as one-sided with hits from
|
||||
// the left side being treated as a miss.
|
||||
RayCastSegment :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Segment, oneSided: bool) -> CastOutput ---
|
||||
|
||||
// Ray cast versus polygon in shape local space. Initial overlap is treated as a miss.
|
||||
RayCastPolygon :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Polygon) -> CastOutput ---
|
||||
|
||||
// Shape cast versus a circle. Initial overlap is treated as a miss.
|
||||
ShapeCastCircle :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Circle) -> CastOutput ---
|
||||
|
||||
// Shape cast versus a capsule. Initial overlap is treated as a miss.
|
||||
ShapeCastCapsule :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Capsule) -> CastOutput ---
|
||||
|
||||
// Shape cast versus a line segment. Initial overlap is treated as a miss.
|
||||
ShapeCastSegment :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Segment) -> CastOutput ---
|
||||
|
||||
// Shape cast versus a convex polygon. Initial overlap is treated as a miss.
|
||||
ShapeCastPolygon :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Polygon) -> CastOutput ---
|
||||
}
|
||||
|
||||
// A convex hull. Used to create convex polygons.
|
||||
// @warning Do not modify these values directly, instead use b2ComputeHull()
|
||||
Hull :: struct {
|
||||
// The final points of the hull
|
||||
points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
|
||||
|
||||
// The number of points
|
||||
count: i32,
|
||||
}
|
||||
|
||||
// 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 maxPolygonVertices points
|
||||
// This welds close points and removes collinear points.
|
||||
// @warning Do not modify a hull once it has been computed
|
||||
ComputeHull :: proc "c" (points: []Vec2) -> Hull {
|
||||
foreign lib {
|
||||
b2ComputeHull :: proc "c" (points: [^]Vec2, count: i32) -> Hull ---
|
||||
}
|
||||
return b2ComputeHull(raw_data(points), i32(len(points)))
|
||||
}
|
||||
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// This determines if a hull is valid. Checks for:
|
||||
// - convexity
|
||||
// - collinear points
|
||||
// This is expensive and should not be called at runtime.
|
||||
ValidateHull :: proc(#by_ptr hull: Hull) -> bool ---
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
SegmentDistanceResult :: struct {
|
||||
// The closest point on the first segment
|
||||
closest1: Vec2,
|
||||
|
||||
// The closest point on the second segment
|
||||
closest2: Vec2,
|
||||
|
||||
// The barycentric coordinate on the first segment
|
||||
fraction1: f32,
|
||||
|
||||
// The barycentric coordinate on the second segment
|
||||
fraction2: f32,
|
||||
|
||||
// The squared distance between the closest points
|
||||
distanceSquared: f32,
|
||||
}
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// Compute the distance between two line segments, clamping at the end points if needed.
|
||||
SegmentDistance :: proc(p1, q1: Vec2, p2, q2: Vec2) -> SegmentDistanceResult ---
|
||||
}
|
||||
|
||||
// A distance proxy is used by the GJK algorithm. It encapsulates any shape.
|
||||
DistanceProxy :: struct {
|
||||
// The point cloud
|
||||
points: [maxPolygonVertices]Vec2 `fmt:"v,count"`,
|
||||
|
||||
// The number of points
|
||||
count: i32,
|
||||
|
||||
// The external radius of the point cloud
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
// Used to warm start b2Distance. Set count to zero on first call or
|
||||
// use zero initialization.
|
||||
DistanceCache :: struct {
|
||||
// The number of stored simplex points
|
||||
count: u16,
|
||||
|
||||
// The cached simplex indices on shape A
|
||||
indexA: [3]u8 `fmt:"v,count"`,
|
||||
|
||||
// The cached simplex indices on shape B
|
||||
indexB: [3]u8 `fmt:"v,count"`,
|
||||
}
|
||||
|
||||
emptyDistanceCache :: DistanceCache{}
|
||||
|
||||
// Input for b2ShapeDistance
|
||||
DistanceInput :: struct {
|
||||
// The proxy for shape A
|
||||
proxyA: DistanceProxy,
|
||||
|
||||
// The proxy for shape B
|
||||
proxyB: DistanceProxy,
|
||||
|
||||
// The world transform for shape A
|
||||
transformA: Transform,
|
||||
|
||||
// The world transform for shape B
|
||||
transformB: Transform,
|
||||
|
||||
// Should the proxy radius be considered?
|
||||
useRadii: bool,
|
||||
}
|
||||
|
||||
// Output for b2ShapeDistance
|
||||
DistanceOutput :: struct {
|
||||
pointA: Vec2, // Closest point on shapeA
|
||||
pointB: Vec2, // Closest point on shapeB
|
||||
distance: f32, // The final distance, zero if overlapped
|
||||
iterations: i32, // Number of GJK iterations used
|
||||
simplexCount: i32, // The number of simplexes stored in the simplex array
|
||||
}
|
||||
|
||||
// Simplex vertex for debugging the GJK algorithm
|
||||
SimplexVertex :: struct {
|
||||
wA: Vec2, // support point in proxyA
|
||||
wB: Vec2, // support point in proxyB
|
||||
w: Vec2, // wB - wA
|
||||
a: f32, // barycentric coordinate for closest point
|
||||
indexA: i32, // wA index
|
||||
indexB: i32, // wB index
|
||||
}
|
||||
|
||||
// Simplex from the GJK algorithm
|
||||
Simplex :: struct {
|
||||
v1, v2, v3: SimplexVertex `fmt:"v,count"`, // vertices
|
||||
count: i32, // number of valid vertices
|
||||
}
|
||||
|
||||
// Input parameters for b2ShapeCast
|
||||
ShapeCastPairInput :: struct {
|
||||
proxyA: DistanceProxy, // The proxy for shape A
|
||||
proxyB: DistanceProxy, // The proxy for shape B
|
||||
transformA: Transform, // The world transform for shape A
|
||||
transformB: Transform, // The world transform for shape B
|
||||
translationB: Vec2, // The translation of shape B
|
||||
maxFraction: f32, // The fraction of the translation to consider, typically 1
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
Sweep :: struct {
|
||||
localCenter: Vec2, // Local center of mass position
|
||||
c1: Vec2, // Starting center of mass world position
|
||||
c2: Vec2, // Ending center of mass world position
|
||||
q1: Rot, // Starting world rotation
|
||||
q2: Rot, // Ending world rotation
|
||||
}
|
||||
|
||||
// Input parameters for b2TimeOfImpact
|
||||
TOIInput :: struct {
|
||||
proxyA: DistanceProxy, // The proxy for shape A
|
||||
proxyB: DistanceProxy, // The proxy for shape B
|
||||
sweepA: Sweep, // The movement of shape A
|
||||
sweepB: Sweep, // The movement of shape B
|
||||
tMax: f32, // Defines the sweep interval [0, tMax]
|
||||
}
|
||||
|
||||
// Describes the TOI output
|
||||
TOIState :: enum c.int {
|
||||
Unknown,
|
||||
Failed,
|
||||
Overlapped,
|
||||
Hit,
|
||||
Separated,
|
||||
}
|
||||
|
||||
// Output parameters for b2TimeOfImpact.
|
||||
TOIOutput :: struct {
|
||||
state: TOIState, // The type of result
|
||||
t: f32, // The time of the collision
|
||||
}
|
||||
|
||||
// Compute the closest points between two shapes represented as point clouds.
|
||||
// DistanceCache cache is input/output. On the first call set DistanceCache.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.
|
||||
ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: []Simplex) -> DistanceOutput {
|
||||
foreign lib {
|
||||
b2ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: [^]Simplex, simplexCapacity: c.int) -> DistanceOutput ---
|
||||
}
|
||||
return b2ShapeDistance(cache, input, raw_data(simplexes), i32(len(simplexes)))
|
||||
}
|
||||
|
||||
|
||||
// Make a proxy for use in GJK and related functions.
|
||||
MakeProxy :: proc "c" (vertices: []Vec2, radius: f32) -> DistanceProxy {
|
||||
foreign lib {
|
||||
b2MakeProxy :: proc "c" (vertices: [^]Vec2, count: i32, radius: f32) -> DistanceProxy ---
|
||||
}
|
||||
return b2MakeProxy(raw_data(vertices), i32(len(vertices)), radius)
|
||||
}
|
||||
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction.
|
||||
ShapeCast :: proc(#by_ptr input: ShapeCastPairInput) -> CastOutput ---
|
||||
|
||||
// Evaluate the transform sweep at a specific time.
|
||||
GetSweepTransform :: proc(#by_ptr sweep: Sweep, time: f32) -> Transform ---
|
||||
|
||||
// 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.
|
||||
TimeOfImpact :: proc(#by_ptr input: TOIInput) -> TOIOutput ---
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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.
|
||||
ManifoldPoint :: struct {
|
||||
// Location of the contact point in world space. Subject to precision loss at large coordinates.
|
||||
// @note Should only be used for debugging.
|
||||
point: Vec2,
|
||||
|
||||
// Location of the contact point relative to bodyA's origin in world space
|
||||
// @note When used internally to the Box2D solver, these are relative to the center of mass.
|
||||
anchorA: Vec2,
|
||||
|
||||
// Location of the contact point relative to bodyB's origin in world space
|
||||
anchorB: Vec2,
|
||||
|
||||
// The separation of the contact point, negative if penetrating
|
||||
separation: f32,
|
||||
|
||||
// The impulse along the manifold normal vector.
|
||||
normalImpulse: f32,
|
||||
|
||||
// The friction impulse
|
||||
tangentImpulse: f32,
|
||||
|
||||
// The maximum normal impulse applied during sub-stepping
|
||||
// todo not sure this is needed
|
||||
maxNormalImpulse: f32,
|
||||
|
||||
// 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.
|
||||
normalVelocity: f32,
|
||||
|
||||
// Uniquely identifies a contact point between two shapes
|
||||
id: u16,
|
||||
|
||||
// Did this contact point exist the previous step?
|
||||
persisted: bool,
|
||||
}
|
||||
|
||||
// A contact manifold describes the contact points between colliding shapes
|
||||
Manifold :: struct {
|
||||
// The manifold points, up to two are possible in 2D
|
||||
points: [2]ManifoldPoint,
|
||||
|
||||
// The unit normal vector in world space, points from shape A to bodyB
|
||||
normal: Vec2,
|
||||
|
||||
// The number of contacts points, will be 0, 1, or 2
|
||||
pointCount: i32,
|
||||
}
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// Compute the contact manifold between two circles
|
||||
CollideCircles :: proc(#by_ptr circleA: Circle, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a capsule and circle
|
||||
CollideCapsuleAndCircle :: proc(#by_ptr capsuleA: Capsule, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between an segment and a circle
|
||||
CollideSegmentAndCircle :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a polygon and a circle
|
||||
CollidePolygonAndCircle :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a capsule and circle
|
||||
CollideCapsules :: proc(#by_ptr capsuleA: Capsule, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between an segment and a capsule
|
||||
CollideSegmentAndCapsule :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a polygon and capsule
|
||||
CollidePolygonAndCapsule :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between two polygons
|
||||
CollidePolygons :: proc(#by_ptr polygonA: Polygon, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between an segment and a polygon
|
||||
CollideSegmentAndPolygon :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a smooth segment and a circle
|
||||
CollideSmoothSegmentAndCircle :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between an segment and a capsule
|
||||
CollideSmoothSegmentAndCapsule :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform, cache: ^DistanceCache) -> Manifold ---
|
||||
|
||||
// Compute the contact manifold between a smooth segment and a rounded polygon
|
||||
CollideSmoothSegmentAndPolygon :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform, cache: ^DistanceCache) -> Manifold ---
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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, such as a reference to a b2Shape.
|
||||
* 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.
|
||||
*
|
||||
* @note This is an advanced feature and normally not used by applications directly.
|
||||
*/
|
||||
|
||||
// The default category bit for a tree proxy. Used for collision filtering.
|
||||
defaultCategoryBits :: 0x00000001
|
||||
|
||||
// Convenience mask bits to use when you don't need collision filtering and just want
|
||||
// all results.
|
||||
defaultMaskBits :: 0xFFFFFFFF
|
||||
|
||||
// A node in the dynamic tree. This is private data placed here for performance reasons.
|
||||
// 16 + 16 + 8 + pad(8)
|
||||
TreeNode :: struct {
|
||||
// The node bounding box
|
||||
aabb: AABB, // 16
|
||||
|
||||
// Category bits for collision filtering
|
||||
categoryBits: u32, // 4
|
||||
|
||||
using _: struct #raw_union {
|
||||
// The node parent index
|
||||
parent: i32,
|
||||
|
||||
// The node freelist next index
|
||||
next: i32,
|
||||
}, // 4
|
||||
|
||||
// Child 1 index
|
||||
child1: i32, // 4
|
||||
|
||||
// Child 2 index
|
||||
child2: i32, // 4
|
||||
|
||||
// User data
|
||||
// todo could be union with child index
|
||||
userData: i32, // 4
|
||||
|
||||
// Leaf = 0, free node = -1
|
||||
height: i16, // 2
|
||||
|
||||
// Has the AABB been enlarged?
|
||||
enlarged: bool, // 1
|
||||
|
||||
// Padding for clarity
|
||||
pad: [9]byte,
|
||||
}
|
||||
|
||||
// The dynamic tree structure. This should be considered private data.
|
||||
// It is placed here for performance reasons.
|
||||
DynamicTree :: struct {
|
||||
// The tree nodes
|
||||
nodes: [^]TreeNode `fmt"v,nodeCount"`,
|
||||
|
||||
// The root index
|
||||
root: i32,
|
||||
|
||||
// The number of nodes
|
||||
nodeCount: i32,
|
||||
|
||||
// The allocated node space
|
||||
nodeCapacity: i32,
|
||||
|
||||
// Node free list
|
||||
freeList: i32,
|
||||
|
||||
// Number of proxies created
|
||||
proxyCount: i32,
|
||||
|
||||
// Leaf indices for rebuild
|
||||
leafIndices: [^]i32,
|
||||
|
||||
// Leaf bounding boxes for rebuild
|
||||
leafBoxes: [^]AABB,
|
||||
|
||||
// Leaf bounding box centers for rebuild
|
||||
leafCenters: [^]Vec2,
|
||||
|
||||
// Bins for sorting during rebuild
|
||||
binIndices: [^]i32,
|
||||
|
||||
// Allocated space for rebuilding
|
||||
rebuildCapacity: i32,
|
||||
}
|
||||
|
||||
// This function receives proxies found in the AABB query.
|
||||
// @return true if the query should continue
|
||||
TreeQueryCallbackFcn :: #type proc "c" (proxyId: i32, userData: i32, ctx: rawptr) -> bool
|
||||
|
||||
// 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
|
||||
TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32
|
||||
|
||||
|
||||
// This function receives clipped raycast 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
|
||||
TreeRayCastCallbackFcn :: #type proc "c" (#by_ptr input: RayCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32
|
||||
|
||||
@(link_prefix="b2", default_calling_convention="c")
|
||||
foreign lib {
|
||||
// Constructing the tree initializes the node pool.
|
||||
DynamicTree_Create :: proc() -> DynamicTree ---
|
||||
|
||||
// Destroy the tree, freeing the node pool.
|
||||
DynamicTree_Destroy :: proc(tree: ^DynamicTree) ---
|
||||
|
||||
// Create a proxy. Provide an AABB and a userData value.
|
||||
DynamicTree_CreateProxy :: proc(tree: ^DynamicTree, aabb: AABB, categoryBits: u32, userData: i32) -> i32 ---
|
||||
|
||||
// Destroy a proxy. This asserts if the id is invalid.
|
||||
DynamicTree_DestroyProxy :: proc(tree: ^DynamicTree, proxyId: i32) ---
|
||||
|
||||
// Move a proxy to a new AABB by removing and reinserting into the tree.
|
||||
DynamicTree_MoveProxy :: proc(tree: ^DynamicTree, proxyId: i32, aabb: AABB) ---
|
||||
|
||||
// Enlarge a proxy and enlarge ancestors as necessary.
|
||||
DynamicTree_EnlargeProxy :: proc(tree: ^DynamicTree, proxyId: i32, aabb: AABB) ---
|
||||
|
||||
// Query an AABB for overlapping proxies. The callback class
|
||||
// is called for each proxy that overlaps the supplied AABB.
|
||||
DynamicTree_Query :: proc(#by_ptr tree: DynamicTree, aabb: AABB, maskBits: u32, callback: TreeQueryCallbackFcn, ctx: rawptr) ---
|
||||
|
||||
// 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.
|
||||
// @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 ray
|
||||
// @param context user context that is passed to the callback
|
||||
DynamicTree_RayCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: RayCastInput, maskBits: u32, callback: TreeRayCastCallbackFcn, ctx: rawptr) ---
|
||||
|
||||
// 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
|
||||
DynamicTree_ShapeCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: ShapeCastInput, maskBits: u32, callback: TreeShapeCastCallbackFcn, ctx: rawptr) ---
|
||||
|
||||
// Validate this tree. For testing.
|
||||
DynamicTree_Validate :: proc(#by_ptr tree: DynamicTree) ---
|
||||
|
||||
// Compute the height of the binary tree in O(N) time. Should not be
|
||||
// called often.
|
||||
DynamicTree_GetHeight :: proc(#by_ptr tree: DynamicTree) -> c.int ---
|
||||
|
||||
// Get the maximum balance of the tree. The balance is the difference in height of the two children of a node.
|
||||
DynamicTree_GetMaxBalance :: proc(#by_ptr tree: DynamicTree) -> c.int ---
|
||||
|
||||
// Get the ratio of the sum of the node areas to the root area.
|
||||
DynamicTree_GetAreaRatio :: proc(#by_ptr tree: DynamicTree) -> f32 ---
|
||||
|
||||
// Build an optimal tree. Very expensive. For testing.
|
||||
DynamicTree_RebuildBottomUp :: proc(tree: ^DynamicTree) ---
|
||||
|
||||
// Get the number of proxies created
|
||||
DynamicTree_GetProxyCount :: proc(#by_ptr tree: DynamicTree) -> c.int ---
|
||||
|
||||
// Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted.
|
||||
DynamicTree_Rebuild :: proc(tree: ^DynamicTree, fullBuild: bool) -> c.int ---
|
||||
|
||||
// Shift the world origin. Useful for large worlds.
|
||||
// The shift formula is: position -= newOrigin
|
||||
// @param tree the tree to shift
|
||||
// @param newOrigin the new origin with respect to the old origin
|
||||
DynamicTree_ShiftOrigin :: proc(tree: ^DynamicTree, newOrigin: Vec2) ---
|
||||
|
||||
// Get the number of bytes used by this tree
|
||||
DynamicTree_GetByteCount :: proc(#by_ptr tree: DynamicTree) -> c.int ---
|
||||
}
|
||||
|
||||
// Get proxy user data
|
||||
// @return the proxy user data or 0 if the id is invalid
|
||||
DynamicTree_GetUserData :: proc "contextless" (tree: DynamicTree, proxyId: i32) -> i32 {
|
||||
return tree.nodes[proxyId].userData
|
||||
}
|
||||
|
||||
// Get the AABB of a proxy
|
||||
DynamicTree_GetAABB :: proc "contextless" (tree: DynamicTree, proxyId: i32) -> AABB {
|
||||
return tree.nodes[proxyId].aabb
|
||||
}
|
||||
77
vendor/box2d/id.odin
vendored
Normal file
77
vendor/box2d/id.odin
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package vendor_box2d
|
||||
|
||||
/**
|
||||
* @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.
|
||||
WorldId :: struct {
|
||||
index1: u16,
|
||||
revision: u16,
|
||||
}
|
||||
|
||||
/// Body id references a body instance. This should be treated as an opaque handle.
|
||||
BodyId :: struct {
|
||||
index1: i32,
|
||||
world0: u16,
|
||||
revision: u16,
|
||||
}
|
||||
|
||||
/// Shape id references a shape instance. This should be treated as an opaque handle.
|
||||
ShapeId :: struct {
|
||||
index1: i32,
|
||||
world0: u16,
|
||||
revision: u16,
|
||||
}
|
||||
|
||||
/// Joint id references a joint instance. This should be treated as an opaque handle.
|
||||
JointId :: struct {
|
||||
index1: i32,
|
||||
world0: u16,
|
||||
revision: u16,
|
||||
}
|
||||
|
||||
/// Chain id references a chain instances. This should be treated as an opaque handle.
|
||||
ChainId :: struct {
|
||||
index1: i32,
|
||||
world0: u16,
|
||||
revision: u16,
|
||||
}
|
||||
|
||||
/// Use these to make your identifiers null.
|
||||
/// You may also use zero initialization to get null.
|
||||
nullWorldId :: WorldId{}
|
||||
nullBodyId :: BodyId{}
|
||||
nullShapeId :: ShapeId{}
|
||||
nullJointId :: JointId{}
|
||||
nullChainId :: ChainId{}
|
||||
|
||||
/// Macro to determine if any id is null.
|
||||
IS_NULL :: proc "c" (id: $T) -> bool { return id.index1 == 0 }
|
||||
|
||||
/// Macro to determine if any id is non-null.
|
||||
IS_NON_NULL :: proc "c" (id: $T) -> bool { return id.index1 != 0 }
|
||||
|
||||
/// Compare two ids for equality. Doesn't work for b2WorldId.
|
||||
ID_EQUALS :: proc "c" (id1, id2: $T) -> bool { return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.revision == id2.revision }
|
||||
460
vendor/box2d/math_functions.odin
vendored
Normal file
460
vendor/box2d/math_functions.odin
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
package vendor_box2d
|
||||
|
||||
import "core:c"
|
||||
import "core:math"
|
||||
|
||||
pi :: 3.14159265359
|
||||
|
||||
Vec2 :: [2]f32
|
||||
Rot :: struct {
|
||||
c, s: f32, // cosine and sine
|
||||
}
|
||||
|
||||
Transform :: struct {
|
||||
p: Vec2,
|
||||
q: Rot,
|
||||
}
|
||||
|
||||
Mat22 :: matrix[2, 2]f32
|
||||
AABB :: struct {
|
||||
lowerBound: Vec2,
|
||||
upperBound: Vec2,
|
||||
}
|
||||
|
||||
Vec2_zero :: Vec2{0, 0}
|
||||
Rot_identity :: Rot{1, 0}
|
||||
Transform_identity :: Transform{{0, 0}, {1, 0}}
|
||||
Mat22_zero :: Mat22{0, 0, 0, 0}
|
||||
|
||||
|
||||
// @return the minimum of two floats
|
||||
MinFloat :: proc "c" (a, b: f32) -> f32 {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
// @return the maximum of two floats
|
||||
MaxFloat :: proc "c" (a, b: f32) -> f32 {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
// @return the absolute value of a float
|
||||
AbsFloat :: proc "c" (a: f32) -> f32 {
|
||||
return abs(a)
|
||||
}
|
||||
|
||||
// @return a f32 clamped between a lower and upper bound
|
||||
ClampFloat :: proc "c" (a, lower, upper: f32) -> f32 {
|
||||
return clamp(a, lower, upper)
|
||||
}
|
||||
|
||||
// @return the minimum of two integers
|
||||
MinInt :: proc "c" (a, b: c.int) -> c.int {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
// @return the maximum of two integers
|
||||
MaxInt :: proc "c" (a, b: c.int) -> c.int {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
// @return the absolute value of an integer
|
||||
AbsInt :: proc "c" (a: c.int) -> c.int {
|
||||
return abs(a)
|
||||
}
|
||||
|
||||
// @return an integer clamped between a lower and upper bound
|
||||
ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int {
|
||||
return clamp(a, lower, upper)
|
||||
}
|
||||
|
||||
// Vector dot product
|
||||
Dot :: proc "c" (a, b: Vec2) -> f32 {
|
||||
return a.x * b.x + a.y * b.y
|
||||
}
|
||||
|
||||
// Vector cross product. In 2D this yields a scalar.
|
||||
Cross :: proc "c" (a, b: Vec2) -> f32 {
|
||||
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.
|
||||
CrossVS :: proc "c" (v: Vec2, s: f32) -> Vec2 {
|
||||
return {s * v.y, -s * v.x}
|
||||
}
|
||||
|
||||
// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
|
||||
CrossSV :: proc "c" (s: f32, v: Vec2) -> Vec2 {
|
||||
return {-s * v.y, s * v.x}
|
||||
}
|
||||
|
||||
// Get a left pointing perpendicular vector. Equivalent to b2CrossSV(1, v)
|
||||
LeftPerp :: proc "c" (v: Vec2) -> Vec2 {
|
||||
return {-v.y, v.x}
|
||||
}
|
||||
|
||||
// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1)
|
||||
RightPerp :: proc "c" (v: Vec2) -> Vec2 {
|
||||
return {v.y, -v.x}
|
||||
}
|
||||
|
||||
// Vector addition
|
||||
Add :: proc "c" (a, b: Vec2) -> Vec2 {
|
||||
return a + b
|
||||
}
|
||||
|
||||
// Vector subtraction
|
||||
Sub :: proc "c" (a, b: Vec2) -> Vec2 {
|
||||
return a - b
|
||||
}
|
||||
|
||||
// Vector negation
|
||||
Neg :: proc "c" (a: Vec2) -> Vec2 {
|
||||
return -a
|
||||
}
|
||||
|
||||
// Vector linear interpolation
|
||||
// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
|
||||
Lerp :: proc "c" (a, b: Vec2, t: f32) -> Vec2 {
|
||||
return {(1 - t) * a.x + t * b.x, (1 - t) * a.y + t * b.y}
|
||||
}
|
||||
|
||||
// Component-wise multiplication
|
||||
Mul :: proc "c" (a, b: Vec2) -> Vec2 {
|
||||
return a * b
|
||||
}
|
||||
|
||||
// Multiply a scalar and vector
|
||||
MulSV :: proc "c" (s: f32, v: Vec2) -> Vec2 {
|
||||
return s * v
|
||||
}
|
||||
|
||||
// a + s * b
|
||||
MulAdd :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
|
||||
return a + s * b
|
||||
}
|
||||
|
||||
// a - s * b
|
||||
MulSub :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
|
||||
return a - s * b
|
||||
}
|
||||
|
||||
// Component-wise absolute vector
|
||||
Abs :: proc "c" (a: Vec2) -> (b: Vec2) {
|
||||
b.x = AbsFloat(a.x)
|
||||
b.y = AbsFloat(a.y)
|
||||
return
|
||||
}
|
||||
|
||||
// Component-wise minimum vector
|
||||
Min :: proc "c" (a, b: Vec2) -> (c: Vec2) {
|
||||
c.x = MinFloat(a.x, b.x)
|
||||
c.y = MinFloat(a.y, b.y)
|
||||
return
|
||||
}
|
||||
|
||||
// Component-wise maximum vector
|
||||
Max :: proc "c" (a, b: Vec2) -> (c: Vec2) {
|
||||
c.x = MaxFloat(a.x, b.x)
|
||||
c.y = MaxFloat(a.y, b.y)
|
||||
return
|
||||
}
|
||||
|
||||
// Component-wise clamp vector v into the range [a, b]
|
||||
Clamp :: proc "c" (v: Vec2, a, b: Vec2) -> (c: Vec2) {
|
||||
c.x = ClampFloat(v.x, a.x, b.x)
|
||||
c.y = ClampFloat(v.y, a.y, b.y)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the length of this vector (the norm)
|
||||
Length :: proc "c" (v: Vec2) -> f32 {
|
||||
return math.sqrt(v.x * v.x + v.y * v.y)
|
||||
}
|
||||
|
||||
// Get the length squared of this vector
|
||||
LengthSquared :: proc "c" (v: Vec2) -> f32 {
|
||||
return v.x * v.x + v.y * v.y
|
||||
}
|
||||
|
||||
// Get the distance between two points
|
||||
Distance :: proc "c" (a, b: Vec2) -> f32 {
|
||||
dx := b.x - a.x
|
||||
dy := b.y - a.y
|
||||
return math.sqrt(dx * dx + dy * dy)
|
||||
}
|
||||
|
||||
// Get the distance squared between points
|
||||
DistanceSquared :: proc "c" (a, b: Vec2) -> f32 {
|
||||
c := Vec2{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
|
||||
MakeRot :: proc "c" (angle: f32) -> Rot {
|
||||
// todo determinism
|
||||
return {math.cos(angle), math.sin(angle)}
|
||||
}
|
||||
|
||||
// Normalize rotation
|
||||
NormalizeRot :: proc "c" (q: Rot) -> Rot {
|
||||
mag := math.sqrt(q.s * q.s + q.c * q.c)
|
||||
invMag := f32(mag > 0.0 ? 1.0 / mag : 0.0)
|
||||
return {q.c * invMag, q.s * invMag}
|
||||
}
|
||||
|
||||
// Is this rotation normalized?
|
||||
IsNormalized :: proc "c" (q: Rot) -> bool {
|
||||
// larger tolerance due to failure on mingw 32-bit
|
||||
qq := q.s * q.s + q.c * q.c
|
||||
return 1.0 - 0.0006 < qq && qq < 1 + 0.0006
|
||||
}
|
||||
|
||||
// Normalized linear interpolation
|
||||
// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
|
||||
NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot {
|
||||
omt := 1 - t
|
||||
return NormalizeRot({
|
||||
omt * q1.c + t * q2.c,
|
||||
omt * q1.s + t * q2.s,
|
||||
})
|
||||
}
|
||||
|
||||
// Integration rotation from angular velocity
|
||||
// @param q1 initial rotation
|
||||
// @param deltaAngle the angular displacement in radians
|
||||
IntegrateRotation :: proc "c" (q1: Rot, deltaAngle: f32) -> Rot {
|
||||
// dc/dt = -omega * sin(t)
|
||||
// ds/dt = omega * cos(t)
|
||||
// c2 = c1 - omega * h * s1
|
||||
// s2 = s1 + omega * h * c1
|
||||
q2 := Rot{q1.c - deltaAngle * q1.s, q1.s + deltaAngle * q1.c}
|
||||
mag := math.sqrt(q2.s * q2.s + q2.c * q2.c)
|
||||
invMag := f32(mag > 0.0 ? 1 / mag : 0.0)
|
||||
return {q2.c * invMag, q2.s * invMag}
|
||||
}
|
||||
|
||||
// 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
|
||||
ComputeAngularVelocity :: proc "c" (q1: Rot, q2: Rot, inv_h: f32) -> f32 {
|
||||
// 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
|
||||
omega := inv_h * (q2.s * q1.c - q2.c * q1.s)
|
||||
return omega
|
||||
}
|
||||
|
||||
// Get the angle in radians in the range [-pi, pi]
|
||||
Rot_GetAngle :: proc "c" (q: Rot) -> f32 {
|
||||
// todo determinism
|
||||
return math.atan2(q.s, q.c)
|
||||
}
|
||||
|
||||
// Get the x-axis
|
||||
Rot_GetXAxis :: proc "c" (q: Rot) -> Vec2 {
|
||||
return {q.c, q.s}
|
||||
}
|
||||
|
||||
// Get the y-axis
|
||||
Rot_GetYAxis :: proc "c" (q: Rot) -> Vec2 {
|
||||
return {-q.s, q.c}
|
||||
}
|
||||
|
||||
// Multiply two rotations: q * r
|
||||
MulRot :: proc "c" (q, r: Rot) -> (qr: Rot) {
|
||||
// [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
|
||||
qr.s = q.s * r.c + q.c * r.s
|
||||
qr.c = q.c * r.c - q.s * r.s
|
||||
return
|
||||
}
|
||||
|
||||
// Transpose multiply two rotations: qT * r
|
||||
InvMulRot :: proc "c" (q, r: Rot) -> (qr: Rot) {
|
||||
// [ 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) = qc * rs - qs * rc
|
||||
// c(q - r) = qc * rc + qs * rs
|
||||
qr.s = q.c * r.s - q.s * r.c
|
||||
qr.c = q.c * r.c + q.s * r.s
|
||||
return
|
||||
}
|
||||
|
||||
// relative angle between b and a (rot_b * inv(rot_a))
|
||||
RelativeAngle :: proc "c" (b, a: Rot) -> f32 {
|
||||
// sin(b - a) = bs * ac - bc * as
|
||||
// cos(b - a) = bc * ac + bs * as
|
||||
s := b.s * a.c - b.c * a.s
|
||||
c := b.c * a.c + b.s * a.s
|
||||
return math.atan2(s, c)
|
||||
}
|
||||
|
||||
// Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi]
|
||||
UnwindAngle :: proc "c" (angle: f32) -> f32 {
|
||||
if angle < -pi {
|
||||
return angle + 2.0 * pi
|
||||
} else if angle > pi {
|
||||
return angle - 2.0 * pi
|
||||
}
|
||||
return angle
|
||||
}
|
||||
|
||||
// Rotate a vector
|
||||
RotateVector :: proc "c" (q: Rot, v: Vec2) -> Vec2 {
|
||||
return {q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y}
|
||||
}
|
||||
|
||||
// Inverse rotate a vector
|
||||
InvRotateVector :: proc "c" (q: Rot, v: Vec2) -> Vec2 {
|
||||
return {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)
|
||||
TransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 {
|
||||
x := (t.q.c * p.x - t.q.s * p.y) + t.p.x
|
||||
y := (t.q.s * p.x + t.q.c * p.y) + t.p.y
|
||||
return {x, y}
|
||||
}
|
||||
|
||||
// Inverse transform a point (e.g. world space to local space)
|
||||
InvTransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 {
|
||||
vx := p.x - t.p.x
|
||||
vy := p.y - t.p.y
|
||||
return {t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy}
|
||||
}
|
||||
|
||||
// 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
|
||||
MulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) {
|
||||
C.q = MulRot(A.q, B.q)
|
||||
C.p = RotateVector(A.q, B.p) + A.p
|
||||
return
|
||||
}
|
||||
|
||||
// v2 = A.q' * (B.q * v1 + B.p - A.p)
|
||||
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
|
||||
InvMulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) {
|
||||
C.q = InvMulRot(A.q, B.q)
|
||||
C.p = InvRotateVector(A.q, B.p-A.p)
|
||||
return
|
||||
}
|
||||
|
||||
// Multiply a 2-by-2 matrix times a 2D vector
|
||||
MulMV :: proc "c" (A: Mat22, v: Vec2) -> Vec2 {
|
||||
return A * v
|
||||
}
|
||||
|
||||
// Get the inverse of a 2-by-2 matrix
|
||||
GetInverse22 :: proc "c" (A: Mat22) -> Mat22 {
|
||||
a := A[0, 0]
|
||||
b := A[0, 1]
|
||||
c := A[1, 0]
|
||||
d := A[1, 1]
|
||||
det := a * d - b * c
|
||||
if det != 0.0 {
|
||||
det = 1 / det
|
||||
}
|
||||
|
||||
return Mat22{
|
||||
det * d, -det * b,
|
||||
-det * c, det * a,
|
||||
}
|
||||
}
|
||||
|
||||
// Solve A * x = b, where b is a column vector. This is more efficient
|
||||
// than computing the inverse in one-shot cases.
|
||||
Solve22 :: proc "c" (A: Mat22, b: Vec2) -> Vec2 {
|
||||
a11 := A[0, 0]
|
||||
a12 := A[0, 1]
|
||||
a21 := A[1, 0]
|
||||
a22 := A[1, 1]
|
||||
det := a11 * a22 - a12 * a21
|
||||
if det != 0.0 {
|
||||
det = 1 / det
|
||||
}
|
||||
return {det * (a22 * b.x - a12 * b.y), det * (a11 * b.y - a21 * b.x)}
|
||||
}
|
||||
|
||||
// Does a fully contain b
|
||||
AABB_Contains :: proc "c" (a, b: AABB) -> bool {
|
||||
(a.lowerBound.x <= b.lowerBound.x) or_return
|
||||
(a.lowerBound.y <= b.lowerBound.y) or_return
|
||||
(b.upperBound.x <= a.upperBound.x) or_return
|
||||
(b.upperBound.y <= a.upperBound.y) or_return
|
||||
return true
|
||||
}
|
||||
|
||||
// Get the center of the AABB.
|
||||
AABB_Center :: proc "c" (a: AABB) -> Vec2 {
|
||||
return {0.5 * (a.lowerBound.x + a.upperBound.x), 0.5 * (a.lowerBound.y + a.upperBound.y)}
|
||||
}
|
||||
|
||||
// Get the extents of the AABB (half-widths).
|
||||
AABB_Extents :: proc "c" (a: AABB) -> Vec2 {
|
||||
return {0.5 * (a.upperBound.x - a.lowerBound.x), 0.5 * (a.upperBound.y - a.lowerBound.y)}
|
||||
}
|
||||
|
||||
// Union of two AABBs
|
||||
AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) {
|
||||
c.lowerBound.x = MinFloat(a.lowerBound.x, b.lowerBound.x)
|
||||
c.lowerBound.y = MinFloat(a.lowerBound.y, b.lowerBound.y)
|
||||
c.upperBound.x = MaxFloat(a.upperBound.x, b.upperBound.x)
|
||||
c.upperBound.y = MaxFloat(a.upperBound.y, b.upperBound.y)
|
||||
return
|
||||
}
|
||||
|
||||
Float_IsValid :: proc "c" (a: f32) -> bool {
|
||||
math.is_nan(a) or_return
|
||||
math.is_inf(a) or_return
|
||||
return true
|
||||
}
|
||||
|
||||
Vec2_IsValid :: proc "c" (v: Vec2) -> bool {
|
||||
(math.is_nan(v.x) || math.is_nan(v.y)) or_return
|
||||
(math.is_inf(v.x) || math.is_inf(v.y)) or_return
|
||||
return true
|
||||
}
|
||||
|
||||
Rot_IsValid :: proc "c" (q: Rot) -> bool {
|
||||
(math.is_nan(q.s) || math.is_nan(q.c)) or_return
|
||||
(math.is_inf(q.s) || math.is_inf(q.c)) or_return
|
||||
return IsNormalized(q)
|
||||
}
|
||||
|
||||
Normalize :: proc "c" (v: Vec2) -> Vec2 {
|
||||
length := Length(v)
|
||||
if length < 1e-23 {
|
||||
return Vec2_zero
|
||||
}
|
||||
invLength := 1 / length
|
||||
return invLength * v
|
||||
}
|
||||
|
||||
NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 {
|
||||
length := Length(v)
|
||||
if length < 1e-23 {
|
||||
panic("zero-length Vec2")
|
||||
}
|
||||
invLength := 1 / length
|
||||
return invLength * v
|
||||
}
|
||||
|
||||
GetLengthAndNormalize :: proc "c" (v: Vec2) -> (length: f32, vn: Vec2) {
|
||||
length = Length(v)
|
||||
if length < 1e-23 {
|
||||
return
|
||||
}
|
||||
invLength := 1 / length
|
||||
vn = invLength * v
|
||||
return
|
||||
}
|
||||
1231
vendor/box2d/types.odin
vendored
Normal file
1231
vendor/box2d/types.odin
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user