OpenGL|ES tutorials - Follows NeHe track.

Apprentice
Posts: 13
Joined: 2008.10
Post: #1
Ok guys, several people have been asking about OpenGL|ES development and have been wanting guides on how to get started. I've written a couple tutorials without discussing the iPhone SDK to help myself learn and to share with others. Please feel free to comment and I'll be adding to it as i complete them. The first post will be setting up a default starting point for further tutorials as well as getting the first triangle to draw on the screen. Please enjoy.

Tutorials Links for PDF files:
Lesson 1
Lesson 2
Lesson 3
Lesson 4
Lesson 5
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #2
Setting up an OpenGL Window

Because of the NDA on the iPhone SDK, I will be instructing users where they can download the necessary code from Apple to perform specific operations on that code to get where we need to be.

Begin by going to the development center and getting the sample code for GLGravity. We will use a modified version of this source for our base code.

To create the basis for these tutorials duplicate the GLGravity folder and call it OpenGLCore.

Rename the xcodeproj file to OpenGLCore.xcodeproj.

Open the project.

Remove ReadMe.txt from the project and move it to the trash.

Go to Resources and remove Default.png and icon.png and send the files to the trash, we won't need them either.

In the Models folder, remove the teapot.h file. This is just an array list for the teapot that is so often used in graphics programs.

Rename the GLGravityView.h and .m files to OpenGLCoreView.

Do a Find Selected Text in Project and look for GLGravityView. Replace all Occurances with OpenGLCoreView. Save the changed files (Should be OpenGLCoreView.h/.m, and AppController.m).

Open AppController.h and remove the UIAccerlerationValue and the UIAccelerometerDelegate.

Open AppController.m and remove the reference to teapot.h, remove all defines except kRenderingFrequency.

Find the drawView function and remove everything inside the function. This is where we will do a majority of our code.

Find the setupView function and remove everything from this function as well. This is where we will set up our viewport and configure the state of the GL engine.

Find the applicationDidFinishLaunching function and go to the end, remove the accelerometer code. Also remove the didAccelerate function entirely.

Build and Run the application in the iPhone Simulator. If all goes well you will see an empty black screen. We will use this as the base for the rest of our tutorials for OpenGL|ES.
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #3
Drawing a Triangle
Ok, if you haven't already, please go look at the tutorial for Setting up an OpenGL Window. We will begin from there and get started into OpenGL programming.
Our first project will be a triangle. Go ahead and duplicate the OpenGLCore project. Rename it as you see fit.
Open the project and go to OpenGLCore.h
Next go to AppController.m and locate the setupView function. Here we will go typical OpenGL setup.
First we set up some constants to control how much of the screen we will see. Many of you are used to tutorials where you use gluPerspective. This was one duplicate function that was removed from OpenGL|ES however we can easily add it back in as our own function which will be presented at the end of the article.
Code:
    const GLfloat            zNear = 0.1,
                            zFar = 1000.0,
                            fieldOfView = 60.0;
    GLfloat                    size;

Ok, so now we have our constants and a float for the size of the frustum. So now we are going to set our projection mode and create our view.
Code:
    //Set the OpenGL projection matrix
    glMatrixMode(GL_PROJECTION);
Here we calculate the size of the frustum, and call glFrustum to give it our values. Thiw will give us a nice screen to work with.
Code:
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
Next we go ahead and set our viewport. This tells OpenGL how much room we have to work with.
Code:
    glViewport(0, 0, rect.size.width, rect.size.height);

Now that we are done, we need to enter model mode and load our identity matrix. This resets the view to the origin.
Code:
    //Make the OpenGL modelview matrix the default
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
Ok, so we have set up our view, told it how much we want to be able to see and centered ourselves on the origin. Next we want to tell OpenGL what color to keep our “background”, in this case a nice black.
Code:
    // Clears the view with black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
So, much of the above is pretty typical of your standard OpenGL intro. The only thing vastly different up to this point is the lack of setting a depth buffer and using the glFrustum function instead of gluPerspective.

Now we are totally initialized and we are ready to do some real drawing. Go to the drawView function. This is where things take a different turn from most OpenGL tutorials. Firstly, there is no glBegin and glEnd in OpenGL|ES.

