setUniformTexture from a vector of of Images

Something weird is happening to me on Monday morning.
My problem is, I have a class called “ImageResource” containing a vector of ofImages, and I want to pass one of those images to a shader in my ofApp.

This is the ImageResource class header.

#pragma once
#include "ofMain.h"

class ImageResources
{
public:
    ImageResources();
    void update();
    void setup(); // this is just for test
    ofImage getCurrentImageColor();

    // Images
    vector<ofImage> imageColors;
    ofImage activeImg;
    int textureIndex;
}

Implementation


#include "ImageResources.h"
ImageResources::ImageResources(){}

void ImageResources::setup(){
    // ...
    // fill the imageColors vector
    // ...
    imgIndex = 0;
    activeImg = imageColors.at(imgIndex);
}

void ImageResources::update(){
    // imgIndex may change.
}

ofImage ImageResources::getCurrentImageColor(){
    return imageColors[textureIndex];
}

In my ofApp class I am simply going to use the ImageResources as follow:

        damShader.begin();
        ;
        damShader.setUniformTexture("damImage", imageResources.getCurrentImageColor().getTexture(), 0);
        plane.draw();
        damShader.end();

With a wrong result, it looks like the texture got passed empty:

If I pass the texture as follows:

        damShader.begin();
        ;
        damShader.setUniformTexture("damImage", imageResources.activeimg.getTexture(), 0);

        plane.draw();
        damShader.end();

It works.

I have already tried to see if getCurrentImageColor() was not returni any image, but if I draw it to the screen using getCurrentImageColor().getTexture(0,0) it works.

I have tried to return the ofImage by reference, using

ofImage const & ImageResources::getCurrentImageColor(){
    return imageColors[imgIndex];
};

but the error still persists. Any idea?

Sure im wrong, but are you sure that here are you returning a reference image?

ofImage const & ImageResources::getCurrentImageColor(){
    return imageColors[imgIndex];
};

but the error still persists. Any idea?
ofImage const & ImageResources::getCurrentImageColor(){
    return & imageColors[imgIndex];
};

but the error still persists. Any idea?

This does not work, error:
/OF/of_v20190324_linux64gcc6_release/apps/myApps/test/src/ImageResources.cpp:16: error: reference to type 'const ofImage' (aka 'const ofImage_<unsigned char>') could not bind to an rvalue of type '__gnu_cxx::__alloc_traits<std::allocator<ofImage_<unsigned char> > >::value_type *' (aka 'ofImage_<unsigned char> *')

Do you think it is something related to the fact that I am not passing the variable correctly?

I think that you are passing a copy of the image… but im not an expert

Why it has to be a const method?

ofImage & ImageResources::getCurrentImageColor(){
    return & imageColors[imgIndex];
};

It looks like it needs to be a const:

/src/ImageResources.cpp:20: error: invalid initialization of non-const reference of type ‘ofImage& {aka ofImage_<unsigned char>&}’ from an rvalue of type ‘__gnu_cxx::__alloc_traits<std::allocator<ofImage_<unsigned char> > >::value_type* {aka ofImage_<unsigned char>*}’
     return & imageColors.at(textureIndex);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Seems i was wrong and this is returning a reference, do not know why it has to be const

ofImage const & ImageResources::getCurrentImageColor(){
    return imageColors[imgIndex];
};

Hi, That function looks wrong to me.
The const keyword should not be there.
The following will return a reference to the image in the vector

ofImage & ImageResources::getCurrentImageColor(){
    return imageColors[imgIndex];
};

If you want to make it const you can do it like

const ofImage & ImageResources::getCurrentImageColor() const{
    return imageColors[imgIndex];
};

you can have both methods declared and the compiler chooses which one is the most suited.

Yes, but as I have said before, this does not solve the problem. It looks like the texture is corrupted or not loaded at all.

I did some more test and basically what I see is that in order to have a vector of ofImages, from which you can pick a texture and set it as uniform for a shader, that vector has to be in ofApp.h.
If you put it in another class it is not working. @arturo do you have some hints about this behaviour? I can put all my images in the ofApp class, but it requires a bit of refactoring and I would like to avoid it.

It sounds like you might be destroying the images before using them but not sure where.

I think you are right, I made a test app to try to replicate the issue and it is not happening, the textures are displayed as expected. How could I inadvertently destroy a texture?
I am using textures from a vector of images in a ping-pong fbo:

    updateCol.setUniformTexture("posData", posPingPong.src->getTexture(), 1);  // passing the position information
    updateCol.setUniformTexture("colImage", testImages[1].getTexture(), 2); //broken, texture is not displayed

Probably by copying it somewhere else, in your first example you were copying the image which would be really slow but should work i think but something like that where you copy an image and destroy the original after having set the uniform in the shader could have that effect

Also try using something like renderdoc to see what’s going on in the shader

I see. This is the application test that is currently working:

ImageManager.hpp

#pragma once

#include "ofMain.h"

class ImageManager{
public:
    ImageManager(){};
    vector<ofImage> images;

    void setup(){
        ofImage img1;
        ofImage img2;
        ofImage img3;
        ofImage img4;

        img1.load("moto.jpeg");
        img2.load("trees.jpeg");
        img3.load("veggie.jpeg");
        img4.load("water.jpeg");

        images.push_back(img1);
        images.push_back(img2);
        images.push_back(img3);
        images.push_back(img4);
    }

    ofImage const & getCurrentImageByIndex(int idx){
           return images[idx];
    }

};

ofApp.h

#pragma once

#include "ofMain.h"
#include "ImageManager.hpp"

class ofApp : public ofBaseApp{

public:
    void setup();
    void update();
    void draw();
    void keyPressed(int key);

    ofShader shader;
    ofPlanePrimitive plane;
    vector<ofImage> imagesFromApp;
    ImageManager imageManager;
    bool imagesFromImageManager = false;
};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofDisableArbTex();
    plane.set(ofGetWidth(), ofGetHeight());
    plane.setPosition(ofGetWidth()/2, ofGetHeight()/2, 0);

    shader.load("shaders_gl3/passthru.vert", "shaders_gl3/color.frag");

    ofImage img1;
    ofImage img2;
    ofImage img3;
    ofImage img4;

    img1.load("moto.jpeg");
    img2.load("trees.jpeg");
    img3.load("veggie.jpeg");
    img4.load("water.jpeg");

    imagesFromApp.push_back(img1);
    imagesFromApp.push_back(img2);
    imagesFromApp.push_back(img3);
    imagesFromApp.push_back(img4);

    imageManager.setup();
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    auto index = int(ofGetElapsedTimef()) % imagesFromApp.size();

    shader.begin();
    if(imagesFromImageManager){
        shader.setUniformTexture("uTex0", imageManager.getCurrentImageByIndex(index).getTexture(), 0);
    }       else {
        shader.setUniformTexture("uTex0", imagesFromApp[index].getTexture(), 0);
    }

    plane.draw();
    shader.end();

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if(key == 'm'){
        imagesFromImageManager = !imagesFromImageManager;
    }
}

When you say that “you were copying the image which would be really slow” you mean that my original method:

ofImage ImageResources::getCurrentImageColor(){
    return imageColors[textureIndex];
}

was returning a copy and not a reference, correct?

I will make some comparison test with render doc between the broken app and the working one.

Ok, it looks like ofDisableArbTex it was called after loading the textures. Thanks for the support to all of you :wink: