Display lists and texture coordinates

Started by
6 comments, last by feti 16 years, 5 months ago
I'm writing a tile-based game, as I mentioned in another thread I just posted. About 99% of all the quads I write to the screen will be the same exact dimensions. Now, the problem I have different texture coordinates for each texture I apply. Is there any way I can get away with a single display list of my single tile quad, but so I can change the texture coordinates based on which texture I'm using outside of the display list, directly before I call the display list? From my understanding of opengl, I need to provide the texture coordinates before I specify the vertex, but I'm hoping I am wrong.
Advertisement

Hi.

Yes you need to provide the tex-coords before the vertex - any vertex attribute has to be set before the glVertex call which effectively tells GL that you're done specifying attributes for that vertex.

What I suggest you do is to change from display list to buffer objects. You can have the positions in one buffer (ArrayElement) and the texture coordinates (ArrayElement) in other buffers. When rendering your quad, you always use bind the position buffer and then for the quad, select and bind the appropriate buffer with texture coordinates. Then you draw your buffer object.

If the texture coordinates are easily (algorithmically) computable you can stay with display list and compute the texture coordinates in a vertex shader.

It sounds a bit as if you're using a texture atlas approach... If that is the case, it might be possible to supply the texture coordinates as Uniform variables. You would need to supply the offset and extent for each tile, and then compute the per-vertex texture coordinates.

kind regards,
Nicolai

Thanks for the reply. Sorry it took so long for me to get back. When you say a uniform variable, what do you mean? I'm not quite sure what all in between glNewList() and glEndList() gets calculated each time. I'm a bit confused.

If I specify a variable outside of glNewList() and then utilize that variable inside, is it used as that value at that given time, or does the list expect that variable when the list is called each time so it can compute based on the variable value when the list is called?

When you are finished defining a display list with glEndList() it is never modified again. The list is compiled and you can not change anything, anymore, forever. When you use variables to define the display list, they are only evaluated once - "it is used as that value at that given time".

Example:
float lineLength = 30;
glNewList(id, GL_COMPILE);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(lineLength, 0, 0);
glEnd();
glEndList();

When this code is run, the line drawn will be 30 units along the x-axis - forever. If you want another lineLength, you would have to destroy the display list and create a new one. Display lists may be fast but they are not flexible. Use them only for things that never change (like setting up a considerable, fixed number of OpenGL states). For everything else, look into Vertex Buffer Objects (VBO).

-----

The uniform variables I talked about are programmable shader variables. A shader is small program that can be enabled or disabled like any other OpenGL state. Uniform variables are used to parameterize your shade. A shader can change the texture coordinates by using uniform variables. It could look something like this when rendering (lets assume the shader program has been set up already):

// texture coordinates
float texCoordS = 0.5;
float texCoordT = 0.5;

// specify a uniform variable
glUniform2f(locationOfShaderVariable, texCoordS, texCoordT);

// enable the shader program
glUseProgram(programID);

// use your previously defined display list
glCallList(myDisplayListID);

The shader program could then modify the texture coordinates in the display list using the uniform variables you specified.

-----

Using shaders may be a bit too advanced at the moment. Instead, I recommend you look into using Vertex Buffer Objects to solve your problem with different texture coordinates. VBO's are more complicated than display lists but you have a lot more flexibility. VBO's also tend to take up less memory than display lists and when used correctly they are as fast as display lists.

kind regards,
Nicolai

Well there's one other, often neglected way: using the texture matrix.

If you use a texture atlas (a texture containing all the tile images) you could use the texture matrix to scale, translate and even rotate the texture coordinates. Just switch to GL_TEXTURE matrix mode and use your normal glTranslatef etc.

Another way would be just using different textures for each tile but that would be slow.


Rendering each tile indivually (which you'd have to do even with the texture matrix) is very slow. I'd recommend using VBOs, like ndhb said, defining the visible grid of quads and as you scroll over the map you just update the texture coordinates.

Or you could use shaders and do all the scrolling in the shader (using an atlas and assuming your geometry is always the same, but I think so since you want to use a single DL). This way you could just draw a single fullscreen quad, use a texture that defines the tilemap (one pixel per tile), the texture atlas (that contains the tiles) and just pass your current position to the shader. But I agree with ndhb: this is too advanced for you atm.
If I was helpful, feel free to rate me up ;)If I wasn't and you feel to rate me down, please let me know why!
Great replies guys. Yes, I think those options may be too complex for me at this point. I will look into vertex buffer objects.

My game has 3 possible layers per tile. Here's what I was going to do.

1 Render tile layer 1 (no collision, no alpha layer).
2 Render tile layer 2 (possible collision, buildings, etc).
3 Render objects such as players, weapons, booty, etc.
4 Render tile layer 3 (clouds, walk behind objects, etc. -- no collision).

Is this a smart way to do this? On screen we're talking about 60x40 tiles or so to be rendered * 3 layers + players and weapons. Am I going to be safe with a standard rendering method like I want to go with? Or even better with vertex buffer objects? Or is it going to be necessary to do something more complex down the road to receive fairly decent performance?

Hi Feta.

Your plan doesn't sound bad. As already mentioned by Lord_Evil, the only problem be holding you back performance wise, is the number of texture switches. You have to minimize texture switches when rendering so many small textures. The only other thing that would limit performance is fill rate but I highly doubt you will experience that.

A very common method is to put a lot of images into the same texture object and adjust the texture coordinates for each quad (visible object) accordingly. This is called a Texture Atlas. If you're not using those already, but bind the texture for each quad individually, you will probably run into performance issues. Google a bit around on "Texture Atlas" or read "http://download.nvidia.com/developer/NVTextureSuite/Atlas_Tools/Texture_Atlas_Whitepaper.pdf"

When you have sorted out the texture problem, you could look into VBO's to get rid of the large number of display lists.

kind regards,
Nicolai

Thanks again. I am using a sprite sheet for textures. I don't know if this is a similar concept to a texture atlas, but I'll find out in a moment when I google it. Something else that struck my mind is whether or not multi texturing may help too. I could cut back on tiles by mapping the first texture, then the second texture on top of it on the same tile. Is this something that can help me? Also something to note, if I do end up multitexturing, I will need to change the texture coordinates again and specify a new texture id for the second texture. I don't know the overhead involved in this and if it's even worth it, but I figured I would toss the idea up in the air for you to think about.

Thanks again and any info on multitexturing pro's and con's would be appreciated.

This topic is closed to new replies.

Advertisement