Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 194bf41

Browse files
authoredNov 5, 2024··
Add support for shape serialization (#1)
- Add StreamOut and StreamIn interfaces - Add implementations of StreamOut / StreamIn that use AnyWriter / AnyReader - Add Shape::saveBinaryState and Shape::restoreFromBinaryState - Add Shape::saveWithChildren and Shape::restoreWithChildren - Add convenience versions saveWithChildrenAll and restoreWithChildrenAll
1 parent 0943dc6 commit 194bf41

File tree

5 files changed

+805
-3
lines changed

5 files changed

+805
-3
lines changed
 

‎libs/JoltC/JoltPhysicsC.cpp

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ FN(toJph)(const JPC_Body *in) { assert(in); return reinterpret_cast<const JPH::B
6868
FN(toJpc)(JPH::Body *in) { assert(in); return reinterpret_cast<JPC_Body *>(in); }
6969
FN(toJph)(JPC_Body *in) { assert(in); return reinterpret_cast<JPH::Body *>(in); }
7070

71+
FN(toJph)(JPC_PhysicsMaterial *in) { return reinterpret_cast<JPH::PhysicsMaterial *>(in); }
7172
FN(toJph)(const JPC_PhysicsMaterial *in) { return reinterpret_cast<const JPH::PhysicsMaterial *>(in); }
73+
FN(toJpc)(JPH::PhysicsMaterial *in) { return reinterpret_cast<JPC_PhysicsMaterial *>(in); }
7274
FN(toJpc)(const JPH::PhysicsMaterial *in) { return reinterpret_cast<const JPC_PhysicsMaterial *>(in); }
7375

7476
FN(toJph)(const JPC_ShapeSettings *in) {
@@ -232,6 +234,36 @@ FN(toJph)(const JPC_ConvexHullShape *in) { assert(in); return reinterpret_cast<c
232234
FN(toJpc)(JPH::ConvexHullShape *in) { assert(in); return reinterpret_cast<JPC_ConvexHullShape *>(in); }
233235
FN(toJpc)(const JPH::ConvexHullShape *in) { assert(in); return reinterpret_cast<const JPC_ConvexHullShape *>(in); }
234236

237+
FN(toJph)(JPC_DecoratedShape *in) { assert(in); return reinterpret_cast<JPH::DecoratedShape *>(in); }
238+
FN(toJph)(const JPC_DecoratedShape *in) { assert(in); return reinterpret_cast<const JPH::DecoratedShape *>(in); }
239+
FN(toJpc)(JPH::DecoratedShape *in) { assert(in); return reinterpret_cast<JPC_DecoratedShape *>(in); }
240+
FN(toJpc)(const JPH::DecoratedShape *in) { assert(in); return reinterpret_cast<const JPC_DecoratedShape *>(in); }
241+
242+
FN(toJph)(JPC_RotatedTranslatedShape *in) { assert(in); return reinterpret_cast<JPH::RotatedTranslatedShape *>(in); }
243+
FN(toJph)(const JPC_RotatedTranslatedShape *in) { assert(in); return reinterpret_cast<const JPH::RotatedTranslatedShape *>(in); }
244+
FN(toJpc)(JPH::RotatedTranslatedShape *in) { assert(in); return reinterpret_cast<JPC_RotatedTranslatedShape *>(in); }
245+
FN(toJpc)(const JPH::RotatedTranslatedShape *in) { assert(in); return reinterpret_cast<const JPC_RotatedTranslatedShape *>(in); }
246+
247+
FN(toJph)(JPC_ShapeToIDMap *in) { assert(in); return reinterpret_cast<JPH::Shape::ShapeToIDMap *>(in); }
248+
FN(toJph)(const JPC_ShapeToIDMap *in) { assert(in); return reinterpret_cast<const JPH::Shape::ShapeToIDMap *>(in); }
249+
FN(toJpc)(JPH::Shape::ShapeToIDMap *in) { assert(in); return reinterpret_cast<JPC_ShapeToIDMap *>(in); }
250+
FN(toJpc)(const JPH::Shape::ShapeToIDMap *in) { assert(in); return reinterpret_cast<const JPC_ShapeToIDMap *>(in); }
251+
252+
FN(toJph)(JPC_MaterialToIDMap *in) { assert(in); return reinterpret_cast<JPH::Shape::MaterialToIDMap *>(in); }
253+
FN(toJph)(const JPC_MaterialToIDMap *in) { assert(in); return reinterpret_cast<const JPH::Shape::MaterialToIDMap *>(in); }
254+
FN(toJpc)(JPH::Shape::MaterialToIDMap *in) { assert(in); return reinterpret_cast<JPC_MaterialToIDMap *>(in); }
255+
FN(toJpc)(const JPH::Shape::MaterialToIDMap *in) { assert(in); return reinterpret_cast<const JPC_MaterialToIDMap *>(in); }
256+
257+
FN(toJph)(JPC_IDToShapeMap *in) { assert(in); return reinterpret_cast<JPH::Shape::IDToShapeMap *>(in); }
258+
FN(toJph)(const JPC_IDToShapeMap *in) { assert(in); return reinterpret_cast<const JPH::Shape::IDToShapeMap *>(in); }
259+
FN(toJpc)(JPH::Shape::IDToShapeMap *in) { assert(in); return reinterpret_cast<JPC_IDToShapeMap *>(in); }
260+
FN(toJpc)(const JPH::Shape::IDToShapeMap *in) { assert(in); return reinterpret_cast<const JPC_IDToShapeMap *>(in); }
261+
262+
FN(toJph)(JPC_IDToMaterialMap *in) { assert(in); return reinterpret_cast<JPH::Shape::IDToMaterialMap *>(in); }
263+
FN(toJph)(const JPC_IDToMaterialMap *in) { assert(in); return reinterpret_cast<const JPH::Shape::IDToMaterialMap *>(in); }
264+
FN(toJpc)(JPH::Shape::IDToMaterialMap *in) { assert(in); return reinterpret_cast<JPC_IDToMaterialMap *>(in); }
265+
FN(toJpc)(const JPH::Shape::IDToMaterialMap *in) { assert(in); return reinterpret_cast<const JPC_IDToMaterialMap *>(in); }
266+
235267
FN(toJph)(const JPC_ConstraintSettings *in) {
236268
ENSURE_TYPE(in, JPH::ConstraintSettings);
237269
return reinterpret_cast<const JPH::ConstraintSettings *>(in);
@@ -1936,6 +1968,168 @@ JPC_Shape_CastRay(const JPC_Shape *in_shape,
19361968
assert(in_shape && in_ray && in_id_creator && io_hit);
19371969
return toJph(in_shape)->CastRay(*toJph(in_ray), *toJph(in_id_creator), *toJph(io_hit));
19381970
}
1971+
1972+
JPC_API void
1973+
JPC_Shape_SaveBinaryState(const JPC_Shape *in_shape, void *in_stream_out)
1974+
{
1975+
assert(in_shape && in_stream_out);
1976+
return toJph(in_shape)->SaveBinaryState(*static_cast<JPH::StreamOut *>(in_stream_out));
1977+
}
1978+
1979+
JPC_API void
1980+
JPC_Shape_SaveWithChildren(const JPC_Shape *in_shape, void *in_stream_out, JPC_ShapeToIDMap *io_shape_map, JPC_MaterialToIDMap *io_material_map)
1981+
{
1982+
assert(in_shape && io_shape_map && io_material_map);
1983+
return toJph(in_shape)->SaveWithChildren(*static_cast<JPH::StreamOut *>(in_stream_out), *toJph(io_shape_map), *toJph(io_material_map));
1984+
}
1985+
1986+
JPC_API void
1987+
JPC_Shape_SaveWithChildren_All(const JPC_Shape *in_shape, void *in_stream_out)
1988+
{
1989+
assert(in_shape);
1990+
JPH::Shape::ShapeToIDMap tmp_shape_map;
1991+
JPH::Shape::MaterialToIDMap tmp_material_map;
1992+
return toJph(in_shape)->SaveWithChildren(*static_cast<JPH::StreamOut *>(in_stream_out), tmp_shape_map, tmp_material_map);
1993+
}
1994+
1995+
JPC_API JPC_Shape*
1996+
JPC_Shape_sRestoreFromBinaryState(void *in_stream_in)
1997+
{
1998+
assert(in_stream_in);
1999+
const JPH::Result result = JPH::Shape::sRestoreFromBinaryState(*static_cast<JPH::StreamIn *>(in_stream_in));
2000+
if (result.HasError()) return nullptr;
2001+
JPH::Shape *shape = const_cast<JPH::Shape*>(result.Get().GetPtr());
2002+
shape->AddRef();
2003+
return toJpc(shape);
2004+
}
2005+
2006+
JPC_API JPC_Shape*
2007+
JPC_Shape_sRestoreWithChildren(void *in_stream_in, JPC_IDToShapeMap *io_shape_map, JPC_IDToMaterialMap *io_material_map)
2008+
{
2009+
assert(in_stream_in && io_shape_map && io_material_map);
2010+
const JPH::Result result = JPH::Shape::sRestoreWithChildren(*static_cast<JPH::StreamIn *>(in_stream_in),
2011+
*toJph(io_shape_map),
2012+
*toJph(io_material_map));
2013+
2014+
if (result.HasError()) return nullptr;
2015+
JPH::Shape *shape = const_cast<JPH::Shape*>(result.Get().GetPtr());
2016+
shape->AddRef();
2017+
return toJpc(shape);
2018+
}
2019+
2020+
JPC_API JPC_Shape*
2021+
JPC_Shape_sRestoreWithChildren_All(void *in_stream_in)
2022+
{
2023+
assert(in_stream_in);
2024+
JPH::Shape::IDToShapeMap tmp_shape_map;
2025+
JPH::Shape::IDToMaterialMap tmp_material_map;
2026+
const JPH::Result result = JPH::Shape::sRestoreWithChildren(*static_cast<JPH::StreamIn *>(in_stream_in),
2027+
tmp_shape_map,
2028+
tmp_material_map);
2029+
2030+
if (result.HasError()) return nullptr;
2031+
JPH::Shape *shape = const_cast<JPH::Shape*>(result.Get().GetPtr());
2032+
shape->AddRef();
2033+
return toJpc(shape);
2034+
}
2035+
//--------------------------------------------------------------------------------------------------
2036+
//
2037+
// JPC_Shape Serialization Structures
2038+
//
2039+
//--------------------------------------------------------------------------------------------------
2040+
JPC_API JPC_ShapeToIDMap *
2041+
JPC_ShapeToIDMap_Create()
2042+
{
2043+
return toJpc(new JPH::Shape::ShapeToIDMap());
2044+
}
2045+
2046+
JPC_API void
2047+
JPC_ShapeToIDMap_Add(JPC_ShapeToIDMap *in_map, const JPC_Shape *const *in_shapes, uint32_t in_num_shapes)
2048+
{
2049+
assert(in_map);
2050+
JPH::Shape::ShapeToIDMap& map = *toJph(in_map);
2051+
for (uint32_t i = 0; i < in_num_shapes; ++i)
2052+
{
2053+
uint32_t shape_id = (uint32_t)map.size();
2054+
map[toJph(in_shapes[i])] = shape_id;
2055+
}
2056+
}
2057+
2058+
JPC_API void
2059+
JPC_ShapeToIDMap_Destroy(JPC_ShapeToIDMap *in_map)
2060+
{
2061+
JPH::Free(toJph(in_map));
2062+
}
2063+
2064+
JPC_API JPC_MaterialToIDMap *
2065+
JPC_MaterialToIDMap_Create()
2066+
{
2067+
return toJpc(new JPH::Shape::MaterialToIDMap());
2068+
}
2069+
2070+
JPC_API void
2071+
JPC_MaterialToIDMap_Add(JPC_MaterialToIDMap *in_map, const JPC_PhysicsMaterial *const *in_materials, uint32_t in_num_materials)
2072+
{
2073+
assert(in_map);
2074+
JPH::Shape::MaterialToIDMap& map = *toJph(in_map);
2075+
for (uint32_t i = 0; i < in_num_materials; ++i)
2076+
{
2077+
uint32_t material_id = (uint32_t)map.size();
2078+
map[toJph(in_materials[i])] = material_id;
2079+
}
2080+
}
2081+
2082+
JPC_API void
2083+
JPC_MaterialToIDMap_Destroy(JPC_MaterialToIDMap *in_map)
2084+
{
2085+
JPH::Free(toJph(in_map));
2086+
}
2087+
2088+
JPC_API JPC_IDToShapeMap*
2089+
JPC_IDToShapeMap_Create()
2090+
{
2091+
return toJpc(new JPH::Shape::IDToShapeMap());
2092+
}
2093+
2094+
JPC_API void
2095+
JPC_IDToShapeMap_Add(JPC_IDToShapeMap *in_map, JPC_Shape *const *in_shapes, uint32_t in_num_shapes)
2096+
{
2097+
assert(in_map);
2098+
JPH::Shape::IDToShapeMap& map = *toJph(in_map);
2099+
for (uint32_t i = 0; i < in_num_shapes; ++i)
2100+
{
2101+
map.push_back(toJph(in_shapes[i]));
2102+
}
2103+
}
2104+
2105+
JPC_API void
2106+
JPC_IDToShapeMap_Destroy(JPC_ShapeToIDMap *in_map)
2107+
{
2108+
JPH::Free(toJph(in_map));
2109+
}
2110+
2111+
JPC_API JPC_IDToMaterialMap*
2112+
JPC_IDToMaterialMap_Create()
2113+
{
2114+
return toJpc(new JPH::Shape::IDToMaterialMap());
2115+
}
2116+
2117+
JPC_API void
2118+
JPC_IDToMaterialMap_Add(JPC_IDToMaterialMap *in_map, JPC_PhysicsMaterial *const *in_materials, uint32_t in_num_materials)
2119+
{
2120+
assert(in_map);
2121+
JPH::Shape::IDToMaterialMap& map = *toJph(in_map);
2122+
for (uint32_t i = 0; i < in_num_materials; ++i)
2123+
{
2124+
map.push_back(toJph(in_materials[i]));
2125+
}
2126+
}
2127+
2128+
JPC_API void
2129+
JPC_IDToMaterialMap_Destroy(JPC_ShapeToIDMap *in_map)
2130+
{
2131+
JPH::Free(toJph(in_map));
2132+
}
19392133
//--------------------------------------------------------------------------------------------------
19402134
//
19412135
// JPC_BoxShape
@@ -1985,6 +2179,32 @@ JPC_ConvexHullShape_GetFaceVertices(const JPC_ConvexHullShape *in_shape,
19852179
}
19862180
//--------------------------------------------------------------------------------------------------
19872181
//
2182+
// JPC_DecoratedShape
2183+
//
2184+
//--------------------------------------------------------------------------------------------------
2185+
JPC_API const JPC_Shape*
2186+
JPC_DecoratedShape_GetInnerShape(const JPC_DecoratedShape *in_shape)
2187+
{
2188+
return toJpc(toJph(in_shape)->GetInnerShape());
2189+
}
2190+
//--------------------------------------------------------------------------------------------------
2191+
//
2192+
// JPC_RotatedTranslatedShape
2193+
//
2194+
//--------------------------------------------------------------------------------------------------
2195+
JPC_API void
2196+
JPC_RotatedTranslatedShape_GetRotation(const JPC_RotatedTranslatedShape *in_shape, float out_rotation[4])
2197+
{
2198+
storeVec4(out_rotation, toJph(in_shape)->GetRotation().GetXYZW());
2199+
}
2200+
//--------------------------------------------------------------------------------------------------
2201+
JPC_API void
2202+
JPC_RotatedTranslatedShape_GetPosition(const JPC_RotatedTranslatedShape *in_shape, float out_position[3])
2203+
{
2204+
storeVec3(out_position, toJph(in_shape)->GetPosition());
2205+
}
2206+
//--------------------------------------------------------------------------------------------------
2207+
//
19882208
// JPC_ConstraintSettings
19892209
//
19902210
//--------------------------------------------------------------------------------------------------

‎libs/JoltC/JoltPhysicsC.h

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,16 @@ typedef struct JPC_FixedConstraintSettings JPC_FixedConstraintSettings;
345345
typedef struct JPC_PhysicsSystem JPC_PhysicsSystem;
346346
typedef struct JPC_SharedMutex JPC_SharedMutex;
347347

348-
typedef struct JPC_Shape JPC_Shape;
349-
typedef struct JPC_BoxShape JPC_BoxShape;
350-
typedef struct JPC_ConvexHullShape JPC_ConvexHullShape;
348+
typedef struct JPC_Shape JPC_Shape;
349+
typedef struct JPC_BoxShape JPC_BoxShape;
350+
typedef struct JPC_ConvexHullShape JPC_ConvexHullShape;
351+
typedef struct JPC_DecoratedShape JPC_DecoratedShape;
352+
typedef struct JPC_RotatedTranslatedShape JPC_RotatedTranslatedShape;
353+
354+
typedef struct JPC_ShapeToIDMap JPC_ShapeToIDMap;
355+
typedef struct JPC_MaterialToIDMap JPC_MaterialToIDMap;
356+
typedef struct JPC_IDToShapeMap JPC_IDToShapeMap;
357+
typedef struct JPC_IDToMaterialMap JPC_IDToMaterialMap;
351358

352359
typedef struct JPC_Constraint JPC_Constraint;
353360
typedef struct JPC_PhysicsMaterial JPC_PhysicsMaterial;
@@ -751,6 +758,36 @@ typedef bool (*JPC_BodyDrawFilterFunc)(const JPC_Body *);
751758
// Interfaces (virtual tables)
752759
//
753760
//--------------------------------------------------------------------------------------------------
761+
typedef struct JPC_StreamOutVTable
762+
{
763+
_JPC_VTABLE_HEADER;
764+
765+
// Required, *cannot* be NULL.
766+
void
767+
(*WriteBytes)(void *in_self, const void *in_data, size_t in_num_bytes);
768+
769+
// Required, *cannot* be NULL.
770+
bool
771+
(*IsFailed)(const void *in_self);
772+
} JPC_StreamOutVTable;
773+
774+
typedef struct JPC_StreamInVTable
775+
{
776+
_JPC_VTABLE_HEADER;
777+
778+
// Required, *cannot* be NULL.
779+
void
780+
(*ReadBytes)(void *in_self, void *out_data, size_t in_num_bytes);
781+
782+
// Required, *cannot* be NULL.
783+
bool
784+
(*IsEOF)(const void *in_self);
785+
786+
// Required, *cannot* be NULL.
787+
bool
788+
(*IsFailed)(const void *in_self);
789+
} JPC_StreamInVTable;
790+
754791
typedef struct JPC_BroadPhaseLayerInterfaceVTable
755792
{
756793
_JPC_VTABLE_HEADER;
@@ -1738,6 +1775,69 @@ JPC_Shape_CastRay(const JPC_Shape *in_shape,
17381775
const JPC_RayCast *in_ray,
17391776
const JPC_SubShapeIDCreator *in_id_creator,
17401777
JPC_RayCastResult *io_hit); // *Must* be default initialized (see JPC_RayCastResult)
1778+
1779+
// `in_stream_out` *must* point to a struct that has JPC_StreamOutVTable as its first member
1780+
JPC_API void
1781+
JPC_Shape_SaveBinaryState(const JPC_Shape *in_shape, void *in_stream_out);
1782+
1783+
JPC_API void
1784+
JPC_Shape_SaveWithChildren(const JPC_Shape *in_shape, void *in_stream_out, JPC_ShapeToIDMap *io_shape_map, JPC_MaterialToIDMap *io_material_map);
1785+
1786+
// This version uses temporary maps and thus will save all shape IDs.
1787+
JPC_API void
1788+
JPC_Shape_SaveWithChildren_All(const JPC_Shape *in_shape, void *in_stream_out);
1789+
1790+
// `in_stream_in` *must *point to a struct that has JPC_StreamInVTable as its first member
1791+
JPC_API JPC_Shape*
1792+
JPC_Shape_sRestoreFromBinaryState(void *in_stream_in);
1793+
1794+
// `in_stream_in` *must *point to a struct that has JPC_StreamInVTable as its first member
1795+
JPC_API JPC_Shape*
1796+
JPC_Shape_sRestoreWithChildren(void *in_stream_in, JPC_IDToShapeMap *io_shape_map, JPC_IDToMaterialMap *io_material_map);
1797+
1798+
// This version uses temporary reverse mappings and thus will restore all shape IDs.
1799+
JPC_API JPC_Shape*
1800+
JPC_Shape_sRestoreWithChildren_All(void *in_stream_in);
1801+
//--------------------------------------------------------------------------------------------------
1802+
//
1803+
// JPC_Shape Serialization Structures
1804+
//
1805+
//--------------------------------------------------------------------------------------------------
1806+
JPC_API JPC_ShapeToIDMap*
1807+
JPC_ShapeToIDMap_Create();
1808+
1809+
JPC_API void
1810+
JPC_ShapeToIDMap_Add(JPC_ShapeToIDMap *in_map, const JPC_Shape *const *in_shapes, uint32_t in_num_shapes);
1811+
1812+
JPC_API void
1813+
JPC_ShapeToIDMap_Destroy(JPC_ShapeToIDMap *in_map);
1814+
1815+
JPC_API JPC_MaterialToIDMap*
1816+
JPC_MaterialToIDMap_Create();
1817+
1818+
JPC_API void
1819+
JPC_MaterialToIDMap_Add(JPC_MaterialToIDMap *in_map, const JPC_PhysicsMaterial *const *in_materials, uint32_t in_num_materials);
1820+
1821+
JPC_API void
1822+
JPC_MaterialToIDMap_Destroy(JPC_MaterialToIDMap *in_map);
1823+
1824+
JPC_API JPC_IDToShapeMap*
1825+
JPC_IDToShapeMap_Create();
1826+
1827+
JPC_API void
1828+
JPC_IDToShapeMap_Add(JPC_IDToShapeMap *in_map, JPC_Shape *const *in_shapes, uint32_t in_num_shapes);
1829+
1830+
JPC_API void
1831+
JPC_IDToShapeMap_Destroy(JPC_ShapeToIDMap *in_map);
1832+
1833+
JPC_API JPC_IDToMaterialMap*
1834+
JPC_IDToMaterialMap_Create();
1835+
1836+
JPC_API void
1837+
JPC_IDToMaterialMap_Add(JPC_IDToMaterialMap *in_map, JPC_PhysicsMaterial *const *in_materials, uint32_t in_num_materials);
1838+
1839+
JPC_API void
1840+
JPC_IDToMaterialMap_Destroy(JPC_IDToMaterialMap *in_map);
17411841
//--------------------------------------------------------------------------------------------------
17421842
//
17431843
// JPC_BoxShape
@@ -1770,6 +1870,23 @@ JPC_ConvexHullShape_GetFaceVertices(const JPC_ConvexHullShape *in_shape,
17701870
uint32_t *out_vertices);
17711871
//--------------------------------------------------------------------------------------------------
17721872
//
1873+
// JPC_DecoratedShape
1874+
//
1875+
//--------------------------------------------------------------------------------------------------
1876+
JPC_API const JPC_Shape*
1877+
JPC_DecoratedShape_GetInnerShape(const JPC_DecoratedShape *in_shape);
1878+
//--------------------------------------------------------------------------------------------------
1879+
//
1880+
// JPC_RotatedTranslatedShape
1881+
//
1882+
//--------------------------------------------------------------------------------------------------
1883+
JPC_API void
1884+
JPC_RotatedTranslatedShape_GetRotation(const JPC_RotatedTranslatedShape *in_shape, float out_rotation[4]);
1885+
1886+
JPC_API void
1887+
JPC_RotatedTranslatedShape_GetPosition(const JPC_RotatedTranslatedShape *in_shape, float out_position[3]);
1888+
//--------------------------------------------------------------------------------------------------
1889+
//
17731890
// JPC_ConstraintSettings
17741891
//
17751892
//--------------------------------------------------------------------------------------------------

‎libs/JoltC/JoltPhysicsC_Extensions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ ENSURE_SIZE_ALIGN(JPH::RMat44, JPC_RMatrix)
163163

164164
ENSURE_SIZE_ALIGN(JPH::Shape::SupportingFace, JPC_Shape_SupportingFace)
165165
ENSURE_SIZE_ALIGN(JPH::CharacterVirtual::ExtendedUpdateSettings, JPC_CharacterVirtual_ExtendedUpdateSettings)
166+
ENSURE_SIZE_ALIGN(JPH::RMat44, JPC_RMatrix)
166167

167168
//--------------------------------------------------------------------------------------------------
168169
#define ENSURE_ENUM_EQ(c_const, cpp_enum) static_assert(c_const == static_cast<int>(cpp_enum))

‎libs/JoltC/JoltPhysicsC_Tests.c

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <assert.h>
44
#include <stddef.h>
55
#include <stdio.h>
6+
#include <string.h>
67

78
//#define PRINT_OUTPUT
89

@@ -857,3 +858,279 @@ JoltCTest_HelloWorld(void)
857858
return 1;
858859
}
859860
//--------------------------------------------------------------------------------------------------
861+
// Serialization
862+
//--------------------------------------------------------------------------------------------------
863+
typedef struct BufferStreamOutImpl
864+
{
865+
const JPC_StreamOutVTable *vtable;
866+
void* buffer;
867+
size_t len;
868+
bool failed;
869+
} BufferStreamOutImpl;
870+
871+
static void
872+
BufferedStreamOutImpl_WriteBytes(void *in_self, const void *in_data, size_t in_num_bytes)
873+
{
874+
BufferStreamOutImpl* self = (BufferStreamOutImpl*)in_self;
875+
if (self->failed)
876+
{
877+
return;
878+
}
879+
880+
#ifdef PRINT_OUTPUT
881+
fprintf(stderr, "BufferedStreamOutImpl_WriteBytes(%llx, %llu)\n", (size_t)in_data, in_num_bytes);
882+
#endif
883+
884+
const size_t start = self->len;
885+
self->len += in_num_bytes;
886+
887+
void* new_buffer = realloc(self->buffer, self->len);
888+
if (!new_buffer)
889+
{
890+
free(self->buffer);
891+
self->failed = true;
892+
}
893+
894+
self->buffer = new_buffer;
895+
memcpy(self->buffer + start, in_data, in_num_bytes);
896+
}
897+
898+
static bool
899+
BufferedStreamOutImpl_IsFailed(const void *in_self)
900+
{
901+
const BufferStreamOutImpl* self = (BufferStreamOutImpl*)in_self;
902+
#ifdef PRINT_OUTPUT
903+
fprintf(stderr, "BufferedStreamOutImpl_IsFailed()\n");
904+
#endif
905+
return self->failed;
906+
}
907+
908+
static BufferStreamOutImpl
909+
BufferedStreamOutImpl_Init(void)
910+
{
911+
static const JPC_StreamOutVTable vtable =
912+
{
913+
.WriteBytes = BufferedStreamOutImpl_WriteBytes,
914+
.IsFailed = BufferedStreamOutImpl_IsFailed,
915+
};
916+
BufferStreamOutImpl impl =
917+
{
918+
.vtable = &vtable,
919+
.buffer = NULL,
920+
.len = 0,
921+
.failed = false,
922+
};
923+
return impl;
924+
}
925+
926+
typedef struct BufferStreamInImpl
927+
{
928+
const JPC_StreamInVTable *vtable;
929+
void* buffer;
930+
size_t len;
931+
size_t next;
932+
bool eof;
933+
} BufferStreamInImpl;
934+
935+
static void
936+
BufferedStreamInImpl_ReadBytes(void *in_self, void *out_data, size_t in_num_bytes)
937+
{
938+
BufferStreamInImpl* self = (BufferStreamInImpl*)in_self;
939+
#ifdef PRINT_OUTPUT
940+
fprintf(stderr, "BufferedStreamInImpl_ReadBytes(%llx, %llu)\n", (size_t)out_data, in_num_bytes);
941+
#endif
942+
943+
const size_t remaining = self->len - self->next;
944+
size_t copy_len = in_num_bytes;
945+
if (copy_len > remaining)
946+
{
947+
self->eof = true;
948+
copy_len = remaining;
949+
}
950+
951+
if (copy_len > 0)
952+
{
953+
memcpy(out_data, self->buffer + self->next, copy_len);
954+
self->next += copy_len;
955+
}
956+
}
957+
958+
static bool
959+
BufferedStreamInImpl_IsEOF(const void *in_self)
960+
{
961+
BufferStreamInImpl* self = (BufferStreamInImpl*)in_self;
962+
#ifdef PRINT_OUTPUT
963+
fprintf(stderr, "BufferedStreamInImpl_IsEOF()\n");
964+
#endif
965+
return self->eof;
966+
}
967+
968+
static bool
969+
BufferedStreamInImpl_IsFailed(const void *in_self)
970+
{
971+
#ifdef PRINT_OUTPUT
972+
fprintf(stderr, "BufferedStreamInImpl_IsFailed()\n");
973+
#endif
974+
return false;
975+
}
976+
977+
static BufferStreamInImpl
978+
BufferedStreamInImpl_Init(void)
979+
{
980+
static const JPC_StreamInVTable vtable =
981+
{
982+
.ReadBytes = BufferedStreamInImpl_ReadBytes,
983+
.IsEOF = BufferedStreamInImpl_IsEOF,
984+
.IsFailed = BufferedStreamInImpl_IsFailed,
985+
};
986+
BufferStreamInImpl impl =
987+
{
988+
.vtable = &vtable,
989+
.buffer = NULL,
990+
.len = 0,
991+
.next = 0,
992+
};
993+
return impl;
994+
}
995+
996+
uint32_t
997+
JoltCTest_Serialization(void)
998+
{
999+
JPC_RegisterDefaultAllocator();
1000+
JPC_CreateFactory();
1001+
JPC_RegisterTypes();
1002+
1003+
JPC_TempAllocator *temp_allocator = JPC_TempAllocator_Create(10 * 1024 * 1024);
1004+
const float half_extent[3] = { 1.f, 2.f, 3.f };
1005+
1006+
// Single shape
1007+
{
1008+
JPC_BoxShapeSettings* box_shape_settings = JPC_BoxShapeSettings_Create(half_extent);
1009+
JPC_Shape* box_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings*)box_shape_settings);
1010+
1011+
BufferStreamOutImpl stream_out = BufferedStreamOutImpl_Init();
1012+
JPC_Shape_SaveBinaryState(box_shape, &stream_out);
1013+
assert(!stream_out.failed);
1014+
1015+
BufferStreamInImpl stream_in = BufferedStreamInImpl_Init();
1016+
stream_in.buffer = stream_out.buffer;
1017+
stream_in.len = stream_out.len;
1018+
1019+
JPC_Shape* box_restored = JPC_Shape_sRestoreFromBinaryState(&stream_in);
1020+
assert(JPC_SHAPE_SUB_TYPE_BOX == JPC_Shape_GetSubType(box_restored));
1021+
1022+
float half_extent_restored[3] = { 0, 0, 0 };
1023+
JPC_BoxShape_GetHalfExtent((JPC_BoxShape*)box_restored, half_extent_restored);
1024+
assert(memcmp(half_extent, half_extent_restored, 3 * sizeof(float)) == 0);
1025+
1026+
free(stream_in.buffer);
1027+
}
1028+
1029+
// Compound shapes (save all)
1030+
{
1031+
const float translation[3] = { 4.f, 5.f, 6.f };
1032+
BufferStreamOutImpl stream_out = BufferedStreamOutImpl_Init();
1033+
1034+
{
1035+
JPC_BoxShapeSettings* box_shape_settings = JPC_BoxShapeSettings_Create(half_extent);
1036+
JPC_DecoratedShapeSettings* decorated_shape_settings = JPC_RotatedTranslatedShapeSettings_Create(
1037+
(JPC_ShapeSettings*)box_shape_settings,
1038+
(float[4]) { 0, 0, 0, 1 },
1039+
translation);
1040+
1041+
JPC_Shape* shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings*)decorated_shape_settings);
1042+
JPC_Shape_SaveWithChildren_All(shape, &stream_out);
1043+
assert(!stream_out.failed);
1044+
}
1045+
1046+
BufferStreamInImpl stream_in = BufferedStreamInImpl_Init();
1047+
stream_in.buffer = stream_out.buffer;
1048+
stream_in.len = stream_out.len;
1049+
1050+
{
1051+
JPC_Shape* shape = JPC_Shape_sRestoreWithChildren_All(&stream_in);
1052+
assert(JPC_SHAPE_SUB_TYPE_ROTATED_TRANSLATED == JPC_Shape_GetSubType(shape));
1053+
1054+
JPC_DecoratedShape* decorated = (JPC_DecoratedShape*)shape;
1055+
const JPC_Shape* inner = JPC_DecoratedShape_GetInnerShape(decorated);
1056+
assert(JPC_SHAPE_SUB_TYPE_BOX == JPC_Shape_GetSubType(inner));
1057+
1058+
float half_extent_restored[3] = { 0, 0, 0 };
1059+
JPC_BoxShape_GetHalfExtent((const JPC_BoxShape*)inner, half_extent_restored);
1060+
assert(memcmp(half_extent, half_extent_restored, 3 * sizeof(float)) == 0);
1061+
1062+
float translation_restored[3];
1063+
JPC_RotatedTranslatedShape_GetPosition((JPC_RotatedTranslatedShape*)shape, translation_restored);
1064+
assert(memcmp(translation, translation_restored, 3 * sizeof(float)) == 0);
1065+
}
1066+
1067+
free(stream_in.buffer);
1068+
}
1069+
1070+
// Compound shapes
1071+
{
1072+
BufferStreamOutImpl stream_out = BufferedStreamOutImpl_Init();
1073+
const float translation[3] = { 7.f, 8.f, 9.f };
1074+
1075+
{
1076+
JPC_BoxShapeSettings* box_shape_settings = JPC_BoxShapeSettings_Create(half_extent);
1077+
JPC_DecoratedShapeSettings* decorated_shape_settings = JPC_RotatedTranslatedShapeSettings_Create(
1078+
(JPC_ShapeSettings*)box_shape_settings,
1079+
(float[4]) { 0, 0, 0, 1 },
1080+
translation);
1081+
1082+
JPC_Shape* shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings*)decorated_shape_settings);
1083+
const JPC_Shape* inner_shape = JPC_DecoratedShape_GetInnerShape((JPC_DecoratedShape*)shape);
1084+
1085+
JPC_ShapeToIDMap* shape_to_id = JPC_ShapeToIDMap_Create();
1086+
JPC_MaterialToIDMap* material_to_id = JPC_MaterialToIDMap_Create();
1087+
JPC_ShapeToIDMap_Add(shape_to_id, &inner_shape, 1);
1088+
JPC_Shape_SaveWithChildren(shape, &stream_out, shape_to_id, material_to_id);
1089+
assert(!stream_out.failed);
1090+
JPC_ShapeToIDMap_Destroy(shape_to_id);
1091+
JPC_MaterialToIDMap_Destroy(material_to_id);
1092+
}
1093+
1094+
BufferStreamInImpl stream_in = BufferedStreamInImpl_Init();
1095+
stream_in.buffer = stream_out.buffer;
1096+
stream_in.len = stream_out.len;
1097+
1098+
{
1099+
JPC_IDToShapeMap* id_to_shape = JPC_IDToShapeMap_Create();
1100+
JPC_IDToMaterialMap* id_to_material = JPC_IDToMaterialMap_Create();
1101+
1102+
const float half_extent_alt[3] = { 4.f, 5.f, 6.f };
1103+
JPC_BoxShapeSettings* box_shape_settings = JPC_BoxShapeSettings_Create(half_extent_alt);
1104+
JPC_Shape* box_shape = JPC_ShapeSettings_CreateShape((JPC_ShapeSettings*)box_shape_settings);
1105+
1106+
JPC_IDToShapeMap_Add(id_to_shape, &box_shape, 1);
1107+
JPC_Shape* shape = JPC_Shape_sRestoreWithChildren(&stream_in, id_to_shape, id_to_material);
1108+
assert(JPC_SHAPE_SUB_TYPE_ROTATED_TRANSLATED == JPC_Shape_GetSubType(shape));
1109+
1110+
JPC_DecoratedShape* decorated = (JPC_DecoratedShape*)shape;
1111+
const JPC_Shape* inner = JPC_DecoratedShape_GetInnerShape(decorated);
1112+
assert(JPC_SHAPE_SUB_TYPE_BOX == JPC_Shape_GetSubType(inner));
1113+
1114+
float half_extent_restored[3] = { 0, 0, 0 };
1115+
JPC_BoxShape_GetHalfExtent((const JPC_BoxShape*)inner, half_extent_restored);
1116+
assert(memcmp(half_extent_alt, half_extent_restored, 3 * sizeof(float)) == 0);
1117+
1118+
float translation_restored[3];
1119+
JPC_RotatedTranslatedShape_GetPosition((JPC_RotatedTranslatedShape*)shape, translation_restored);
1120+
assert(memcmp(translation, translation_restored, 3 * sizeof(float)) == 0);
1121+
1122+
JPC_ShapeToIDMap_Destroy(id_to_shape);
1123+
JPC_MaterialToIDMap_Destroy(id_to_material);
1124+
}
1125+
1126+
free(stream_in.buffer);
1127+
1128+
}
1129+
1130+
1131+
JPC_TempAllocator_Destroy(temp_allocator);
1132+
JPC_DestroyFactory();
1133+
1134+
return 1;
1135+
}
1136+
//--------------------------------------------------------------------------------------------------

