Merge remote-tracking branch 'offical/master'

This commit is contained in:
ed
2024-09-09 13:15:00 -04:00
492 changed files with 44673 additions and 6618 deletions
+13 -13
View File
@@ -22,17 +22,17 @@ VERSION_MAJOR :: u8(1)
VERSION_MINOR :: u8(3)
VERSION_PATCH :: u8(17)
VERSION_CREATE :: #force_inline proc(major, minor, patch: u8) -> u32 {
VERSION_CREATE :: #force_inline proc "contextless" (major, minor, patch: u8) -> u32 {
return (u32(major) << 16) | (u32(minor) << 8) | u32(patch)
}
VERSION_GET_MAJOR :: #force_inline proc(version: u32) -> u8 {
VERSION_GET_MAJOR :: #force_inline proc "contextless" (version: u32) -> u8 {
return u8((version >> 16) & 0xff)
}
VERSION_GET_MINOR :: #force_inline proc(version: u32) -> u8 {
VERSION_GET_MINOR :: #force_inline proc "contextless" (version: u32) -> u8 {
return u8((version >> 8) & 0xff)
}
VERSION_GET_PATCH :: #force_inline proc(version: u32) -> u8 {
VERSION_GET_PATCH :: #force_inline proc "contextless" (version: u32) -> u8 {
return u8(version & 0xff)
}
@@ -44,19 +44,19 @@ VERSION :: (u32(VERSION_MAJOR) << 16) | (u32(VERSION_MINOR) << 8) | u32(VERSION_
// Network byte order is always Big Endian. Instead of using the method ENet
// uses (leveraging {n,h}to{n,h}{s,l}), we can just use Odin's endianess types
// to get the correct byte swaps, if any.
HOST_TO_NET_16 :: #force_inline proc(value: u16) -> u16 {
HOST_TO_NET_16 :: #force_inline proc "contextless" (value: u16) -> u16 {
return transmute(u16)u16be(value)
}
HOST_TO_NET_32 :: #force_inline proc(value: u32) -> u32 {
HOST_TO_NET_32 :: #force_inline proc "contextless" (value: u32) -> u32 {
return transmute(u32)u32be(value)
}
NET_TO_HOST_16 :: #force_inline proc(value: u16) -> u16 {
NET_TO_HOST_16 :: #force_inline proc "contextless" (value: u16) -> u16 {
return u16(transmute(u16be)value)
}
NET_TO_HOST_32 :: #force_inline proc(value: u32) -> u32 {
NET_TO_HOST_32 :: #force_inline proc "contextless" (value: u32) -> u32 {
return u32(transmute(u32be)value)
}
@@ -115,7 +115,7 @@ PacketFreeCallback :: proc "c" (packet: ^Packet)
Packet :: struct {
referenceCount: uint,
flags: u32,
data: [^]u8,
data: [^]u8 `fmt:"v,dataLength"`,
dataLength: uint,
freeCallback: PacketFreeCallback,
userData: rawptr,
@@ -148,7 +148,7 @@ IncomingCommand :: struct {
command: Protocol,
fragmentCount: u32,
fragmentsRemaining: u32,
fragments: [^]u32,
fragments: [^]u32 `fmt:"v,fragmentCount"`,
packet: ^Packet,
}
@@ -221,7 +221,7 @@ Peer :: struct {
address: Address,
data: rawptr,
state: PeerState,
channels: [^]Channel,
channels: [^]Channel `fmt:"v,channelCount"`,
channelCount: uint,
incomingBandwidth: u32,
outgoingBandwidth: u32,
@@ -292,7 +292,7 @@ Host :: struct {
mtu: u32,
randomSeed: u32,
recalculateBandwidthLimits: i32,
peers: [^]Peer,
peers: [^]Peer `fmt:"v,peerCount"`,
peerCount: uint,
channelLimit: uint,
serviceTime: u32,
@@ -308,7 +308,7 @@ Host :: struct {
compressor: Compressor,
packetData: [2][PROTOCOL_MAXIMUM_MTU]u8,
receivedAddress: Address,
receivedData: [^]u8,
receivedData: [^]u8 `fmt:"v,receivedDataLength"`,
receivedDataLength: uint,
totalSentData: u32,
totalSentPackets: u32,
+5 -5
View File
@@ -2,22 +2,22 @@ package ENet
TIME_OVERFLOW :: u32(86400000)
TIME_LESS :: #force_inline proc(a, b: u32) -> bool {
TIME_LESS :: #force_inline proc "contextless" (a, b: u32) -> bool {
return a - b >= TIME_OVERFLOW
}
TIME_GREATER :: #force_inline proc(a, b: u32) -> bool {
TIME_GREATER :: #force_inline proc "contextless" (a, b: u32) -> bool {
return b - a >= TIME_OVERFLOW
}
TIME_LESS_EQUAL :: #force_inline proc(a, b: u32) -> bool {
TIME_LESS_EQUAL :: #force_inline proc "contextless" (a, b: u32) -> bool {
return !TIME_GREATER(a, b)
}
TIME_GREATER_EQUAL :: #force_inline proc(a, b: u32) -> bool {
TIME_GREATER_EQUAL :: #force_inline proc "contextless" (a, b: u32) -> bool {
return TIME_LESS(a, b)
}
TIME_DIFFERENCE :: #force_inline proc(a, b: u32) -> u32 {
TIME_DIFFERENCE :: #force_inline proc "contextless" (a, b: u32) -> u32 {
return a - b >= TIME_OVERFLOW ? b - a : a - b
}
+8 -8
View File
@@ -12,21 +12,21 @@ import "core:c"
fds_bits: [FD_SETSIZE / 8 / size_of(c.long)]c.ulong,
}
@(private="file") FD_ZERO :: #force_inline proc(s: ^fd_set) {
@(private="file") FD_ZERO :: #force_inline proc "contextless" (s: ^fd_set) {
for i := size_of(fd_set) / size_of(c.long); i != 0; i -= 1 {
s.fds_bits[i] = 0
}
}
@(private="file") FD_SET :: #force_inline proc(d: i32, s: ^fd_set) {
@(private="file") FD_SET :: #force_inline proc "contextless" (d: i32, s: ^fd_set) {
s.fds_bits[d / (8 * size_of(c.long))] |= c.ulong(1) << (c.ulong(d) % (8 * size_of(c.ulong)))
}
@(private="file") FD_CLR :: #force_inline proc(d: i32, s: ^fd_set) {
@(private="file") FD_CLR :: #force_inline proc "contextless" (d: i32, s: ^fd_set) {
s.fds_bits[d / (8 * size_of(c.long))] &~= c.ulong(1) << (c.ulong(d) % (8 * size_of(c.ulong)))
}
@(private="file") FD_ISSET :: #force_inline proc(d: i32, s: ^fd_set) -> bool {
@(private="file") FD_ISSET :: #force_inline proc "contextless" (d: i32, s: ^fd_set) -> bool {
return (s.fds_bits[d / (8 * size_of(c.long))] & c.ulong(1) << (c.ulong(d) % (8 * size_of(c.ulong)))) != 0
}
// }
@@ -42,18 +42,18 @@ Buffer :: struct {
SocketSet :: distinct fd_set
SOCKETSET_EMPTY :: #force_inline proc(sockset: ^SocketSet) {
SOCKETSET_EMPTY :: #force_inline proc "contextless" (sockset: ^SocketSet) {
FD_ZERO(cast(^fd_set)sockset)
}
SOCKETSET_ADD :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKETSET_ADD :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) {
FD_SET(i32(socket), cast(^fd_set)sockset)
}
SOCKETSET_REMOVE :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKETSET_REMOVE :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) {
FD_CLR(i32(socket), cast(^fd_set)sockset)
}
SOCKSET_CHECK :: #force_inline proc(sockset: ^SocketSet, socket: Socket) -> bool {
SOCKSET_CHECK :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) -> bool {
return FD_ISSET(i32(socket), cast(^fd_set)sockset)
}
+8 -8
View File
@@ -20,7 +20,7 @@ foreign WinSock2 {
fd_array: [FD_SETSIZE]SOCKET,
}
@(private="file") FD_CLR :: proc(fd: SOCKET, s: ^fd_set) {
@(private="file") FD_CLR :: proc "contextless" (fd: SOCKET, s: ^fd_set) {
for i := u32(0); i < s.fd_count; i += 1 {
if s.fd_array[i] == fd {
for i < s.fd_count - 1 {
@@ -33,7 +33,7 @@ foreign WinSock2 {
}
}
@(private="file") FD_SET :: proc(fd: SOCKET, s: ^fd_set) {
@(private="file") FD_SET :: proc "contextless" (fd: SOCKET, s: ^fd_set) {
for i := u32(0); i < s.fd_count; i += 1 {
if s.fd_array[i] == fd {
return
@@ -46,11 +46,11 @@ foreign WinSock2 {
s.fd_count += 1
}
@(private="file") FD_ZERO :: #force_inline proc (s: ^fd_set) {
@(private="file") FD_ZERO :: #force_inline proc "contextless" (s: ^fd_set) {
s.fd_count = 0
}
@(private="file") FD_ISSET :: #force_inline proc (fd: SOCKET, s: ^fd_set) -> bool {
@(private="file") FD_ISSET :: #force_inline proc "contextless" (fd: SOCKET, s: ^fd_set) -> bool {
return __WSAFDIsSet(fd, s) != 0
}
// }
@@ -66,18 +66,18 @@ Buffer :: struct {
SocketSet :: distinct fd_set
SOCKETSET_EMPTY :: #force_inline proc(sockset: ^SocketSet) {
SOCKETSET_EMPTY :: #force_inline proc "contextless" (sockset: ^SocketSet) {
FD_ZERO(cast(^fd_set)sockset)
}
SOCKETSET_ADD :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKETSET_ADD :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) {
FD_SET(SOCKET(socket), cast(^fd_set)sockset)
}
SOCKETSET_REMOVE :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKETSET_REMOVE :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) {
FD_CLR(SOCKET(socket), cast(^fd_set)sockset)
}
SOCKSET_CHECK :: #force_inline proc(sockset: ^SocketSet, socket: Socket) -> bool {
SOCKSET_CHECK :: #force_inline proc "contextless" (sockset: ^SocketSet, socket: Socket) -> bool {
return FD_ISSET(SOCKET(socket), cast(^fd_set)sockset)
}
+21
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
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
+1523
View File
File diff suppressed because it is too large Load Diff
Vendored Executable
+72
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
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
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+522
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
View File
File diff suppressed because it is too large Load Diff
+22 -22
View File
@@ -168,7 +168,7 @@ buffer :: struct {
data_free_method: data_free_method,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
meshopt_compression_mode :: enum c.int {
@@ -207,7 +207,7 @@ buffer_view :: struct {
meshopt_compression: meshopt_compression,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
accessor_sparse :: struct {
@@ -221,11 +221,11 @@ accessor_sparse :: struct {
indices_extras: extras_t,
values_extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
indices_extensions_count: uint,
indices_extensions: [^]extension,
indices_extensions: [^]extension `fmt:"v,indices_extensions_count"`,
values_extensions_count: uint,
values_extensions: [^]extension,
values_extensions: [^]extension `fmt:"v,values_extensions_count"`,
}
accessor :: struct {
@@ -245,7 +245,7 @@ accessor :: struct {
sparse: accessor_sparse,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
attribute :: struct {
@@ -262,7 +262,7 @@ image :: struct {
mime_type: cstring,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
sampler :: struct {
@@ -273,7 +273,7 @@ sampler :: struct {
wrap_t: c.int,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
texture :: struct {
@@ -284,7 +284,7 @@ texture :: struct {
basisu_image: ^image,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
texture_transform :: struct {
@@ -303,7 +303,7 @@ texture_view :: struct {
transform: texture_transform,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
pbr_metallic_roughness :: struct {
@@ -408,7 +408,7 @@ material :: struct {
unlit: b32,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
material_mapping :: struct {
@@ -442,7 +442,7 @@ primitive :: struct {
draco_mesh_compression: draco_mesh_compression,
mappings: []material_mapping,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
mesh :: struct {
@@ -452,7 +452,7 @@ mesh :: struct {
target_names: []cstring,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
skin :: struct {
@@ -462,7 +462,7 @@ skin :: struct {
inverse_bind_matrices: ^accessor,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
camera_perspective :: struct {
@@ -492,7 +492,7 @@ camera :: struct {
},
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
light :: struct {
@@ -527,7 +527,7 @@ node :: struct {
has_mesh_gpu_instancing: b32,
mesh_gpu_instancing: mesh_gpu_instancing,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
scene :: struct {
@@ -535,7 +535,7 @@ scene :: struct {
nodes: []^node,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
animation_sampler :: struct {
@@ -544,7 +544,7 @@ animation_sampler :: struct {
interpolation: interpolation_type,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
animation_channel :: struct {
@@ -553,7 +553,7 @@ animation_channel :: struct {
target_path: animation_path_type,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
animation :: struct {
@@ -562,7 +562,7 @@ animation :: struct {
channels: []animation_channel,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
material_variant :: struct {
@@ -577,7 +577,7 @@ asset :: struct {
min_version: cstring,
extras: extras_t,
extensions_count: uint,
extensions: [^]extension,
extensions: [^]extension `fmt:"v,extensions_count"`,
}
data :: struct {
@@ -609,7 +609,7 @@ data :: struct {
extras: extras_t,
data_extensions_count: uint,
data_extensions: [^]extension,
data_extensions: [^]extension `fmt:"v,extensions_count"`,
extensions_used: []cstring,
extensions_required: []cstring,
+1 -1
View File
@@ -338,7 +338,7 @@ foreign lib {
node_set_list_tight :: proc(node: ^Node, tight: b32) -> (success: b32) ---
// Returns the info string from a fenced code block.
get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) ---
node_get_fence_info :: proc(node: ^Node) -> (fence_info: cstring) ---
// Sets the info string in a fenced code block, returning `true` on success and `false` on failure.
node_set_fence_info :: proc(node: ^Node, fence_info: cstring) -> (success: b32) ---
+4 -4
View File
@@ -3459,10 +3459,10 @@ DRED_DEVICE_STATE :: enum i32 {
}
DRED_PAGE_FAULT_OUTPUT2 :: struct {
PageFaultVA: GPU_VIRTUAL_ADDRESS,
pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1,
pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1,
PageFaultFlags: DRED_PAGE_FAULT_FLAGS,
PageFaultVA: GPU_VIRTUAL_ADDRESS,
pHeadExistingAllocationNode: ^DRED_ALLOCATION_NODE1,
pHeadRecentFreedAllocationNode: ^DRED_ALLOCATION_NODE1,
PageFaultFlags: DRED_PAGE_FAULT_FLAGS,
}
DEVICE_REMOVED_EXTENDED_DATA1 :: struct {
+2 -2
View File
@@ -476,8 +476,8 @@ IVersionInfo3_VTable :: struct {
}
ArgPair :: struct {
pName: wstring,
pValue: wstring,
pName: wstring,
pValue: wstring,
}
IPdbUtils_UUID_STRING :: "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D"
+25 -6
View File
@@ -8,25 +8,38 @@ Surface :: distinct rawptr
Config :: distinct rawptr
Context :: distinct rawptr
Boolean :: b32
FALSE :: false
TRUE :: true
NO_DISPLAY :: Display(uintptr(0))
NO_CONTEXT :: Context(uintptr(0))
NO_SURFACE :: Surface(uintptr(0))
DEFAULT_DISPLAY :: NativeDisplayType(uintptr(0))
CONTEXT_OPENGL_CORE_PROFILE_BIT :: 0x00000001
WINDOW_BIT :: 0x0004
OPENGL_BIT :: 0x0008
OPENGL_ES2_BIT :: 0x0004
OPENGL_ES3_BIT :: 0x00000040
ALPHA_SIZE :: 0x3021
BLUE_SIZE :: 0x3022
GREEN_SIZE :: 0x3023
RED_SIZE :: 0x3024
DEPTH_SIZE :: 0x3025
STENCIL_SIZE :: 0x3026
NATIVE_VISUAL_ID :: 0x302E
SURFACE_TYPE :: 0x3033
NONE :: 0x3038
COLOR_BUFFER_TYPE :: 0x303F
RENDERABLE_TYPE :: 0x3040
CONFORMANT :: 0x3042
HEIGHT :: 0x3056
WIDTH :: 0x3057
BACK_BUFFER :: 0x3084
RENDER_BUFFER :: 0x3086
@@ -35,6 +48,7 @@ GL_COLORSPACE_LINEAR :: 0x308A
RGB_BUFFER :: 0x308E
GL_COLORSPACE :: 0x309D
CONTEXT_CLIENT_VERSION :: 0x3098
CONTEXT_MAJOR_VERSION :: 0x3098
CONTEXT_MINOR_VERSION :: 0x30FB
CONTEXT_OPENGL_PROFILE_MASK :: 0x30FD
@@ -45,15 +59,20 @@ foreign import egl "system:EGL"
@(default_calling_convention="c", link_prefix="egl")
foreign egl {
GetDisplay :: proc(display: NativeDisplayType) -> Display ---
Initialize :: proc(display: Display, major: ^i32, minor: ^i32) -> i32 ---
BindAPI :: proc(api: u32) -> i32 ---
ChooseConfig :: proc(display: Display, attrib_list: ^i32, configs: ^Config, config_size: i32, num_config: ^i32) -> i32 ---
Initialize :: proc(display: Display, major: ^i32, minor: ^i32) -> Boolean ---
BindAPI :: proc(api: u32) -> Boolean ---
ChooseConfig :: proc(display: Display, attrib_list: ^i32, configs: ^Config, config_size: i32, num_config: ^i32) -> Boolean ---
CreateWindowSurface :: proc(display: Display, config: Config, native_window: NativeWindowType, attrib_list: ^i32) -> Surface ---
CreateContext :: proc(display: Display, config: Config, share_context: Context, attrib_list: ^i32) -> Context ---
MakeCurrent :: proc(display: Display, draw: Surface, read: Surface, ctx: Context) -> i32 ---
SwapInterval :: proc(display: Display, interval: i32) -> i32 ---
SwapBuffers :: proc(display: Display, surface: Surface) -> i32 ---
MakeCurrent :: proc(display: Display, draw: Surface, read: Surface, ctx: Context) -> Boolean ---
QuerySurface :: proc(display: Display, surface: Surface, attribute: i32, value: ^i32) -> Boolean ---
SwapInterval :: proc(display: Display, interval: i32) -> Boolean ---
SwapBuffers :: proc(display: Display, surface: Surface) -> Boolean ---
GetProcAddress :: proc(name: cstring) -> rawptr ---
GetConfigAttrib :: proc(display: Display, config: Config, attribute: i32, value: ^i32) -> Boolean ---
DestroyContext :: proc(display: Display, ctx: Context) -> Boolean ---
DestroySurface :: proc(display: Display, surface: Surface) -> Boolean ---
Terminate :: proc(display: Display) -> Boolean ---
}
gl_set_proc_address :: proc(p: rawptr, name: cstring) {
+260 -304
View File
@@ -1,3 +1,15 @@
/*
Created in 2009, the GGPO networking SDK pioneered the use of rollback networking in peer-to-peer games.
It's designed specifically to hide network latency in fast paced, twitch style games which require very
precise inputs and frame perfect execution.
Traditional techniques account for network transmission time by adding delay to a players input, resulting
in a sluggish, laggy game-feel. Rollback networking uses input prediction and speculative execution to
send player inputs to the game immediately, providing the illusion of a zero-latency network. Using rollback,
the same timings, reactions visual and audio queues, and muscle memory your players build up playing offline
translate directly online. The GGPO networking SDK is designed to make incorporating rollback networking
into new and existing games as easy as possible.
*/
package vendor_ggpo
foreign import lib "GGPO.lib"
@@ -19,31 +31,27 @@ PlayerType :: enum c.int {
SPECTATOR,
}
/*
* The Player structure used to describe players in add_player
*
* size: Should be set to the size_of(Player)
*
* type: One of the PlayerType values describing how inputs should be handled
* Local players must have their inputs updated every frame via
* add_local_inputs. Remote players values will come over the
* network.
*
* player_num: The player number. Should be between 1 and the number of players
* In the game (e.g. in a 2 player game, either 1 or 2).
*
* If type == PLAYERTYPE_REMOTE:
*
* remote.ip_address: The ip address of the ggpo session which will host this
* player.
*
* remote.port: The port where udp packets should be sent to reach this player.
* All the local inputs for this session will be sent to this player at
* ip_address:port.
*
*/
// The Player structure used to describe players in add_player
//
// size: Should be set to the size_of(Player)
//
// type: One of the PlayerType values describing how inputs should be handled
// Local players must have their inputs updated every frame via
// add_local_inputs. Remote players values will come over the
// network.
//
// player_num: The player number. Should be between 1 and the number of players
// In the game (e.g. in a 2 player game, either 1 or 2).
//
// If type == PLAYERTYPE_REMOTE:
//
// remote.ip_address: The ip address of the ggpo session which will host this
// player.
//
// remote.port: The port where udp packets should be sent to reach this player.
// All the local inputs for this session will be sent to this player at
// ip_address:port.
Player :: struct {
size: c.int,
type: PlayerType,
@@ -80,32 +88,29 @@ ErrorCode :: enum c.int {
INVALID_HANDLE :: PlayerHandle(-1)
/*
* The EventCode enumeration describes what type of event just happened.
*
* CONNECTED_TO_PEER - Handshake with the game running on the
* other side of the network has been completed.
*
* SYNCHRONIZING_WITH_PEER - Beginning the synchronization
* process with the client on the other end of the networking. The count
* and total fields in the u.synchronizing struct of the Event
* object indicate progress.
*
* SYNCHRONIZED_WITH_PEER - The synchronziation with this
* peer has finished.
*
* RUNNING - All the clients have synchronized. You may begin
* sending inputs with synchronize_inputs.
*
* DISCONNECTED_FROM_PEER - The network connection on
* the other end of the network has closed.
*
* TIMESYNC - The time synchronziation code has determined
* that this client is too far ahead of the other one and should slow
* down to ensure fairness. The u.timesync.frames_ahead parameter in
* the Event object indicates how many frames the client is.
*
*/
// The EventCode enumeration describes what type of event just happened.
//
// CONNECTED_TO_PEER - Handshake with the game running on the
// other side of the network has been completed.
//
// SYNCHRONIZING_WITH_PEER - Beginning the synchronization
// process with the client on the other end of the networking. The count
// and total fields in the u.synchronizing struct of the Event
// object indicate progress.
//
// SYNCHRONIZED_WITH_PEER - The synchronziation with this
// peer has finished.
//
// RUNNING - All the clients have synchronized. You may begin
// sending inputs with synchronize_inputs.
//
// DISCONNECTED_FROM_PEER - The network connection on
// the other end of the network has closed.
//
// TIMESYNC - The time synchronziation code has determined
// that this client is too far ahead of the other one and should slow
// down to ensure fairness. The u.timesync.frames_ahead parameter in
// the Event object indicates how many frames the client is.
EventCode :: enum c.int {
CONNECTED_TO_PEER = 1000,
SYNCHRONIZING_WITH_PEER = 1001,
@@ -117,13 +122,10 @@ EventCode :: enum c.int {
CONNECTION_RESUMED = 1007,
}
/*
* The Event structure contains an asynchronous event notification sent
* by the on_event callback. See EventCode, above, for a detailed
* explanation of each event.
*/
Event :: struct {
// The Event structure contains an asynchronous event notification sent
// by the on_event callback. See EventCode, above, for a detailed
// explanation of each event.
Event :: struct {
code: EventCode,
using u: struct #raw_union {
connected: struct {
@@ -153,100 +155,83 @@ EventCode :: enum c.int {
},
}
/*
* The SessionCallbacks structure contains the callback functions that
* your application must implement. GGPO.net will periodically call these
* functions during the game. All callback functions must be implemented.
*/
//
// The SessionCallbacks structure contains the callback functions that
// your application must implement. GGPO.net will periodically call these
// functions during the game. All callback functions must be implemented.
//
SessionCallbacks :: struct {
/*
* begin_game callback - This callback has been deprecated. You must
* implement it, but should ignore the 'game' parameter.
*/
// begin_game callback - This callback has been deprecated. You must
// implement it, but should ignore the 'game' parameter.
begin_game: proc "c" (game: cstring) -> bool,
/*
* save_game_state - The client should allocate a buffer, copy the
* entire contents of the current game state into it, and copy the
* length into the len parameter. Optionally, the client can compute
* a checksum of the data and store it in the checksum argument.
*/
// save_game_state - The client should allocate a buffer, copy the
// entire contents of the current game state into it, and copy the
// length into the len parameter. Optionally, the client can compute
// a checksum of the data and store it in the checksum argument.
save_game_state: proc "c" (buffer: ^[^]byte, len: ^c.int, checksum: ^c.int, frame: c.int) -> bool,
/*
* load_game_state - GGPO.net will call this function at the beginning
* of a rollback. The buffer and len parameters contain a previously
* saved state returned from the save_game_state function. The client
* should make the current game state match the state contained in the
* buffer.
*/
// load_game_state - GGPO.net will call this function at the beginning
// of a rollback. The buffer and len parameters contain a previously
// saved state returned from the save_game_state function. The client
// should make the current game state match the state contained in the
// buffer.
load_game_state: proc "c" (buffer: [^]byte, len: c.int) -> bool,
/*
* log_game_state - Used in diagnostic testing. The client should use
* the log function to write the contents of the specified save
* state in a human readible form.
*/
// log_game_state - Used in diagnostic testing. The client should use
// the log function to write the contents of the specified save
// state in a human readible form.
log_game_state: proc "c" (filename: cstring, buffer: [^]byte, len: c.int) -> bool,
/*
* free_buffer - Frees a game state allocated in save_game_state. You
* should deallocate the memory contained in the buffer.
*/
// free_buffer - Frees a game state allocated in save_game_state. You
// should deallocate the memory contained in the buffer.
free_buffer: proc "c" (buffer: rawptr),
/*
* advance_frame - Called during a rollback. You should advance your game
* state by exactly one frame. Before each frame, call synchronize_input
* to retrieve the inputs you should use for that frame. After each frame,
* you should call advance_frame to notify GGPO.net that you're
* finished.
*
* The flags parameter is reserved. It can safely be ignored at this time.
*/
// advance_frame - Called during a rollback. You should advance your game
// state by exactly one frame. Before each frame, call synchronize_input
// to retrieve the inputs you should use for that frame. After each frame,
// you should call advance_frame to notify GGPO.net that you're
// finished.
//
// The flags parameter is reserved. It can safely be ignored at this time.
advance_frame: proc "c" (flags: c.int) -> bool,
/*
* on_event - Notification that something has happened. See the EventCode
* structure above for more information.
*/
// on_event - Notification that something has happened. See the EventCode
// structure above for more information.
on_event: proc "c" (info: ^Event) -> bool,
}
/*
* The NetworkStats function contains some statistics about the current
* session.
*
* network.send_queue_len - The length of the queue containing UDP packets
* which have not yet been acknowledged by the end client. The length of
* the send queue is a rough indication of the quality of the connection.
* The longer the send queue, the higher the round-trip time between the
* clients. The send queue will also be longer than usual during high
* packet loss situations.
*
* network.recv_queue_len - The number of inputs currently buffered by the
* GGPO.net network layer which have yet to be validated. The length of
* the prediction queue is roughly equal to the current frame number
* minus the frame number of the last packet in the remote queue.
*
* network.ping - The roundtrip packet transmission time as calcuated
* by GGPO.net. This will be roughly equal to the actual round trip
* packet transmission time + 2 the interval at which you call idle
* or advance_frame.
*
* network.kbps_sent - The estimated bandwidth used between the two
* clients, in kilobits per second.
*
* timesync.local_frames_behind - The number of frames GGPO.net calculates
* that the local client is behind the remote client at this instant in
* time. For example, if at this instant the current game client is running
* frame 1002 and the remote game client is running frame 1009, this value
* will mostly likely roughly equal 7.
*
* timesync.remote_frames_behind - The same as local_frames_behind, but
* calculated from the perspective of the remote player.
*
*/
// The NetworkStats function contains some statistics about the current
// session.
//
// network.send_queue_len - The length of the queue containing UDP packets
// which have not yet been acknowledged by the end client. The length of
// the send queue is a rough indication of the quality of the connection.
// The longer the send queue, the higher the round-trip time between the
// clients. The send queue will also be longer than usual during high
// packet loss situations.
//
// network.recv_queue_len - The number of inputs currently buffered by the
// GGPO.net network layer which have yet to be validated. The length of
// the prediction queue is roughly equal to the current frame number
// minus the frame number of the last packet in the remote queue.
//
// network.ping - The roundtrip packet transmission time as calcuated
// by GGPO.net. This will be roughly equal to the actual round trip
// packet transmission time + 2 the interval at which you call idle
// or advance_frame.
//
// network.kbps_sent - The estimated bandwidth used between the two
// clients, in kilobits per second.
//
// timesync.local_frames_behind - The number of frames GGPO.net calculates
// that the local client is behind the remote client at this instant in
// time. For example, if at this instant the current game client is running
// frame 1002 and the remote game client is running frame 1009, this value
// will mostly likely roughly equal 7.
//
// timesync.remote_frames_behind - The same as local_frames_behind, but
// calculated from the perspective of the remote player.
NetworkStats :: struct {
network: struct {
send_queue_len: c.int,
@@ -263,29 +248,27 @@ NetworkStats :: struct {
@(default_calling_convention="c")
@(link_prefix="ggpo_")
foreign lib {
/*
* start_session --
*
* Used to being a new GGPO.net session. The ggpo object returned by start_session
* uniquely identifies the state for this session and should be passed to all other
* functions.
*
* session - An out parameter to the new ggpo session object.
*
* cb - A SessionCallbacks structure which contains the callbacks you implement
* to help GGPO.net synchronize the two games. You must implement all functions in
* cb, even if they do nothing but 'return true';
*
* game - The name of the game. This is used internally for GGPO for logging purposes only.
*
* num_players - The number of players which will be in this game. The number of players
* per session is fixed. If you need to change the number of players or any player
* disconnects, you must start a new session.
*
* input_size - The size of the game inputs which will be passsed to add_local_input.
*
* local_port - The port GGPO should bind to for UDP traffic.
*/
// start_session --
//
// Used to being a new GGPO.net session. The ggpo object returned by start_session
// uniquely identifies the state for this session and should be passed to all other
// functions.
//
// session - An out parameter to the new ggpo session object.
//
// cb - A SessionCallbacks structure which contains the callbacks you implement
// to help GGPO.net synchronize the two games. You must implement all functions in
// cb, even if they do nothing but 'return true';
//
// game - The name of the game. This is used internally for GGPO for logging purposes only.
//
// num_players - The number of players which will be in this game. The number of players
// per session is fixed. If you need to change the number of players or any player
// disconnects, you must start a new session.
//
// input_size - The size of the game inputs which will be passsed to add_local_input.
//
// local_port - The port GGPO should bind to for UDP traffic.
start_session :: proc(session: ^^Session,
cb: ^SessionCallbacks,
game: cstring,
@@ -294,17 +277,15 @@ foreign lib {
localport: u16) -> ErrorCode ---
/*
* add_player --
*
* Must be called for each player in the session (e.g. in a 3 player session, must
* be called 3 times).
*
* player - A Player struct used to describe the player.
*
* handle - An out parameter to a handle used to identify this player in the future.
* (e.g. in the on_event callbacks).
*/
// add_player --
//
// Must be called for each player in the session (e.g. in a 3 player session, must
// be called 3 times).
//
// player - A Player struct used to describe the player.
//
// handle - An out parameter to a handle used to identify this player in the future.
// (e.g. in the on_event callbacks).
add_player :: proc(session: ^Session,
player: ^Player,
handle: ^PlayerHandle) -> ErrorCode ---
@@ -342,30 +323,28 @@ foreign lib {
frames: c.int) -> ErrorCode ---
/*
* start_spectating --
*
* Start a spectator session.
*
* cb - A SessionCallbacks structure which contains the callbacks you implement
* to help GGPO.net synchronize the two games. You must implement all functions in
* cb, even if they do nothing but 'return true';
*
* game - The name of the game. This is used internally for GGPO for logging purposes only.
*
* num_players - The number of players which will be in this game. The number of players
* per session is fixed. If you need to change the number of players or any player
* disconnects, you must start a new session.
*
* input_size - The size of the game inputs which will be passsed to add_local_input.
*
* local_port - The port GGPO should bind to for UDP traffic.
*
* host_ip - The IP address of the host who will serve you the inputs for the game. Any
* player partcipating in the session can serve as a host.
*
* host_port - The port of the session on the host
*/
// start_spectating --
//
// Start a spectator session.
//
// cb - A SessionCallbacks structure which contains the callbacks you implement
// to help GGPO.net synchronize the two games. You must implement all functions in
// cb, even if they do nothing but 'return true';
//
// game - The name of the game. This is used internally for GGPO for logging purposes only.
//
// num_players - The number of players which will be in this game. The number of players
// per session is fixed. If you need to change the number of players or any player
// disconnects, you must start a new session.
//
// input_size - The size of the game inputs which will be passsed to add_local_input.
//
// local_port - The port GGPO should bind to for UDP traffic.
//
// host_ip - The IP address of the host who will serve you the inputs for the game. Any
// player partcipating in the session can serve as a host.
//
// host_port - The port of the session on the host
start_spectating :: proc(session: ^^Session,
cb: ^SessionCallbacks,
game: cstring,
@@ -375,152 +354,129 @@ foreign lib {
host_ip: cstring,
host_port: u16) -> ErrorCode ---
/*
* close_session --
* Used to close a session. You must call close_session to
* free the resources allocated in start_session.
*/
// close_session --
// Used to close a session. You must call close_session to
// free the resources allocated in start_session.
close_session :: proc(session: ^Session) -> ErrorCode ---
/*
* set_frame_delay --
*
* Change the amount of frames ggpo will delay local input. Must be called
* before the first call to synchronize_input.
*/
// set_frame_delay --
//
// Change the amount of frames ggpo will delay local input. Must be called
// before the first call to synchronize_input.
set_frame_delay :: proc(session: ^Session,
player: PlayerHandle,
frame_delay: c.int) -> ErrorCode ---
/*
* idle --
* Should be called periodically by your application to give GGPO.net
* a chance to do some work. Most packet transmissions and rollbacks occur
* in idle.
*
* timeout - The amount of time GGPO.net is allowed to spend in this function,
* in milliseconds.
*/
// idle --
// Should be called periodically by your application to give GGPO.net
// a chance to do some work. Most packet transmissions and rollbacks occur
// in idle.
//
// timeout - The amount of time GGPO.net is allowed to spend in this function,
// in milliseconds.
idle :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* add_local_input --
*
* Used to notify GGPO.net of inputs that should be trasmitted to remote
* players. add_local_input must be called once every frame for
* all player of type PLAYERTYPE_LOCAL.
*
* player - The player handle returned for this player when you called
* add_local_player.
*
* values - The controller inputs for this player.
*
* size - The size of the controller inputs. This must be exactly equal to the
* size passed into start_session.
*/
// add_local_input --
//
// Used to notify GGPO.net of inputs that should be trasmitted to remote
// players. add_local_input must be called once every frame for
// all player of type PLAYERTYPE_LOCAL.
//
// player - The player handle returned for this player when you called
// add_local_player.
//
// values - The controller inputs for this player.
//
// size - The size of the controller inputs. This must be exactly equal to the
// size passed into start_session.
add_local_input :: proc(session: ^Session,
player: PlayerHandle,
values: rawptr,
size: c.int) -> ErrorCode ---
/*
* synchronize_input --
*
* You should call synchronize_input before every frame of execution,
* including those frames which happen during rollback.
*
* values - When the function returns, the values parameter will contain
* inputs for this frame for all players. The values array must be at
* least (size * players) large.
*
* size - The size of the values array.
*
* disconnect_flags - Indicated whether the input in slot (1 << flag) is
* valid. If a player has disconnected, the input in the values array for
* that player will be zeroed and the i-th flag will be set. For example,
* if only player 3 has disconnected, disconnect flags will be 8 (i.e. 1 << 3).
*/
// synchronize_input --
//
// You should call synchronize_input before every frame of execution,
// including those frames which happen during rollback.
//
// values - When the function returns, the values parameter will contain
// inputs for this frame for all players. The values array must be at
// least (size * players) large.
//
// size - The size of the values array.
//
// disconnect_flags - Indicated whether the input in slot (1 << flag) is
// valid. If a player has disconnected, the input in the values array for
// that player will be zeroed and the i-th flag will be set. For example,
// if only player 3 has disconnected, disconnect flags will be 8 (i.e. 1 << 3).
synchronize_input :: proc(session: ^Session,
values: rawptr,
size: c.int,
disconnect_flags: ^c.int) -> ErrorCode ---
/*
* disconnect_player --
*
* Disconnects a remote player from a game. Will return ERRORCODE_PLAYER_DISCONNECTED
* if you try to disconnect a player who has already been disconnected.
*/
// disconnect_player --
//
// Disconnects a remote player from a game. Will return ERRORCODE_PLAYER_DISCONNECTED
// if you try to disconnect a player who has already been disconnected.
disconnect_player :: proc(session: ^Session,
player: PlayerHandle) -> ErrorCode ---
/*
* advance_frame --
*
* You should call advance_frame to notify GGPO.net that you have
* advanced your gamestate by a single frame. You should call this everytime
* you advance the gamestate by a frame, even during rollbacks. GGPO.net
* may call your save_state callback before this function returns.
*/
// advance_frame --
//
// You should call advance_frame to notify GGPO.net that you have
// advanced your gamestate by a single frame. You should call this everytime
// you advance the gamestate by a frame, even during rollbacks. GGPO.net
// may call your save_state callback before this function returns.
advance_frame :: proc(session: ^Session) -> ErrorCode ---
/*
* get_network_stats --
*
* Used to fetch some statistics about the quality of the network connection.
*
* player - The player handle returned from the add_player function you used
* to add the remote player.
*
* stats - Out parameter to the network statistics.
*/
// get_network_stats --
//
// Used to fetch some statistics about the quality of the network connection.
//
// player - The player handle returned from the add_player function you used
// to add the remote player.
//
// stats - Out parameter to the network statistics.
get_network_stats :: proc(session: ^Session,
player: PlayerHandle,
stats: ^NetworkStats) -> ErrorCode ---
/*
* set_disconnect_timeout --
*
* Sets the disconnect timeout. The session will automatically disconnect
* from a remote peer if it has not received a packet in the timeout window.
* You will be notified of the disconnect via a EVENTCODE_DISCONNECTED_FROM_PEER
* event.
*
* Setting a timeout value of 0 will disable automatic disconnects.
*
* timeout - The time in milliseconds to wait before disconnecting a peer.
*/
// set_disconnect_timeout --
//
// Sets the disconnect timeout. The session will automatically disconnect
// from a remote peer if it has not received a packet in the timeout window.
// You will be notified of the disconnect via a EVENTCODE_DISCONNECTED_FROM_PEER
// event.
//
// Setting a timeout value of 0 will disable automatic disconnects.
//
// timeout - The time in milliseconds to wait before disconnecting a peer.
set_disconnect_timeout :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* set_disconnect_notify_start --
*
* The time to wait before the first EVENTCODE_NETWORK_INTERRUPTED timeout
* will be sent.
*
* timeout - The amount of time which needs to elapse without receiving a packet
* before the EVENTCODE_NETWORK_INTERRUPTED event is sent.
*/
// set_disconnect_notify_start --
//
// The time to wait before the first EVENTCODE_NETWORK_INTERRUPTED timeout
// will be sent.
//
// timeout - The amount of time which needs to elapse without receiving a packet
// before the EVENTCODE_NETWORK_INTERRUPTED event is sent.
set_disconnect_notify_start :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* log --
*
* Used to write to the ggpo.net log. In the current versions of the
* SDK, a log file is only generated if the "quark.log" environment
* variable is set to 1. This will change in future versions of the
* SDK.
*/
// log --
//
// Used to write to the ggpo.net log. In the current versions of the
// SDK, a log file is only generated if the "quark.log" environment
// variable is set to 1. This will change in future versions of the
// SDK.
log :: proc(session: ^Session, fmt: cstring, #c_vararg args: ..any) ---
/*
* logv --
*
* A varargs compatible version of log. See log for
* more details.
*/
// logv --
//
// A varargs compatible version of log. See log for
// more details.
logv :: proc(session: ^Session, fmt: cstring, args: c.va_list) ---
}
+1 -1
View File
@@ -575,7 +575,7 @@ PRELOAD_TABLE :: "_PRELOAD"
L_Reg :: struct {
name: cstring,
func: CFunction,
func: CFunction,
}
L_NUMSIZES :: size_of(Integer)*16 + size_of(Number)
+3 -3
View File
@@ -69,9 +69,9 @@ decoder :: struct {
outputSampleRate: u32,
converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */
pInputCache: rawptr, /* In input format. Can be null if it's not needed. */
inputCacheCap: u64, /* The capacity of the input cache. */
inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
inputCacheCap: u64, /* The capacity of the input cache. */
inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
allocationCallbacks: allocation_callbacks,
data: struct #raw_union {
vfs: struct {
+3 -3
View File
@@ -381,7 +381,7 @@ device_config :: struct {
noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will not be clipped after returning. Only applies when the playback sample format is f32. */
noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */
noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
dataCallback: device_data_proc,
notificationCallback: device_notification_proc,
stopCallback: stop_proc,
@@ -813,7 +813,7 @@ context_type :: struct {
/*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr,
pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
} when SUPPORT_PULSEAUDIO else struct {}),
jack: (struct {
@@ -1140,7 +1140,7 @@ device :: struct {
pulse: (struct {
/*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr,
/*pa_context**/ pPulseContext: rawptr,
/*pa_stream**/ pStreamPlayback: rawptr,
/*pa_stream**/ pStreamCapture: rawptr,
} when SUPPORT_PULSEAUDIO else struct {}),
+34 -32
View File
@@ -80,9 +80,10 @@ foreign lib {
HasHostError :: proc(stream: Stream) -> b32 ---
}
/** Translate portmidi error number into human readable message.
These strings are constants (set at compile time) so client has
no need to allocate storage
/**
Translate portmidi error number into human readable message.
These strings are constants (set at compile time) so client has
no need to allocate storage
*/
GetErrorText :: proc (errnum: Error) -> string {
@(default_calling_convention="c")
@@ -92,9 +93,10 @@ GetErrorText :: proc (errnum: Error) -> string {
return string(Pm_GetErrorText(errnum))
}
/** Translate portmidi host error into human readable message.
These strings are computed at run time, so client has to allocate storage.
After this routine executes, the host error is cleared.
/**
Translate portmidi host error into human readable message.
These strings are computed at run time, so client has to allocate storage.
After this routine executes, the host error is cleared.
*/
GetHostErrorText :: proc (buf: []byte) -> string {
@(default_calling_convention="c")
@@ -133,8 +135,8 @@ foreign lib {
/**
Timestamp is used to represent a millisecond clock with arbitrary
start time. The type is used for all MIDI timestampes and clocks.
Timestamp is used to represent a millisecond clock with arbitrary
start time. The type is used for all MIDI timestampes and clocks.
*/
Timestamp :: distinct i32
TimeProc :: proc "c" (time_info: rawptr) -> Timestamp
@@ -258,47 +260,47 @@ foreign lib {
/* Filter bit-mask definitions */
/** filter active sensing messages (0xFE): */
FILT_ACTIVE :: 1 << 0x0E
FILT_ACTIVE :: 1 << 0x0E
/** filter system exclusive messages (0xF0): */
FILT_SYSEX :: 1 << 0x00
FILT_SYSEX :: 1 << 0x00
/** filter MIDI clock message (0xF8) */
FILT_CLOCK :: 1 << 0x08
FILT_CLOCK :: 1 << 0x08
/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
FILT_PLAY :: (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B)
FILT_PLAY :: (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B)
/** filter tick messages (0xF9) */
FILT_TICK :: 1 << 0x09
FILT_TICK :: 1 << 0x09
/** filter undefined FD messages */
FILT_FD :: 1 << 0x0D
FILT_FD :: 1 << 0x0D
/** filter undefined real-time messages */
FILT_UNDEFINED :: FILT_FD
FILT_UNDEFINED :: FILT_FD
/** filter reset messages (0xFF) */
FILT_RESET :: 1 << 0x0F
FILT_RESET :: 1 << 0x0F
/** filter all real-time messages */
FILT_REALTIME :: FILT_ACTIVE | FILT_SYSEX | FILT_CLOCK | FILT_PLAY | FILT_UNDEFINED | FILT_RESET | FILT_TICK
FILT_REALTIME :: FILT_ACTIVE | FILT_SYSEX | FILT_CLOCK | FILT_PLAY | FILT_UNDEFINED | FILT_RESET | FILT_TICK
/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
FILT_NOTE :: (1 << 0x19) | (1 << 0x18)
FILT_NOTE :: (1 << 0x19) | (1 << 0x18)
/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
FILT_CHANNEL_AFTERTOUCH :: 1 << 0x1D
/** per-note aftertouch (0xA0-0xAF) */
FILT_POLY_AFTERTOUCH :: 1 << 0x1A
FILT_POLY_AFTERTOUCH :: 1 << 0x1A
/** filter both channel and poly aftertouch */
FILT_AFTERTOUCH :: FILT_CHANNEL_AFTERTOUCH | FILT_POLY_AFTERTOUCH
FILT_AFTERTOUCH :: FILT_CHANNEL_AFTERTOUCH | FILT_POLY_AFTERTOUCH
/** Program changes (0xC0-0xCF) */
FILT_PROGRAM :: 1 << 0x1C
FILT_PROGRAM :: 1 << 0x1C
/** Control Changes (CC's) (0xB0-0xBF)*/
FILT_CONTROL :: 1 << 0x1B
FILT_CONTROL :: 1 << 0x1B
/** Pitch Bender (0xE0-0xEF*/
FILT_PITCHBEND :: 1 << 0x1E
FILT_PITCHBEND :: 1 << 0x1E
/** MIDI Time Code (0xF1)*/
FILT_MTC :: 1 << 0x01
FILT_MTC :: 1 << 0x01
/** Song Position (0xF2) */
FILT_SONG_POSITION :: 1 << 0x02
FILT_SONG_POSITION :: 1 << 0x02
/** Song Select (0xF3)*/
FILT_SONG_SELECT :: 1 << 0x03
FILT_SONG_SELECT :: 1 << 0x03
/** Tuning request (0xF6)*/
FILT_TUNE :: 1 << 0x06
FILT_TUNE :: 1 << 0x06
/** All System Common messages (mtc, song position, song select, tune request) */
FILT_SYSTEMCOMMON :: FILT_MTC | FILT_SONG_POSITION | FILT_SONG_SELECT | FILT_TUNE
FILT_SYSTEMCOMMON :: FILT_MTC | FILT_SONG_POSITION | FILT_SONG_SELECT | FILT_TUNE
Channel :: #force_inline proc "c" (channel: c.int) -> c.int {
return 1<<c.uint(channel)
@@ -367,11 +369,11 @@ foreign lib {
}
/**
MessageMake() encodes a short Midi message into a 32-bit word. If data1
and/or data2 are not present, use zero.
MessageMake() encodes a short Midi message into a 32-bit word. If data1
and/or data2 are not present, use zero.
MessageStatus(), MessageData1(), and
MessageData2() extract fields from a 32-bit midi message.
MessageStatus(), MessageData1(), and
MessageData2() extract fields from a 32-bit midi message.
*/
MessageMake :: #force_inline proc "c" (status: c.int, data1, data2: c.int) -> Message {
return Message(((data2 << 16) & 0xFF0000) | ((data1 << 8) & 0xFF00) | (status & 0xFF))
+5 -7
View File
@@ -110,6 +110,8 @@ GuiDefaultProperty :: enum c.int {
LINE_COLOR, // Line control color
BACKGROUND_COLOR, // Background color
TEXT_LINE_SPACING, // Text spacing between lines
TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding)
TEXT_WRAP_MODE, // Text wrap-mode inside text bounds
}
// Label
@@ -163,11 +165,7 @@ GuiDropdownBoxProperty :: enum c.int {
// TextBox/TextBoxMulti/ValueBox/Spinner
GuiTextBoxProperty :: enum c.int {
TEXT_INNER_PADDING = 16, // TextBox/TextBoxMulti/ValueBox/Spinner inner text padding
TEXT_LINES_SPACING, // TextBoxMulti lines separation
TEXT_ALIGNMENT_VERTICAL, // TextBoxMulti vertical alignment: 0-CENTERED, 1-UP, 2-DOWN
TEXT_MULTILINE, // TextBox supports multiple lines
TEXT_WRAP_MODE, // TextBox wrap mode for multiline: 0-NO_WRAP, 1-CHAR_WRAP, 2-WORD_WRAP
TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
}
// Spinner
@@ -229,8 +227,8 @@ foreign lib {
// Style set/get functions
GuiSetStyle :: proc(control: GuiControl, property: GuiControlProperty, value: c.int) --- // Set one style property
GuiGetStyle :: proc(control: GuiControl, property: GuiControlProperty) -> c.int --- // Get one style property
GuiSetStyle :: proc(control: GuiControl, property: c.int, value: c.int) --- // Set one style property
GuiGetStyle :: proc(control: GuiControl, property: c.int) -> c.int --- // Get one style property
// Styles loading functions
+23 -8
View File
@@ -84,7 +84,6 @@ package raylib
import "core:c"
import "core:fmt"
import "core:mem"
import "core:strings"
import "core:math/linalg"
_ :: linalg
@@ -447,9 +446,9 @@ VrStereoConfig :: struct #align(4) {
// File path list
FilePathList :: struct {
capacity: c.uint, // Filepaths max entries
count: c.uint, // Filepaths entries count
paths: [^]cstring, // Filepaths entries
capacity: c.uint, // Filepaths max entries
count: c.uint, // Filepaths entries count
paths: [^]cstring, // Filepaths entries
}
// Automation event
@@ -1029,7 +1028,6 @@ foreign lib {
SetTraceLogLevel :: proc(logLevel: TraceLogLevel) --- // Set the current threshold (minimum) log level
MemAlloc :: proc(size: c.uint) -> rawptr --- // Internal memory allocator
MemRealloc :: proc(ptr: rawptr, size: c.uint) -> rawptr --- // Internal memory reallocator
MemFree :: proc(ptr: rawptr) --- // Internal memory free
// Set custom callbacks
// WARNING: Callbacks setup is intended for advance users
@@ -1256,7 +1254,7 @@ foreign lib {
LoadImage :: proc(fileName: cstring) -> Image --- // Load image from file into CPU memory (RAM)
LoadImageRaw :: proc(fileName: cstring, width, height: c.int, format: PixelFormat, headerSize: c.int) -> Image --- // Load image from RAW file data
LoadImageSvg :: proc(fileNameOrString: cstring, width, height: c.int) -> Image --- // Load image from SVG file data or string with specified size
LoadImageAnim :: proc(fileName: cstring, frames: [^]c.int) -> Image --- // Load image sequence from file (frames appended to image.data)
LoadImageAnim :: proc(fileName: cstring, frames: ^c.int) -> Image --- // Load image sequence from file (frames appended to image.data)
LoadImageFromMemory :: proc(fileType: cstring, fileData: rawptr, dataSize: c.int) -> Image --- // Load image from memory buffer, fileType refers to extension: i.e. '.png'
LoadImageFromTexture :: proc(texture: Texture2D) -> Image --- // Load image from GPU texture data
LoadImageFromScreen :: proc() -> Image --- // Load image from screen buffer and (screenshot)
@@ -1684,8 +1682,25 @@ TextFormat :: proc(text: cstring, args: ..any) -> cstring {
// Text formatting with variables (sprintf style) and allocates (must be freed with 'MemFree')
TextFormatAlloc :: proc(text: cstring, args: ..any) -> cstring {
str := fmt.tprintf(string(text), ..args)
return strings.clone_to_cstring(str, MemAllocator())
return fmt.caprintf(string(text), ..args, allocator=MemAllocator())
}
// Internal memory free
MemFree :: proc{
MemFreePtr,
MemFreeCstring,
}
@(default_calling_convention="c")
foreign lib {
@(link_name="MemFree")
MemFreePtr :: proc(ptr: rawptr) ---
}
MemFreeCstring :: proc "c" (s: cstring) {
MemFreePtr(rawptr(s))
}
+6
View File
@@ -41,6 +41,12 @@ MAJOR_VERSION :: 2
MINOR_VERSION :: 0
PATCHLEVEL :: 16
VERSION :: proc "contextless" (ver: ^version) {
ver.major = MAJOR_VERSION
ver.minor = MINOR_VERSION
ver.patch = PATCHLEVEL
}
@(default_calling_convention="c", link_prefix="SDL_")
foreign lib {
GetVersion :: proc(ver: ^version) ---
+4 -4
View File
@@ -171,9 +171,9 @@ KeyboardEvent :: struct {
TEXTEDITINGEVENT_TEXT_SIZE :: 32
TextEditingEvent :: struct {
type: EventType, /**< ::SDL_TEXTEDITING */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */
text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */
text: [TEXTEDITINGEVENT_TEXT_SIZE]u8, /**< The editing text */
start: i32, /**< The start cursor of selected editing text */
length: i32, /**< The length of selected editing text */
}
@@ -184,7 +184,7 @@ TextInputEvent :: struct {
type: EventType, /**< ::SDL_TEXTINPUT */
timestamp: u32, /**< In milliseconds, populated using SDL_GetTicks() */
windowID: u32, /**< The window with keyboard focus, if any */
text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */
text: [TEXTINPUTEVENT_TEXT_SIZE]u8, /**< The input text */
}
MouseMotionEvent :: struct {
+23 -23
View File
@@ -54,29 +54,29 @@ GameControllerAxis :: enum c.int {
}
GameControllerButton :: enum c.int {
INVALID = -1,
A,
B,
X,
Y,
BACK,
GUIDE,
START,
LEFTSTICK,
RIGHTSTICK,
LEFTSHOULDER,
RIGHTSHOULDER,
DPAD_UP,
DPAD_DOWN,
DPAD_LEFT,
DPAD_RIGHT,
MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
PADDLE1, /* Xbox Elite paddle P1 */
PADDLE2, /* Xbox Elite paddle P3 */
PADDLE3, /* Xbox Elite paddle P2 */
PADDLE4, /* Xbox Elite paddle P4 */
TOUCHPAD, /* PS4/PS5 touchpad button */
MAX,
INVALID = -1,
A,
B,
X,
Y,
BACK,
GUIDE,
START,
LEFTSTICK,
RIGHTSTICK,
LEFTSHOULDER,
RIGHTSHOULDER,
DPAD_UP,
DPAD_DOWN,
DPAD_LEFT,
DPAD_RIGHT,
MISC1, /* Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button */
PADDLE1, /* Xbox Elite paddle P1 */
PADDLE2, /* Xbox Elite paddle P3 */
PADDLE3, /* Xbox Elite paddle P2 */
PADDLE4, /* Xbox Elite paddle P4 */
TOUCHPAD, /* PS4/PS5 touchpad button */
MAX,
}
+4 -4
View File
@@ -19,10 +19,10 @@ TouchDeviceType :: enum c.int {
}
Finger :: struct {
id: FingerID,
x: f32,
y: f32,
pressure: f32,
id: FingerID,
x: f32,
y: f32,
pressure: f32,
}
TOUCH_MOUSEID :: ~u32(0)
+1 -1
View File
@@ -166,7 +166,7 @@ datatype :: enum c.int {
UINT32,
FLOAT,
MAX_TYPES,
MAX_TYPES,
}
@(default_calling_convention="c", link_prefix="stbir_")
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -8,7 +8,7 @@ endif
wasm:
mkdir -p ../lib
clang -c -Os --target=wasm32 -nostdlib stb_truetype_wasm.c -o ../lib/stb_truetype_wasm.o
$(CC) -c -Os --target=wasm32 -nostdlib stb_truetype_wasm.c -o ../lib/stb_truetype_wasm.o
unix:
mkdir -p ../lib
-3
View File
@@ -1,5 +1,2 @@
#define STB_RECT_PACK_IMPLEMENTATION
#include "stb_rect_pack.h"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
+1 -7
View File
@@ -65,14 +65,8 @@ ceil :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
sqrt :: proc "c" (x: f64) -> f64 { return math.sqrt(x) }
@(require, linkage="strong", link_name="stbtt_pow")
pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) }
@(require, linkage="strong", link_name="stbtt_fmod")
fmod :: proc "c" (x, y: f64) -> f64 {
context = runtime.default_context()
// NOTE: only called in the `stbtt_GetGlyphSDF` code path.
panic("`math.round` is broken on 32 bit targets, see #3856")
}
fmod :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
@(require, linkage="strong", link_name="stbtt_cos")
cos :: proc "c" (x: f64) -> f64 { return math.cos(x) }
@(require, linkage="strong", link_name="stbtt_acos")
+2 -2
View File
@@ -11,8 +11,8 @@ Have a look at the `example/` directory for the rendering of a basic triangle.
## Getting the wgpu-native libraries
For native support (not the browser), some libraries are required. Fortunately this is
extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1),
the bindings are for v0.19.4.1 at the moment.
extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1),
the bindings are for v22.1.0.1 at the moment.
These are expected in the `lib` folder under the same name as they are released (just unzipped).
By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`),
+4 -2
View File
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame,
loadOp = .Clear,
storeOp = .Store,
clearValue = { r = 0, g = 1, b = 0, a = 1 },
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 1 },
},
},
)
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
wgpu.RenderPassEncoderEnd(render_pass_encoder)
wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer)
+4 -2
View File
@@ -158,15 +158,17 @@ frame :: proc "c" (dt: f32) {
view = frame,
loadOp = .Clear,
storeOp = .Store,
clearValue = { r = 0, g = 1, b = 0, a = 1 },
depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
clearValue = { 0, 1, 0, 1 },
},
},
)
defer wgpu.RenderPassEncoderRelease(render_pass_encoder)
wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
wgpu.RenderPassEncoderEnd(render_pass_encoder)
wgpu.RenderPassEncoderRelease(render_pass_encoder)
command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
defer wgpu.CommandBufferRelease(command_buffer)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -5,7 +5,9 @@ import "vendor:wgpu"
GetSurface :: proc(instance: wgpu.Instance, window: ^sdl2.Window) -> wgpu.Surface {
window_info: sdl2.SysWMinfo
sdl2.VERSION(&window_info.version)
sdl2.GetWindowWMInfo(window, &window_info)
if window_info.subsystem == .WAYLAND {
display := window_info.info.wl.display
surface := window_info.info.wl.surface
+91 -96
View File
@@ -44,6 +44,7 @@ class WebGPUInterface {
BlendFactor: ["zero", "one", "src", "one-minus-src", "src-alpha", "one-minus-src-alpha", "dst", "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", "constant", "one-minus-constant", ],
PresentMode: ["fifo", "fifo-relaxed", "immediate", "mailbox", ],
TextureAspect: ["all", "stencil-only", "depth-only"],
DeviceLostReason: [undefined, "unknown", "destroyed"],
};
/** @type {WebGPUObjectManager<{}>} */
@@ -382,13 +383,19 @@ class WebGPUInterface {
*/
RenderPassColorAttachment(start) {
const viewIdx = this.mem.loadPtr(start + 4);
const resolveTargetIdx = this.mem.loadPtr(start + 8);
const resolveTargetIdx = this.mem.loadPtr(start + 12);
let depthSlice = this.mem.loadU32(start + 8);
if (depthSlice == 0xFFFFFFFF) { // DEPTH_SLICE_UNDEFINED.
depthSlice = undefined;
}
return {
view: viewIdx > 0 ? this.textureViews.get(viewIdx) : undefined,
resolveTarget: resolveTargetIdx > 0 ? this.textureViews.get(resolveTargetIdx) : undefined,
loadOp: this.enumeration("LoadOp", start + 12),
storeOp: this.enumeration("StoreOp", start + 16),
depthSlice: depthSlice,
loadOp: this.enumeration("LoadOp", start + 16),
storeOp: this.enumeration("StoreOp", start + 20),
clearValue: this.Color(start + 24),
};
}
@@ -950,14 +957,25 @@ class WebGPUInterface {
/**
* @param {number} adapterIdx
* @param {number} propertiesPtr
* @param {number} infoPtr
*/
wgpuAdapterGetProperties: (adapterIdx, propertiesPtr) => {
this.assert(propertiesPtr != 0);
// Unknown adapter.
this.mem.storeI32(propertiesPtr + 28, 3);
wgpuAdapterGetInfo: (adapterIdx, infoPtr) => {
this.assert(infoPtr != 0);
// WebGPU backend.
this.mem.storeI32(propertiesPtr + 32, 2);
this.mem.storeI32(infoPtr + 20, 2);
// Unknown adapter.
this.mem.storeI32(infoPtr + 24, 3);
// NOTE: I don't think getting the other fields in this struct is possible.
// `adapter.requestAdapterInfo` is deprecated.
},
/**
* @param {number} infoPtr
*/
wgpuAdapterInfoFreeMembers: (infoPtr) => {
// NOTE: nothing to free.
},
/**
@@ -970,50 +988,6 @@ class WebGPUInterface {
return adapter.features.has(this.enums.FeatureName[featureInt]);
},
/**
* @param {number} adapterIdx
* @param {number} callbackPtr
* @param {0|number} userdata
*/
wgpuAdapterRequestAdapterInfo: async (adapterIdx, callbackPtr, userdata) => {
const adapter = this.adapters.get(adapterIdx);
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
const info = await adapter.requestAdapterInfo();
const addr = this.mem.exports.wgpu_alloc(16);
const vendorLength = new TextEncoder().encode(info.vendor).length;
const vendorAddr = this.mem.exports.wgpu_alloc(vendorLength);
this.mem.storeString(vendorAddr, info.vendor);
this.mem.storeI32(addr + 0, vendorAddr);
const architectureLength = new TextEncoder().encode(info.architecture).length;
const architectureAddr = this.mem.exports.wgpu_alloc(architectureLength);
this.mem.storeString(architectureAddr, info.architecture);
this.mem.storeI32(addr + 4, architectureAddr);
const deviceLength = new TextEncoder().encode(info.device).length;
const deviceAddr = this.mem.exports.wgpu_alloc(deviceLength);
this.mem.storeString(deviceAddr, info.device);
this.mem.storeI32(addr + 8, deviceAddr);
const descriptionLength = new TextEncoder().encode(info.description).length;
const descriptionAddr = this.mem.exports.wgpu_alloc(descriptionLength);
this.mem.storeString(descriptionAddr, info.description);
this.mem.storeI32(addr + 12, descriptionAddr);
callback(addr, userdata);
this.mem.exports.wgpu_free(descriptionAddr);
this.mem.exports.wgpu_free(deviceAddr);
this.mem.exports.wgpu_free(architectureAddr);
this.mem.exports.wgpu_free(vendorAddr);
this.mem.exports.wgpu_free(addr);
},
/**
* @param {number} adapterIdx
* @param {0|number} descriptorPtr
@@ -1040,14 +1014,69 @@ class WebGPUInterface {
};
}
let device;
let deviceIdx;
try {
const device = await adapter.requestDevice(descriptor);
device = await adapter.requestDevice(descriptor);
deviceIdx = this.devices.create(device);
// NOTE: don't callback here, any errors that happen later will then be caught by the catch here.
} catch (e) {
console.warn(e);
callback(1, null, null, userdata);
const messageLength = new TextEncoder().encode(e.message).length;
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, e.message);
callback(1, null, messageAddr, userdata);
this.mem.exports.wgpu_free(messageAddr);
}
let callbacksPtr = descriptorPtr + 24 + this.mem.intSize;
const deviceLostCallbackPtr = this.mem.loadPtr(callbacksPtr);
if (deviceLostCallbackPtr != 0) {
const deviceLostUserData = this.mem.loadPtr(callbacksPtr) + 4;
const deviceLostCallback = this.mem.exports.__indirect_function_table.get(deviceLostCallbackPtr);
device.lost.then((info) => {
const reason = this.enums.DeviceLostReason.indexOf(info.reason);
const messageLength = new TextEncoder().encode(info.message).length;
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, info.message);
deviceLostCallback(reason, messageAddr, deviceLostUserData);
this.mem.exports.wgpu_free(messageAddr);
});
}
callbacksPtr += 8;
// Skip over `nextInChain`.
callbacksPtr += 4;
const uncapturedErrorCallbackPtr = this.mem.loadPtr(callbacksPtr);
if (uncapturedErrorCallbackPtr != 0) {
const uncapturedErrorUserData = this.mem.loadPtr(callbacksPtr + 4);
const uncapturedErrorCallback = this.mem.exports.__indirect_function_table.get(uncapturedErrorCallbackPtr);
device.onuncapturederror = (ev) => {
let status = 4; // Unknown
if (ev.error instanceof GPUValidationError) {
status = 1; // Validation
} else if (ev.error instanceof GPUOutOfMemoryError) {
status = 2; // OutOfMemory
} else if (ev.error instanceof GPUInternalError) {
status = 3; // Internal
}
const messageLength = new TextEncoder().encode(ev.error.message).length;
const messageAddr = this.mem.exports.wgpu_alloc(messageLength + 1);
this.mem.storeString(messageAddr, ev.error.message);
uncapturedErrorCallback(status, messageAddr, uncapturedErrorUserData);
this.mem.exports.wgpu_free(messageAddr);
};
}
callback(0, deviceIdx, null, userdata);
@@ -1918,29 +1947,6 @@ class WebGPUInterface {
device.pushErrorScope(this.enums.ErrorFilter[filterInt]);
},
/**
* @param {number} deviceIdx
* @param {number} callbackPtr
* @param {number} userdata
*/
wgpuDeviceSetUncapturedErrorCallback: (deviceIdx, callbackPtr, userdata) => {
const device = this.devices.get(deviceIdx);
const callback = this.mem.exports.__indirect_function_table.get(callbackPtr);
device.onuncapturederror = (ev) => {
console.warn(ev.error);
let status = 4;
if (error instanceof GPUValidationError) {
status = 1;
} else if (error instanceof GPUOutOfMemoryError) {
status = 2;
} else if (error instanceof GPUInternalError) {
status = 3;
}
callback(status, null, userdata);
};
},
...this.devices.interface(true),
/* ---------------------- Instance ---------------------- */
@@ -2646,23 +2652,23 @@ class WebGPUInterface {
const formatStr = navigator.gpu.getPreferredCanvasFormat();
const format = this.enums.TextureFormat.indexOf(formatStr);
this.mem.storeUint(capabilitiesPtr + this.mem.intSize, 1);
this.mem.storeUint(capabilitiesPtr + 8, 1);
const formatAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(formatAddr, format);
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*2, formatAddr);
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize, formatAddr);
// NOTE: present modes don't seem to actually do anything in JS, we can just give back a default FIFO though.
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*3, 1);
this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*2, 1);
const presentModesAddr = this.mem.exports.wgpu_alloc(4);
this.mem.storeI32(presentModesAddr, 0);
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*4, presentModesAddr);
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*3, presentModesAddr);
// Browser seems to support opaque (1) and premultiplied (2).
this.mem.storeUint(capabilitiesPtr + this.mem.intSize*5, 2);
this.mem.storeUint(capabilitiesPtr + 8 + this.mem.intSize*4, 2);
const alphaModesAddr = this.mem.exports.wgpu_alloc(8);
this.mem.storeI32(alphaModesAddr + 0, 1); // Opaque.
this.mem.storeI32(alphaModesAddr + 4, 2); // premultiplied.
this.mem.storeI32(capabilitiesPtr + this.mem.intSize*6, alphaModesAddr);
this.mem.storeI32(capabilitiesPtr + 8 + this.mem.intSize*5, alphaModesAddr);
},
/**
@@ -2680,17 +2686,6 @@ class WebGPUInterface {
// TODO: determine suboptimal and/or status.
},
/**
* @param {number} surfaceIdx
* @param {number} texturePtr
* @returns {number}
*/
wgpuSurfaceGetPreferredFormat: (surfaceIdx, adapterIdx) => {
const formatStr = navigator.gpu.getPreferredCanvasFormat();
const format = this.enums.TextureFormat.indexOf(formatStr);
return format;
},
/**
* @param {number} surfaceIdx
*/
+113 -53
View File
@@ -13,7 +13,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-windows-" + ARCH + "-" + TYPE + "/wgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -27,6 +27,8 @@ when ODIN_OS == .Windows {
"system:advapi32.lib",
"system:user32.lib",
"system:gdi32.lib",
"system:ole32.lib",
"system:oleaut32.lib",
}
} else when ODIN_OS == .Darwin {
@(private) ARCH :: "x86_64" when ODIN_ARCH == .amd64 else "aarch64" when ODIN_ARCH == .arm64 else #panic("unsupported WGPU Native architecture")
@@ -34,7 +36,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -49,7 +51,7 @@ when ODIN_OS == .Windows {
@(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/libwgpu_native" + EXT
when !#exists(LIB) {
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v0.19.4.1, make sure to read the README at '" + #directory + "vendor/wgpu/README.md'")
#panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v22.1.0.1, make sure to read the README at '" + #directory + "README.md'")
}
foreign import libwgpu {
@@ -220,7 +222,8 @@ CullMode :: enum i32 {
DeviceLostReason :: enum i32 {
Undefined = 0x00000000,
Destroyed = 0x00000001,
Unknown = 0x00000001,
Destroyed = 0x00000002,
}
ErrorFilter :: enum i32 {
@@ -264,6 +267,30 @@ FeatureName :: enum i32 {
PipelineStatisticsQuery,
StorageResourceBindingArray,
PartiallyBoundBindingArray,
TextureFormat16bitNorm,
TextureCompressionAstcHdr,
// TODO: requires wgpu.h api change
// TimestampQueryInsidePasses,
MappablePrimaryBuffers = 0x0003000E,
BufferBindingArray,
UniformBufferAndStorageTextureArrayNonUniformIndexing,
// TODO: requires wgpu.h api change
// AddressModeClampToZero,
// AddressModeClampToBorder,
// PolygonModeLine,
// PolygonModePoint,
// ConservativeRasterization,
// ClearTexture,
// SprivShaderPassThrough,
// MultiView,
VertexAttribute64bit = 0x00030019,
TextureFormatNv12,
RayTracingAccelarationStructure,
RayQuery,
ShaderF64,
ShaderI16,
ShaderPrimitiveIndex,
ShaderEarlyDepthTest,
}
FilterMode :: enum i32 {
@@ -520,6 +547,18 @@ TextureFormat :: enum i32 {
ASTC12x10UnormSrgb = 0x0000005D,
ASTC12x12Unorm = 0x0000005E,
ASTC12x12UnormSrgb = 0x0000005F,
// Native.
// From FeatureName.TextureFormat16bitNorm
R16Unorm = 0x00030001,
R16Snorm,
Rg16Unorm,
Rg16Snorm,
Rgba16Unorm,
Rgba16Snorm,
// From FeatureName.TextureFormatNv12
NV12,
}
TextureSampleType :: enum i32 {
@@ -581,13 +620,13 @@ VertexStepMode :: enum i32 {
VertexBufferNotUsed = 0x00000002,
}
// WGSLFeatureName :: enum i32 {
// Undefined = 0x00000000,
// ReadonlyAndReadwriteStorageTextures = 0x00000001,
// Packed4x8IntegerDotProduct = 0x00000002,
// UnrestrictedPointerParameters = 0x00000003,
// PointerCompositeAccess = 0x00000004,
// }
WGSLFeatureName :: enum i32 {
Undefined = 0x00000000,
ReadonlyAndReadwriteStorageTextures = 0x00000001,
Packed4x8IntegerDotProduct = 0x00000002,
UnrestrictedPointerParameters = 0x00000003,
PointerCompositeAccess = 0x00000004,
}
BufferUsage :: enum i32 {
MapRead = 0x00000000,
@@ -634,22 +673,18 @@ TextureUsage :: enum i32 {
}
TextureUsageFlags :: bit_set[TextureUsage; Flags]
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
Proc :: distinct rawptr
DeviceLostCallback :: #type proc "c" (reason: DeviceLostReason, message: cstring, userdata: rawptr)
ErrorCallback :: #type proc "c" (type: ErrorType, message: cstring, userdata: rawptr)
Proc :: distinct rawptr
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
AdapterRequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, device: Device, message: cstring, /* NULLABLE */ userdata: rawptr)
// AdapterRequestAdapterInfoCallback :: #type proc "c" (adapterInfo: AdapterInfo, /* NULLABLE */ userdata: rawptr)
BufferMapAsyncCallback :: #type proc "c" (status: BufferMapAsyncStatus, /* NULLABLE */ userdata: rawptr)
DeviceCreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
DeviceCreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: cstring, /* NULLABLE */ userdata: rawptr)
InstanceRequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: cstring, /* NULLABLE */ userdata: rawptr)
QueueOnSubmittedWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, /* NULLABLE */ userdata: rawptr)
ShaderModuleGetCompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, /* NULLABLE */ userdata: rawptr)
ChainedStruct :: struct {
next: ^ChainedStruct,
@@ -661,28 +696,23 @@ ChainedStructOut :: struct {
sType: SType,
}
// AdapterInfo :: struct {
// next: ^ChainedStructOut,
// vendor: cstring,
// architecture: cstring,
// device: cstring,
// description: cstring,
// backendType: BackendType,
// adapterType: AdapterType,
// vendorID: u32,
// deviceID: u32,
// }
AdapterProperties :: struct {
AdapterInfo :: struct {
nextInChain: ^ChainedStructOut,
vendorID: u32,
vendorName: cstring,
vendor: cstring,
architecture: cstring,
deviceID: u32,
name: cstring,
driverDescription: cstring,
adapterType: AdapterType,
device: cstring,
description: cstring,
backendType: BackendType,
adapterType: AdapterType,
vendorID: u32,
deviceID: u32,
}
when ODIN_OS == .JS {
#assert(int(BackendType.WebGPU) == 2)
#assert(offset_of(AdapterInfo, backendType) == 20)
#assert(int(AdapterType.Unknown) == 3)
#assert(offset_of(AdapterInfo, adapterType) == 24)
}
BindGroupEntry :: struct {
@@ -943,6 +973,7 @@ StorageTextureBindingLayout :: struct {
SurfaceCapabilities :: struct {
nextInChain: ^ChainedStructOut,
usages: TextureUsageFlags,
formatCount: uint,
formats: /* const */ [^]TextureFormat `fmt:"v,formatCount"`,
presentModeCount: uint,
@@ -950,6 +981,16 @@ SurfaceCapabilities :: struct {
alphaModeCount: uint,
alphaModes: /* const */ [^]CompositeAlphaMode `fmt:"v,alphaModeCount"`,
}
when ODIN_OS == .JS {
#assert(offset_of(SurfaceCapabilities, formatCount) == 8)
#assert(offset_of(SurfaceCapabilities, formats) == 8 + 1*size_of(int))
#assert(offset_of(SurfaceCapabilities, presentModeCount) == 8 + 2*size_of(int))
#assert(offset_of(SurfaceCapabilities, presentModes) == 8 + 3*size_of(int))
#assert(offset_of(SurfaceCapabilities, alphaModeCount) == 8 + 4*size_of(int))
#assert(offset_of(SurfaceCapabilities, alphaModes) == 8 + 5*size_of(int))
}
SurfaceConfiguration :: struct {
nextInChain: ^ChainedStruct,
@@ -1040,6 +1081,12 @@ TextureViewDescriptor :: struct {
aspect: TextureAspect,
}
UncapturedErrorCallbackInfo :: struct {
nextInChain: ^ChainedStruct,
callback: ErrorCallback,
userdata: rawptr,
}
VertexAttribute :: struct {
format: VertexFormat,
offset: u64,
@@ -1120,12 +1167,21 @@ ProgrammableStageDescriptor :: struct {
RenderPassColorAttachment :: struct {
nextInChain: ^ChainedStruct,
/* NULLABLE */ view: TextureView,
// depthSlice: u32,
depthSlice: u32,
/* NULLABLE */ resolveTarget: TextureView,
loadOp: LoadOp,
storeOp: StoreOp,
clearValue: Color,
}
when ODIN_OS == .JS {
#assert(size_of(RenderPassColorAttachment) == 56)
#assert(offset_of(RenderPassColorAttachment, view) == 4)
#assert(offset_of(RenderPassColorAttachment, depthSlice) == 8)
#assert(offset_of(RenderPassColorAttachment, resolveTarget) == 12)
#assert(offset_of(RenderPassColorAttachment, loadOp) == 16)
#assert(offset_of(RenderPassColorAttachment, storeOp) == 20)
#assert(offset_of(RenderPassColorAttachment, clearValue) == 24)
}
RequiredLimits :: struct {
nextInChain: ^ChainedStruct,
@@ -1194,6 +1250,10 @@ DeviceDescriptor :: struct {
defaultQueue: QueueDescriptor,
deviceLostCallback: DeviceLostCallback,
deviceLostUserdata: rawptr,
uncapturedErrorCallbackInfo: UncapturedErrorCallbackInfo,
}
when ODIN_OS == .JS {
#assert(offset_of(DeviceDescriptor, deviceLostCallback) == 24 + size_of(int))
}
RenderPassDescriptor :: struct {
@@ -1245,16 +1305,18 @@ foreign libwgpu {
// Methods of Adapter
@(link_name="wgpuAdapterEnumerateFeatures")
RawAdapterEnumerateFeatures :: proc(adapter: Adapter, features: [^]FeatureName) -> uint ---
@(link_name="wgpuAdapterGetInfo")
RawAdapterGetInfo :: proc(adapter: Adapter, info: ^AdapterInfo) ---
@(link_name="wgpuAdapterGetLimits")
RawAdapterGetLimits :: proc(adapter: Adapter, limits: ^SupportedLimits) -> b32 ---
@(link_name="wgpuAdapterGetProperties")
RawAdapterGetProperties :: proc(adapter: Adapter, properties: ^AdapterProperties) ---
AdapterHasFeature :: proc(adapter: Adapter, feature: FeatureName) -> b32 ---
// AdapterRequestAdapterInfo :: proc(adapter: Adapter, callback: AdapterRequestAdapterInfoCallback, /* NULLABLE */ userdata: rawptr) ---
AdapterRequestDevice :: proc(adapter: Adapter, /* NULLABLE */ descriptor: /* const */ ^DeviceDescriptor, callback: AdapterRequestDeviceCallback, /* NULLABLE */ userdata: rawptr = nil) ---
AdapterReference :: proc(adapter: Adapter) ---
AdapterRelease :: proc(adapter: Adapter) ---
// Procs of AdapterInfo
AdapterInfoFreeMembers :: proc(adapterInfo: AdapterInfo) ---
// Methods of BindGroup
BindGroupSetLabel :: proc(bindGroup: BindGroup, label: cstring) ---
BindGroupReference :: proc(bindGroup: BindGroup) ---
@@ -1348,13 +1410,12 @@ foreign libwgpu {
DevicePopErrorScope :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
DevicePushErrorScope :: proc(device: Device, filter: ErrorFilter) ---
DeviceSetLabel :: proc(device: Device, label: cstring) ---
DeviceSetUncapturedErrorCallback :: proc(device: Device, callback: ErrorCallback, userdata: rawptr) ---
DeviceReference :: proc(device: Device) ---
DeviceRelease :: proc(device: Device) ---
// Methods of Instance
InstanceCreateSurface :: proc(instance: Instance, descriptor: /* const */ ^SurfaceDescriptor) -> Surface ---
// InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
InstanceHasWGSLLanguageFeature :: proc(instance: Instance, feature: WGSLFeatureName) -> b32 ---
InstanceProcessEvents :: proc(instance: Instance) ---
InstanceRequestAdapter :: proc(instance: Instance, /* NULLABLE */ options: /* const */ ^RequestAdapterOptions, callback: InstanceRequestAdapterCallback, /* NULLABLE */ userdata: rawptr = nil) ---
InstanceReference :: proc(instance: Instance) ---
@@ -1455,9 +1516,8 @@ foreign libwgpu {
RawSurfaceGetCapabilities :: proc(surface: Surface, adapter: Adapter, capabilities: ^SurfaceCapabilities) ---
@(link_name="wgpuSurfaceGetCurrentTexture")
RawSurfaceGetCurrentTexture :: proc(surface: Surface, surfaceTexture: ^SurfaceTexture) ---
SurfaceGetPreferredFormat :: proc(surface: Surface, adapter: Adapter) -> TextureFormat ---
SurfacePresent :: proc(surface: Surface) ---
// SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
SurfaceSetLabel :: proc(surface: Surface, label: cstring) ---
SurfaceUnconfigure :: proc(surface: Surface) ---
SurfaceReference :: proc(surface: Surface) ---
SurfaceRelease :: proc(surface: Surface) ---
@@ -1500,8 +1560,8 @@ AdapterGetLimits :: proc(adapter: Adapter) -> (limits: SupportedLimits, ok: bool
return
}
AdapterGetProperties :: proc(adapter: Adapter) -> (properties: AdapterProperties) {
RawAdapterGetProperties(adapter, &properties)
AdapterGetInfo :: proc(adapter: Adapter) -> (info: AdapterInfo) {
RawAdapterGetInfo(adapter, &info)
return
}
@@ -1634,8 +1694,8 @@ SurfaceGetCurrentTexture :: proc(surface: Surface) -> (surface_texture: SurfaceT
// WGPU Native bindings
BINDINGS_VERSION :: [4]u8{0, 19, 4, 1}
BINDINGS_VERSION_STRING :: "0.19.4.1"
BINDINGS_VERSION :: [4]u8{22, 1, 0, 1}
BINDINGS_VERSION_STRING :: "22.1.0.1"
when ODIN_OS != .JS {
@(private="file", init)
+5
View File
@@ -72,6 +72,11 @@ XkbAllEventsMask :: XkbEventMask {
.ExtensionDeviceNotify,
}
/* ---- X11/extensions/XI2.h ---------------------------------------------------------*/
XIAllDevices :: 0
XIAllMasterDevices :: 1
/* ---- X11/Xlib.h ---------------------------------------------------------*/
+1675 -1675
View File
File diff suppressed because it is too large Load Diff
+41 -5
View File
@@ -9,13 +9,49 @@ foreign xlib {
foreign import xcursor "system:Xcursor"
@(default_calling_convention="c", link_prefix="X")
foreign xcursor {
cursorGetTheme :: proc(display: ^Display) -> cstring ---
cursorGetDefaultSize :: proc(display: ^Display) -> i32 ---
cursorLibraryLoadImage :: proc(name: cstring, theme: cstring, size: i32) -> rawptr ---
cursorImageLoadCursor :: proc(display: ^Display, img: rawptr) -> Cursor ---
cursorImageDestroy :: proc(img: rawptr) ---
cursorGetTheme :: proc(display: ^Display) -> cstring ---
cursorGetDefaultSize :: proc(display: ^Display) -> i32 ---
cursorLibraryLoadCursor :: proc(display: ^Display, name: cstring) -> Cursor ---
cursorLibraryLoadImage :: proc(name: cstring, theme: cstring, size: i32) -> rawptr ---
cursorImageLoadCursor :: proc(display: ^Display, img: rawptr) -> Cursor ---
cursorImageDestroy :: proc(img: rawptr) ---
}
foreign import xfixes "system:Xfixes"
@(default_calling_convention="c", link_prefix="XFixes")
foreign xfixes {
HideCursor :: proc(display: ^Display, window: Window) ---
ShowCursor :: proc(display: ^Display, window: Window) ---
}
foreign import xrandr "system:Xrandr"
@(default_calling_convention="c")
foreign xrandr {
XRRSizes :: proc(display: ^Display, screen: i32, nsizes: ^i32) -> [^]XRRScreenSize ---
XRRGetScreenResources :: proc(display: ^Display, window: Window) -> ^XRRScreenResources ---
XRRFreeScreenResources :: proc(resources: ^XRRScreenResources) ---
XRRGetOutputInfo :: proc(display: ^Display, resources: ^XRRScreenResources, output: RROutput) -> ^XRROutputInfo ---
XRRFreeOutputInfo :: proc(output_info: ^XRROutputInfo) ---
XRRGetCrtcInfo :: proc(display: ^Display, resources: ^XRRScreenResources, crtc: RRCrtc) -> ^XRRCrtcInfo ---
XRRFreeCrtcInfo :: proc(crtc_info: ^XRRCrtcInfo) ---
XRRGetMonitors :: proc(dpy: ^Display, window: Window, get_active: b32, nmonitors: ^i32) -> [^]XRRMonitorInfo ---
}
foreign import xinput "system:Xi"
foreign xinput {
XISelectEvents :: proc(display: ^Display, window: Window, masks: [^]XIEventMask, num_masks: i32) -> i32 ---
XIQueryVersion :: proc(display: ^Display, major: ^i32, minor: ^i32) -> Status ---
}
XISetMask :: proc(ptr: [^]u8, event: XIEventType) {
ptr[cast(i32)event >> 3] |= (1 << cast(uint)((cast(i32)event) & 7))
}
XIMaskIsSet :: proc(ptr: [^]u8, event: i32) -> bool {
return (ptr[event >> 3] & (1 << cast(uint)((event) & 7))) != 0
}
/* ---- X11/Xlib.h ---------------------------------------------------------*/
@(default_calling_convention="c", link_prefix="X")
+499 -311
View File
File diff suppressed because it is too large Load Diff