Rendering large filmstrips

I’m currently having a couple problems implementing an animated background class (see below). My intuition is telling me that if im getting this many errors I’m probably doing something wrong and should step back and redo stuff.

A client im working with is looking for an animated background in their plugin. I made and rendered something in blender and have a folder of png files for every frame (128 frames in total).

Each frame is a 2000 x 1200 px image, which (after compression) results in a sprite sheet around 100MB

My current implementation is based on my personal implementation of filmstrip sliders, but minus all the slider stuff.

#pragma once

#include <juce_gui_basics/juce_gui_basics.h>

class AnimatedBackground : public juce::ImageComponent
{
public:
    AnimatedBackground() : juce::ImageComponent ("AnimatedBackground")
    {
		if (BinaryData::sprite_sheet_png != nullptr && BinaryData::sprite_sheet_pngSize > 0){
			auto loadedImage = juce::ImageCache::getFromMemory (BinaryData::sprite_sheet_png, BinaryData::sprite_sheet_pngSize);
			
			if (loadedImage.isValid()){
				image = loadedImage;
				jassert(image.isValid());
				setImage (image);
			} else {
				DBG("Failed to load img from mem");
			}

		} else {
			DBG("Image is cooked, fix it");
		}
	
		updateFrameNumber(0);
    }
	
    ~AnimatedBackground()
    {
	}
	
	void paint (juce::Graphics& g) override
	{
		// Draw the current frame of the animation
		// draw a frame of the background image using the current frame number
		int frameX = currentFrame % framesPerRow;
		int frameY = currentFrame / framesPerRow;

		g.drawImage (
			image,
			0,
			0,
			getWidth(),
			getHeight(),
			frameX * FRAME_WIDTH,
			frameY * FRAME_HEIGHT,
			image.getWidth(),
			image.getHeight() / image.getWidth()
		);
	}

	// change the number of frames used for the bg image, update frame height too
	void updateNumFrames(int numFrames){
		_numFrames = numFrames;
		FRAME_HEIGHT = image.getHeight() / numFrames;
	}
	
	// update the frame that should be rendered then repaint 
	void updateFrameNumber(int frame)
	{
		currentFrame = frame;
		if (currentFrame < 0) currentFrame = 0;
		if (currentFrame >= image.getHeight()) currentFrame = image.getHeight() - 1;

		// Update the image to the current frame
		repaint();
	}


    private:
        juce::Image image;
		int currentFrame = 0;
		int FRAME_WIDTH = 2000;
		int FRAME_HEIGHT = 1200;
		int framesPerRow = 16;
		int _numFrames;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimatedBackground)
};

Please excuse the messy code lol, it’s been powered by caffeine and a little lack of sleep.

I would greatly appreciate some input about my code, wether or not this method is a ‘best practice’ or even close to it, and if its absolute sh*t, a better way to implement something like this.

The thing i would like to avoid is OpenGL / Rendering things in the plugin real time.

I want to avoid burdening the end users PC with too much since the actual models i would have to render are too high-poly to expect every computer to support them.

To the people who’ve read all of this mess, thank you <3

The compressed size doesn’t really matter since the image will be uncompressed when you load it. 2000 x 1200 pixels x 128 frames x 4 bytes = 1.14 GB of RAM just for this animation. That seems excessive.

For an animation this size it might be better to save it as a video and play that.

1 Like

mm ok ok ok that makes sense.

I’ve been able to get this somewhat working by segmenting the filmstrip and loading it as i need it, but i might look into that video idea.

I’ve also just lowered the source resolution, im going to hope that it doesnt affect the appearance of the UI too much, but i guess we’ll see!

Direct2D loads images onto the GPU, which has a limit to the maximum image dimensions. It can vary, but you might experience some GPUs rejecting images that have any dimension greater than approximately 7000 pixels.

1 Like

Thanks for that! I spent way too much time fiddling with how much i could load XD

JUCE has virtual texture support for read-only images to surpass these limits.

2 Likes