Reputation: 13
I'm trying to port over some OpenGL code from an Android project to iOS. I've done a little bit of iOS programming before so i'm familiar with the syntax of Objective-C but I can't seem to figure out how these GLKMatrixStacks work. Here is some Java code that I am trying to port with an example of how I need to use the stack.
public void drawLeftHip()
{
float[] temp = new float[16];
System.arraycopy(mModelMatrix, 0, temp, 0, mModelMatrix.length);
stack.push(temp);
//Global transformations here
Matrix.translateM(mModelMatrix, 0, -1.0f, -.75f, 0.0f);
Matrix.rotateM(mModelMatrix, 0, lThighAngle, 1.0f, 0.0f, 0.0f);
//draw children
drawLeftThigh();
//left hip
Matrix.scaleM(mModelMatrix, 0, .25f, .25f, .25f);
drawPackedTriangleBuffer(mSphereData, mSphereVertexCount, mModelMatrix, mColorBlack); //draw the triangle with the given model matrix
mModelMatrix = stack.pop();
}
I basically make a copy of mModelMatrix (a 4x4 matrix) and push it on the stack, do my global transformations, draw children, do local transformations, and finally pop the stack.
I've tried using a NSMutableArray for the purpose of a stack but I can't use it because I need to use GLKMatrix4 which is not if type (id).
Upvotes: 0
Views: 716
Reputation: 126127
GLKMatrix4
represents a 4x4 matrix. It's just a union encapsulating a 16-element float
array, so it's analogous to the float[16]
array in your example. If you work with GLKBaseEffect
you're already using these for your ModelView and Projection matrices. (If you're rolling your own shaders, using the GLKit matrix/vector types and corresponding math utilities is a good idea anyway, since they're optimized to provide good performance on iOS devices.)
To follow the pattern of your example:
Use GLKMatrixStackCreate
to create a stack, then GLKMatrixStackLoad
to copy your current ModelView matrix onto the stack. This function automatically copies the matrix so you don't need to create a copy yourself as in your example.
Use GLKMatrix4Translate
, GLKMatrix4Rotate
, etc to transform your ModelView matrix before drawing with it. (Don't forget to upload the changed matrices to your shader's uniform variables, or if using GLKBaseEffect
update its transform
property and tell it to prepareToDraw
, before drawing.)
Finally, use one of the GLKMatrixStackGet
functions to retrieve the saved matrix from the stack.
This pattern doesn't actually make use of the stack, though -- it just saves and loads a single matrix. You can extend the pattern by using GLMatrixStackPush
to save additional matrices and GLKMatrixStackPop
to restore to a prior state. (The pop function doesn't return the top matrix before disposing of it, so use a GLKMatrixStackGet
function if you want to retrieve it first.) This pattern still doesn't make optimal use of the stack, though -- a better way is to keep all your matrix operations in the stack. Here's a quick (untested) example:
// subclass of GLKViewController as in the "OpenGL Game" Xcode template
@implementation MyViewController
{
GLKMatrixStack mvStack;
}
- (void)setupGL
{
// ... other setup code ...
// set up base transform
mvStack = GLKMatrixStackCreate(NULL);
GLKMatrixStackTranslate(mvStack, /* ... coords ... */);
GLKMatrixStackScale(mvStack, /* ... coords ... */);
GLKMatrixStackRotate(mvStack, /* ... coords ... */);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// save the base transform
GLKMatrixStackPush(mvStack);
// additional transforms for figure
GLKMatrixStackTranslate(mvStack, /* ... coords ... */);
GLKMatrixStackScale(mvStack, /* ... coords ... */);
GLKMatrixStackRotate(mvStack, /* ... coords ... */);
[self drawBody];
// restore the base transform
GLKMatrixStackPop(mvStack);
}
- (void)drawBody
{
self.effect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(mvStack);
// ... draw body ...
// save body transform
GLKMatrixStackPush(mvStack);
// transform to left leg coordinate space
GLKMatrixStackTranslate(mvStack, /* ... coords ... */);
GLKMatrixStackScale(mvStack, /* ... coords ... */);
GLKMatrixStackRotate(mvStack, /* ... coords ... */);
[self drawLeg];
// restore to body coordinates
GLKMatrixStackPop(mvStack);
// transform to right leg coordinate space
GLKMatrixStackTranslate(mvStack, /* ... coords ... */);
GLKMatrixStackScale(mvStack, /* ... coords ... */);
GLKMatrixStackRotate(mvStack, /* ... coords ... */);
[self drawLeg];
// restore to body coordinates
GLKMatrixStackPop(mvStack);
}
- (void)drawLeg
{
self.effect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(mvStack);
// ... draw upper leg ...
// save upper leg transform
GLKMatrixStackPush(mvStack);
// transform to lower leg coordinate space
GLKMatrixStackTranslate(mvStack, /* ... coords ... */);
GLKMatrixStackScale(mvStack, /* ... coords ... */);
GLKMatrixStackRotate(mvStack, /* ... coords ... */);
self.effect.transform.modelviewMatrix = GLKMatrixStackGetMatrix4(mvStack);
// ... draw lower leg ...
// restore to upper leg coordinates
GLKMatrixStackPop(mvStack);
}
Read the documentation on GLKMatrixStack
for more info.
Upvotes: 3