Skip to content
José Carlos edited this page May 4, 2026 · 6 revisions

plmctrl API

Documentation for the plmctrl C++ shared library. Function prototypes are defined in plmctrl.h; implementations live in plmctrl.cpp. Wrappers in other languages call these functions with light error handling.

The library supports two PLM types, auto-detected from the window dimensions you pass to SetPLMWindowPos:

Mode Resolution (N × M) Superpixel (rows, cols) Levels Bitpacked frame
VIS 1358 × 800 2 × 2 16 2N × 2M
NIR alpha sample 904 × 800 3 × 2 32 (3N+4) × 2M

Each bitpacked frame stores 24 holograms by spreading their bits across the R, G and B channels (8 bits each). The alpha channel is set to 255.


Display / UI control

StartUI

void StartUI(unsigned int number_of_frames)

Starts the display thread and opens the PLM debug window. Allocates internal storage for number_of_frames bitpacked frames (each frame holds 24 holograms).

unsigned int number_of_frames
// Maximum number of bitpacked frames stored in plmctrl's memory.

SetPLMWindowPos

void SetPLMWindowPos(int width, int height, int x0 = 0, int y0 = 0)

Sets the PLM window's physical pixel size and the screen-space top-left corner where it should be placed. The mode (VIS / NIR) is auto-detected from (width, height):

  • 1358 × 800 → VIS
  • 904 × 800 → NIR
int width    // Window width in pixels.
int height   // Window height in pixels.
int x0       // X coordinate of the window's top-left corner, in virtual desktop space.
int y0       // Y coordinate of the window's top-left corner, in virtual desktop space.
// Example: a 1080p main monitor with the PLM panel sitting to its right → (x0, y0) = (1920, 0).

SetWindowed

void SetWindowed(bool windowed_mode)

Switches between fullscreen-borderless on the target monitor and a regular movable window. Useful when debugging in another secondary monitor (not the PLM).

bool windowed_mode  // true = windowed, false = borderless fullscreen.

Sequence control

StartSequence

bool StartSequence(int number_of_frames)

Starts displaying the configured sequence from the beginning. number_of_frames must not exceed the value passed to StartUI. Returns true on success.

int number_of_frames  // Number of frames in the sequence to play.

SetFrameSequence

bool SetFrameSequence(unsigned long long* sequence, unsigned long long length)

Defines the playback order. sequence[i] is the index of the bitpacked frame to display in slot i. Returns false if length > number_of_frames (from StartUI).

unsigned long long* sequence  // Array of frame indices.
unsigned long long  length    // Number of entries in `sequence`.

SetPLMFrame

bool SetPLMFrame(unsigned long long offset = 0)

Selects which bitpacked frame is currently shown on the PLM. Returns false if offset is past the end of storage.

unsigned long long offset  // Frame index in plmctrl storage.

InsertPLMFrame

bool InsertPLMFrame(unsigned char* frame,
                    unsigned long long num_frames = 1,
                    unsigned long long offset     = 0,
                    int type                       = 0)

Copies num_frames bitpacked frames into plmctrl's storage starting at slot offset. The expected per-pixel layout depends on type:

unsigned char*     frame       // Pointer to source frame data, row-major.
unsigned long long num_frames  // Number of frames to insert.
unsigned long long offset      // Destination slot index in plmctrl storage.
int                type        // 0 = RGB (3 bytes/pixel), 1 = RGBA (4 bytes/pixel).

Each frame is width × height pixels, where width / height are the bitpacked-frame dimensions for the current PLM mode (see table at top).


Bitpacking

The bitpack functions take a stack of phase profiles in [0, 1) (representing [0, 2π)) and pack them into a single RGBA frame. CPU and GPU variants exist for both VIS and NIR. The GPU variants run a DirectX 11 compute shader (BitpackHologramsCS.hlsl for VIS, BitpackHologramsNIR_CS.hlsl for NIR) and are typically much faster.

BitpackHolograms (VIS, CPU)

bool BitpackHolograms(float* phase, unsigned char* frame,
                      unsigned long long N, unsigned long long M,
                      int num_holograms)
float*             phase          // N × M × num_holograms floats, row-major, normalised [0, 1).
unsigned char*     frame          // Output buffer, sized 4 × (2N) × (2M) bytes (RGBA).
unsigned long long N              // Phase profile width.
unsigned long long M              // Phase profile height.
int                num_holograms  // 1..24.

BitpackHologramsNIR (NIR, CPU)

bool BitpackHologramsNIR(float* phase, unsigned char* frame,
                         unsigned long long N, unsigned long long M,
                         int num_holograms)

