Skip to content

Commit

Permalink
fix for skipped shape in ray cast callback (returning -1)
Browse files Browse the repository at this point in the history
  • Loading branch information
erincatto committed Dec 12, 2024
1 parent 2c939c2 commit bcc834b
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 8 deletions.
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ if(PROJECT_IS_TOP_LEVEL)
if(BOX2D_UNIT_TESTS OR BOX2D_SAMPLES OR BOX2D_BENCHMARKS)
SET(ENKITS_BUILD_EXAMPLES OFF CACHE BOOL "Build enkiTS examples")

# Emscripten pthread support for enkiTS
if(EMSCRIPTEN)
set(EMSCRIPTEN_PTHREADS_COMPILER_FLAGS "-pthread -s USE_PTHREADS=1")
set(EMSCRIPTEN_PTHREADS_LINKER_FLAGS "${EMSCRIPTEN_PTHREADS_COMPILER_FLAGS} -s ALLOW_MEMORY_GROWTH")
string(APPEND CMAKE_C_FLAGS " ${EMSCRIPTEN_PTHREADS_COMPILER_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS " ${EMSCRIPTEN_PTHREADS_COMPILER_FLAGS}")
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${EMSCRIPTEN_PTHREADS_LINKER_FLAGS}")
endif()

# Used in tests and samples
FetchContent_Declare(
enkits
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ Please file an issue or start a chat on discord.
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)
Support development of Box2D through [Github Sponsors](https://github.com/sponsors/erincatto).

Please consider starring this repository and subscribing to my [YouTube channel](https://www.youtube.com/@erin_catto).

## Ports, wrappers, and bindings
- https://github.com/EnokViking/Box2DBeef
Expand Down
21 changes: 18 additions & 3 deletions samples/sample_collision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,21 @@ class RayCastWorld : public Sample
bodyDef.position = { x, y };
bodyDef.rotation = b2MakeRot( RandomFloatRange( -b2_pi, b2_pi ) );

int mod = m_bodyIndex % 3;
if (mod == 0)
{
bodyDef.type = b2_staticBody;
}
else if (mod == 1)
{
bodyDef.type = b2_kinematicBody;
}
else if (mod == 2)
{
bodyDef.type = b2_dynamicBody;
bodyDef.gravityScale = 0.0f;
}

m_bodyIds[m_bodyIndex] = b2CreateBody( m_worldId, &bodyDef );

b2ShapeDef shapeDef = b2DefaultShapeDef();
Expand Down Expand Up @@ -1816,9 +1831,9 @@ class RayCastWorld : public Sample
}

int m_bodyIndex;
b2BodyId m_bodyIds[e_maxCount];
ShapeUserData m_userData[e_maxCount];
b2Polygon m_polygons[4];
b2BodyId m_bodyIds[e_maxCount] = {};
ShapeUserData m_userData[e_maxCount] = {};
b2Polygon m_polygons[4] = {};
b2Capsule m_capsule;
b2Circle m_circle;
b2Segment m_segment;
Expand Down
2 changes: 1 addition & 1 deletion samples/sample_continuous.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ class Drop : public Sample
float h = 0.05f;
for ( int j = 0; j <= count; ++j )
{
b2Polygon box = b2MakeOffsetBox( w, h, { x, 0.0f }, b2Rot_identity );
b2Polygon box = b2MakeOffsetBox( 0.5f * w, h, { x, 0.0f }, b2Rot_identity );
b2CreatePolygonShape( groundId, &shapeDef, &box );
x += w;
}
Expand Down
15 changes: 15 additions & 0 deletions shared/human.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,21 @@ void DestroyHuman( Human* human )
human->isSpawned = false;
}

void Human_SetVelocity( Human* human, b2Vec2 velocity )
{
for ( int i = 0; i < boneId_count; ++i )
{
b2BodyId bodyId = human->bones[i].bodyId;

if ( B2_IS_NULL( bodyId ) )
{
continue;
}

b2Body_SetLinearVelocity( bodyId, velocity );
}
}

void Human_ApplyRandomAngularImpulse( Human* human, float magnitude )
{
assert( human->isSpawned == true );
Expand Down
1 change: 1 addition & 0 deletions shared/human.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ void CreateHuman( Human* human, b2WorldId worldId, b2Vec2 position, float scale,

void DestroyHuman( Human* human );

void Human_SetVelocity( Human* human, b2Vec2 velocity );
void Human_ApplyRandomAngularImpulse( Human* human, float magnitude );
void Human_SetJointFrictionTorque( Human* human, float torque );
void Human_SetJointSpringHertz( Human* human, float hertz );
Expand Down
2 changes: 2 additions & 0 deletions src/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
// - cannot debug
// - breaks code navigation

// todo_erin consider code-gen: https://github.com/IbrahimHindawi/haikal

// Array declaration that doesn't need the type T to be defined
#define B2_ARRAY_DECLARE( T, PREFIX ) \
typedef struct \
Expand Down
4 changes: 3 additions & 1 deletion src/dynamic_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1241,13 +1241,15 @@ b2TreeStats b2DynamicTree_RayCast( const b2DynamicTree* tree, const b2RayCastInp
float value = callback( &subInput, nodeId, node->userData, context );
result.leafVisits += 1;

// The user may return -1 to indicate this shape should be skipped

if ( value == 0.0f )
{
// The client has terminated the ray cast.
return result;
}

if ( 0.0f < value && value < maxFraction )
if ( 0.0f < value && value <= maxFraction )
{
// Update segment bounding box.
maxFraction = value;
Expand Down
111 changes: 110 additions & 1 deletion src/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,123 @@ void b2Yield()
SwitchToThread();
}

#elif defined( __linux__ ) || defined( __APPLE__ ) || defined( __EMSCRIPTEN__ )
#elif defined( __linux__ ) || defined( __EMSCRIPTEN__ )

#include <sched.h>
#include <sys/time.h>
#include <time.h>

b2Timer b2CreateTimer( void )
{
// todo_erin

//struct timespec ts;
//clock_gettime( CLOCK_MONOTONIC_RAW, &ts );

//struct timespec res;
//clock_getres( CLOCK_MONOTONIC, &res );

b2Timer timer;
struct timeval t;
gettimeofday( &t, 0 );
timer.start_sec = t.tv_sec;
timer.start_usec = t.tv_usec;
return timer;
}

float b2GetMilliseconds( const b2Timer* timer )
{
struct timeval t;
gettimeofday( &t, 0 );
time_t start_sec = timer->start_sec;
suseconds_t start_usec = (suseconds_t)timer->start_usec;

// http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
if ( t.tv_usec < start_usec )
{
int nsec = ( start_usec - t.tv_usec ) / 1000000 + 1;
start_usec -= 1000000 * nsec;
start_sec += nsec;
}

if ( t.tv_usec - start_usec > 1000000 )
{
int nsec = ( t.tv_usec - start_usec ) / 1000000;
start_usec += 1000000 * nsec;
start_sec -= nsec;
}
return 1000.0f * ( t.tv_sec - start_sec ) + 0.001f * ( t.tv_usec - start_usec );
}

float b2GetMillisecondsAndReset( b2Timer* timer )
{
struct timeval t;
gettimeofday( &t, 0 );
time_t start_sec = timer->start_sec;
suseconds_t start_usec = (suseconds_t)timer->start_usec;

// http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
if ( t.tv_usec < start_usec )
{
int nsec = ( start_usec - t.tv_usec ) / 1000000 + 1;
start_usec -= 1000000 * nsec;
start_sec += nsec;
}

if ( t.tv_usec - start_usec > 1000000 )
{
int nsec = ( t.tv_usec - start_usec ) / 1000000;
start_usec += 1000000 * nsec;
start_sec -= nsec;
}

timer->start_sec = t.tv_sec;
timer->start_usec = t.tv_usec;

return 1000.0f * ( t.tv_sec - start_sec ) + 0.001f * ( t.tv_usec - start_usec );
}

void b2SleepMilliseconds( int milliseconds )
{
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = ( milliseconds % 1000 ) * 1000000;
nanosleep( &ts, NULL );
}

void b2Yield()
{
sched_yield();
}

#elif defined( __APPLE__ )

#include <sched.h>
#include <sys/time.h>
#include <time.h>

//#include <mach/mach_time.h>

b2Timer b2CreateTimer( void )
{
// todo_erin
//#include <mach/mach_time.h>

//// Get current time
//uint64_t start = mach_absolute_time();

//// To convert to nanoseconds, you'll need to use mach_timebase_info
//mach_timebase_info_data_t timebase;
//mach_timebase_info( &timebase );

//// Convert to nanoseconds
//uint64_t elapsed_ns = ( start * timebase.numer ) / timebase.denom;

//mach_timebase_info_data_t timebase;
//mach_timebase_info( &timebase );
//// timebase.numer and timebase.denom can be used to calculate frequency
//// Specifically, frequency = 1e9 / (timebase.numer / timebase.denom)

b2Timer timer;
struct timeval t;
gettimeofday( &t, 0 );
Expand Down
8 changes: 7 additions & 1 deletion src/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -2146,7 +2146,13 @@ static float RayCastCallback( const b2RayCastInput* input, int proxyId, int shap
{
b2ShapeId id = { shapeId + 1, world->worldId, shape->revision };
float fraction = worldContext->fcn( id, output.point, output.normal, output.fraction, worldContext->userContext );
worldContext->fraction = fraction;

// The user may return -1 to skip this shape
if (0.0f <= fraction && fraction <= 1.0f)
{
worldContext->fraction = fraction;
}

return fraction;
}

Expand Down

0 comments on commit bcc834b

Please sign in to comment.