Lets begin with the first major difference. Borrowing from most tutorials, you are used to seeing:
Code:
    glBegin(GL_TRIANGLES);                        // Drawing Using Triangles
        glVertex3f( 0.0f, 1.0f, 0.0f);                // Top
        glVertex3f(-1.0f,-1.0f, 0.0f);                // Bottom Left
        glVertex3f( 1.0f,-1.0f, 0.0f);                // Bottom Right
    glEnd();                            // Finished Drawing The Triangle
We take a different approach by defining an array of vertexes:
Code:
const GLfloat triVerticies[] = {
0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f
};
Because our draw code gets called every time by the animation timer we need to clear the screen before we draw.

Code:
    glClear(GL_COLOR_BUFFER_BIT);
When we last left off in setupView, we were on the model view, so we will reset our position so that other rotations don't compound our view and cause weird things to happen.
Code:
    glLoadIdentity();            // Reset The Current Modelview Matrix
Next we will move ourselves so that the triangle doesn't show up in the center of the screen.
Code:
    glTranslatef(0.0f,2.0f,-6.0f);    // Move up 2 Units And Into The Screen 6.0
Now we are going to create a vertex point that contains our triangle's vertexes and enable the Vertex Array in OpenGL. We do this by telling glVertexPointer that we are giving it values in groups of 3, that they are floats, and that we want it to begin at the beginning of the array, and then tell it what array to use.

Code:
glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
Lastly we will be drawing our array on the screen. We tell it that it is a triangle strip, that we want it to start at array index 0, and that we want it to use 3 vertexes from the array. We provided it with 3 sets of 3 vertexes, so that's what it will draw.
Code:
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
Save the AppController.m file, and build the application and you should see a nice white triangle appear just above the center of the screen.

Now I promised that I would show how to do gluPerspective. Its pretty simple.

Code:
- (void)gluPerspective:(double)fovy :(double)aspect :(double)zNear :(double)zFar
{
    // Start in projection mode.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    double xmin, xmax, ymin, ymax;
    
    ymax = zNear * tan(fovy * M_PI / 360.0);
    ymin = -ymax;
    xmin = ymin * aspect;
    xmax = ymax * aspect;    
    
    glFrustumf(xmin, xmax, ymin, ymax, zNear, zFar);
    
}
By using this function, you can remove the code from setting the GL_PROJECTION view to the glFrustum call and make the call
Code:
[self gluPerspective:60.0f:((GLfloat)rect.size.width/(GLfloat)rect.size.height):0.1f:1000.0f];

Here is the entirety of the 2 functions we wrote for those who want to see it all together.
SetupView:
Code:
    const GLfloat            zNear = 0.1,
                            zFar = 1000.0,
                            fieldOfView = 60.0;
    GLfloat                    size;
    
    //Set the OpenGL projection matrix
    glMatrixMode(GL_PROJECTION);
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
    glViewport(0, 0, rect.size.width, rect.size.height);
    
    //Make the OpenGL modelview matrix the default
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // Clears the view with black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
DrawView:
Code:
    const GLfloat triVertices[] = {
        0.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f
    };
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,2.0f,-6.0f);                        // Move Up 2 Units And Into The Screen 6.0

    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
Have fun and stay tuned for the next tutorial where we color our triangle.
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #4
Coloring our triangle
Last time we left off with a single blank triangle. Not much fun. Today we will add a little bit of code that will get us to a colored triangle. We will start with AppController.m from our last project.
Just after our creation of our vertexes, we will now create an array of colors that correspond to the points of the triangle.
Code:
const GLubyte triColors[] = {
255, 0, 0,
0,255,0,
0, 0, 255
};
Now, after we enable the VERTEX_ARRAY client state we want to add in 2 more lines of code to make use of our color scheme. Here we set our color pointer to tell it we have 3 unsigned bytes per color. Start at index 0, and give it the triColors. Then we need to enable the color array in our client.
Code:
glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);
    glEnableClientState(GL_COLOR_ARRAY);
