How to use glDrawElements to draw a building?

Hello all,

I’m working in a 3D project. But I’m not very well in OpenGL.
Some one give me a structure of a building, and I have to draw it in 3D.

A building includes a footprint, a height and latitude. So a building looks like a box 3D, some things likes this (please view the image). A building can have more than 4 vertex:

http://img237.imageshack.us/img237/1434/boxjp2.jpg

He gives me a building class looks like this (I have removed some data) and he said that I should use the glDrawElements function. This is the building class code (please read the cpp file):

http://video.igala.net/building.cpp.html

I have used the glDrawElements function like this :

[b]
    glEnableClientState ( GL_VERTEX_ARRAY );
    int nbVertices = pbuilding->getData()->GetWallVerticesCount();
    GLfloat *vertices = pbuilding->getData()->GLWallVertices();
 
    glVertexPointer( 3, GL_FLOAT, 0, vertices );
    int n = pbuilding->getData()->getNbRings();
    unsigned int* pn = pbuilding->getData()->GetWallIndicesCount();
    unsigned int** indices = pbuilding->getData()->GLWallIndices();
    for (int i=0; i<n; ++i){
        if (n == 0)
        glDrawElements(GL_TRIANGLES, pn[i], GL_UNSIGNED_SHORT, (GLvoid*)indices[i]);
    }
    
    glDisableClientState(GL_VERTEX_ARRAY);
 [/b]
[/b][/QUOTE]

But it does not run, the programme was crashed when it start to draw.

Does any one can tell how to can I draw this building?

Thanks so much,

First: In your source file, your indices array (unsigned int** m_WallIndices;) is of type unsigned int and when you use glDrawElements you use GL_UNSIGNED_SHORT. It should be GL_UNSIGNED_INT.

Second: In your for loop glDrawElements will never be called. If n == 0 the for loop will terminate immediately because of i < n. If n > 0 the for loop will iterate n times but n != 0, so the loop do nothing at all. This tell me that your program don’t crash when drawing.

Third: In your source file I see


// wall vertices:
// 4 points per wall
// 8 value per point: 2 texture coordinates + (x,y,z) coordinates, + normal coordinates computed later
m_WallVertices = new float [m_nbWallVertices * 8 * 4];

Your m_WallVertices array is interleaved with other data so
glVertexPointer( 3, GL_FLOAT, 0, vertices ); should be something like glVertexPointer( 3, GL_FLOAT, 8*sizeof(GL_FLOAT), &vertices[2] );

Look at the references pages for glVertexPointer and glDrawElements documentation.

Thanks for your time to help me.

First: I have changed as you said.
Second: n == 0 is only for testing :), I have removed.
Third: Could you please explain more detail? I need to starting at 0, so why we need to change to glVertexPointer( 3, GL_FLOAT, 8*sizeof(GL_FLOAT), &vertices[2] ) ?

For glVertexPointer, I noticed in your building.cpp file that the m_WallVertices array contain for each vertex a 2 dimensions texture coordinate + a normal. I have supposed that pbuilding->getData()->GLWallVertices() function call return the m_WallVertices array. So in memory the array will look like this:

m_WallVertices[0] = texture coordinate u for vertex 0
m_WallVertices[1] = texture coordinate v for vertex 0
m_WallVertices[2] = vertex position x for vertex 0
m_WallVertices[3] = vertex position y for vertex 0
m_WallVertices[4] = vertex position z for vertex 0
m_WallVertices[5] = vertex normal x for vertex 0
m_WallVertices[6] = vertex normal y for vertex 0
m_WallVertices[7] = vertex normal z for vertex 0

m_WallVertices[8] = texture coordinate u for vertex 1

m_WallVertices[10] = vertex position x for vertex 1

m_WallVertices[13] = vertex normal x for vertex 1

So with this array layout you have to tell OpenGL that your vertex position data begin at address &vertices[2] and you have to jump 8sizeof(GL_FLOAT) bytes to get the next vertex position data.If you use texturing, to tell OpenGL where the texture coordinate data is you need to call glTexCoorPointer(2,GL_FLOAT,8sizeof(GL_FLOAT),&vertices[0]).If you use OpenGL lighting you need to call glNormalPointer(GL_FLOAT,8*sizeof(GL_FLOAT),&vertices[5]).

After checking the code again it seems that the comment is misleading about the order of data for vertex position and normal. So glVertexPointer(3, GL_FLOAT, 8sizeof(GL_FLOAT),&vertices[5]) <=> glNormalPointer(GL_FLOAT,8sizeof(GL_FLOAT),&vertices[2]).

He gives me a building class

Ask your project coordinator for the exact layout of data for m_WallVertices array if you cannot find it yourself.

It works well now, just replace sizeof(GL_FLOAT) by sizeof(float).

OMG.

Thanks all,

how does that help???

The new code now is:


	int nbVertices = pbuilding->getData()->GetWallVerticesCount();
		glEnableClientState ( GL_VERTEX_ARRAY );
		GLfloat *vertices = pbuilding->getData()->GLWallVertices();
		
		glVertexPointer( 3, GL_FLOAT, 8*sizeof(float), vertices+5 );
		int n = pbuilding->getData()->getNbRings();
		unsigned int* pn = pbuilding->getData()->GetWallIndicesCount();
		unsigned short** indices = pbuilding->getData()->GLWallIndices();
		
		for (int i=0; i<n; ++i){
			glDrawElements(GL_TRIANGLE_FAN, pn[i], GL_UNSIGNED_SHORT, indices[i]);
		}
		
		glDisableClientState(GL_VERTEX_ARRAY);


You can see this line: glVertexPointer( 3, GL_FLOAT, 8*sizeof(float), vertices+5 );

can you check the following:
int size1 = sizeof(GL_FLOAT);
int size2 = sizeof(float);

and post it back here.

Of course replace GL_FLOAT with GLfloat. GL_FLOAT is a enum I think.

Damn! right! for some reasons i thought of GL_FLOAT as GLfloat.