Skip to content

mzogithub/emulse-core

Repository files navigation

EMULSE Core: Native Film Simulation Pipeline

Open-source native processing core extracted from EMULSE, a physically-based film simulation engine. Proprietary emulsion models replaced with standard implementations for open-source release.

EMULSE is a production film emulation engine that recreates the look of silver-halide photography through physically-based grain, halation, bloom, and color science. This repository contains the native C++ processing pipeline, exposed to TypeScript via N-API.

What This Demonstrates

  • C++ engine development: image processing pipeline, per-pixel compute, separable Gaussian blur, Perlin noise synthesis
  • Pipeline architecture: ordered processing stages, enable/disable, per-stage profiling, preset system
  • Real-time mindset: contiguous memory layout, batch pixel processing, zero external dependencies
  • Native/TS boundary: clean N-API binding with strict ownership rules
  • OpenUSD awareness: sample stage file and inspector script

Open-Source Scope

The full EMULSE engine includes proprietary algorithms that remain closed-source. This core module replaces those with standard textbook implementations that preserve the same architecture:

  • Grain: Perlin noise (production uses physically-based halide crystal models)
  • Halation: Gaussian blur + threshold (production uses spectral light transport)
  • Color grading: Lift/Gamma/Gain (production uses full spectral sensitometry curves)

The architecture, pipeline design, N-API boundary, and stage system are representative of the real codebase.

Quick Start

# Prerequisites: Node.js >= 20, CMake >= 3.15, C++17 compiler

npm install
npm run build        # builds native C++ addon + TypeScript
npm run demo         # runs pipeline at 256/512/1024 resolution, writes output PPMs
npm run bench        # per-stage timing at multiple resolutions
npm run test         # C++ unit tests + TypeScript integration tests

Architecture

emulse-core/
├── native/engine_core/          # C++ engine core (~65% of meaningful logic)
│   ├── include/
│   │   ├── imaging/             # ImageBuffer (RGBA float), color space utils
│   │   ├── pipeline/            # Pipeline orchestrator, abstract Stage
│   │   ├── stages/              # ToneMap, Grain, Halation, Bloom, ColorGrade
│   │   └── math/                # Vec3, Perlin noise
│   ├── src/                     # Implementation + N-API binding
│   └── CMakeLists.txt
├── packages/
│   ├── engine_ts/               # TypeScript wrapper, types, presets
│   └── demo/                    # Demo runner + benchmark
├── tests/
│   ├── cpp/                     # 13 C++ unit tests
│   └── ts/                      # 9 TypeScript integration tests
├── tools/usd/                   # OpenUSD sample stage + Python inspector
├── docs/                        # Architecture, decisions, workflow
└── .github/workflows/           # CI: build + test (ubuntu + macos)

Pipeline Stages

Processing order matches a physical film workflow:

Stage Description Complexity
ToneMap Exposure compensation + Reinhard tone mapping O(pixels)
ColorGrade Lift/Gamma/Gain per channel + saturation O(pixels)
Halation Bright extraction + separable Gaussian blur + warm tint blend O(pixels * radius)
Bloom Similar to halation, wider kernel, neutral tint O(pixels * radius)
Grain Per-channel Perlin noise with luminance-dependent response O(pixels * octaves)

Benchmark

npm run bench

Sample output (Apple M-series, Release build):

Resolution  | ToneMap  | ColorGrade | Halation  |    Bloom |    Grain |    Total
------------|----------|------------|-----------|---------|---------|----------
    128x128 |       17 |         56 |      1240 |    2100 |      598 |     4011
    256x256 |       62 |        218 |      5309 |    8690 |     2394 |    16674
    512x512 |      242 |        864 |     23108 |   36974 |     9340 |    70528
  1024x1024 |      971 |       3398 |    103224 |  169430 |    37766 |   314791
  2048x2048 |     3920 |      13600 |    420000 |  680000 |   152000 |  1269520

Halation and Bloom scale with O(pixels * blur_radius) due to the Gaussian kernel. ToneMap, ColorGrade, and Grain scale linearly with pixel count.

TS-to-C++ Boundary Rules

  1. C++ owns all pixel data. JS never holds raw image pointers.
  2. Config crosses as plain objects. No prototypes, no class instances.
  3. Images stay in C++. Only timing data and metadata come back to JS.
  4. Export via PPM. Simple, dependency-free output format.
  5. Validation in TypeScript. Native code asserts but trusts the binding layer.

Presets

The TypeScript wrapper includes convenience presets:

pipe.presetClean();        // neutral digital look
pipe.presetFilmClassic();  // warm grain, subtle halation
pipe.presetVintage();      // heavy grain, strong halation, desaturated

OpenUSD

tools/usd/ contains a minimal .usda stage and a Python inspector. See tools/usd/README.md for USD concepts and how they relate to engine asset pipelines.

Documentation

License

MIT

About

C++ film simulation pipeline engine - sanitized core showcase from Impossible Labs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors