Reputation: 6857
I'm working on GUI in OpenGL. I'm using this image to texture my button:
You can't see it very well, but it has a light border (2 pixels width) around it.
What I want to achieve is to have nicely resizable button which keeps it's borders untouched. According to hints given me here, on StackOverflow I decided to use 9-cell-pattern, so I divided my quad into 9 parts like this:
I really like an effect I achieved if it goes about borders, but the problem is with a quad that is in the center (9th):
I would like to repeat or wrap a texture like I do but with ignoring borders.
So my question is - is there any way to do this with only one texture which I'm using now? Or should I create second texture, which would be decreased by a border width and to render this quad in the middle with this texture?
Also I don't know if it's necessary, but I'm putting here a fragment of my code:
This is a code I'm using for tiling/wrapping a texture:
switch(m_bTiling)
{
case true:
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT );
break;
case false:
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_CLAMP );
break;
}
And here is a code to draw quads:
// Top left quad [1]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0f, 1.0-maxTexCoordBorderY);
glVertex2i(pos.x, pos.y + m_borderWidth);
// Top left
glTexCoord2f(0.0f, 1.0);
glVertex2i(pos.x, pos.y);
// Top right
glTexCoord2f(maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + m_borderWidth, pos.y);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, 1.0-maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);
glEnd();
// Top middle quad [2]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);
// Top left
glTexCoord2f(maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + m_borderWidth, pos.y);
// Top right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + width - m_borderWidth, pos.y);
// Bottom right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);
glEnd();
// Top right quad [3]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(1.0 - maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);
// Top left
glTexCoord2f(1.0 - maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + width - m_borderWidth, pos.y);
// Top right
glTexCoord2f(1.0, 1.0);
glVertex2i(pos.x + width, pos.y);
// Bottom right
glTexCoord2f(1.0, 1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + width, pos.y + m_borderWidth);
glEnd();
// Middle left quad [4]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0, maxTexCoordBorderY);
glVertex2i(pos.x, pos.y + height - m_borderWidth);
// Top left
glTexCoord2f(0.0, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x, pos.y + m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
glEnd();
// Middle right quad [5]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
// Top left
glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);
// Top right
glTexCoord2f(1.0, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x + width, pos.y + m_borderWidth);
// Bottom right
glTexCoord2f(1.0, maxTexCoordBorderY);
glVertex2i(pos.x + width, pos.y + height - m_borderWidth);
glEnd();
// Bottom left quad [6]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0, 0.0);
glVertex2i(pos.x, pos.y + height);
// Top left
glTexCoord2f(0.0, maxTexCoordBorderY);
glVertex2i(pos.x, pos.y + height - m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, 0.0);
glVertex2i(pos.x + m_borderWidth, pos.y + height);
glEnd();
// Bottom middle quad [7]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX, 0.0);
glVertex2i(pos.x + m_borderWidth, pos.y + height);
// Top left
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 0.0);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height);
glEnd();
// Bottom right quad [8]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(1.0 - maxTexCoordBorderX, 0.0);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height);
// Top left
glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
// Top right
glTexCoord2f(1.0, maxTexCoordBorderY);
glVertex2i(pos.x + width, pos.y + height - m_borderWidth);
// Bottom right
glTexCoord2f(1.0, 0.0);
glVertex2i(pos.x + width, pos.y + height);
glEnd();
// Middle middle quad [9]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
// Top left
glTexCoord2f(maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
glEnd();
Upvotes: 3
Views: 1663
Reputation: 14668
If you were stretching the edges/center, you'd be fine, but since you're tiling, you're going to have to create a second texture with just the center part.
Note that this can be done programmatically if you have the size of the border. You'd copy the contents of the center into a new 2d array then upload that to another texture.
Another solution (as I stated in a comment) would be to set the texture coordinates of the middle middle quad to the same ones as the inner vertices of the corner. That way the texture of the center quad is stretched out. Note that this will create some weird stretching on the shine in the top right corner unless the entire thing is contained in the top right corner quad. You'd still have issues with this if you wanted to use your repeat solution.
If you still want to repeat the center part and don't mind moving your entire rendering pipeline to non-deprecated OpenGL, then ananthonline's answer is better. If you don't want to/can't move your rendering code to more modern OpenGL, then the texture copy is pretty much the only solution.
Upvotes: 0
Reputation: 10896
Well - I see your problem. You're using a constant value of maxTexCoordBorderX (and Y) for your "middle middle" quad. You need to recompute the UV coords of the center quads as the size changes (ex: width / (currWidth - 2 * borderWidth)), then you can set that texture to repeat always, but since you modify the texture coords as the ui element resizes, the center part won't ever repeat.
Of course - if you're going to use a VBO or something more performant at some point of time in the future, you can simply define two fragment shaders (each with their own sampler2D objects; one repeats, the other stretches) for each of the tiling modes and render all corner quads and middle-middle quads using the "repeat" shader and all edge quads using the stretch shader. This will not require a recompute and ought to be very fast.
Note: You're drawing multiple quads here, this is not a good idea. I would recommend using an indexed mesh with shared vertices. This will minimize the possibility of "tears" at the borders of your quads.
Upvotes: 1