Thats it. Now you have a colored triangle. Here is the entirety of our function DrawView:
Code:
    const GLfloat triVertices[] = {
        0.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f
    };
    const GLubyte triColors[] = {
        255, 0, 0,
        0,255,0,
        0, 0, 255
    };

    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,2.0f,-6.0f);                        // Move Up 2 Units And Into The Screen 6.0
    
    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #5
Rotating
Last time we discussed the easy addition of color to our triangle. This time we will be covering rotation. Again, this will be a short tutorial as it is really simple.
Lets begin by adding a variable to our AppController.h file called rtri. This will hold our value for how much we are rotating our triangle by.
Code:
    GLfloat                    rtri;
Because we are only using it in AppController.m we won't be adding a property or synthesizing.
Next open up AppController.m and we will add the meat to this. First we will want to initialize our rtri value so go into SetupValue and initialize it to 0.0f immediately after our glClearColor.
Code:
    rtri = 0.0f;
Next we go to the DrawView. Immediately after the glLoadIdentity we will want to rotate our view by the rtri rotation value. We rotate around the y-axis by rtri degrees with the following call.
Code:
    glRotatef(rtri,0.0f,1.0f,0.0f);                        // Rotate The Triangle On The Y axis ( NEW )
Once we have rotated our view, feel free to increment rtri by whatever makes you feel comfortable. I went ahead and added it after glDrawArrays.
Code:
    rtri+=1.0f;
    if(rtri > 360.0f)
    {
        rtri -= 360.0f;
    }
So there we have it. We rotate our triangle by 1 degree every frame.
Here are SetupView and DrawView in their entirety as of this lesson.
SetupView:
Code:
    const GLfloat            zNear = 0.1,
                            zFar = 1000.0,
                            fieldOfView = 60.0;
    GLfloat                    size;
    
    //Set the OpenGL projection matrix
    glMatrixMode(GL_PROJECTION);
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
    glViewport(0, 0, rect.size.width, rect.size.height);
    
    //Make the OpenGL modelview matrix the default
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // Clears the view with black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    rtri = 0.0f;
DrawView:
Code:
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,2.0f,-6.0f);                        // Move Left 1.5 Units And Into The Screen 6.0
    glRotatef(rtri,0.0f,1.0f,0.0f);                        // Rotate The Triangle On The Y axis ( NEW )
    
    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);    
    
    rtri+=1.0f;
    if(rtri > 360.0f)
    {
        rtri -= 360.0f;
    }
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #6
Hi everyone,

Are these tutorials helping anyone out? I'm just wondering if i should continue to try and recreate the NeHe tutorials or if i should just drop it?

I'm half way through the next tutorial with a spinning pyramid. Currently I'm working on the spinning cube. I am trying to generate the easiest way to assign multiple vertexes the same color and then change the color associated with them for each face. This would give 8 vertexes and 6 colors instead of 6 arrays of 4 vertexes and 6 arrays of 4 colors.

Also, I am going to produce these as PDF files tonight. I'll post the link as soon as they are converted.
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2008.10
Post: #7
I've found these tutorials to be pretty helpful so far. I was gonna post a "good on ya" but didn't want to mess up your nice tutorial thread Wink
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2008.10
Post: #8
dragagon Wrote:Hi everyone,

Are these tutorials helping anyone out? I'm just wondering if i should continue to try and recreate the NeHe tutorials or if i should just drop it?

I'm half way through the next tutorial with a spinning pyramid. Currently I'm working on the spinning cube. I am trying to generate the easiest way to assign multiple vertexes the same color and then change the color associated with them for each face. This would give 8 vertexes and 6 colors instead of 6 arrays of 4 vertexes and 6 arrays of 4 colors.

Also, I am going to produce these as PDF files tonight. I'll post the link as soon as they are converted.

Worked through Lessons 2 & 3, very well done!

There was one error though in your original code:
Code:
glVertexPointer(3, GL_FLOAT, 0, triVertices);
The original triangle array was called triVertexes. Changing both to one or the other gets rid of the error (which you did in your composite code at the bottom). I know that for newbs like myself this type of thing can be a real hang up.

