diff --git a/README.md b/README.md index ed3e512..47e6fc2 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,10 @@ Backend-neutral physics runtime components for OpenUSD-based applications. > **Status: Phase 1 core extraction.** The repository builds and installs -> `physicsCore` and `physicsJolt`; neutral rigid-transform values and typed -> handles are implemented, but descriptors, rigid-body runtime behavior, an -> OpenUSD bridge, and a solver backend are not. The +> `physicsCore` and `physicsJolt`; neutral rigid-transform values, typed +> handles, and validated box/body/fixed-constraint descriptors are +> implemented, but rigid-body runtime behavior, an OpenUSD bridge, and a +> solver backend are not. The > [capability matrix](docs/reference/CAPABILITY_MATRIX.md) is the only page > that states what exists, and the [current roadmap](docs/roadmap/current.md) > states what comes next. @@ -55,7 +56,7 @@ their backend. | Component | Kind | Role | State | | --- | --- | --- | --- | -| `physicsCore` | plain C++ library | Handles, descriptors, world lifecycle, state, and optional query contracts; no OpenUSD and no backend SDK | neutral values and handles present; remaining runtime API planned | +| `physicsCore` | plain C++ library | Handles, descriptors, world lifecycle, state, and optional query contracts; no OpenUSD and no backend SDK | neutral values, handles, and validated descriptors present; remaining runtime API planned | | `physicsJolt` | plain C++ library | First rigid-body backend implementing `physicsCore` | package scaffold present; backend unavailable | | `physicsUsd` | OpenUSD-facing C++ library | Translate standard `UsdPhysics` declarations to runtime descriptors and maintain transient prim/resource mappings | planned | | `secondaryMotion` | plain C++ library | Solver-neutral spring-chain and collider contracts | deferred until the rigid-body boundary is extracted | diff --git a/docs/architecture/PACKAGE_CONTRACT.md b/docs/architecture/PACKAGE_CONTRACT.md index 16f57d7..74581a4 100644 --- a/docs/architecture/PACKAGE_CONTRACT.md +++ b/docs/architecture/PACKAGE_CONTRACT.md @@ -2,8 +2,8 @@ > **Status: accepted, revised 2026-09-22.** `physicsCore` and `physicsJolt` > install and pass a clean-prefix consumer test. `physicsCore` now includes -> neutral values and typed handles; descriptors and world behavior remain -> unimplemented. +> neutral values, typed handles, and validated descriptors; world behavior +> remains unimplemented. ## 1. Purpose @@ -15,7 +15,7 @@ not need this repository's source tree. | Package | Imported target | Provides | Planned phase | | --- | --- | --- | --- | -| `physicsCore` | `physicsCore::physicsCore` | Version surface plus neutral vector, quaternion, transform, and typed handles; descriptors, world, and query contracts follow in Phase 1 | values and handles present; runtime Phase 1 | +| `physicsCore` | `physicsCore::physicsCore` | Version surface plus neutral vector, quaternion, transform, typed handles, validated box/body/fixed-constraint descriptors, and semantic collision filters; world and query contracts follow in Phase 1 | values, handles, and descriptors present; runtime Phase 1 | | `physicsJolt` | `physicsJolt::physicsJolt` | Phase 0 explicit unavailable status; Jolt-backed world construction follows in Phase 2 | scaffold present; backend Phase 2 | | `physicsUsd` | `physicsUsd::physicsUsd` | USD translation, mappings, and synchronization records | 4 | | `secondaryMotion` | `secondaryMotion::secondaryMotion` | generic secondary-motion contracts | 6, if admitted | diff --git a/docs/architecture/WORKSPACE.md b/docs/architecture/WORKSPACE.md index 597a761..bf17281 100644 --- a/docs/architecture/WORKSPACE.md +++ b/docs/architecture/WORKSPACE.md @@ -15,13 +15,14 @@ that contradicts it updates this document first, in a focused change. | Identity | Kind | Directory | Planned manifest | Role | Created in | Status | | --- | --- | --- | --- | --- | --- | --- | -| `physicsCore` | plain static CMake library | `libs/physicsCore/` | `openstrata.library.yaml` | Solver-neutral value types, handles, descriptors, world lifecycle, state, validation, and optional query contracts. No OpenUSD or backend SDK. | Phase 0 scaffold; Phase 1 runtime | values and handles implemented; remaining runtime planned | +| `physicsCore` | plain static CMake library | `libs/physicsCore/` | `openstrata.library.yaml` | Solver-neutral value types, handles, descriptors, world lifecycle, state, validation, and optional query contracts. No OpenUSD or backend SDK. | Phase 0 scaffold; Phase 1 runtime | values, handles, and validated descriptors implemented; remaining runtime planned | | `physicsJolt` | plain static CMake library | `backends/physicsJolt/` | `openstrata.library.yaml` | Jolt implementation of `physicsCore`; owns Jolt initialization, filters, jobs, resources, stepping, and queries. | Phase 0 scaffold; Phase 2 backend | scaffolded; backend unavailable | | `physicsUsd` | plain static CMake library | `libs/physicsUsd/` | `openstrata.library.yaml` | Standard `UsdPhysics` to core descriptors, transform conversion, transient scene/resource mapping, and synchronization records. | Phase 4 | reserved | The Phase 0 targets established package and dependency boundaries. -`physicsCore` now has supported value and handle slices, while its package as -a whole remains partial. `physicsJolt` remains a partial unavailable scaffold. +`physicsCore` now has supported value, handle, and descriptor slices, while +its package as a whole remains partial. `physicsJolt` remains a partial +unavailable scaffold. ### 1.2 Later, only when the responsibility is real diff --git a/docs/design/RIGID_BODY_CONTRACT.md b/docs/design/RIGID_BODY_CONTRACT.md index 43f3dd5..ec44d11 100644 --- a/docs/design/RIGID_BODY_CONTRACT.md +++ b/docs/design/RIGID_BODY_CONTRACT.md @@ -1,9 +1,9 @@ # Rigid-body runtime contract > **Status: proposed, revised 2026-09-22.** This document describes the -> intended extraction target. Neutral values and handles are implemented; see -> the [capability matrix](../reference/CAPABILITY_MATRIX.md) for the exact -> current boundary. +> intended extraction target. Neutral values, handles, and descriptors are +> implemented; see the [capability matrix](../reference/CAPABILITY_MATRIX.md) +> for the exact current boundary. ## 1. Purpose @@ -73,6 +73,15 @@ when a phase requires them. Collision filtering must be expressed semantically. A Jolt object-layer or broad-phase-layer index is not a public collision category. +Phase 1 represents filtering with two 64-bit sets: `categories` states the +semantic categories to which a body belongs, and `collidesWith` states the +categories it accepts. A pair is admitted only when each body's categories +intersect the other body's `collidesWith` set. `categories` must be non-zero; +`collidesWith` may be zero for an intentionally non-colliding body. The +default is category bit zero colliding with every category. This represents +Stage Runner's static/moving policy, MMD's 16 groups and per-body masks, and +future bridge-assigned categories without exposing backend layer numbers. + ### 5.3 Constraints Phase 1 preserves fixed constraints. Later descriptors may cover revolute, @@ -180,7 +189,8 @@ contract. Broad additions require a consumer scenario and tests. - **RB-O2 (resolved for Phase 1):** minimal vector, rotation, and transform values live in `physicsCore`; a separate package requires an independent consumer and an architecture revision. -- **RB-O3:** collision category/mask vocabulary that serves Stage Runner and - MMD without exposing backend layers. +- **RB-O3 (resolved for Phase 1):** use the 64-bit `categories` and + `collidesWith` sets defined in §5.2. Backend layer assignment is private and + may cache distinct filter combinations without changing this contract. - **RB-O4:** semantics and ordering of changed-body extraction across create, sleep, wake, teleport, and destroy. diff --git a/docs/reference/CAPABILITY_MATRIX.md b/docs/reference/CAPABILITY_MATRIX.md index b6c944e..99b5a19 100644 --- a/docs/reference/CAPABILITY_MATRIX.md +++ b/docs/reference/CAPABILITY_MATRIX.md @@ -6,8 +6,9 @@ capability on this page. > **Tree status (2026-09-22): Phase 1 core extraction.** Buildable and > installable `physicsCore` and `physicsJolt` package boundaries exist. -> `physicsCore` provides neutral rigid-transform values and typed handles, but -> no descriptors or world contract exists yet. No solver backend or OpenUSD +> `physicsCore` provides neutral rigid-transform values, typed handles, and +> validated box/body/fixed-constraint descriptors with semantic collision +> filters, but no world contract exists yet. No solver backend or OpenUSD > plugin exists. ## 1. Status vocabulary @@ -38,12 +39,12 @@ capability on this page. | Capability | Status | Evidence / note | | --- | --- | --- | -| `physicsCore` package | partial | Installable `physicsCore::physicsCore` provides version, value, and handle surfaces; descriptors and runtime contract remain Phase 1 | +| `physicsCore` package | partial | Installable `physicsCore::physicsCore` provides version, value, handle, and descriptor surfaces; the runtime contract remains Phase 1 | | Neutral vector, quaternion, and transform values | supported | `physicsCore.values_handles` and the installed-consumer test cover the public headers and identity defaults | | Opaque shape/body/constraint handles | supported | [`physics_core_values_handles_test.cpp`](../../libs/physicsCore/tests/physics_core_values_handles_test.cpp) covers invalid zero, typed identity, comparison, hashing, and representation size | -| Shape descriptors | planned | Box first; sphere/capsule with Phase 4 | -| Static and dynamic bodies | planned | No implementation | -| Fixed constraints | planned | No implementation | +| Shape descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers the validated box descriptor; sphere/capsule remain Phase 4 | +| Static and dynamic body descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers shape identity, motion type, rigid transform, mass, and collision filter validation; no body lifecycle exists yet | +| Fixed-constraint descriptors | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers two distinct valid body handles; no constraint lifecycle exists yet | | Force and velocity operations | planned | No implementation | | Fixed-step world | planned | No implementation | | Direct body state | planned | No implementation | @@ -51,7 +52,7 @@ capability on this page. | Segment query capability | planned | No implementation | | Ground query capability | planned | No implementation | | Ray or shape-cast capabilities | planned | Later consumer-driven addition | -| Neutral collision filtering | planned | `RB-O3` unresolved | +| Neutral collision filtering | supported | [`physics_core_descriptors_test.cpp`](../../libs/physicsCore/tests/physics_core_descriptors_test.cpp) covers 64-bit category/mask semantics and pair matching without backend layer identifiers; `RB-O3` is resolved | ## 4. Backends diff --git a/docs/roadmap/README.md b/docs/roadmap/README.md index f1b0436..845443f 100644 --- a/docs/roadmap/README.md +++ b/docs/roadmap/README.md @@ -9,7 +9,7 @@ status and ordering. | Phase | Status | Current outcome | | --- | --- | --- | -| 1 — extract `physicsCore` | in progress | Neutral values and typed handles are implemented; descriptors and validation are next. | +| 1 — extract `physicsCore` | in progress | Neutral values, typed handles, validated descriptors, and semantic collision filters are implemented; world lifecycle is next. | | 2 — extract `physicsJolt` | not started | Waits for Phase 1 and an accepted Jolt dependency. | | 3 — Stage Runner migration | not started | Waits for installable Phase 1–2 packages. | | 4 — `physicsUsd` foundation | not started | Waits for the neutral rigid-body contract. | diff --git a/docs/roadmap/current.md b/docs/roadmap/current.md index 716a31c..1288b4c 100644 --- a/docs/roadmap/current.md +++ b/docs/roadmap/current.md @@ -1,8 +1,8 @@ # Current roadmap — Phase 1 `physicsCore` extraction > **Status: Phase 1 in progress, 2026-09-22.** Phase 0 closed with successful -> hosted graph, Linux, and Windows cells. Neutral values and typed handles are -> the first implemented extraction slice. +> hosted graph, Linux, and Windows cells. Neutral values, typed handles, and +> validated descriptors are the implemented extraction slices. ## 1. Outcome @@ -11,8 +11,7 @@ preserves the Stage Runner behavior without depending on Stage Runner, OpenUSD, or Jolt. ```text -values and handles - -> descriptors and validation +values, handles, and descriptors -> world lifecycle and state -> optional segment and ground queries -> Phase 2 Jolt extraction @@ -24,21 +23,26 @@ values and handles installed `usd_physics/core/` include root. - Typed 64-bit `ShapeHandle`, `BodyHandle`, and `ConstraintHandle` values preserve invalid zero, comparison, and hashing behavior. -- `physicsCore.values_handles` and the clean-prefix installed consumer cover - this public slice. +- Box shape, static/dynamic body, and fixed-constraint descriptors preserve + the Stage Runner extraction baseline against neutral transforms and handles. +- Descriptor validation rejects unsupported enum values, non-finite transforms, + invalid dimensions, invalid masses, missing categories, and invalid handles + with `std::invalid_argument`. +- `CollisionFilter` uses 64-bit `categories` and `collidesWith` sets; no + backend layer identifier enters the public contract. +- `physicsCore.values_handles`, `physicsCore.descriptors`, and the clean-prefix + installed consumer cover these public slices. - `RB-O1` has a proposed mixed error policy in the [rigid-body contract](../design/RIGID_BODY_CONTRACT.md#9-errors-and-validation). +- `RB-O3` is resolved by the semantic category/mask contract in + [the body descriptor](../design/RIGID_BODY_CONTRACT.md#52-bodies). ## 3. Remaining Phase 1 work -- Extract box shape, static/dynamic body, and fixed-constraint descriptors - against the neutral values and handles. -- Implement and test descriptor, vector, transform, and fixed-step validation; - use those tests to accept or revise `RB-O1`. +- Implement and test fixed-step validation; use the world tests to accept or + revise the remaining `RB-O1` branches. - Extract the single-owner world lifecycle, force/velocity commands, direct state, fixed stepping, and changed-state draining contract. -- Settle `RB-O3` collision category/mask vocabulary before collision data is - frozen in the public body descriptor. - Settle `RB-O4` changed-state ordering across create, sleep, wake, teleport, and destroy before the world contract is accepted. - Extract optional segment and ground query capabilities with ignored-body and @@ -53,6 +57,6 @@ values and handles - `physicsCore` public headers and link interfaces contain no OpenUSD, Jolt, Stage Runner, MMD, or VRM dependency. - A clean-prefix consumer includes and exercises the runtime contract. -- `RB-O1`, `RB-O3`, and the Phase 1 portion of `RB-O4` are accepted or narrowed - to explicitly deferred behavior. +- `RB-O1` and the Phase 1 portion of `RB-O4` are accepted or narrowed to + explicitly deferred behavior; the accepted `RB-O3` filter remains covered. - The capability matrix and package contract describe only the tested surface. diff --git a/libs/physicsCore/CMakeLists.txt b/libs/physicsCore/CMakeLists.txt index c1409a4..0c3f029 100644 --- a/libs/physicsCore/CMakeLists.txt +++ b/libs/physicsCore/CMakeLists.txt @@ -23,12 +23,16 @@ if(NOT DEFINED PHYSICSCORE_BUILD_TESTS) ${_physics_core_tests_default}) endif() -add_library(physicsCore STATIC src/version.cpp) +add_library(physicsCore STATIC + src/descriptors.cpp + src/version.cpp) add_library(physicsCore::physicsCore ALIAS physicsCore) set_target_properties(physicsCore PROPERTIES EXPORT_NAME physicsCore POSITION_INDEPENDENT_CODE ON) target_compile_features(physicsCore PUBLIC cxx_std_17) +target_compile_options(physicsCore PUBLIC + "$<$:/EHsc>") target_compile_definitions(physicsCore PRIVATE USDPHYSICS_CORE_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} USDPHYSICS_CORE_VERSION_MINOR=${PROJECT_VERSION_MINOR} diff --git a/libs/physicsCore/include/usd_physics/core/descriptors.h b/libs/physicsCore/include/usd_physics/core/descriptors.h new file mode 100644 index 0000000..ce7017a --- /dev/null +++ b/libs/physicsCore/include/usd_physics/core/descriptors.h @@ -0,0 +1,59 @@ +#pragma once + +#include "usd_physics/core/handles.h" +#include "usd_physics/core/value_types.h" + +#include + +namespace usd_physics::core { + +enum class ShapeType { + box, +}; + +struct ShapeDescriptor { + ShapeType type{ShapeType::box}; + Vector3 halfExtents{0.5, 0.5, 0.5}; +}; + +enum class MotionType { + staticBody, + dynamicBody, +}; + +using CollisionCategories = std::uint64_t; + +struct CollisionFilter { + CollisionCategories categories{1}; + CollisionCategories collidesWith{~CollisionCategories{0}}; +}; + +[[nodiscard]] constexpr bool +collisionFiltersAllowPair(CollisionFilter first, CollisionFilter second) noexcept { + return (first.categories & second.collidesWith) != 0 && + (second.categories & first.collidesWith) != 0; +} + +struct BodyDescriptor { + ShapeHandle shape; + MotionType motionType{MotionType::staticBody}; + Transform initialTransform; + double mass{1.0}; + CollisionFilter collisionFilter; +}; + +enum class ConstraintType { + fixed, +}; + +struct ConstraintDescriptor { + ConstraintType type{ConstraintType::fixed}; + BodyHandle firstBody; + BodyHandle secondBody; +}; + +void validateShapeDescriptor(const ShapeDescriptor& descriptor); +void validateBodyDescriptor(const BodyDescriptor& descriptor); +void validateConstraintDescriptor(const ConstraintDescriptor& descriptor); + +} // namespace usd_physics::core diff --git a/libs/physicsCore/src/descriptors.cpp b/libs/physicsCore/src/descriptors.cpp new file mode 100644 index 0000000..8daec90 --- /dev/null +++ b/libs/physicsCore/src/descriptors.cpp @@ -0,0 +1,79 @@ +#include "usd_physics/core/descriptors.h" + +#include +#include + +namespace usd_physics::core { +namespace { + +bool isFinite(Vector3 value) noexcept { + return std::isfinite(value.x) && std::isfinite(value.y) && std::isfinite(value.z); +} + +bool isFinite(Quaternion value) noexcept { + return std::isfinite(value.w) && std::isfinite(value.x) && + std::isfinite(value.y) && std::isfinite(value.z); +} + +void validateTransform(Transform value) { + if (!isFinite(value.translation)) { + throw std::invalid_argument("body translation must be finite"); + } + if (!isFinite(value.rotation)) { + throw std::invalid_argument("body rotation must be finite"); + } +} + +} // namespace + +void validateShapeDescriptor(const ShapeDescriptor& descriptor) { + if (descriptor.type != ShapeType::box) { + throw std::invalid_argument("shape type is unsupported"); + } + if (!isFinite(descriptor.halfExtents)) { + throw std::invalid_argument("box half extents must be finite"); + } + if (descriptor.halfExtents.x <= 0.0 || descriptor.halfExtents.y <= 0.0 || + descriptor.halfExtents.z <= 0.0) { + throw std::invalid_argument("box half extents must be positive"); + } +} + +void validateBodyDescriptor(const BodyDescriptor& descriptor) { + if (!descriptor.shape) { + throw std::invalid_argument("a physics body requires a valid shape handle"); + } + validateTransform(descriptor.initialTransform); + + switch (descriptor.motionType) { + case MotionType::staticBody: + case MotionType::dynamicBody: + break; + default: + throw std::invalid_argument("body motion type is unsupported"); + } + + if (!std::isfinite(descriptor.mass) || + (descriptor.motionType == MotionType::dynamicBody && descriptor.mass <= 0.0) || + (descriptor.motionType == MotionType::staticBody && descriptor.mass < 0.0)) { + throw std::invalid_argument( + "body mass must be finite, non-negative for static bodies, and positive for dynamic bodies"); + } + if (descriptor.collisionFilter.categories == 0) { + throw std::invalid_argument("a physics body requires at least one collision category"); + } +} + +void validateConstraintDescriptor(const ConstraintDescriptor& descriptor) { + if (descriptor.type != ConstraintType::fixed) { + throw std::invalid_argument("constraint type is unsupported"); + } + if (!descriptor.firstBody || !descriptor.secondBody) { + throw std::invalid_argument("a physics constraint requires two valid body handles"); + } + if (descriptor.firstBody == descriptor.secondBody) { + throw std::invalid_argument("a physics constraint requires two distinct bodies"); + } +} + +} // namespace usd_physics::core diff --git a/libs/physicsCore/tests/CMakeLists.txt b/libs/physicsCore/tests/CMakeLists.txt index 2c8477c..fba196a 100644 --- a/libs/physicsCore/tests/CMakeLists.txt +++ b/libs/physicsCore/tests/CMakeLists.txt @@ -5,3 +5,7 @@ add_test(NAME physicsCore.scaffold COMMAND physics_core_scaffold_test) add_executable(physics_core_values_handles_test physics_core_values_handles_test.cpp) target_link_libraries(physics_core_values_handles_test PRIVATE physicsCore::physicsCore) add_test(NAME physicsCore.values_handles COMMAND physics_core_values_handles_test) + +add_executable(physics_core_descriptors_test physics_core_descriptors_test.cpp) +target_link_libraries(physics_core_descriptors_test PRIVATE physicsCore::physicsCore) +add_test(NAME physicsCore.descriptors COMMAND physics_core_descriptors_test) diff --git a/libs/physicsCore/tests/physics_core_descriptors_test.cpp b/libs/physicsCore/tests/physics_core_descriptors_test.cpp new file mode 100644 index 0000000..f1fbb21 --- /dev/null +++ b/libs/physicsCore/tests/physics_core_descriptors_test.cpp @@ -0,0 +1,108 @@ +#include "usd_physics/core/descriptors.h" + +#include +#include +#include + +namespace { + +using namespace usd_physics::core; + +template bool rejectsInvalidArgument(Function&& function) { + try { + std::forward(function)(); + } catch (const std::invalid_argument&) { + return true; + } + return false; +} + +} // namespace + +int main() { + const ShapeDescriptor defaultBox; + if (defaultBox.type != ShapeType::box || + defaultBox.halfExtents != Vector3{0.5, 0.5, 0.5}) { + return 1; + } + validateShapeDescriptor(defaultBox); + + const BodyDescriptor staticBody{ShapeHandle{1}, MotionType::staticBody, + Transform{}, 0.0, + {CollisionCategories{1} << 2, 0}}; + const BodyDescriptor dynamicBody{ + ShapeHandle{1}, MotionType::dynamicBody, + Transform{{1.0, 2.0, 3.0}, {0.5, 0.5, 0.5, 0.5}}, 2.0, + {CollisionCategories{1} << 3, + (CollisionCategories{1} << 2) | (CollisionCategories{1} << 3)}}; + validateBodyDescriptor(staticBody); + validateBodyDescriptor(dynamicBody); + if (collisionFiltersAllowPair(staticBody.collisionFilter, + dynamicBody.collisionFilter) || + !collisionFiltersAllowPair(dynamicBody.collisionFilter, + dynamicBody.collisionFilter) || + collisionFiltersAllowPair({}, {1, 0})) { + return 2; + } + + const ConstraintDescriptor fixedConstraint{ConstraintType::fixed, BodyHandle{1}, + BodyHandle{2}}; + validateConstraintDescriptor(fixedConstraint); + + const auto infinity = std::numeric_limits::infinity(); + const auto nan = std::numeric_limits::quiet_NaN(); + if (!rejectsInvalidArgument([] { + validateShapeDescriptor( + {static_cast(-1), Vector3{0.5, 0.5, 0.5}}); + }) || + !rejectsInvalidArgument([] { + validateShapeDescriptor({ShapeType::box, Vector3{0.0, 0.5, 0.5}}); + }) || + !rejectsInvalidArgument([&] { + validateShapeDescriptor({ShapeType::box, Vector3{infinity, 0.5, 0.5}}); + }) || + !rejectsInvalidArgument([] { validateBodyDescriptor({}); }) || + !rejectsInvalidArgument([] { + validateBodyDescriptor( + {ShapeHandle{1}, static_cast(-1), {}, 1.0, {}}); + }) || + !rejectsInvalidArgument([&] { + validateBodyDescriptor({ShapeHandle{1}, MotionType::staticBody, + Transform{{nan, 0.0, 0.0}, {}}, 0.0, {}}); + }) || + !rejectsInvalidArgument([&] { + validateBodyDescriptor({ShapeHandle{1}, MotionType::staticBody, + Transform{{}, {1.0, 0.0, infinity, 0.0}}, 0.0, {}}); + }) || + !rejectsInvalidArgument([] { + validateBodyDescriptor( + {ShapeHandle{1}, MotionType::dynamicBody, {}, 0.0, {}}); + }) || + !rejectsInvalidArgument([] { + validateBodyDescriptor( + {ShapeHandle{1}, MotionType::staticBody, {}, -1.0, {}}); + }) || + !rejectsInvalidArgument([&] { + validateBodyDescriptor( + {ShapeHandle{1}, MotionType::dynamicBody, {}, nan, {}}); + }) || + !rejectsInvalidArgument([] { + validateBodyDescriptor( + {ShapeHandle{1}, MotionType::staticBody, {}, 0.0, {0, 0}}); + }) || + !rejectsInvalidArgument([] { + validateConstraintDescriptor({ConstraintType::fixed, {}, BodyHandle{2}}); + }) || + !rejectsInvalidArgument([] { + validateConstraintDescriptor( + {ConstraintType::fixed, BodyHandle{1}, BodyHandle{1}}); + }) || + !rejectsInvalidArgument([] { + validateConstraintDescriptor( + {static_cast(-1), BodyHandle{1}, BodyHandle{2}}); + })) { + return 3; + } + + return 0; +} diff --git a/tests/installed_consumer/main.cpp b/tests/installed_consumer/main.cpp index c98e11a..3a33ac9 100644 --- a/tests/installed_consumer/main.cpp +++ b/tests/installed_consumer/main.cpp @@ -1,3 +1,4 @@ +#include "usd_physics/core/descriptors.h" #include "usd_physics/core/handles.h" #include "usd_physics/core/value_types.h" #include "usd_physics/core/version.h" @@ -14,5 +15,10 @@ int main() { if (!body || transform.translation.y != 2.0) { return 2; } + const usd_physics::core::ShapeDescriptor box; + usd_physics::core::validateShapeDescriptor(box); + usd_physics::core::validateBodyDescriptor( + {usd_physics::core::ShapeHandle{1}, usd_physics::core::MotionType::dynamicBody, + transform, 1.0, {}}); return usd_physics::jolt::backendAvailable() ? 3 : 0; } diff --git a/tests/run_installed_consumer.cmake b/tests/run_installed_consumer.cmake index b467f00..edb5cbe 100644 --- a/tests/run_installed_consumer.cmake +++ b/tests/run_installed_consumer.cmake @@ -36,6 +36,7 @@ set(_configure_args -S "${CONSUMER_SOURCE_DIR}" -B "${_build}" -G "${TEST_GENERATOR}" + "-DCMAKE_BUILD_TYPE=${TEST_CONFIG}" "-DCMAKE_PREFIX_PATH=${_prefix}") if(TEST_GENERATOR_PLATFORM) list(APPEND _configure_args -A "${TEST_GENERATOR_PLATFORM}")