5
votes

I am trying to get my render function to work. I am using vertex arrays. Here is the my vertex structure.

struct Vertex 
{
    float x, y, z;              // The x, y and z floating point values     
    float u, v;                 // The u - v texture coordinates
    float padding[3];   // needs to be multiple of 32
};

Here is my render code:

// Render the mesh
void WLD::render(GLuint* textures, long curRegion, CFrustum cfrustum)
{

    int num = 0;

    // Set up my indices
    GLuint indicies[3];

    // Cycle through the PVS
    while(num < regions[curRegion].visibility.size())
    {
        int i = regions[curRegion].visibility[num];

        if(!regions[i].dead && regions[i].meshptr != NULL)
        {
            if(cfrustum.BoxInFrustum(regions[i].meshptr->min[0], regions[i].meshptr->min[2], regions[i].meshptr->min[1], regions[i].meshptr->max[0], regions[i].meshptr->max[2], regions[i].meshptr->max[1]))
            {
                // Cycle through every polygon in the mesh and render it
                for(int j = 0; j < regions[i].meshptr->polygonCount; j++)
                {   
                    // Assign the index for the polygon to the index in the huge vertex array
                    indicies[0] = regions[i].meshptr->poly[j].vertIndex[0];
                    indicies[1] = regions[i].meshptr->poly[j].vertIndex[1];
                    indicies[2] = regions[i].meshptr->poly[j].vertIndex[2];

                    glEnableClientState(GL_VERTEX_ARRAY);
                    glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &verticies[0].x);

                    // Texture index
                    int tex = regions[i].meshptr->poly[j].tex;
                    // Need to bind this to the polygon I render.

                    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                    glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &verticies[0].u);
                    glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indicies);

                    glDisableClientState(GL_VERTEX_ARRAY);
                    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                }
            }
        }
    num++;
    }
}

One of the arguments, GLuint* textures contains all the loaded textures. So the value returned by line int tex = regions[i].meshptr->poly[j].tex; is the index in the textures for this specific polygon. How do I bind that to each polygon when I render it? Let me know if you have any questions.

I know I need to use glClientActiveTexture() but one, it says it's undefined and I can't find the correct header, and two, I have no idea how it is used. I couldn't find any good examples. So how do I, if say the polygon references texture index 4, bind it to the polygon as I render with glClientActiveTexture.

2
Perhaps a solution would be to create a texture atlas. The only issue would be to get the correct texture coordinates, but that can be done client side by classes and XML. Then you do not have to worry about switching textures. - user406009
You're mistreating vertex arrays. The idea of a vertex array is, that you're batching a large set of triangles in a single glDrawElements call, not switch the vertex array pointer for each triangle and have glDrawElements call exactly one triangle. Also there's no requirement to pad your vertex structure to a multiple of 32 (whatever?). - datenwolf
@datenwolf But in his case it seems neccessary, as he wants each polygon with a different texture (although there are other approaches for this). - Christian Rau
@Christian Rau: He could use texture arrays for this opengl.org/wiki/Array_Texture , but I agree a texture atlas probably was the sane solution. - datenwolf
@Moniker: If you persist with your original approach, try to sort the triangles per texture first, to swap textures as few times as possible during rendering. This is, and has always been, a Good Idea (tm). - Macke

2 Answers

3
votes

What you are trying to do is not generally possible. You usually do not attempt to render a single stream of triangles (a glDraw* call) with multiple textures. Well, not the way you mean, at any rate.

Each triangle within a single draw call must pull from the same set of textures as every other triangle within that draw call.

The general solution is to combine the images into a single texture. This is commonly called a "texture atlas". In this case, the texture coordinates on the vertices describe where in the texture atlas (which is a single texture) to pull image data from.

If you are using GL 4.0-capable hardware (D3D11) and GLSL, then there are tricks you can play to dynamically select between 16 textures based on arbitrary computations. And for earlier hardware, you could use shaders to pick between textures. But both cases would be slower than just massaging the data properly.

1
votes

You can do this with your currect approach. You don't need glClientActiveTexture. This function is for multitexturing and I suppose every polygon has only a single texture applied. So just bind the neccessary texture using glBindTexture(GL_TEXTURE_2D, textures[tex]) and don't forget to glEnable(GL_TEXTURE_2D) (if not using shaders) before drawing the polygon.

But although it works, this is obviously not the best way to do it. Vertex arrays are there to render multiple primitives (triangles) in one go (one call to glDrawElements) and you missuse them to render single triangles. The first and easiest idea would be to at least sort your polygons by texture index and then render all triangles with the same texture in one call to glDrawElements. Look at Nicol's answer for more advanced approaches.