Brainstorming a 16bit LED mapper

Hi there! I’m new here but stumbled across this awesome framework from the Processing world and Kotlin.

Recently, I’ve been deep into 16 bit LED strips and chips, and have worked on some pretty amazing projects that take advantage of their advanced lighting capabilities to create liquid/organic light not achievable with traditional 8bit LED fixtures and chips.

I’m a big fan of the Processing and P5.js creative coding platforms and wanted to work on some tools to make it easier to export parts of the canvas to LED strips to facilitate more rapid lighting experiments. This is fairly straight forward with Processing (call loadPixels() and navigate the pixels array).

Checking out OPENRNDR’s API, it appears there’s support for scalable color data by storing the rgb values in doubles out of the box (Processing you need to change the colorMode, but is there)

This leads me to my question - how would one attempt to extract the color information from the draw window during execution, inside the extend block? Is there an equivalent function to loadPixels() that returns values in the ColorRGBa format that I’m missing? I would want to preserve the raw double values for each hue so I can then map to 16 bit LED strips. For reference, 16 bit LED strips store 65k levels of brightness for each color/channel, so this would represent 48 bit RGB color in the graphics context, I think…

Hi @octobeard ! Welcome to the forum :slight_smile:

This section of the guide is related to what you are looking for:

I think what you want is possible. Here I created a simple program that draws a 1000 pixel wide gradient from black to white. It does so in 32 bits. Then I print the red component of 1000 pixels on a horizontal line. The printed values have 1000 unique values, which is not the case if you switch to ColorType.UINT8.

import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.ColorType
import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget
import org.openrndr.extra.shadestyles.linearGradient
fun main() = application {
    configure {
        width = 1000
        height = 200
    }

    program {
        // Like a Processing PGraphics
        val rt = renderTarget(width, height) {
            colorBuffer(type = ColorType.FLOAT32)
        }

        // Draw a gradient into rt
        drawer.isolatedWithTarget(rt) {
            shadeStyle = linearGradient(ColorRGBa.BLACK, ColorRGBa.WHITE, rotation = 90.0)
            stroke = null
            rectangle(bounds)
        }

        val shadow = rt.colorBuffer(0).shadow
        // loadPixels
        shadow.download()

        repeat(width) { x ->
            println("$x -> ${shadow[x, 100].r}")
        }

        extend {
            drawer.image(rt.colorBuffer(0))
        }
    }
}

Okay interesting - I was looking at the color buffer objects and they seemed a bit heavy weight at first glance. Hopefully this is something that won’t undermine the performance of existing sketches too much if I was to integrate an easy to use library on top to enable the mapping of this data. I’ll check this out!

So checking your example here, the only way to do this is to do all rendering inside a render target. There’s no way to easily grab this information globally? For personal projects, this is probably not a big deal, as I’d make sure all draw ops use the isolatedWithTarget modifier, but for integrating an approach across generic OPENRNDR sketches it looks like this wouldn’t work out of the box - you’d need to restructure them to only render to the target instead…

Is one of your concerns performance? I don’t have any issues using RenderTargets and ColorBuffers in my 10 year old laptop…

If you want to be able to easily forward any programs output to the LED strip what you could do is to create an extension, like Screenshots() or ScreenRecorder(). Then with adding just one line in your programs you could be sending content to your LED strip. As in extend(StreamToLED()).

The Screenshots extension, as an example, takes care of creating an RenderTarget and saving it to disk. Here’s its code:

Here’s how to write extensions:

If this might be useful in your case I can help you write it.

Very much appreciate this input. I’ll look into trying to do this myself, but I’ll absolutely tap you for some feedback when I have something working or if I hit any dead ends! An extension makes the most sense after looking more deeply into the architecture.