‎src/zphysics.zig

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,129 @@ pub fn RefTargetHeader(comptime first_field_align: u29) type {
9191
};
9292
}
9393

94+
pub const StreamOut = extern struct {
95+
__v: *const VTable,
96+
97+
pub fn Methods(comptime T: type) type {
98+
return extern struct {
99+
pub inline fn writeBytes(self: *T, data: [*]const u8, num_bytes: usize) u32 {
100+
return @as(*StreamOut.VTable, @ptrCast(self.__v))
101+
.writeBytes(@as(*StreamOut, @ptrCast(self)), data, num_bytes);
102+
}
103+
pub inline fn isFailed(self: *const T) bool {
104+
return @as(*const StreamOut.VTable, @ptrCast(self.__v))
105+
.isFailed(@as(*const StreamOut, @ptrCast(self)));
106+
}
107+
};
108+
}
109+
110+
pub const VTable = extern struct {
111+
__header: VTableHeader = .{},
112+
writeBytes: *const fn (self: *StreamOut, data: [*]const u8, num_bytes: usize) callconv(.C) void,
113+
isFailed: *const fn (self: *StreamOut) callconv(.C) bool,
114+
};
115+
116+
comptime {
117+
assert(@sizeOf(VTable) == @sizeOf(c.JPC_StreamOutVTable));
118+
}
119+
};
120+
121+
pub const AnyWriterStreamOut = extern struct {
122+
usingnamespace StreamOut.Methods(@This());
123+
__v: *const StreamOut.VTable = &vtable,
124+
writer: *const std.io.AnyWriter,
125+
failed: bool = false,
126+
127+
const vtable = StreamOut.VTable{
128+
.writeBytes = _writeBytes,
129+
.isFailed = _isFailed,
130+
};
131+
132+
pub fn init(writer: *const std.io.AnyWriter) AnyWriterStreamOut {
133+
return .{ .writer = writer };
134+
}
135+
136+
fn _writeBytes(iself: *StreamOut, data: [*]const u8, num_bytes: usize) callconv(.C) void {
137+
const self = @as(*AnyWriterStreamOut, @ptrCast(iself));
138+
self.writer.writeAll(data[0..num_bytes]) catch {
139+
self.failed = true;
140+
};
141+
}
142+
143+
fn _isFailed(iself: *StreamOut) callconv(.C) bool {
144+
const self = @as(*AnyWriterStreamOut, @ptrCast(iself));
145+
return self.failed;
146+
}
147+
};
148+
149+
pub const StreamIn = extern struct {
150+
__v: *const VTable,
151+
152+
pub fn Methods(comptime T: type) type {
153+
return extern struct {
154+
pub inline fn readBytes(self: *T, data: [*]u8, num_bytes: usize) u32 {
155+
return @as(*StreamIn.VTable, @ptrCast(self.__v))
156+
.readBytes(@as(*StreamIn, @ptrCast(self)), data, num_bytes);
157+
}
158+
pub inline fn isEOF(self: *const T) bool {
159+
return @as(*const StreamIn.VTable, @ptrCast(self.__v))
160+
.isEof(@as(*const StreamIn, @ptrCast(self)));
161+
}
162+
pub inline fn isFailed(self: *const T) bool {
163+
return @as(*const StreamIn.VTable, @ptrCast(self.__v))
164+
.isFailed(@as(*const StreamIn, @ptrCast(self)));
165+
}
166+
};
167+
}
168+
169+
pub const VTable = extern struct {
170+
__header: VTableHeader = .{},
171+
readBytes: *const fn (self: *StreamIn, data: [*]u8, num_bytes: usize) callconv(.C) void,
172+
isEof: *const fn (self: *StreamIn) callconv(.C) bool,
173+
isFailed: *const fn (self: *StreamIn) callconv(.C) bool,
174+
};
175+
176+
comptime {
177+
assert(@sizeOf(VTable) == @sizeOf(c.JPC_StreamInVTable));
178+
}
179+
};
180+
181+
pub const AnyReaderStreamIn = extern struct {
182+
usingnamespace StreamIn.Methods(@This());
183+
__v: *const StreamIn.VTable = &vtable,
184+
reader: *const std.io.AnyReader,
185+
failed: bool = false,
186+
eof: bool = false,
187+
188+
const vtable = StreamIn.VTable{
189+
.readBytes = _readBytes,
190+
.isEof = _isEof,
191+
.isFailed = _isFailed,
192+
};
193+
194+
pub fn init(reader: *const std.io.AnyReader) AnyReaderStreamIn {
195+
return .{ .reader = reader };
196+
}
197+
198+
fn _readBytes(iself: *StreamIn, data: [*]u8, num_bytes: usize) callconv(.C) void {
199+
const self = @as(*AnyReaderStreamIn, @ptrCast(iself));
200+
self.reader.readNoEof(data[0..num_bytes]) catch |err| switch (err) {
201+
error.EndOfStream => self.eof = true,
202+
else => self.failed = true,
203+
};
204+
}
205+
206+
fn _isEof(iself: *StreamIn) callconv(.C) bool {
207+
const self = @as(*AnyReaderStreamIn, @ptrCast(iself));
208+
return self.eof;
209+
}
210+
211+
fn _isFailed(iself: *StreamIn) callconv(.C) bool {
212+
const self = @as(*AnyReaderStreamIn, @ptrCast(iself));
213+
return self.failed;
214+
}
215+
};
216+
94217
pub const BroadPhaseLayerInterface = extern struct {
95218
__v: *const VTable,
96219

@@ -3433,6 +3556,20 @@ pub const Shape = opaque {
34333556
}
34343557
};
34353558