Same as BitpackHolograms but produces the NIR (3N+4) × 2M output and uses the NIR per-column-parity LUT for quantization.

float*             phase          // N × M × num_holograms floats.
unsigned char*     frame          // Output buffer, sized 4 × (3N+4) × (2M) bytes.
unsigned long long N              // Phase profile width.
unsigned long long M              // Phase profile height.
int                num_holograms  // 1..24.

BitpackHologramsGPU (VIS, GPU)

bool BitpackHologramsGPU(float* phase, unsigned char* frame,
                         unsigned long long N, unsigned long long M,
                         int num_holograms,
                         bool same_phase)

Compute-shader version of BitpackHolograms.

float*             phase          // Phase profile data (see same_phase below).
unsigned char*     frame          // Output buffer, 4 × (2N) × (2M) bytes.
unsigned long long N              // Phase profile width.
unsigned long long M              // Phase profile height.
int                num_holograms  // 1..24.
bool               same_phase     // false: phase contains N × M × num_holograms floats (one per hologram).
                                  // true:  phase contains a single N × M frame, used for all holograms.
                                  //        Lets you skip the 24× allocation for uniform test patterns.

BitpackHologramsNIRGPU (NIR, GPU)

bool BitpackHologramsNIRGPU(float* phase, unsigned char* frame,
                            unsigned long long N, unsigned long long M,
                            int num_holograms,
                            bool same_phase)

Compute-shader version of BitpackHologramsNIR. Output is 4 × (3N+4) × (2M) bytes. same_phase works as for the VIS variant.


BitpackAndInsertGPU / BitpackAndInsertNIRGPU

bool BitpackAndInsertGPU(float* phase,
                         unsigned long long N, unsigned long long M,
                         int num_holograms,
                         unsigned long long offset,
                         bool same_phase)

bool BitpackAndInsertNIRGPU(float* phase,
                            unsigned long long N, unsigned long long M,
                            int num_holograms,
                            unsigned long long offset,
                            bool same_phase)

Convenience wrappers — equivalent to calling BitpackHologramsGPU / BitpackHologramsNIRGPU followed by InsertPLMFrame and SetPLMFrame. The bitpacked output is written into plmctrl's internal buffer at offset, and that frame is then displayed.

unsigned long long offset      // Destination slot in plmctrl frame storage.
// All other parameters as for the corresponding BitpackHolograms*GPU.

Phase-map calibration

The phase map controls how each quantized level drives the four (VIS) or six (NIR) sub-pixel electrodes of a superpixel. This is not really necessary with the default settings from the library. This was added before we knew the proper mapping, so we measured it and used the following functions to set it.

SetPhaseMap (VIS)

bool SetPhaseMap(int* new_phase_map)

Sets the VIS phase map: 16 levels × 4 cells = 64 ints ({0, 1}). Cell order per level follows the TI DLP6750 layout — [E3, E2, E1, E0]. Switches the library to VIS mode.

int* new_phase_map  // 64 ints, row-major (level then cell).

SetPhaseMapNIR (NIR)

bool SetPhaseMapNIR(int* new_phase_map)

Sets the NIR phase map: 32 levels × 6 cells = 192 ints ({0, 1}). Switches the library to NIR mode.

int* new_phase_map  // 192 ints, row-major (level then cell).

Direct PLM comms (LightCrafter)

These functions talk to the PLM's over USB. They are just a convenience to avoid using LightCrafter for configuring the PLM.

Note: these are only available in builds with INCLUDE_LIGHTCRAFTER_WRAPPERS defined.

Open / Close

int Open()
int Close()

Open or close the USB connection to the PLM. Most other comms calls require the device to be open.

Play / Stop

int Play()
int Stop()

Start / stop the PLM's pattern sequence on the device side (independent of the host display thread).

SetSource

int SetSource(unsigned int source, unsigned int portWidth)

Selects the input source (e.g. parallel RGB, FPD-Link) and the input port bus width.

SetPortSwap

int SetPortSwap(unsigned int port, unsigned int swap)

Configures port-swap settings on the input bus.

SetPortConfig / SetConnectionType

int SetPortConfig(int connection_type)
int SetConnectionType(int connection_type)

Configure the data port / connection type.

SetVideoPatternMode / GetVideoPatternMode

int SetVideoPatternMode()
int GetVideoPatternMode()

Switches the PLM into Video Pattern mode (required for 24×-bitpacked playback) and reads the current mode back.

GetConnectionType

int GetConnectionType()

Returns the currently configured input connection type.

UpdateLUT

int UpdateLUT(int play_mode, int connection_type)

Pushes the LUT/sequence configuration to the controller for the given play mode and connection type.