Thank you for doing these, I really appreciate it!
Quote this message in a reply
Nibbie
Posts: 1
Joined: 2008.10
Post: #9
dragagon Wrote:Are these tutorials helping anyone out? I'm just wondering if i should continue to try and recreate the NeHe tutorials or if i should just drop it?

Of course it helps people Smile thanks for your time et job

Do you think OpenGL SE is a good way on IPhone to animate lots of sprites ??

Thanks again

Arnaud
Quote this message in a reply
Apprentice
Posts: 13
Joined: 2008.10
Post: #10
Well, sorry it took a while. I was busy, hope you enjoy lesson 5. Also, please feel free to download the PDF versions of these lessons from my site. The links are in the initial post. Enjoy!

Drawing 3D models that rotate
Today we will look into the creation of 3D models for both the Pyramid and the Cube from the NeHe tutorials. This will take a divergent step away from what we are used to doing. We are going to create our 5 points for our triangle and create an index list along the same way that GLGravity did.
Code:
const GLfloat triVerticies[] = {
0.0f, 1.0f, 0.0f,            // 0 - top of the triangle
-1.0f, -1.0f,  0.0f,        // 1 - SouthWest corner B+-----+G
1.0f, -1.0f,  0.0f,        // 2 - SouthEast corner  | \ / |
                //                R
1.0f, -1.0f, -1.0f,        // 3 - NorthEast corner  | / \ |
-1.0f, -1.0f, -1.0f        // 4 - NorthWest corner G+-----+B
};
This array shows how we set up our pyramid along with a color guide to help us order our index list. Something to keep in mind is that the order of our vertexes in the index must correspond to the order of the colors in the color array. We also need a count of our indexes, this is the total indexes in triIndexes including the number at the front.
Code:
// We need the number of vertexes we will be rendering, this is 16
const GLint triIndexCount = 16;
// List our indexes. The first number is the number of indexes in our face
// Followed by the RGB faces. these correspond to the order of the tricolors array.
// Keep that in mind as you order your indexes.
const GLfloat triIndexes[] = {
//  #, R, G, B
    3, 0, 1, 2,        // front face - top, sw, se
    3, 0, 3, 2,        // right face - top, ne, se
    3, 0, 3, 4,        // back face - top, ne, nw
    3, 0, 1, 4        // left face - top, sw, nw
}
Later you will see that we change from glDrawArrays to glDrawElements. Because of this we also need to modify our triColor array. This array now corresponds to each color in our index list. Because we have 5 points, we now need 5 arrays. Our top point is red, points 1 and 3 are green, and points 2 and 4 are blue. So here is our new color array.
Code:
// Each color is associated with a specific vertex in the index list now.
GLubyte triColors[] = {
255, 0, 0,    // Red
0,255,0,    // Green
0, 0, 255,    // Blue
0,255,0,        // Green
0, 0, 255    // Blue
};
Lastly the only thing to change is to remove glDrawArrays and add in the new code to make use of glDrawElements. Like so:
Code:
    for(int i = 0; i < triIndexCount; i += triIndexes[i] + 1)
    {
        glDrawElements(GL_TRIANGLES, triIndexes[i], GL_UNSIGNED_SHORT, &triIndexes[i+1]);
    }

Thats all there is to it. Now we have a rotating pyramid with multicolors.
Now we are ready to draw our cube. But first we need to add the cube data.
Start with AppController.h and add a new variable rquad to the class. Again, we will not be setting a property or synthesizing.
Code:
    GLfloat                    rquad;
Once we have that set we are finally going to set the depth buffer, otherwise we will be looking at a very weird cube.
Go into AppController.m and go to the setupView function. After the size variable but before we go into projection mode add the following.
Code:
    glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing
This allows OpenGL to do testing for which faces are physically in front of others. OpenGL has a glClearDepth function, but OpenGL|ES removed this function as well and just assumes you want to clear the entire buffer.
Also, because we added rquad, we need to initialize it in our setupView function. After the initialization of rtri, add rquad.
Code:
    rquad = 0.0f;
Now that we have cleared our buffer, now we need to tell the clear function when to actually clear it so it can recalculate the face order. To do this we add a flag to glClear in the drawView function. Replace the old one with this new one:
Code:
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

