GLKView nested subview frame size and bounds size incorrect
Asked Answered
Q

1

0

Here is an example "GLKView Subview" app I wrote, based on the OpenGL Game sample project in Xcode 4.5. It creates a GLKView subview with its delegate set to the File Owner's GLKViewController, so that both OpenGL ES 2 views are controlled by one controller:

http://d-h.st/7R1

Here is a screenshot, I've tinted the subview's background red for contrast:

http://d-h.st/om4

I was excited that I had a straightforward way to add multiple GLKViews under one GLKViewController and EAGLContext (for sharing textures etc), until I realized that the frame size is broken in:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    NSLog(@"My view frame: %@", NSStringFromCGRect(view.bounds));

    float aspect = fabsf(view.bounds.size.width / view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);

    self.effect.transform.projectionMatrix = projectionMatrix;

    GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -4.0f);
    baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f);

    // Compute the model view matrix for the object rendered with GLKit
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -1.5f);
    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f);
    modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);

    self.effect.transform.modelviewMatrix = modelViewMatrix;

    // Compute the model view matrix for the object rendered with ES2
    modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 1.5f);
    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f);
    modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);

    _modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);

    if(view == self.view)
    {
        glClearColor(0.65f, 0.65f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindVertexArrayOES(_vertexArray);

        // Render the object with GLKit
        [self.effect prepareToDraw];

        glDrawArrays(GL_TRIANGLES, 0, 36);

        // Render the object again with ES2
        glUseProgram(_program);

        glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
        glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

        glDrawArrays(GL_TRIANGLES, 0, 36);

        [self.subview display];
    }
    else
    {
        glClearColor(1.0f, 0.65f, 0.65f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindVertexArrayOES(_vertexArray);

        // Render the object with GLKit
        [self.effect prepareToDraw];

        glDrawArrays(GL_TRIANGLES, 0, 36);

        // Render the object again with ES2
        glUseProgram(_program);

        glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
        glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

        glDrawArrays(GL_TRIANGLES, 0, 36);
    }
}

Output in iOS Simulator with iPhone 4" Retina:

2013-04-27 15:50:56.149 GLKView Subview[48136:11903] My view frame: {{0, 0}, {568, 320}}
2013-04-27 15:50:56.152 GLKView Subview[48136:11903] My view frame: {{0, 0}, {248, 100}}

The subview's frame should be {100, 100} but for some reason it's coming out to {248, 100}. I've tried everything I can think of, even embedding it in a UIView, thinking that perhaps its autoresize constraints were getting set wrong if the main GLKView was its parent. As you can see the UIView's size is correct but the child GLKView's size is borked.

As a developer, this seemed like the first thing to try, but Apple generally has other ideas. Without autoresize, GLKView is useless for freeform layouts that work with any device size.

I managed to get multiple GLKViewControllers sharing a single EAGLContext working as child controllers in a different project. But I don't see why we should have to carry the baggage of creating a GLKViewController every time we want to add a GLKView to the screen. My guess is that GLKViewController gets confused when it's a delegate for a GLKView that isn't its own view.

I also managed to get my views working manually by just using glViewport() and after losing two days to GLKView issues, I would probably recommend going that route to anyone reading this (gaining cross platform advantages as well).

I'm hoping there is a simple explanation/fix, even if it's just "you have to make a GLKViewController for every GLKView". Thanks in advance to anyone who manages to get it working. If not, maybe an example of this bug feature will help someone.

Quarters answered 27/4, 2013 at 22:28 Comment(0)
Q
0

I found a workaround. Just use the example project, but turn off the rightmost red bar in the Autosizing adjustment for both the GLKView and its black parent UIView.

Explanation: since the aspect ratio is different going from the 3.5" to 4" iPhone display, the autosizing tries to meet the right margin constraint, which stretches the views horizontally. By telling it to maintain the left margin and the width, but NOT the right margin, it positions and sizes the views correctly within the main view.

Still, something wonky is going on because if you embed another white UIView inside of the black UIView and set all of its size and margin constraints, it autosizes properly within its black parent UIView, while the GLKView fails to do so if you check all of its constraints. The GLKView appears to still be autosizing against the root UIView, which for now appears to be a bug. It could have something to do with setting the GLKView delegate to File's Owner. I've submitted Apple Bug ID# 13777142 that you can refer to if you wish to submit your own bug report.

P.S. I don't see these issues if I embed each GLKView in its own GLKViewController like the other posts on Stack Overflow say to do.

Quarters answered 30/4, 2013 at 22:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.