Merge pull request #4074 from odin-lang/vendor/box2d

`vendor:box2d`
This commit is contained in:
gingerBill
2024-08-14 11:15:34 +01:00
committed by GitHub
14 changed files with 3952 additions and 1 deletions

View File

@@ -1,4 +1,7 @@
package all
import wgpu "vendor:wgpu"
_ :: wgpu
import b2 "vendor:box2d"
_ :: wgpu
_ :: b2

21
vendor/box2d/LICENSE vendored Normal file
View 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
View File

@@ -0,0 +1,32 @@
![Box2D Logo](https://box2d.org/images/logo.svg)
# Status
[![Build Status](https://github.com/erincatto/box2c/actions/workflows/build.yml/badge.svg)](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

1510
vendor/box2d/box2d.odin vendored Normal file

File diff suppressed because it is too large Load Diff

72
vendor/box2d/build_box2d.sh vendored Executable file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -eu
VERSION="3.0.0"
RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz"
cd "$(odin root)"/vendor/box2d
curl -O -L "$RELEASE"
tar -xzvf "v$VERSION.tar.gz"
cd "box2d-$VERSION"
DISABLE_FLAGS="-DBOX2D_SAMPLES=OFF -DBOX2D_VALIDATE=OFF -DBOX2D_UNIT_TESTS=OFF"
case "$(uname -s)" in
Darwin)
export MACOSX_DEPLOYMENT_TARGET="11"
case "$(uname -m)" in
"x86_64" | "amd64")
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_avx2.a
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_amd64_sse2.a
;;
*)
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_darwin_arm64.a
;;
esac
;;
*)
case "$(uname -m)" in
"x86_64" | "amd64")
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DBOX2D_AVX2=ON -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other_amd64_avx2.a
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DBOX2D_AVX2=OFF -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other_amd64_sse2.a
;;
*)
rm -rf build
mkdir build
cmake $DISABLE_FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build
cmake --build build
cp build/src/libbox2d.a ../lib/box2d_other.a
;;
esac
;;
esac
cd ..
rm -rf v3.0.0.tar.gz
rm -rf box2d-3.0.0

473
vendor/box2d/collision.odin vendored Normal file
View File