3559+
pub fn restoreFromBinaryState(stream_in: *StreamIn) !*Shape {
3560+
const shape = c.JPC_Shape_sRestoreFromBinaryState(stream_in);
3561+
if (shape == null)
3562+
return error.FailedToRestoreShape;
3563+
return @as(*Shape, @ptrCast(shape));
3564+
}
3565+
3566+
pub fn restoreWithChildrenAll(stream_in: *StreamIn) !*Shape {
3567+
const shape = c.JPC_Shape_sRestoreWithChildren_All(stream_in);
3568+
if (shape == null)
3569+
return error.FailedToRestoreShape;
3570+
return @as(*Shape, @ptrCast(shape));
3571+
}
3572+
34363573
fn Methods(comptime T: type) type {
34373574
return struct {
34383575
pub fn asShape(shape: *const T) *const Shape {
@@ -3531,6 +3668,14 @@ pub const Shape = opaque {
35313668
);
35323669
return .{ .has_hit = has_hit, .hit = hit };
35333670
}
3671+
3672+
pub fn saveBinaryState(shape: *const T, stream_out: *StreamOut) void {
3673+
c.JPC_Shape_SaveBinaryState(@as(*const c.JPC_Shape, @ptrCast(shape)), stream_out);
3674+
}
3675+
3676+
pub fn saveWithChildrenAll(shape: *const T, stream_out: *StreamOut) void {
3677+
c.JPC_Shape_SaveWithChildren_All(@as(*const c.JPC_Shape, @ptrCast(shape)), stream_out);
3678+
}
35343679
};
35353680
}
35363681
};
@@ -3896,6 +4041,12 @@ test "jolt_c.helloworld" {
38964041
try expect(ret != 0);
38974042
}
38984043