There, now we are clearing our depth buffer every frame.
Ok, everything is now in place we can focus on drawing our cube.
Here I need to introduce a few things that we normally aren't used to seeing as OpenGL usually goes. Because we are using GL_VERTEX_ARRAY and GL_COLOR_ARRAY to draw our triangle, we need to clean up when we are done by disabling these. Right after we finish our drawElement for loop, we need to disable these, in case we don't use them in further draw methods.
Code:
glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
Its good to clean up your client states after you are done drawing (later you can comment these out and see how it affects the cube ~_*)
So, now you are wondering, how to I draw a cube. Well here goes. We begin by adding some new code after the state disabling.
Code:
const GLfloat cubeVertices[] = {
-1.0f, 1.0f, 1.0f,    // 0, Top Left Front Of The Cube           4+-----+5
1.0f, 1.0f, 1.0f,    // 1, Top Right Front Of The Cube           /|    /|
1.0f,-1.0f, 1.0f,    // 2, Bottom Right Front Of The Cube          / |7  / |
-1.0f,-1.0f, 1.0f,    // 3, Bottom Left Front Of The Cube        0+-----+1 +6
-1.0f, 1.0f,-1.0f,    // 4, Top Left Back Of The Cube             |     |  /
1.0f, 1.0f,-1.0f,    // 5, Top Right Back Of The Cube         |     | /
1.0f,-1.0f,-1.0f,    // 6, Bottom Right Back Of The Cube        3+-----+2
-1.0f,-1.0f,-1.0f    // 7, Bottom Left Back Of The Cube
};

// We need the number of faces we will be rendering, this is 6 faces, 5 values per face
int cubeIndexCount = 30;

const GLushort cubeIndexes[] = {
    4, 0, 1, 4, 5, // Top
    4, 3, 2, 7, 6, // Bottom
    4, 0, 1, 3, 2, // Front
    4, 4, 5, 7, 6, // Back
    4, 0, 4, 3, 7, // Left
    4, 1, 5, 2, 6  // Right
};

const GLubyte cubeColors[] = {
    3,   0, 255,   0, // Top - Green
    3, 255, 125,   0, // Bottom - Orange
    3, 255,   0,   0, // Front - Red
    3, 255, 255,   0, // Back - Yellow
    3,   0,   0, 255, // Left - Blue
    3, 255,   0, 255  // Right - Violet
};
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,-2.0f,-6.0f);                        // Move Down 2.0 Units And Into The Screen 6.0
    glRotatef(rquad,1.0f,1.0f,1.0f);                        // Rotate The Cube On all 3 axises
Next, like before we set up our vertex pointer.
Code:
    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
Notice that we aren't doing anything with the color array, this is why we turned it off after our last drawing completed. Instead we will be using glColor4f as part of the for loop you will see next. Now the syntax might seem a little strange to newer programmers who have never seen a for loop work with more than 1 variable. Here goes.
Code:
    for(int i = 0, j = 0; i < cubeIndexCount; i += cubeIndexes[i] + 1, j += cubeColors[j] + 1)
    {
        glColor4f(cubeColors[j+1], cubeColors[j+2], cubeColors[j+3], 0.0);
        glDrawElements(GL_TRIANGLE_STRIP, cubeIndexes[i], GL_UNSIGNED_SHORT, &cubeIndexes[i+1]);    
    }
The for loop initializes 2 variables, i and j. 'i' is used for the cube indexes like the triangles before, but j is used to control the cube colors. The middle of the for loop is the same, only 1 ending type. The last part is 2 increment phases, we need to increment 'i' by the number of indexes we have to advance, but j needs to be incremented by the number of colors we are using. Notice the comma to seperate the 2 statements in each section of the for loop. Neat huh?
Ok, like before, we are using a Vertex array, so we need to disable the client state after we finish drawing, do that now.
Code:
    glDisableClientState(GL_VERTEX_ARRAY);
Lastly we added that new rotate variable for the cube so we will decrement it to make it spin a different direction.
Code:
    rquad-=0.75f;
    if( rquad < -360.0f)
    {
        rquad += 360.0f;
    }
