# Quickstart

ovphysx is an SDK for ovstage/USD-based physics simulation, available as a Python wheel and a C/C++ package.
This guide shows how to get started with both. You learn the required SDK layout, CMake configuration, runtime setup, and where to go next.

## Prerequisites

For both Python and C:

- Prepare a simple USD file such as `scene.usda` for ovstage population.
- **x86_64 only:** a CPU with **AVX** (Advanced Vector Extensions). Pre-built ovphysx
  x86_64 binaries require AVX; `ovphysx_initialize()` fails fast when AVX is unavailable.
  On Linux x86_64, check with `grep -qw avx /proc/cpuinfo`. Linux aarch64 wheels are unaffected.
- Install CUDA Toolkit and a compatible NVIDIA driver (recommended, but can be skipped if only CPU simulation is used).

## Quick Start by Language

### Python

Install the wheel:

```bash
pip install ovphysx
```

```python
import ovstage
import ovphysx
from ovphysx import PhysX

stage = ovstage.Stage("scene")
ovstage.population.open_usd(
    stage, "scene.usda", ordinal=1, domains=ovstage.PopulationDomain.PHYSICS
)

physx = PhysX()
physx.attach_ovstage(stage, read_ordinal=1)
physx.step(1.0 / 60.0)
physx.detach_ovstage()
physx.release()
stage.destroy()
```

