dart_bclibc

Dart FFI bindings for the bclibc ballistics engine.

Made in Ukraine

License Pub Version powered by bclibc

Linux Windows macOS

CI

A thin, zero-copy Dart wrapper around libbclibc_ffi — a high-performance 3-DOF + spin drift ballistic solver engine with RK4/Euler integration. Ships with the bclibc C++ source as a git submodule; no pre-built binaries required.

Pure Dart — no Flutter dependency. For Flutter apps (Android/iOS/Linux/macOS/Windows native bundling, plus Web/WebAssembly support), depend on dart_bclibc_flutter instead, which re-exports everything here.


Table of Contents


Quick start

import 'package:dart_bclibc/bclibc.dart';

final bc = BcLibC.open(); // loads the native library once

final shot = BcShot(
  bc: 0.295,
  weightGrain: 168.0,
  diameterInch: 0.308,
  lengthInch: 1.22,
  muzzleVelocityFps: 2750.0,
  sightHeightFt: 0.1148,
  twistInch: 10.0,
  tempC: 15.0,
  pressureHpa: 1013.25,
  altitudeFt: 0.0,
  dragTable: [BcDragPoint(0.0, 0.0), /* … Mach / CD pairs … */],
  lookAngleRad: 0.0,
  barrelElevationRad: 0.0,
);

final hit = bc.integrateShot(
  shot,
  BcTrajectoryRequest(rangeLimitFt: 3000.0, rangeStepFt: 100.0),
);

for (final pt in hit.trajectory) {
  print('${pt.distanceFt} ft  ${pt.velocityFps} fps  ${pt.heightFt} ft');
}

API

Input types

Dart type Description
BcShot Preferred shot input (natural units). All physics conversion — atmosphere density, Coriolis trig, PCHIP drag curve, cant — is performed inside C++ via BCLIBCFFI_Shot::to_shot_props().
BcShotProps Legacy shot input (pre-computed BcAtmosphere/BcCoriolis structs).
BcTrajectoryRequest Step size, range limit, and BCLIBCFFI_TrajFlag filter bitmask.
BcConfig Solver knobs (step multiplier, accuracy, gravity constant, etc.).
BcDragPoint One Mach / CD entry for the drag table.
BcWind One wind segment (velocity, direction, distance bounds).

Result types

Dart type Description
BcTrajectoryData One filtered trajectory record.
BcHitResult Full trajectory list + BCLIBCFFI_TerminationReason.
BcInterception Single interpolated point from integrateAtShot.
BcMaxRangeResult Max range (ft) + angle (rad) from findMaxRangeShot.

BcLibC methods

Method Description
BcLibC.open() Load the native library (call once at startup).
integrateShot(BcShot, BcTrajectoryRequest) Full filtered trajectory.
integrateAtShot(BcShot, key, value) Single interpolated point at a trajectory key.
findZeroAngleShot(BcShot, distanceFt) Barrel elevation to zero at distance.
findApexShot(BcShot) Highest point of the trajectory arc.
findMaxRangeShot(BcShot) Maximum range and corresponding angle.
getCorrection(distanceFt, offsetFt) Angular correction (rad) for a linear offset.
calculateEnergy(grains, fps) Kinetic energy (ft-lb).
calculateOgw(grains, fps) Optimal Game Weight.

Legacy BcShotProps-based overloads (findApex, findMaxRange, etc.) are retained for backwards compatibility.

Enums

Dart enum Description
BCLIBCFFI_TrajFlag Trajectory filter flags (BCLIBCFFI_TRAJ_FLAG_RANGE, BCLIBCFFI_TRAJ_FLAG_APEX, …)
BcTerminationReason Why integration stopped (BcHitResult.reason).
BcBaseTrajInterpKey Key field selector for integrateAtShot (.posX, .time, .mach, …).
BcIntegrationMethod BcIntegrationMethod.rk4 (default) or .euler (BcShot.method).

BcTerminationReason, BcBaseTrajInterpKey, and BcIntegrationMethod (from lib/ffi/bclibc_types.dart) are platform-agnostic — the same types work with both BcLibC (native) and BcLibCWeb (web). They replace the raw ffigen-generated BCLIBCFFI_* enum classes in the public API; those still exist in bclibc_bindings.g.dart but are native-internal implementation detail now.


Async API