4044+
extern fn JoltCTest_Serialization() u32;
4045+
test "jolt_c.serialization" {
4046+
const ret = JoltCTest_Serialization();
4047+
try expect(ret != 0);
4048+
}
4049+
38994050
test "zphysics.BodyCreationSettings" {
39004051
try init(std.testing.allocator, .{});
39014052
defer deinit();
@@ -4668,6 +4819,42 @@ test "zphysics.debugrenderer" {
46684819
physics_system.drawBodies(&draw_settings, draw_filter);
46694820
}
46704821

4822+
test "zphysics.serialization" {
4823+
try init(std.testing.allocator, .{});
4824+
defer deinit();
4825+
4826+
const half_extents: [3]f32 = .{ 1.0, 2.0, 3.0 };
4827+
const shape_settings = try BoxShapeSettings.create(half_extents);
4828+
defer shape_settings.release();
4829+
4830+
const shape = try shape_settings.createShape();
4831+
defer shape.release();
4832+
4833+
var buf: std.ArrayListUnmanaged(u8) = .{};
4834+
defer buf.deinit(std.testing.allocator);
4835+
4836+
{
4837+
const writer = buf.writer(std.testing.allocator).any();
4838+
var stream_out = AnyWriterStreamOut.init(&writer);
4839+
shape.saveBinaryState(@ptrCast(&stream_out));
4840+
try std.testing.expectEqual(1 + 8 + 4 + 12 + 4, buf.items.len);
4841+
}
4842+
4843+
{
4844+
var stream = std.io.fixedBufferStream(buf.items);
4845+
const reader = stream.reader().any();
4846+
var stream_in = AnyReaderStreamIn.init(&reader);
4847+
const shape_restored = try Shape.restoreFromBinaryState(@ptrCast(&stream_in));
4848+
defer shape_restored.release();
4849+
4850+
try std.testing.expectEqual(Shape.SubType.box, shape_restored.getSubType());
4851+
4852+
const box_shape_restored = BoxShape.asBoxShape(shape_restored);
4853+
const half_extent_restored = box_shape_restored.getHalfExtent();
4854+
try std.testing.expectEqual(half_extents, half_extent_restored);
4855+
}
4856+
}
4857+
46714858
test {
46724859
std.testing.refAllDecls(@This());
46734860
}

0 commit comments

Comments
 (0)
Please sign in to comment.