Thats all there is to it. Go ahead and compile and run the code and check out our nice new rotating cube.

Here are the new functions in their entirety.
SetupView:
Code:
    const GLfloat            zNear = 0.01,
                            zFar = 1000.0,
                            fieldOfView = 45.0;
    GLfloat                    size;
    
    glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing

    //Set the OpenGL projection matrix
    glMatrixMode(GL_PROJECTION);
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
    glViewport(0, 0, rect.size.width, rect.size.height);
    
    //Make the OpenGL modelview matrix the default
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // Clears the view with black
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    rtri = 0.0f;
    rquad = 0.0f;
drawView:
Code:
const GLfloat triVertices[] = {
0.0f,  1.0f,  0.0f,        // 0 - top of the triangle
-1.0f, -1.0f, 1.0f,        // 1 - SouthWest corner B+-----+G
1.0f, -1.0f, 1.0f,        // 2 - SouthEast corner  | \ / |
                //                R
1.0f, -1.0f, -1.0f,        // 3 - NorthEast corner  | / \ |
-1.0f, -1.0f, -1.0f        // 4 - NorthWest corner G+-----+B
};

// We need the number of faces we will be rendering, this is 16
int triIndexCount = 16;
// List our indexes. The first number is the number of indexes in our face
// Followed by the RGB faces. these correspond to the order of the tricolors array.
// Keep that in mind as you order your indexes.
GLushort triIndexes[] = {
//  #, R, G, B
    3, 0, 1, 2,        // front face - top, sw, se
    3, 0, 3, 2,        // right face - top, ne, se
    3, 0, 3, 4,        // back face - top, ne, nw
    3, 0, 1, 4        // left face - top, sw, nw
};

