Tiled textured quads


I’m trying to draw a textured quad which has a tiled texture, but when I set my uv coords to >textureSize it doesn’t wrap the texture.

I tried doing this

	GLenum textureTarget = (GLenum)m_texture.getTextureTarget();  
	glTexParameterf(textureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);			// wrap U  
	glTexParameterf(textureTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);			// wrap V  
	glTexParameteri(textureTarget,GL_TEXTURE_MAG_FILTER,GL_NEAREST);		// turn antialias to ¨nearest neigbour¨  
	glTexParameteri(textureTarget,GL_TEXTURE_MIN_FILTER,GL_NEAREST);		// same again  

prior to glbegin, but it didn’t seem to work,

any ideas how I can do this?



What you have is the first part of doing repeated textures.

The second part is adjusting the texCords in the draw function

glBegin( GL_QUADS );  
			glTexCoord2f(tx0,ty0);			glVertex3i(px0, py0,0);  
			glTexCoord2f(tx1,ty0);			glVertex3i(px1, py0,0);  
			glTexCoord2f(tx1,ty1);			glVertex3i(px1, py1,0);  
			glTexCoord2f(tx0,ty1);			glVertex3i(px0, py1,0);  

The glTexCoord2f tells openGL how to map the bitmap image onto the polygon (in our case it is just a quad/rectangle). A number of 0.0 means where the image starts. A number of 1.0 means where the image ends. You can of course go over and put in 2.0 or 3.0 - to mean show the image 3 times in this direction.

Because we are calculating the image to fit exactly onto the rectangle you don’t see any repeating action but if we said that ty1 was to be 2.0 then you would see the texture repeated twice in the vertical direction.

We are doing some other stuff with the texture coords - which is why you don’t just see

glTexCoord2f(0.0, 0.0);
glTexCoord2f(1.0, 0.0);


But you might try just multiplying some by 2 or 3 and see what happens.

glTexCoord2f(tx1, ty1*2);
glTexCoord2f(tx0, ty1*2);

Hi Theo

thanks for your advice, much appreciated.

I was trying what you suggested already though and it doesn’t behave as expected. heres what I have

#define img_width  32  
#define img_height 32  
#define img_depth   3  
// in testApp:: setup()  
tex.allocate(img_width, img_height, GL_RGB);  
tex.loadData(pixelData, img_width, img_height, GL_RGB);  
// in testApp::draw()  
glTexParameterf(tex.getTextureTarget(), GL_TEXTURE_WRAP_S, GL_REPEAT);  
glTexParameterf(tex.getTextureTarget(), GL_TEXTURE_WRAP_T, GL_REPEAT);  
glBegin( GL_QUADS );   
glBindTexture (tex.getTextureTarget(), tex.getTextureName());  
glTexCoord2f(0.f,  0.f);      glVertex3i(100.f,        100.f, 0);   
glTexCoord2f(32.f, 0.f);      glVertex3i(100.f + 64.f, 100.f, 0);   
glTexCoord2f(32.f, 64.f);     glVertex3i(100.f + 64.f, 100.f + 64.f, 0);   
glTexCoord2f(0.f,  64.f);     glVertex3i(100.f,        100.f + 64.f, 0);   

As you described I would expect my Texture to tile twice in the vertical direction. But instead it halves in size in the vertical direction, as expected, but the 2nd half of the quad contains the bottom edge of the texture stretched across the remainder of the image…

I’ve attached an example to illustrate what I mean

i’ve noticed that if I comment out the following in ofTexture.cpp

	textureName[0] = 0;  
	bFlipTexture = false;  
//	if (GLEE_ARB_texture_rectangle){  
//		textureTarget = GL_TEXTURE_RECTANGLE_ARB;  
//	} else {  
		textureTarget = GL_TEXTURE_2D;  
//	}  

which returns my texture coordinates to a conventional 0 - 1.0 scheme, then tiling works correctly again, so its something to do with the GLEE_ARB_texture_rectangle approach. is there a clean way for me to specify that new ofTextures should use the GL_TEXTURE_2D approach rather than commenting it out of ofTexture.cpp?



