mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 18:02:02 +00:00
@@ -1,4 +1,7 @@
|
||||
package all
|
||||
|
||||
import wgpu "vendor:wgpu"
|
||||
_ :: wgpu
|
||||
import b2 "vendor:box2d"
|
||||
|
||||
_ :: wgpu
|
||||
_ :: b2
|
||||
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
|
||||
1510
vendor/box2d/box2d.odin
vendored
Normal file
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
72
vendor/box2d/build_box2d.sh
vendored
Executable 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
473
vendor/box2d/collision.odin
vendored
Normal 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
87
vendor/box2d/id.odin
vendored
Normal 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
|
||||
}
|
||||
BIN
vendor/box2d/lib/box2d_darwin_amd64_avx2.a
vendored
Normal file
BIN
vendor/box2d/lib/box2d_darwin_amd64_avx2.a
vendored
Normal file
Binary file not shown.
BIN
vendor/box2d/lib/box2d_darwin_amd64_sse2.a
vendored
Normal file
BIN
vendor/box2d/lib/box2d_darwin_amd64_sse2.a
vendored
Normal file
Binary file not shown.
BIN
vendor/box2d/lib/box2d_darwin_arm64.a
vendored
Normal file
BIN
vendor/box2d/lib/box2d_darwin_arm64.a
vendored
Normal file
Binary file not shown.
BIN
vendor/box2d/lib/box2d_windows_amd64_avx2.lib
vendored
Normal file
BIN
vendor/box2d/lib/box2d_windows_amd64_avx2.lib
vendored
Normal file
Binary file not shown.
BIN
vendor/box2d/lib/box2d_windows_amd64_sse2.lib
vendored
Normal file
BIN
vendor/box2d/lib/box2d_windows_amd64_sse2.lib
vendored
Normal file
Binary file not shown.
522
vendor/box2d/math_functions.odin
vendored
Normal file
522
vendor/box2d/math_functions.odin
vendored
Normal 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
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