There’s actually nothing specific to ES2.0 in this port - the code is exactly the same as in tutorial 3, but we are now passing all the data required to draw 3D shapes.

There are a couple of gotchas - for some reason in the default OpenGL template that xCode gives you does not have a depth buffer. So we need to add that to the initialisation in EAGLView.m

```
glGenRenderbuffers(1, &depthbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, framebufferWidth, framebufferHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer);
```

The other interesting thing in this project is that I’ve added rotation to the objects. This requires saving the model view matrix so we can rotate the objects individually. So in the code we now have:

```
// reset our modelview to identity
esMatrixLoadIdentity(&modelView);
// translate back into the screen by 6 units and down by 1 unit
esTranslate(&modelView, 0.0f , -1.0f, -6.0f);
// save the current modelView
ESMatrix savedModelView=modelView;
// rotate the triangle
esRotate(&modelView, rPyramid, 0.0, 1.0, 0.0);
// tell the GPU we want to use our program
glUseProgram(simpleProgram);
// create our new mvp matrix
esMatrixMultiply(&mvp, &modelView, &projection );
// set the mvp uniform
glUniformMatrix4fv(uniformMvp, 1, GL_FALSE, (GLfloat*) &mvp.m[0][0] );
... do the drawing of the pyramid
// now draw a cube
// translate up by 3 units
esTranslate(&savedModelView, 0.0f , 3.0f, 0.0f);
// rotate by 45 degrees around the z axis
esRotate(&savedModelView, rCube, 0.0, 0.0, 1.0f);
// create our new mvp matrix
esMatrixMultiply(&mvp, &savedModelView, &projection );
// update the mvp uniform
glUniformMatrix4fv(uniformMvp, 1, GL_FALSE, (GLfloat*) &mvp.m[0][0] );
... do the drawing of the cube
```

We can save our matix pretty easily by just assigning it to another instance of the ESMatrix struct - this will copy all the values across so we can take a snapshot of it.

If you want to get clever you can re-implement the push and pop matrix functionality using std::stack.

Tutorial 5 is available here.