9

I'm having an issue rendering in OpenGL ES 1.1 for an iPhone game that I'm building.

In short, I am rendering 3 items:

  1. Background (works fine)
  2. A number of spherical objects (works fine)
  3. A simple line circle that changes size (I am getting a problem here).

Basically, I am getting an EXC_BAD_ACCESS error when I call drawArrays on the circle. I have tested the code in the basic iPhone OpenGL template and it works just fine, so I can't really track why it's not working here. Can someone point me in the right way?

Here is the drawCircle code used to render the circle.

- (void) drawCircles
{
if (!m_circleEffects.empty())
{
    int segments = 24;
    for (int i = 0; i < m_circleEffects.size(); i++)
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(m_circleEffects[i].position.x, m_circleEffects[i].position.y, 0);

        float radius;
        if(m_circleEffects[i].isPulseOutward)
            radius = cos(m_circleEffects[i].frameCounter * M_PI / 720);
        else
            radius = sin(m_circleEffects[i].frameCounter * M_PI / 720);

        GLfloat circlePoints[segments * 3];                    
        int count = 0;

        for (GLfloat i = 0; i < 360.0f; i += (360.0f / segments))
        {
            circlePoints[count++] = (cos(i * M_PI / 180) * radius);
            circlePoints[count++] = (sin(i * M_PI / 180) * radius);
            circlePoints[count++] = z + 1;
        }

        glEnableClientState(GL_VERTEX_ARRAY);  
        glVertexPointer(3, GL_FLOAT, 0, circlePoints);                       
        glDrawArrays(GL_LINE_LOOP, 0, segments);   
        glDisableClientState(GL_VERTEX_ARRAY);
    }      
    m_circleEffects.clear();
}
}

And the following is my other rendering code. It is called prior to the above code in the run loop. Everything in the following seems to work OK.

- (void)passInVisualsToUse:(vector<Visual>)visuals
{
frameCounter += 0.2;
if (frameCounter >= 360)
    frameCounter -= 360;

glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);

glDepthMask(GL_FALSE);

glBindTexture(GL_TEXTURE_2D, m_backgroundTexture);

glDrawTexfOES(0, 0, 0, 480, 320);
glDepthMask(GL_TRUE);

vector<Visual>::const_iterator visual = visuals.begin();
for (int visualIndex = 0;
     visual != visuals.end();
     ++visual, ++visualIndex)
{        

    if (visual->ObjectType == 1)
        glBindTexture(GL_TEXTURE_2D, m_oneTexture);
    else if (visual->ObjectType == 2)
        glBindTexture(GL_TEXTURE_2D, m_twoTexture);
    else if (visual->ObjectType == 3)
        glBindTexture(GL_TEXTURE_2D, m_threeTexture);
    else
        glBindTexture(GL_TEXTURE_2D, m_fourTexture);

    // Set the viewport transform.
    vec3 position = visual->Position;

    // Set the light position.
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(position.x, position.y, position.z);
    float rotationAngle = visual->RotationAngle;
    glRotatef(rotationAngle, 0, 1, 0);

    float scale = visual->Scale;   

    if (visual->ShouldThrob)
    {
        float scaleFactor = scale + sin(frameCounter) / 25;
        glScalef(scaleFactor, scaleFactor, scale);

        BOOL isPulseOutward;
        if (visual->isPulseOutward)
            isPulseOutward = YES;
        else
            isPulseOutward = NO;

        CircleEffect toAdd;
        toAdd.position = position;
        toAdd.frameCounter = frameCounter;
        toAdd.isPulseOutward = isPulseOutward;
        m_circleEffects.push_back(toAdd);
    }
    else
        glScalef(scale, scale, scale);

    // Set the projection transform.
    float h = (float)screenSize.size.height / (float)screenSize.size.width;

    mat4 projection = mat4::Ortho(xleft, xright, h * xleft, h * xright, znear, zfar);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(projection.Pointer());

    // Draw the surface.
    int stride = sizeof(vec3) + sizeof(vec3) + sizeof(vec2);
    const GLvoid* texCoordOffset = (const GLvoid*) (2 * sizeof(vec3));
    const Drawable& drawable = m_drawables[visualIndex];
    glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
    glVertexPointer(3, GL_FLOAT, stride, 0);
    const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
    glNormalPointer(GL_FLOAT, stride, normalOffset);
    glTexCoordPointer(2, GL_FLOAT, stride, texCoordOffset);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
    glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
}


glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
}

The relevant buffers have been set-up elsewhere, and as mentioned, the second code all works fine.

Basically, I am getting an EXC_BAD_ACCESS on the drawArrays code in the top code snippet. Anyone have any ideas why?

Thanks

paynio
  • 111
  • 4
  • 10
  • Are you rendering this on a background thread? Is there a chance that something else could be accessing the OpenGL context at the same time as this? I've seen that cause crashes like this in the past. – Brad Larson May 27 '11 at 18:36
  • No, it's on the main thread, and I've not got anything else running on a background thread that could be accessing the context. By the way, I enjoyed your OpenGL lectures: they were very helpful when I set out learning a few months back! [Can I hold you to blame if I can't solve this OpenGL problem? :-)] – paynio May 31 '11 at 13:55

3 Answers3

10

My guess is the GL state has an array still bound that shouldn't be.

If it works on its own, then that method might be fine. But a previous method may not have returned the state to what it should be or something.

v01d
  • 1,576
  • 14
  • 19
  • Thanks v01d, I think you might be on the right lines. I've got a few other functions that are used to initialize the openGL set-up, textures etc. I'll try and work through these again, and if I can't solve the problem, I'll post the remaining code. – paynio May 31 '11 at 13:56
  • 3
    One thing you might want to try also, is make an easy method/macro to check the GL error state and abort if one is found. And then go crazy peppering it around your code. If you have the debugger running you'll catch an error early. Not that this is what is necessarily your problem, but I've had bad access crashes later on from a previous call that was malformed. If you make it a macro call you could make it easily disabled for release and then you can leave the error checks in your code. – v01d Jun 01 '11 at 12:59
  • Thanks v01d, that sounds a very good plan. Will try this a bit later and see if I can find something. – paynio Jun 01 '11 at 15:29
  • 3
    OK, so I finally tracked down the problem, and v01d was right. In the code above I had not unbound the element and array buffers that I was using to render the 'drawable' objects onscreen. When I unbound them by adding "glBindBuffer(GL_ARRAY_BUFFER, 0)" and "glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)" at the end of my render function, then I was able to render a separate object using glDrawArrays later. – paynio Jun 08 '11 at 14:42
  • the glerror suggestion helped me - I had the same crash, but in my case I was passing GL_UNSIGNED_SHORT to glVertexPointer and *NOT* GL_SHORT :) sigh. – Goblinhack May 17 '20 at 02:12
2

This kind of crash also happen when trying to make low-level OpenGL calls from within graphics libraries or engines, e.g. Cocos2D. For example, Cocos2D sets handful of GL states enabled: GL_TEXTURE_COORD_ARRAY, GL_VERTEX_ARRAY, GL_COLOR_ARRAY. In this example, if yor code do not make use of texturing, it will crash unless you disable GL_TEXTURE_COORD_ARRAY.

Thanks v01d for hinting that!

Tomek Cejner
  • 1,152
  • 1
  • 11
  • 17
0

As v01d said, you forget to unbind the buffer of previous state, use followed code to clear it.

glBindBuffer(GL_ARRAY_BUFFER, 0)
andrewchan2022
  • 4,953
  • 45
  • 48