`domains` is an OR-combinable bitmask whose ovstage default (`RENDERING`) omits
physics. For arbitrary USD prefer `ALL` (equivalently `PHYSICS | RENDERING`);
`PHYSICS` alone is only safe when the content is known not to put physics under
native scene-graph instances — refer to
[Population domains](../ovstage_integration.md#population-domains).

### C/C++

Download the ovphysx SDK package from the [GitHub Releases](https://github.com/NVIDIA-Omniverse/PhysX/releases) page and extract it to a local path.
You also need CMake 3.16 or newer and a C or C++ compiler.

Repository source builds fetch OVStage automatically from public PyPI. The
manual download below is only for users of the prebuilt OVPhysX SDK.

**ovstage is not part of the SDK.** ovphysx binds to the application-supplied
ovstage, so the package ships no ovstage headers, library, or runtime. Download
the matching native archive for your platform from the
[OVStage GitHub Releases](https://github.com/NVIDIA-Omniverse/ovstage/releases)
page and extract it to a separate directory beside ovphysx. This release uses
OVStage `0.1.0.346039`, published under the `v0.1.0` release. Do not overlay the
two package trees.

`find_package(ovphysx)` pulls it in via `find_dependency(ovstage)`, so just add
both roots to `CMAKE_PREFIX_PATH`. This is required even if you never call ovstage because the
public ovphysx headers `#include <ovstage/...>`.

**SDK Directory Layout**

```text
ovphysx/
├── SKILLS.md             # Skills index
├── skills/               # Agent skills runbooks
├── include/ovphysx/     # Public headers (ovphysx.h, ovphysx_types.h, and related headers)
├── lib/                 # Shared libraries and CMake package config
│   └── cmake/ovphysx/   # find_package(ovphysx) support
├── plugins/             # Carbonite, PhysX, and USD runtime plugins
│   └── gpu/             # GPU-only plugins (loaded only when GPU is enabled)
├── samples/             # CI-tested C sample source + USD data
├── docs/                # Documentation (HTML + Markdown)
├── LICENSE.txt
└── ovstage-THIRD-PARTY-NOTICES.txt
```

**Build Your First App**

**CMakeLists.txt**

The SDK ships a complete, CI-tested sample. Its CMake project links both the
ovphysx and ovstage companion targets:

```cmake
cmake_minimum_required(VERSION 3.16)
project(HelloWorldC C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

find_package(ovphysx REQUIRED)

add_executable(hello_world_c main.c)

# Explicitly set the language to C (not C++)
set_source_files_properties(main.c PROPERTIES LANGUAGE C)
set_target_properties(hello_world_c PROPERTIES
    C_STANDARD 11
    C_STANDARD_REQUIRED ON
)


# Add compiler-specific flags to enforce strict C compilation
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
    # GCC/Clang: Add -Werror=implicit-function-declaration to catch C++ leakage
    target_compile_options(hello_world_c PRIVATE 
        -Werror=implicit-function-declaration
        -pedantic
    )
endif()

if(MSVC)
    # MSVC: Compile as C code explicitly
    target_compile_options(hello_world_c PRIVATE /TC)
endif()

target_link_libraries(hello_world_c PRIVATE ovphysx::ovphysx ovphysx::ovstage)
target_include_directories(hello_world_c PRIVATE "${CMAKE_CURRENT_LIST_DIR}/../common")
get_filename_component(OVPHYSX_TEST_DATA_DIR "${CMAKE_CURRENT_LIST_DIR}/../../data" ABSOLUTE)
target_compile_definitions(hello_world_c PRIVATE
    OVPHYSX_TEST_DATA="${OVPHYSX_TEST_DATA_DIR}"
)
if(WIN32)
    ovphysx_copy_runtime_dlls(hello_world_c)
endif()

```

#### Source

The sample creates and populates an ovstage instance, attaches it with the
sealed read ordinal, waits for the physics step, and cleans up in lifetime-safe
order:

```c
#include "ovphysx/ovphysx.h"
#include "ovstage_sample.h"
#include <stdio.h>

static int run(void)
{
  // Create PhysX instance with default args
  ovphysx_create_args create_args = OVPHYSX_CREATE_ARGS_DEFAULT;
  ovphysx_handle_t handle = 0;
  
  ovphysx_result_t result = ovphysx_create_instance(&create_args, &handle);
  if (result.status != OVPHYSX_API_SUCCESS) {
    fprintf(stderr, "Failed to create PhysX instance\n");
  ovphysx_shutdown();
    return 1;
  }

  // Populate ovstage from USD and attach it to ovphysx
  ovphysx_sample_stage_attachment_t stage_attachment = {0};
  if (!ovphysx_sample_attach_usd_with_ovstage(
          handle, OVPHYSX_TEST_DATA "/simple_physics_scene.usda", &stage_attachment)) {
    fprintf(stderr, "Failed to attach ovstage scene\n");
    ovphysx_destroy_instance(handle);
  ovphysx_shutdown();
    return 1;
  }

  // Step the simulation
  ovphysx_enqueue_result_t step_result = ovphysx_step(handle, 0.016f);
  if (step_result.status != OVPHYSX_API_SUCCESS) {
    fprintf(stderr, "Failed to step simulation\n");
    ovphysx_sample_destroy_stage(handle, &stage_attachment);
    ovphysx_destroy_instance(handle);
  ovphysx_shutdown();
    return 1;
  }

  // Wait for step to complete
  ovphysx_op_wait_result_t step_wait_result = {0};
  ovphysx_result_t step_wait_status = ovphysx_wait_op(handle, step_result.op_index, UINT64_MAX, &step_wait_result);
  int step_ok = (step_wait_status.status == OVPHYSX_API_SUCCESS && step_wait_result.num_errors == 0);
  ovphysx_destroy_wait_result(&step_wait_result);
  if (!step_ok) {
    fprintf(stderr, "Simulation step failed\n");
    ovphysx_sample_destroy_stage(handle, &stage_attachment);
    ovphysx_destroy_instance(handle);
  ovphysx_shutdown();
    return 1;
  }

  printf("Simulation step completed successfully\n");

  ovphysx_sample_destroy_stage(handle, &stage_attachment);
  ovphysx_destroy_instance(handle);
  ovphysx_shutdown();
  printf("Cleanup complete\n");

  return 0;
}

int main(void) {
    ovphysx_result_t init_r = ovphysx_initialize();
    if (init_r.status != OVPHYSX_API_SUCCESS) {
        fprintf(stderr, "ovphysx_initialize() failed\n");
        return 1;
    }
  int rc = run();
  return rc;
}
```

**Configure and Build**

Point `CMAKE_PREFIX_PATH` at the SDK root (the directory containing `include/`,
`lib/`, and `plugins/`) and build the bundled sample:

```bash
cmake -B build -S /path/to/ovphysx/samples/c_samples/hello_world_c \
  -DCMAKE_PREFIX_PATH="/path/to/ovphysx;/path/to/ovstage"
cmake --build build
```

## Runtime Libraries (C/C++)

### Linux

The CMake config bakes RPATH into your executable automatically.
No `LD_LIBRARY_PATH` manipulation is needed. Run the binary directly.

### Windows

Use the `ovphysx_copy_runtime_dlls(<target>)` helper provided by the CMake package
(already shown in the `CMakeLists.txt` example).
This copies the OVPhysX DLLs and plugins next to your executable. Keep the
separate OVStage package intact and add its `bin`, `bin/plugins`,
`bin/plugins/omni.client.lib`, and `bin/plugins/omni.usd_resolver` directories
to the process `PATH` before launch.

```powershell
$env:OVSTAGE_ROOT = "C:\path\to\extracted\ovstage"
$env:PATH = "$env:OVSTAGE_ROOT\bin;$env:OVSTAGE_ROOT\bin\plugins;$env:OVSTAGE_ROOT\bin\plugins\omni.client.lib;$env:OVSTAGE_ROOT\bin\plugins\omni.usd_resolver;$env:PATH"
```

## Result

You now have a minimal C or C++ application that links against `ovphysx::ovphysx`, consumes an application-owned ovstage, and runs a simulation step.

## Next Steps

- Full C API reference: refer to the [C API Reference](../api.md)
- More tutorials: [Hello World](hello_world.md), [Tensor Bindings](tensor_bindings.md), [Contact Binding](contact_binding.md)
