LibGDX: Dynamic Textures with Pixmap

Also shader masks!

While poking around with some shader techniques, I got curious about how I could generate a texture at run-time based on some arbitrary (a.k.a. user) input and use that to do fun things in the shader. As it turns out, LibGDX has a class called Pixmap which is a good fit for the task.

Pixmap provides an in-memory, modifiable image. It exposes methods to draw shapes and images onto the Pixmap, so you can think of it as a blank canvas of pixels. Pixmap is, under the covers, a flat array of color data for each pixel. It lets you define the format of that array. Pixmap.Format.RGBA8888, for example, means each pixel has four color components (red, green, blue, and alpha; in that order) and each color is represented as a single byte. Pixmap.Format.Alpha on the other hand uses just a single byte per pixel to represent its transparency value. If the various format options are confusing to you, you can probably stick with one of the two I've listed. Or if you're loading a Pixmap from an image, it deals with the format for you.

The other thing to keep in mind is that you will have to manually dispose of the Pixmap when you're done with it, since the memory it uses is not garbage collected (it's off-heap).

With this in mind I created a demo game in which an image is initially hidden (transparent) and is revealed by "scribbling" over the window with the left mouse button.

DrawingGame in all its glory!

The basic concept is to use a Pixmap to create a mask—anywhere the Pixmap is transparent, the rendered image will be transparent; anywhere it's opaque, the rendered image will be opaque. I 'draw' on the Pixmap using mouse input. A custom fragment shader will receive two textures: the standard texture from a regular old SpriteBatch and our mask texture (which I update when the Pixmap changes). The fragment shader simply multiplies the fragment's usual alpha with our mask alpha. Good to go!

So this really demonstrates two concepts: 1) a dynamically created texture using Pixmap, and 2) passing multiple textures to a shader to do funky things. One ancillary detail is that the mouse input needs to be linearly interpolated ("lerped") when dragging the mouse around or else you just get a spinkling of dots instead of a nice paint brush effect. Entire code listing below with (hopefully sufficient) commenting.

This is basically just the default vertex shader. Nothing to change here.

The fragment shader where the mask texture is applied.

And our two images: smiley-outline.png and smiley-color.png.

Smiley outline

Smiley color