Applying a texture to a rectangle

I’m trying to apply a jpg texture to a rectangle.
This is my main code:

    ofiOSWindowSettings settings;
    settings.enableRetina = true; // enables retina resolution if the device supports it.
    settings.enableDepth = true; // enables depth buffer for 3d drawing.
    settings.enableAntiAliasing = true; // enables anti-aliasing which smooths out graphics on the screen.
    settings.numOfAntiAliasingSamples = 2; // number of samples used for anti-aliasing.
    settings.enableHardwareOrientation = false; // enables native view orientation.
    settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated.
    settings.glesVersion = OFXIOS_RENDERER_ES2; // type of renderer to use, ES1, ES2, ES3
    settings.windowControllerType = ofxiOSWindowControllerType::GL_KIT; // Window Controller Type
    settings.colorType = ofxiOSRendererColorFormat::RGBA8888; // color format used default RGBA8888
    settings.depthType = ofxiOSRendererDepthFormat::DEPTH_24; // depth format (16/24) if depth enabled
    settings.stencilType = ofxiOSRendererStencilFormat::STENCIL_NONE; // stencil mode
    settings.windowMode = OF_FULLSCREEN;
    settings.setupOrientation = OF_ORIENTATION_90_RIGHT;
    settings.enableMultiTouch = true; // enables multitouch support and updates touch.id etc.
    ofCreateWindow(settings);

This is how my setup code looks:

ofSetOrientation(OF_ORIENTATION_90_RIGHT);
ofSetFrameRate(60);

ofDisableArbTex();
backgroundTexture.enableMipmap();
ofLoadImage(backgroundTexture, "earth.jpg");
backgroundTexture.generateMipmap();

This is my draw code:

ofPushMatrix();
    
        backgroundTexture.bind();
        ofSetColor(0, 0, 0);
        ofDrawRectangle(10, 10, 700, 700);
        
        backgroundTexture.unbind();

ofPopMatrix();

The only thing I can see drawn is a black rectangle and I’m not sure why.

Thanks for any pointers!

ofDrawRectangle is probably not what you want since there’s not “texture” information in the vertices.

also when you set the draw color to 0, you are tinting the pixels, all images will look black since any color tinted black is black

you can use a mesh to draw and add texture info

ofSetColor(255);
ofMesh m;
m.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);
m.addVertex(…);
m.addTextureCoordinate(…);
m.addVertex(…);
m.addTextureCoordinate(…);
m.addVertex(…);
m.addTextureCoordinate(…);
m.addVertex(…);
m.addTextureCoordinate(…);
backgroundTexture.bind();
m.draw();
backgroundTexture.unbind();

note that for the texture coordinate I usually do something like

m.addTextureCoordinate(backgroundTexture.getTexture().getCoordForPct(…) );

getCoordForPct or getCoordForPoint can help you out a lot

ps this is a complicated way to draw an image – I wonder if you can do this? (I don’t have a lot of experience with mipmaps, but just thinking of a simpler way)

in h:

ofImage img;

in setup:

ofDisableArbTex();
img.getTexture().enableMipmap();
img.load(“earth.jpg”);
img.getTexture().generateMipmap();

in draw:

img.draw(10,10,700,700);

Here is also a handy convenience function in case you want to use mesh anyway:

static ofMesh rectMesh(float x, float y, float w, float h, bool normalized)
{
	ofMesh mesh;
	mesh.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);

	mesh.addVertex(ofVec3f(x, y));
	mesh.addTexCoord(ofVec2f(0, 0));

	mesh.addVertex(ofVec3f(x + w, y));
	mesh.addTexCoord(ofVec2f(normalized ? 1 : w, 0));

	mesh.addVertex(ofVec3f(x, y + h));
	mesh.addTexCoord(ofVec2f(0, normalized ? 1 : h));

	mesh.addVertex(ofVec3f(x + w, y + h));
	mesh.addTexCoord(ofVec2f(normalized ? 1 : w, normalized ? 1 : h));

	return mesh;
}

In your case:

ofMesh m = rectMesh(10, 10, 700, 700, true); // ofDisableArbTex() normalized texture coordinates so normalized = true
2 Likes

thx @lshoek that’s super handy !

Thanks for the great information guys. Using the helper function from @Ishoek I’ve got the texture to display, but now have a new problem.

If the texture isn’t a power of 2 I’m getting black border around the right and bottom sides of it. See screenshot.

setup:

ofDisableArbTex();

backgroundTexture.enableMipmap();
ofLoadImage(backgroundTexture, “test.jpg”);
backgroundTexture.generateMipmap();

npotBackgroundTexture.enableMipmap();
ofLoadImage(npotBackgroundTexture, “test-npot.jpg”);
npotBackgroundTexture.generateMipmap();

draw:

backgroundTexture.bind();
ofMesh m = MeshHelpers::rectMesh(0, 0, backgroundTexture.getWidth(), backgroundTexture.getHeight(), true);
m.draw();
backgroundTexture.unbind();

npotBackgroundTexture.bind();
ofMesh m2 = MeshHelpers::rectMesh(600, 600, npotBackgroundTexture.getWidth(), npotBackgroundTexture.getHeight(), true);
m2.draw();
npotBackgroundTexture.unbind();

Got this all working by just drawing the texture directly, but I’m still interested why it exhibits this behavior if anyone can explain. Thanks!

Nice that you solved it!

The npot texture (w/ mipmapping enabled) displays fine on my system in an empty app with a default main(). Therefore, I think this issue has to do with your window settings and more specifically iOS/GLES2. Did you try disabling mipmaps for the npot texture? This post might shed some light on the issue. (I’m on Windows so I don’t know if this still holds true)

for non power of two textures, when you disable ARB they have will have padding since they are stored in in a the smallest power of 2 which can hold the data, which means the rectMesh needs to be fixed to account for that. For example, an image which is 100x200 will be stored in a texture which is 128x256, so some padding (28 pixels in x, 56 pixels in y). Right now, the rectMesh assumes that your texture is full of data since it sets the texture coordinate to (1 or h) for height and (1 or w) for width.

That’s why I recommend using a function like this:

backgroundTexture.getTexture().getCoordForPct(0,1);

since it knows about the padding and will account for it. In the rectMesh function it assumes your texture is all data / no padding.

2 Likes

Ah interesting. I haven’t encountered this padding issue before so sorry for any confusion I may have caused. Here is a fix:

static ofMesh rectMesh(float x, float y, float w, float h, const ofTexture& tex)
{
	ofMesh mesh;
	mesh.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);

	mesh.addVertex(ofVec3f(x, y));
	mesh.addTexCoord(tex.getCoordFromPercent(0, 0));

	mesh.addVertex(ofVec3f(x + w, y));
	mesh.addTexCoord(tex.getCoordFromPercent(1, 0));

	mesh.addVertex(ofVec3f(x, y + h));
	mesh.addTexCoord(tex.getCoordFromPercent(0, 1));

	mesh.addVertex(ofVec3f(x + w, y + h));
	mesh.addTexCoord(tex.getCoordFromPercent(1, 1));

	return mesh;
}
2 Likes

Thanks for the responses, that’s really useful information to know. I’m starting to dust off my old OpenGL knowledge and making some good progress on my app. Thanks for the pointing me in the right direction with the textures.