@@ -0,0 +1,473 @@
package vendor_box2d
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,
}
// 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,
}
/**
* @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,
}
// 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
}
/**
* @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,
}
/**
* @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
_: [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

87
vendor/box2d/id.odin vendored Normal file
View File

@@ -0,0 +1,87 @@
package vendor_box2d
import "base:intrinsics"
/**
* @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 Odin:
*
* @code{.odin}
* worldId := b2.WorldId{}
* @endcode
*
* This is 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 :: #force_inline proc "c" (id: $T) -> bool
where intrinsics.type_is_struct(T),
intrinsics.type_has_field(T, "index1") {
return id.index1 == 0
}
/// Macro to determine if any id is non-null.
IS_NON_NULL :: #force_inline proc "c" (id: $T) -> bool
where intrinsics.type_is_struct(T),
intrinsics.type_has_field(T, "index1") {
return id.index1 != 0
}
/// Compare two ids for equality. Doesn't work for b2WorldId.
ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool
where intrinsics.type_is_struct(T),
intrinsics.type_has_field(T, "index1"),
intrinsics.type_has_field(T, "world0"),
intrinsics.type_has_field(T, "revision") {
return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.revision == id2.revision
}

Binary file not shown.

Binary file not shown.

BIN
vendor/box2d/lib/box2d_darwin_arm64.a vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

522
vendor/box2d/math_functions.odin vendored Normal file
View File

@@ -0,0 +1,522 @@
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
@(deprecated="Prefer the built-in 'min(a, b)'", require_results)
MinFloat :: proc "c" (a, b: f32) -> f32 {
return min(a, b)
}
// @return the maximum of two floats
@(deprecated="Prefer the built-in 'max(a, b)'", require_results)
MaxFloat :: proc "c" (a, b: f32) -> f32 {
return max(a, b)
}
// @return the absolute value of a float
@(deprecated="Prefer the built-in 'abs(a)'", require_results)
AbsFloat :: proc "c" (a: f32) -> f32 {
return abs(a)
}
// @return a f32 clamped between a lower and upper bound
@(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results)
ClampFloat :: proc "c" (a, lower, upper: f32) -> f32 {
return clamp(a, lower, upper)
}
// @return the minimum of two integers
@(deprecated="Prefer the built-in 'min(a, b)'", require_results)
MinInt :: proc "c" (a, b: c.int) -> c.int {
return min(a, b)
}
// @return the maximum of two integers
@(deprecated="Prefer the built-in 'max(a, b)'", require_results)
MaxInt :: proc "c" (a, b: c.int) -> c.int {
return max(a, b)
}
// @return the absolute value of an integer
@(deprecated="Prefer the built-in 'abs(a)'", require_results)
AbsInt :: proc "c" (a: c.int) -> c.int {
return abs(a)
}
// @return an integer clamped between a lower and upper bound
@(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results)
ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int {
return clamp(a, lower, upper)
}
// Vector dot product
@(require_results)
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.
@(require_results)
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.
@(require_results)
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.
@(require_results)
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)
@(require_results)
LeftPerp :: proc "c" (v: Vec2) -> Vec2 {
return {-v.y, v.x}
}
// Get a right pointing perpendicular vector. Equivalent to b2CrossVS(v, 1)
@(require_results)
RightPerp :: proc "c" (v: Vec2) -> Vec2 {
return {v.y, -v.x}
}
// Vector addition
@(deprecated="Prefer 'a + b'", require_results)
Add :: proc "c" (a, b: Vec2) -> Vec2 {
return a + b
}
// Vector subtraction
@(deprecated="Prefer 'a - b'", require_results)
Sub :: proc "c" (a, b: Vec2) -> Vec2 {
return a - b
}
// Vector negation
@(deprecated="Prefer '-a'", require_results)
Neg :: proc "c" (a: Vec2) -> Vec2 {
return -a
}
// Vector linear interpolation
// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
@(require_results)
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
@(deprecated="Prefer 'a * b'", require_results)
Mul :: proc "c" (a, b: Vec2) -> Vec2 {
return a * b
}
// Multiply a scalar and vector
@(deprecated="Prefer 's * v'", require_results)
MulSV :: proc "c" (s: f32, v: Vec2) -> Vec2 {
return s * v
}
// a + s * b
@(deprecated="Prefer 'a + s * b'", require_results)
MulAdd :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
return a + s * b
}
// a - s * b
@(deprecated="Prefer 'a - s * b'", require_results)
MulSub :: proc "c" (a: Vec2, s: f32, b: Vec2) -> Vec2 {
return a - s * b
}
// Component-wise absolute vector
@(require_results)
Abs :: proc "c" (a: Vec2) -> (b: Vec2) {
b.x = abs(a.x)
b.y = abs(a.y)
return
}
// Component-wise minimum vector
@(require_results)
Min :: proc "c" (a, b: Vec2) -> (c: Vec2) {
c.x = min(a.x, b.x)
c.y = min(a.y, b.y)
return
}
// Component-wise maximum vector
@(require_results)
Max :: proc "c" (a, b: Vec2) -> (c: Vec2) {
c.x = max(a.x, b.x)
c.y = max(a.y, b.y)
return
}
// Component-wise clamp vector v into the range [a, b]
@(require_results)
Clamp :: proc "c" (v: Vec2, a, b: Vec2) -> (c: Vec2) {
c.x = clamp(v.x, a.x, b.x)
c.y = clamp(v.y, a.y, b.y)
return
}
// Get the length of this vector (the norm)
@(require_results)
Length :: proc "c" (v: Vec2) -> f32 {
return math.sqrt(v.x * v.x + v.y * v.y)
}
// Get the length squared of this vector
@(require_results)
LengthSquared :: proc "c" (v: Vec2) -> f32 {
return v.x * v.x + v.y * v.y
}
// Get the distance between two points
@(require_results)
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
@(require_results)
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
@(require_results)
MakeRot :: proc "c" (angle: f32) -> Rot {
// todo determinism
return {math.cos(angle), math.sin(angle)}
}
// Normalize rotation
@(require_results)
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?
@(require_results)
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/
@(require_results)
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
@(require_results)
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
@(require_results)
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]
@(require_results)
Rot_GetAngle :: proc "c" (q: Rot) -> f32 {
// todo determinism
return math.atan2(q.s, q.c)
}
// Get the x-axis
@(require_results)
Rot_GetXAxis :: proc "c" (q: Rot) -> Vec2 {
return {q.c, q.s}
}
// Get the y-axis
@(require_results)
Rot_GetYAxis :: proc "c" (q: Rot) -> Vec2 {
return {-q.s, q.c}
}
// Multiply two rotations: q * r
@(require_results)
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
@(require_results)
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))
@(require_results)
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]
@(require_results)
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
@(require_results)
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
@(require_results)
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)
@(require_results)
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)
@(require_results)
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
@(require_results)
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)
@(require_results)
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
@(deprecated="Prefer 'A * v'", require_results)
MulMV :: proc "c" (A: Mat22, v: Vec2) -> Vec2 {
return A * v
}
// Get the inverse of a 2-by-2 matrix
@(require_results)
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.
@(require_results)
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
@(require_results)
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.
@(require_results)
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).
@(require_results)
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
@(require_results)
AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) {
c.lowerBound.x = min(a.lowerBound.x, b.lowerBound.x)
c.lowerBound.y = min(a.lowerBound.y, b.lowerBound.y)
c.upperBound.x = max(a.upperBound.x, b.upperBound.x)
c.upperBound.y = max(a.upperBound.y, b.upperBound.y)
return
}
@(require_results)
Float_IsValid :: proc "c" (a: f32) -> bool {
math.is_nan(a) or_return
math.is_inf(a) or_return
return true
}
@(require_results)
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
}
@(require_results)
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)
}
@(require_results)
Normalize :: proc "c" (v: Vec2) -> Vec2 {
length := Length(v)
if length < 1e-23 {
return Vec2_zero
}
invLength := 1 / length
return invLength * v
}
@(require_results)
NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 {
length := Length(v)
if length < 1e-23 {
panic("zero-length Vec2")
}
invLength := 1 / length
return invLength * v
}
@(require_results)
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

File diff suppressed because it is too large Load Diff