AsyncCalculator — the Future-returning counterpart to Calculator that also works on Flutter Web (wasm-backed) — lives in dart_bclibc_flutter instead of this package, since a real web implementation only makes sense inside a Flutter Web app (see that package's README for Web / WebAssembly). This package (dart_bclibc) exposes the synchronous Calculator only; wrap it in your own Isolate.run if you want off-isolate execution in a plain Dart project:

import 'dart:isolate';
import 'package:dart_bclibc/bclibc.dart';

final result = await Isolate.run(
  () => Calculator().fire(shot: shot, trajectoryRange: Distance.meter(1000)),
);

Atmosphere and Coriolis

When using BcShot:

  • Pass pressureHpa: 0 for vacuum (zero drag).
  • Pass latitudeDeg: double.nan to disable Coriolis (default BcShot value).
  • Pass azimuthDeg: double.nan for flat-fire drift only.

Unit system

lib/unit.dart provides typed unit wrappers with an in_() / toDouble() API:

import 'package:dart_bclibc/unit.dart';

final t = Temperature.celsius(15.0);
print(t.in_(TemperatureUnit.fahrenheit)); // 59.0

final d = Distance.meters(100.0);
print(d.in_(DistanceUnit.feet));          // 328.084...

Available types: Distance, Velocity, Temperature, Pressure, Angular, Weight, Energy.


Building

Prerequisites

  • Dart SDK ≥ 3.11.4
  • CMake ≥ 3.13
  • C++17 compiler (GCC / Clang on Linux/macOS, MSVC 2022 on Windows)
  • LLVM/Clang dev headers (only for regenerating FFI bindings)

Clone

git clone --recurse-submodules https://github.com/ballistics-lab/dart-bclibc.git
cd dart-bclibc/dart

If you cloned without --recurse-submodules:

git submodule update --init

Build native library

From the repo root:

make build

Or directly, from dart/:

dart run bin/build_native.dart

Both build libbclibc_ffi via CMake and copy it into dart/lib/native/<platform>/ — resolved automatically at runtime via a package: URI, independent of the caller's working directory. BcLibC.open() also checks the BCLIBC_FFI_PATH environment variable first, if set.

For Flutter apps the native library is instead built and bundled automatically by flutter build, via dart_bclibc_flutter's platform CMakeLists.txt/Gradle/podspec integration — no changes to the app's own platform config are required. See dart_bclibc_flutter's README for details.

Consuming apps: dart test

Apps that depend on dart_bclibc (not dart_bclibc_flutter) need to build the native library explicitly before testing/running, since plain dart test/dart run never run a platform build:

dart run dart_bclibc:build_native

Wire it into your own test target, e.g. in a Makefile:

test: build-bclibc
	dart test

build-bclibc:
	dart run dart_bclibc:build_native

Regenerate FFI bindings

# Install LLVM first:
#   Linux:   sudo apt install libclang-dev clang
#   macOS:   brew install llvm
#   Windows: winget install LLVM

make ffigen

The generated file is lib/ffi/bclibc_bindings.g.dart.

Run tests

make test

Native library

Platform Library name
Linux libbclibc_ffi.so
macOS libbclibc_ffi.dylib
Windows bclibc_ffi.dll

Android, iOS, and WebAssembly are covered by dart_bclibc_flutter instead, since they only ever run inside a Flutter app. During development the path can be overridden via the BCLIBC_FFI_PATH environment variable.


Dependencies

Dependency Role
bclibc C++ ballistic solver engine (3-DOF + spin drift, RK4) — LGPL-3.0, bundled as a git submodule
ffi Dart ↔ C FFI bindings
path Cross-platform path joining, used by the native build/load helpers

License

Copyright (C) 2026 Yaroshenko Dmytro (o-murphy)

This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License v3.0 as published by the Free Software Foundation.

See LICENSE for the full text. See CHANGELOG for release history.

Note

bclibc (the ballistic solver engine, located in bclibc/) is licensed separately under the GNU Lesser General Public License v3.0. See bclibc/LICENSE.

Warning

Risk notice. This package performs approximate simulations of complex physical processes. Calculation results must not be considered as completely or reliably reflecting actual projectile behaviour. Results may be used for educational purposes only and must not be relied upon in any context where an incorrect calculation could cause financial harm or put a human life at risk.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.