#pragma once
#include "core.h"
#include "box3d/id.h"
#include "box3d/math_functions.h"
#include "box3d/types.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define B3_SNAP_FNV_INIT 14695981039346656037ull
#define B3_SNAP_FNV_PRIME 1099511628211ull
static inline uint64_t b3FnvMixPosition( uint64_t hash, b3Pos p )
{
#if defined( BOX3D_DOUBLE_PRECISION )
uint64_t bx, by, bz;
memcpy( &bx, &p.x, 8 );
memcpy( &by, &p.y, 8 );
memcpy( &bz, &p.z, 8 );
#else
uint32_t fx, fy, fz;
memcpy( &fx, &p.x, 4 );
memcpy( &fy, &p.y, 4 );
memcpy( &fz, &p.z, 4 );
uint64_t bx = fx, by = fy, bz = fz;
#endif
hash = ( hash ^ bx ) * B3_SNAP_FNV_PRIME;
hash = ( hash ^ by ) * B3_SNAP_FNV_PRIME;
hash = ( hash ^ bz ) * B3_SNAP_FNV_PRIME;
return hash;
}
typedef struct b3World b3World;
#define B3_REC_MAGIC 0x43523342u
#define B3_REC_VERSION_MAJOR 2
#define B3_REC_VERSION_MINOR 2
typedef struct b3RecHeader
{
uint32_t magic; uint16_t versionMajor; uint16_t versionMinor; uint8_t pointerWidth; uint8_t bigEndian; uint8_t validationEnabled; uint8_t reserved;
float lengthScale; uint32_t reserved2;
uint32_t reserved3; uint64_t snapshotSize; uint64_t registryOffset; uint64_t registryByteCount; } b3RecHeader;
_Static_assert( sizeof( b3RecHeader ) == 48, "recording header must be 48 bytes" );
typedef struct b3RecBuffer
{
uint8_t* data;
int capacity;
int size;
bool countOnly;
} b3RecBuffer;
typedef enum b3GeometryKind
{
b3_geometryHull,
b3_geometryMesh,
b3_geometryHeightField,
b3_geometryCompound,
} b3GeometryKind;
typedef struct b3GeometryEntry
{
uint64_t contentHash;
uint32_t id;
b3GeometryKind kind;
int byteCount;
uint8_t* bytes;
int hashNext;
} b3GeometryEntry;
typedef struct b3GeometryRegistry
{
b3GeometryEntry* entries;
int count;
int capacity;
void* dedupMap;
} b3GeometryRegistry;
typedef struct b3RecTag
{
uint64_t key; uint64_t id; char name[B3_BODY_NAME_LENGTH + 1]; } b3RecTag;
typedef struct b3Recording
{
b3RecBuffer buffer;
int recordStart; b3Mutex* lock; b3GeometryRegistry registry;
b3RecTag* tags;
int tagCount;
int tagCapacity;
void* tagMap;
b3AABB accumulatedBounds;
bool haveBounds;
} b3Recording;
typedef bool b3RecCType_BOOL;
typedef int32_t b3RecCType_I32;
typedef uint8_t b3RecCType_U8;
typedef uint16_t b3RecCType_U16;
typedef uint32_t b3RecCType_U32;
typedef uint64_t b3RecCType_U64;
typedef float b3RecCType_F32;
typedef double b3RecCType_F64;
typedef b3Vec3 b3RecCType_VEC3;
typedef b3Quat b3RecCType_QUAT;
typedef b3Transform b3RecCType_TRANSFORM;
typedef b3Pos b3RecCType_POSITION;
typedef b3WorldTransform b3RecCType_WORLDXF;
typedef b3Matrix3 b3RecCType_MATRIX3;
typedef b3AABB b3RecCType_AABB;
typedef b3Sphere b3RecCType_SPHERE;
typedef b3Capsule b3RecCType_CAPSULE;
typedef b3QueryFilter b3RecCType_QUERYFILTER;
typedef b3ShapeProxy b3RecCType_SHAPEPROXY;
typedef uint32_t b3RecCType_GEOMID;
typedef b3Filter b3RecCType_FILTER;
typedef b3SurfaceMaterial b3RecCType_MATERIAL;
typedef b3MassData b3RecCType_MASSDATA;
typedef b3MotionLocks b3RecCType_LOCKS;
typedef const char* b3RecCType_STR;
typedef b3WorldId b3RecCType_WORLDID;
typedef b3BodyId b3RecCType_BODYID;
typedef b3ShapeId b3RecCType_SHAPEID;
typedef b3JointId b3RecCType_JOINTID;
typedef b3BodyDef b3RecCType_BODYDEF;
typedef b3ShapeDef b3RecCType_SHAPEDEF;
typedef b3ExplosionDef b3RecCType_EXPLOSIONDEF;
typedef b3ParallelJointDef b3RecCType_PARALLELJOINTDEF;
typedef b3DistanceJointDef b3RecCType_DISTANCEJOINTDEF;
typedef b3FilterJointDef b3RecCType_FILTERJOINTDEF;
typedef b3MotorJointDef b3RecCType_MOTORJOINTDEF;
typedef b3PrismaticJointDef b3RecCType_PRISMATICJOINTDEF;
typedef b3RevoluteJointDef b3RecCType_REVOLUTEJOINTDEF;
typedef b3SphericalJointDef b3RecCType_SPHERICALJOINTDEF;
typedef b3WeldJointDef b3RecCType_WELDJOINTDEF;
typedef b3WheelJointDef b3RecCType_WHEELJOINTDEF;
#define ARG( TAG, field ) b3RecCType_##TAG field;
#define B3_REC_OP( op, Name, RET, ... ) \
typedef struct \
{ \
__VA_ARGS__ \
} b3RecArgs_##Name;
#include "recording_ops.inl"
#undef B3_REC_OP
#undef ARG
enum
{
#define B3_REC_OP( op, Name, RET, ... ) b3_recOp##Name = ( op ),
#include "recording_ops.inl"
#undef B3_REC_OP
};
void b3RecBufAppend( b3RecBuffer* buf, const void* data, int size );
void b3RecBufFree( b3RecBuffer* buf );
void b3RecW_U8( b3RecBuffer* buf, uint8_t v );
void b3RecW_U16( b3RecBuffer* buf, uint16_t v );
void b3RecW_U32( b3RecBuffer* buf, uint32_t v );
void b3RecW_U64( b3RecBuffer* buf, uint64_t v );
void b3RecW_I32( b3RecBuffer* buf, int32_t v );
void b3RecW_F32( b3RecBuffer* buf, float v );
void b3RecW_F64( b3RecBuffer* buf, double v );
void b3RecW_BOOL( b3RecBuffer* buf, bool v );
void b3RecW_VEC3( b3RecBuffer* buf, b3Vec3 v );
void b3RecW_QUAT( b3RecBuffer* buf, b3Quat v );
void b3RecW_TRANSFORM( b3RecBuffer* buf, b3Transform v );
void b3RecW_POSITION( b3RecBuffer* buf, b3Pos v );
void b3RecW_WORLDXF( b3RecBuffer* buf, b3WorldTransform v );
void b3RecW_MATRIX3( b3RecBuffer* buf, b3Matrix3 v );
void b3RecW_AABB( b3RecBuffer* buf, b3AABB v );
void b3RecW_QUERYFILTER( b3RecBuffer* buf, b3QueryFilter v );
void b3RecW_SHAPEPROXY( b3RecBuffer* buf, b3ShapeProxy v );
void b3RecW_TREESTATS( b3RecBuffer* buf, b3TreeStats v );
void b3RecW_RAYRESULT( b3RecBuffer* buf, b3RayResult v );
void b3RecW_PLANERESULT( b3RecBuffer* buf, b3PlaneResult v );
void b3RecW_WORLDID( b3RecBuffer* buf, b3WorldId v );
void b3RecW_BODYID( b3RecBuffer* buf, b3BodyId v );
void b3RecW_SHAPEID( b3RecBuffer* buf, b3ShapeId v );
void b3RecW_JOINTID( b3RecBuffer* buf, b3JointId v );
void b3RecW_SPHERE( b3RecBuffer* buf, b3Sphere v );
void b3RecW_CAPSULE( b3RecBuffer* buf, b3Capsule v );
void b3RecW_GEOMID( b3RecBuffer* buf, uint32_t v );
void b3RecW_FILTER( b3RecBuffer* buf, b3Filter v );
void b3RecW_MATERIAL( b3RecBuffer* buf, b3SurfaceMaterial v );
void b3RecW_MASSDATA( b3RecBuffer* buf, b3MassData v );
void b3RecW_LOCKS( b3RecBuffer* buf, b3MotionLocks v );
void b3RecW_STR( b3RecBuffer* buf, const char* s );
void b3RecW_EXPLOSIONDEF( b3RecBuffer* buf, b3ExplosionDef v );
void b3RecW_BODYDEF( b3RecBuffer* buf, b3BodyDef v );
void b3RecW_SHAPEDEF( b3RecBuffer* buf, b3ShapeDef v );
void b3RecW_PARALLELJOINTDEF( b3RecBuffer* buf, b3ParallelJointDef v );
void b3RecW_DISTANCEJOINTDEF( b3RecBuffer* buf, b3DistanceJointDef v );
void b3RecW_FILTERJOINTDEF( b3RecBuffer* buf, b3FilterJointDef v );
void b3RecW_MOTORJOINTDEF( b3RecBuffer* buf, b3MotorJointDef v );
void b3RecW_PRISMATICJOINTDEF( b3RecBuffer* buf, b3PrismaticJointDef v );
void b3RecW_REVOLUTEJOINTDEF( b3RecBuffer* buf, b3RevoluteJointDef v );
void b3RecW_SPHERICALJOINTDEF( b3RecBuffer* buf, b3SphericalJointDef v );
void b3RecW_WELDJOINTDEF( b3RecBuffer* buf, b3WeldJointDef v );
void b3RecW_WHEELJOINTDEF( b3RecBuffer* buf, b3WheelJointDef v );
void b3RecBeginRecord( b3Recording* rec, uint8_t opcode );
void b3RecEndRecord( b3Recording* rec );
#define B3_REC_OP( op, Name, RET, ... ) \
void b3RecWriteArgs_##Name( b3Recording* rec, const b3RecArgs_##Name* a ); \
void b3RecWrite_##Name( b3Recording* rec, const b3RecArgs_##Name* a );
#include "recording_ops.inl"
#undef B3_REC_OP
#define B3_REC_RETDECL_RET_NONE( Name )
#define B3_REC_RETDECL_RET_BODYID( Name ) void b3RecWriteRet_##Name( b3Recording* rec, const b3RecArgs_##Name* a, b3BodyId id );
#define B3_REC_RETDECL_RET_SHAPEID( Name ) void b3RecWriteRet_##Name( b3Recording* rec, const b3RecArgs_##Name* a, b3ShapeId id );
#define B3_REC_RETDECL_RET_JOINTID( Name ) void b3RecWriteRet_##Name( b3Recording* rec, const b3RecArgs_##Name* a, b3JointId id );
#define B3_REC_OP( op, Name, RET, ... ) B3_REC_RETDECL_##RET( Name )
#include "recording_ops.inl"
#undef B3_REC_OP
#undef B3_REC_RETDECL_RET_NONE
#undef B3_REC_RETDECL_RET_BODYID
#undef B3_REC_RETDECL_RET_SHAPEID
#undef B3_REC_RETDECL_RET_JOINTID
#define B3_REC( world, Name, ... ) \
do \
{ \
if ( ( world )->recording != NULL ) \
{ \
b3RecArgs_##Name recArgs = { __VA_ARGS__ }; \
b3RecWrite_##Name( ( world )->recording, &recArgs ); \
} \
} \
while ( 0 )
#define B3_REC_CREATE( world, Name, id, ... ) \
do \
{ \
if ( ( world )->recording != NULL ) \
{ \
b3RecArgs_##Name recCreateArgs = { __VA_ARGS__ }; \
b3RecWriteRet_##Name( ( world )->recording, &recCreateArgs, id ); \
} \
} \
while ( 0 )
int b3RecReserveU32( b3RecBuffer* buf );
void b3RecPatchU32( b3RecBuffer* buf, int offset, uint32_t v );
void b3RecCommitRecord( b3Recording* rec, uint8_t opcode, const uint8_t* payload, int payloadSize );
typedef struct b3RecQueryWriter
{
union
{
b3OverlapResultFcn* overlapFcn;
b3CastResultFcn* castFcn;
b3PlaneResultFcn* planeFcn;
b3MoverFilterFcn* moverFilterFcn;
} userFcn;
void* userContext;
b3RecBuffer buf; int countOffset; uint32_t hitCount;
uint64_t tagId; const char* tagName; } b3RecQueryWriter;
void b3RecQueryBegin( b3RecQueryWriter* w, void* context, uint64_t tagId, const char* tagName );
void b3RecQueryCommit( b3Recording* rec, uint8_t opcode, b3RecQueryWriter* w );
bool b3RecOverlapTrampoline( b3ShapeId id, void* ctx );
float b3RecCastTrampoline( b3ShapeId id, b3Pos point, b3Vec3 normal, float fraction, uint64_t userMaterialId, int triangleIndex,
int childIndex, void* ctx );
bool b3RecPlaneTrampoline( b3ShapeId id, const b3PlaneResult* planes, int planeCount, void* ctx );
uint32_t b3InternGeometry( b3GeometryRegistry* reg, b3GeometryKind kind, uint64_t contentHash, uint8_t* bytes, int byteCount );
uint32_t b3AppendGeometry( b3GeometryRegistry* reg, b3GeometryKind kind, uint64_t contentHash, uint8_t* bytes, int byteCount );
void b3FreeRegistry( b3GeometryRegistry* reg );
void b3RecWriteRegistry( b3Recording* rec );
uint64_t b3HashQueryTag( uint64_t id, const char* name );
void b3RecInternTag( b3Recording* rec, uint64_t key, uint64_t id, const char* name );
uint32_t b3RecInternHull( b3Recording* rec, const b3HullData* hull );
uint32_t b3RecInternMesh( b3Recording* rec, const b3MeshData* mesh );
uint32_t b3RecInternHeightField( b3Recording* rec, const b3HeightFieldData* hf );
uint32_t b3RecInternCompound( b3Recording* rec, const b3CompoundData* compound );
uint64_t b3Hash64Blob( const uint8_t* bytes, int n );
void b3StartRecordingIntoBuffer( b3World* world, b3Recording* recording );
void b3StopRecordingInternal( b3World* world );
void b3RecAccumulateBounds( b3Recording* rec, b3AABB bounds );
uint64_t b3HashWorldState( b3World* world );