Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Processing in Rust

First we start by creating the rendering functionality. We create a lib.rs file. This will expose a C function that the Nuke plugin can link to. This C function receives the ImagePlaneBuffer data, and calls the DCC Oxidizer functionality to translate that buffer data into a Rust native Image object. From that point on, you can do all the processing in Rust to how you'd like to do it. After that, the data is send back to Nuke, where it can finish the rendering.

As a starting point, it is recommended to use the example for Nuke. This contains the bare minimum code to start writing your image processing functionality.

If you want to do everything from scratch, please read the Create build.rs as well.

The Rust code:

#![allow(unused)]
fn main() {
use dcc_oxidizer::buffers::{converter::Converter, nuke::ImagePlaneBuffer};
use image::Rgba32FImage;
use libc::size_t;
use rayon::prelude::*;

#[unsafe(no_mangle)]
/// Render provided stripe from Nuke and modify provided buffer.
pub unsafe extern "C" fn render(
    buffer: *mut ImagePlaneBuffer,
    width: size_t,
    height: size_t,
    current_y_position: size_t,
) {
    let buffer_ref = unsafe {
        if buffer.is_null() {
            return;
        }
        buffer.as_mut().unwrap()
    };

    // In real scenarios make sure to handle the errors properly, as this will cause a panic if it fails.
    let mut processing_image: Rgba32FImage = unsafe { buffer_ref.get_image().unwrap() };

    processing_image
        .par_enumerate_pixels_mut()
        .for_each(|(x, y, pixel)| {
            pixel[0] = pixel[0] * 0.5 + x as f32 / width as f32;
            pixel[1] = pixel[1] * 0.5 + (current_y_position as f32 + y as f32) / height as f32;
        });

    unsafe {
        buffer_ref.apply_image(processing_image).unwrap();
    }
}
}

Basically the code does 4 things:

  1. Receive the ImagePlaneBuffer from Nuke.
  2. Convert the ImagePlaneBuffer into a native Rust Image object.
  3. Perform some image processing (just a simple UV overlay example).
  4. Copy the processed Image back into Nuke ImagePlane format.

Error handling

In a production ready scenario you would need to cover error handling as well. One possible way to do so is send send a CString back to Nuke. If the CString is empty, no error occured. If the ptr is not null, then call the Op::Error with the data to show to the user.

Also keep in mind that Nuke might abort the render while the render is still running. In this case you would need to make the abort() boolean available to Rust, and adjust the logic for rendering to abort when this is true. For the scope of simplicity this is not handled in this code.

Rayon

Optionally, I used Rayon in this example. Not really necessary for this UV example. It allows for multithreaded rendering with the Image crate. But as you are probably doing something more advanced than simple UV calculations, it is probably worth to do it this way.

Build

If you haven't used the default example, please read the Create build.rs file first.