// Each color is associated with a specific vertex in the index list now.
GLubyte triColors[] = {
255, 0, 0,    // Red
0,255,0,    // Green
0, 0, 255,    // Blue
0,255,0,        // Green
0, 0, 255    // Blue
};
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,2.0f,-6.0f);                        // Move Up 2 Units And Into The Screen 6.0
    glRotatef(rtri,0.0f,1.0f,0.0f);                        // Rotate The Triangle On The Y axis ( NEW )
    
    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    for(int i = 0; i < triIndexCount; i += triIndexes[i] + 1)
    {
        glDrawElements(GL_TRIANGLES, triIndexes[i], GL_UNSIGNED_SHORT, &triIndexes[i+1]);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
const GLfloat cubeVertices[] = {
-1.0f, 1.0f, 1.0f,            // 0, Top Left Front Of The Cube           4+-----+5
1.0f, 1.0f, 1.0f,            // 1, Top Right Front Of The Cube           /|    /|
1.0f,-1.0f, 1.0f,            // 2, Bottom Right Front Of The Cube          / |7  / |
-1.0f,-1.0f, 1.0f,            // 3, Bottom Left Front Of The Cube        0+-----+1 +6
-1.0f, 1.0f,-1.0f,            // 4, Top Left Back Of The Cube             |     |  /
1.0f, 1.0f,-1.0f,            // 5, Top Right Back Of The Cube         |     | /
1.0f,-1.0f,-1.0f,            // 6, Bottom Right Back Of The Cube        3+-----+2
-1.0f,-1.0f,-1.0f            // 7, Bottom Left Back Of The Cube
};

// We need the number of faces we will be rendering, this is 6 faces, 5 values per face
int cubeIndexCount = 30;

const GLushort cubeIndexes[] = {
    4, 0, 1, 4, 5, // Top
    4, 3, 2, 7, 6, // Bottom
    4, 0, 1, 3, 2, // Front
    4, 4, 5, 7, 6, // Back
    4, 0, 4, 3, 7, // Left
    4, 1, 5, 2, 6  // Right
};

const GLubyte cubeColors[] = {
    3,   0, 255,   0, // Top - Green
    3, 255, 125,   0, // Bottom - Orange
    3, 255,   0,   0, // Front - Red
    3, 255, 255,   0, // Back - Yellow
    3,   0,   0, 255, // Left - Blue
    3, 255,   0, 255  // Right - Violet
};
    glLoadIdentity();                                    // Reset The Current Modelview Matrix
    glTranslatef(0.0f,-2.0f,-6.0f);                        // Move Down 2 Units And Into The Screen 6.0
    glRotatef(rquad,1.0f,1.0f,1.0f);                        // Rotate The Cube On all 3 axises
    
    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
    glEnableClientState(GL_VERTEX_ARRAY);

    for(int i = 0, j = 0; i < cubeIndexCount; i += cubeIndexes[i] + 1, j += cubeColors[j] + 1)
    {
        glColor4f(cubeColors[j+1], cubeColors[j+2], cubeColors[j+3], 0.0);
        glDrawElements(GL_TRIANGLE_STRIP, cubeIndexes[i], GL_UNSIGNED_SHORT, &cubeIndexes[i+1]);    
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    
    rtri+=1.0f;
    if(rtri > 360.0f)
    {
        rtri -= 360.0f;
    }
    rquad-=0.75f;
    if(rquad < -360.0f)
    {
        rquad += 360.0f;
    }
See you next time when we begin to tackle textures!
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2008.11
Post: #11
hi, these are great tutorials, i really appreciate you doing these!

One snag i ran into, I get an EXC_BAD_ACCESS error when i debug on the iphone. It runs fine in the simulator. and i dont get any compile errors.

Here is a snippet from the error trace, I've bolded the line that the arrow points to in xcode:

0x31283878 <+1748> b 0x31283d80 <DrawTriangles+3036>
0x3128387c <+1752> b 0x31283dbc <DrawTriangles+3096>
0x31283880 <+1756> ldr r0, [r1]
0x31283884 <+1760> b 0x31283c78 <DrawTriangles+2772>
0x31283888 <+1764> ldr r0, [r1], #4
0x3128388c <+1768> ldr r3, [r1]
0x31283890 <+1772> b 0x3128397c <DrawTriangles+2008>
0x31283894 <+1776> ldmia r1, {r0, r3, ip}
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2008.11
Post: #12
miketucker Wrote:One snag i ran into, I get an EXC_BAD_ACCESS error when i debug on the iphone. It runs fine in the simulator. and i dont get any compile errors.

I've got the same problem here. If I want to color the vertices I receive an EXC_BAD_ACCESS.

Code:
- (void)drawView:(GLView*)view {
    glClear(GL_COLOR_BUFFER_BIT);
    
    glLoadIdentity();            // Reset The Current Modelview Matrix
    glTranslatef(0.0f,2.0f,-6.0f);    // Move up 2 Units And Into The Screen 6.0
    
    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    
    glColorPointer(3, GL_UNSIGNED_BYTE, 0, triColors);
    glEnableClientState(GL_COLOR_ARRAY);
    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
}

edit:
http://discussions.apple.com/thread.jspa...start=6135

I found that glColorPointer is the problem. The documentation says, that the size argument can be 3 or 4.
If I set it to 3 it doesn't work. 4 works great after you added a 4th value to the color array so that you've got 3 RGBA colors. If you want all colors full opaque, set it to 255. After that it works an your phone. At least on mine.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #13
No, the documentation clearly says (in section 2.8) that ColorPointer does not accept 3 as a size argument. This is one of the many differences between OpenGL and OpenGL ES.

It is a bug in the simulator that this is allowed through; future versions of the simulator will strictly enforce the ES limits.
Quote this message in a reply
Nibbie
Posts: 4
Joined: 2008.11
Post: #14
arekkusu Wrote:No, the documentation clearly says (in section 2.8) that ColorPointer does not accept 3 as a size argument. This is one of the many differences between OpenGL and OpenGL ES.

It is a bug in the simulator that this is allowed through; future versions of the simulator will strictly enforce the ES limits.
Have a look at your XCode Documentation under glColorPointer:

Quote:size
Specifies the number of components per color. Must be 3 or 4. The initial value is 4.
Quote this message in a reply
Member
Posts: 312
Joined: 2006.10
Post: #15
That's for the Mac OS X OpenGL documentation, not for OpenGL ES.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Track down an autorelease bug kendric 2 3,348 Jun 28, 2009 05:09 AM
Last Post: kendric