I think I can see what your problem is.

glTexCoord2f expects the values to be in percent of the image not number of pixels.

so that means a range of 0.0 to 1.0 represents the whole image.

a tex coordinate of 32.0f means 32 times the width of the image!

so I think what you are after is this.

glBindTexture (tex.getTextureTarget(), tex.getTextureName());   
glTexCoord2f(0.f,  0.f);      glVertex3i(100.f,        100.f, 0);   
glTexCoord2f(1.0f, 0.f);      glVertex3i(100.f + 64.f, 100.f, 0);   
glTexCoord2f(1.0f, 2.0f);     glVertex3i(100.f + 64.f, 100.f + 64.f, 0);   
glTexCoord2f(0.f,  2.0f);     glVertex3i(100.f,        100.f + 64.f, 0);   

oh - I see.
yeah that makes sense.

if you would prefer to use openGL without GLEE_ARB_texture_rectangle then you could just comment it out - or maybe make your own texture class that extends off of ofTexture - might be good anyway if you are looking to do the repeat stuff to.

something like:

#include "ofMain.h"  
class myTextureClass : public ofTexture{  
       //your new methods   
       //and your overiden functions here         

when using textures which have been created with a texture target of textureTarget = GL_TEXTURE_2D then what you have suggested is true, but by default my machine creates textures using the textureTarget = GL_TEXTURE_RECTANGLE_ARB approach, which requires uv coords to be specified in terms of texture width in pixels, if you exceed the actual texture width then it clamps the texture at the edge as shown in the image i attached above.

ok got ya, thanks for the advice, much appreciated :slight_smile:


i was just trying to do something similar and built a subclass for ofTexture which does just this:


#ifndef _TILED_TEXTURE_H_  
#define _TILED_TEXTURE_H_  
#include "ofMain.h"  
class ofxTiledTexture : public ofTexture {  
	public :  
        void    allocate(int w, int h, int internalGlDataType);  
        void    allocate(int w, int h, int internalGlDataType, bool smooth);  
        void    draw(float x, float y, float w, float h, float p, float q);          


#include "ofxTiledTexture.h"  
void ofxTiledTexture::allocate(int w, int h, int internalGlDataType) {  
    allocate(w, h, internalGlDataType, true);  
void ofxTiledTexture::allocate(int w, int h, int internalGlDataType, bool smooth) {  
	// 	can pass in anything (320x240) (10x5)  
	// 	here we make it power of 2 for opengl (512x256), (16x8)  
	if (GLEE_ARB_texture_rectangle){  
		tex_w = w;  
		tex_h = h;  
	} else {  
		tex_w = ofNextPow2(w);  
		tex_h = ofNextPow2(h);  
	if (GLEE_ARB_texture_rectangle){  
		tex_t = w;  
		tex_u = h;  
	} else {  
		tex_t = 1.0f;  
		tex_u = 1.0f;  
	// attempt to free the previous bound texture, if we can:  
	glGenTextures(1, (GLuint *)textureName);   // could be more then one, but for now, just one  
    glBindTexture(textureTarget, (GLuint)textureName[0]);  
    glTexImage2D(textureTarget, 0, internalGlDataType, tex_w, tex_h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);  // init to black...  
    glTexParameterf(textureTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);  
    glTexParameterf(textureTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);  
    if (smooth) {  
        glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    
        glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   
    } else {  
        glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);   
        glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
	width = w;  
	height = h;  
	bFlipTexture = false;  
void ofxTiledTexture::draw(float x, float y, float w, float h, float p, float q) {  
	// bind the texture  
	glBindTexture( textureTarget, (GLuint)textureName[0] );  
    GLint px0 = 0;		// up to you to get the aspect ratio right  
    GLint py0 = 0;  
    GLint px1 = (GLint)w;  
    GLint py1 = (GLint)h;  
    if (bFlipTexture == true){  
        GLint temp = py0;  
        py0 = py1;  
        py1 = temp;  
    // for rect mode center, let's do this:  
    if (ofGetRectMode() == OF_RECTMODE_CENTER){  
        px0 = (GLint)-w/2;  
        py0 = (GLint)-h/2;  
        px1 = (GLint)+w/2;  
        py1 = (GLint)+h/2;  
    // -------------------------------------------------  
    // complete hack to remove border artifacts.  
    // slightly, slightly alters an image, scaling...  
    // to remove the border.  
    // we need a better solution for this, but  
    // to constantly add a 2 pixel border on all uploaded images  
    // is insane..  
    GLfloat offsetw = 0;  
    GLfloat offseth = 0;  
    if (textureTarget == GL_TEXTURE_2D){  
        offsetw = 1.0f/(tex_w);  
        offseth = 1.0f/(tex_h);  
    // -------------------------------------------------  
    GLfloat tx0 = 0+offsetw;  
    GLfloat ty0 = 0+offseth;  
    GLfloat tx1 = tex_t - offsetw;  
    GLfloat ty1 = tex_u - offseth;  
    glTranslated(x, y, 0);  
    float s = (px1-px0)/p;  
    float t = (py1-py0)/q;  
    for (int j = 0; j < q; j++) {  
        for (int i = 0; i < p; i++) {  
            glTexCoord2f(tx0,ty0);			  glVertex3i(px0+i*s,       py0+j*t,        0);  
            glTexCoord2f(tx1,ty0);			  glVertex3i(px0+(i+1)*s,   py0+j*t,        0);  
            glTexCoord2f(tx1,ty1);			  glVertex3i(px0+(i+1)*s,   py0+(j+1)*t,    0);  
            glTexCoord2f(tx0,ty1);			  glVertex3i(px0+i*s,       py0+(j+1)*t,    0);  

and a nice example using live video…


#ifndef _TEST_APP  
#define _TEST_APP  
#include "ofMain.h"  
#include "ofAddons.h"  
#include "ofxTiledTexture.h"  
class testApp : public ofSimpleApp {  
		void setup();  
		void update();  
		void draw();  
		void mouseMoved(int x, int y);  
        int             mouseX;  
        int             mouseY;  
        ofxTiledTexture tex;  
        ofVideoGrabber  video;  


#include "testApp.h"  
void testApp::setup() {  
    video.initGrabber(160, 120);  
    tex.allocate(video.width, video.height, GL_RGB);   
void testApp::update() {  
	if (video.isFrameNew()) {  
		tex.loadData(video.getPixels(), video.width, video.height, GL_RGB);  
void testApp::draw() {  
    tex.draw(0, 0, ofGetWidth(), ofGetHeight(), ofGetWidth()/float(ABS(mouseX)+1), ofGetHeight()/float(ABS(mouseY)+1));  
void testApp::mouseMoved(int x, int y) {  
    mouseX = x;  
    mouseY = y;  


Hi !

I’ve seen wasn’t updated to 006/0061. and I’ve updated , but seems I’ve did it but something is wrong , some bug or frezee state at draw state I guess.
If someone want to try it…


You can get the updated version for 0061 on GitHub: http://github.com/prisonerjohn/openFram-…-edTexture/

I was just looking at this and the spec ( http://www.opengl.org/registry/specs/AR-…-tangle.txt ) says:

However, non-power-of-two sized textures have limitations that do not apply to power-of-two sized textures.

NPOTS textures may not use mipmap filtering; POTS textures support both mipmapped and non-mipmapped filtering. NPOTS textures support only the GL_CLAMP, GL_CLAMP_TO_EDGE, and GL_CLAMP_TO_BORDER wrap modes; POTS textures support GL_CLAMP_TO_EDGE, GL_REPEAT, GL_CLAMP, GL_MIRRORED_REPEAT, and GL_CLAMP_TO_BORDER (and GL_MIRROR_CLAMP_ATI and GL_MIRROR_CLAMP_TO_EDGE_ATI if ATI_texture_mirror_once is supported).