I'm in a multimedia class in college, and we're "learning" OpenGL as part of the class. I'm trying to figure out how the OpenGL camera vs. modelview works, and so I found this example. I'm trying to port the example to Python using the OpenGL bindings - it starts up OpenGL much faster, so for testing purposes it's a lot nicer - but I keep running into a stack overflow error with the glPushMatrix in this code:

  def cube(): 
      for x in xrange(10):
          glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
          glutSolidCube(2); #draw the cube

According to this reference, that happens when the matrix stack is full.

So I thought, "well, if it's full, let me just pop the matrix off the top of the stack, and there will be room". I modified the code to:

  def cube(): 
      for x in xrange(10):
          glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
          glutSolidCube(2); #draw the cube

And now I get a buffer underflow error - which apparently happens when the stack has only one matrix.

So am I just waaay off base in my understanding? Or is there some way to increase the matrix stack size?

Also, if anyone has some good (online) references (examples, etc.) for understanding how the camera/model matrices work together, I would sincerely appreciate them!



Here is the pastebin of the full code: http://pastebin.com/QXxNisuA

  • 2
    \$\begingroup\$ Is that your entire code? Are you sure you aren't doing any more glPushMatrix that don't have a corresponding glPopMatrix? Are you sure the for isn't affecting only the glPushMatrix instruction? \$\endgroup\$
    – r2d2rigo
    Feb 27, 2011 at 14:44
  • \$\begingroup\$ Yes, we need to see your other code. Where are you setting up the projection matrix? Are you switched to GL_MODELVIEW mode yet? (The projection matrix stack is incredibly small.) \$\endgroup\$
    – TheBuzzSaw
    Feb 27, 2011 at 16:54
  • \$\begingroup\$ Definitely avoid your second code sample. Having a glPopMatrix just floating there without a corresponding glPushMatrix would certainly lead to an underflow. Your first code sample looks OK; there must be an issue in the rest of your code. \$\endgroup\$
    – TheBuzzSaw
    Feb 27, 2011 at 17:07
  • \$\begingroup\$ I deleted my answer because it contained error. I assumed something which was not true. \$\endgroup\$
    – Notabene
    Feb 27, 2011 at 17:14
  • 1
    \$\begingroup\$ Why don't you ask this on Stack'Flow? \$\endgroup\$ Feb 28, 2011 at 1:28

2 Answers 2


Edited to add: this isn't important for now as it will still work just fine and makes learning OpenGL easier but do note that the whole matrix stack system is deprecated in OpenGL 3.x and beyond. One possible replacement is GLM.

The code in your pastebin fails to even run for me.

In particular, your list indices in the display function are out of range (your list has 10 elements : python lists start at 0; you index from 0+1 to 10+1).

I think you also had some globals missing in the mouse handling function but that could be from me moving code around in an attempt to at least make it look like python ;)

Anyway, with these fixes, the code shown below DOES work for me, with no signs of GL matrix stack under/overflow !

import sys
from math import sin, cos
from random import randint
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
#angle of rotation
xpos= ypos= zpos= xrot= yrot= angle= lastx= lasty = 0

#positions of the cubes
positionz = []
positionx = []

def init():
    global positionz, positionx
    glEnable(GL_DEPTH_TEST) #enable the depth testing
    glEnable(GL_LIGHTING) #enable the lighting
    glEnable(GL_LIGHT0) #enable LIGHT0, our Diffuse Light
    glShadeModel(GL_SMOOTH) #set the shader to smooth shader

    positionx = [randint(0, 10) for x in xrange(10)]
    positionz = [randint(0, 10) for x in xrange(10)]

def camera():
    global xrot, yrot, xpos, ypos, zpos
    glRotatef(xrot,1.0,0.0,0.0)  #rotate our camera on teh x-axis (left and right)
    glRotatef(yrot,0.0,1.0,0.0)  #rotate our camera on the y-axis (up and down)
    glTranslated(-xpos,-ypos,-zpos) #translate the screen to the position of our camera

def display():
    global angle
    glClearColor(0.0,0.0,0.0,1.0) #clear the screen to black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #clear the color buffer and the depth buffer
    for x in xrange(10):
        glTranslated(-positionx[x] * 10, 0, -positionz[x] * 10) #translate the cube
        glutSolidCube(2) #draw the cube
    glutSwapBuffers() #swap the buffers
    angle += angle #increase the angle

def reshape(w, h):
    glViewport(0, 0, w, h); #set the viewport to the current window specifications
    glMatrixMode(GL_PROJECTION); #set the matrix to projection

    gluPerspective(60, w / h, 1.0, 1000.0)
    #set the perspective (angle of sight, width, height, , depth)
    glMatrixMode(GL_MODELVIEW); #set the matrix back to model

def keyboard (key, x, y):
    global xrot, xpos, ypos, zpos, xrot, yrot, angle, lastx, lasty, positionz, positionx
    if (key=='q'):
        xrot += 1
        if (xrot >360):
            xrot -= 360
    if (key=='z'):
        xrot -= 1;
        if (xrot < -360): xrot += 360
    if (key=='w'):
        yrotrad = (yrot / 180 * 3.141592654)
        xrotrad = (xrot / 180 * 3.141592654)
        xpos += float(sin(yrotrad))
        zpos -= float(cos(yrotrad))
        ypos -= float(sin(xrotrad))
    if (key=='s'):
        yrotrad = (yrot / 180 * 3.141592654)
        xrotrad = (xrot / 180 * 3.141592654)
        xpos -= float(sin(yrotrad))
        zpos += float(cos(yrotrad))
        ypos += float(sin(xrotrad))
    if (key=='d'):
        yrotrad = (yrot / 180 * 3.141592654)
        xpos += float(cos(yrotrad)) * 0.2
        zpos += float(sin(yrotrad)) * 0.2
    if (key=='a'):
        yrotrad = (yrot / 180 * 3.141592654)
        xpos -= float(cos(yrotrad)) * 0.2
        zpos -= float(sin(yrotrad)) * 0.2
    if (key==27):

def mouseMovement(x, y):
    global lastx, lasty, xrot, yrot
    diffx=x-lastx #check the difference between the current x and the last x position
    diffy=y-lasty #check the difference between the current y and the last y position
    lastx=x #set lastx to the current x position
    lasty=y #set lasty to the current y position
    xrot += float(diffy) #set the xrot to xrot with the addition of the difference in the y position
    yrot += float(diffx) #set the xrot to yrot with the addition of the difference in the x position

glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(500, 500)
glutInitWindowPosition (100, 100)
glutCreateWindow("A basic OpenGL Window")
#check for mouse movement
glutKeyboardFunc (keyboard)
  • 4
    \$\begingroup\$ You just did their homework! Will they learn what went wrong and how to fix it, or will they just copy and paste and move on? \$\endgroup\$
    – Will
    Feb 28, 2011 at 9:25
  • 1
    \$\begingroup\$ So being too helpful is a reason to vote down ? And fixing what was basically a single off by one mistake is "doing their homework" ? If you look at the full code the OP put on pastebin, you'll note I just moved code around so I could read it more easily, and changed those two wrong indices... \$\endgroup\$
    – Bethor
    Feb 28, 2011 at 9:56
  • 1
    \$\begingroup\$ This is actually useful - my problem wasnt \$\endgroup\$ Feb 28, 2011 at 16:11
  • \$\begingroup\$ This reply is actually useful, and also has very little to do with my actual homework. As I initially posted, I'm interested in figuring out how the camera works - which means that I will be fiddling around with this code. Bethor answered my question (it was a one-off error, built into the original code example), and went above and beyond and cleaned up the code. Hence getting accepted. (drat SO for auto-posting my comment and cutting my time off before I could draft a decent comment) \$\endgroup\$ Feb 28, 2011 at 16:23
  • \$\begingroup\$ Lots of lots of code :) \$\endgroup\$ Feb 28, 2011 at 20:03

OpenGL can store and restore matrices on a stack using glPushMatrix and glPopMatrix. It is very important that each push has a corresponding pop - if you push more than you pop, you get told when all the drawing is over that you are overflowing the stack. If you pop more than you push, you get told immediately that you are underflowing the stack. This is how OpenGL lets you localise programming errors.

So ensure that all pushes everywhere have a corresponding pop.

Everywhere you push, ensure there is a corresponding pop in the exit of that code block.

If your code is throwing an exception (i.e. your iterating out of bounds in your array?), it may be that you need to place the pop in a finally block, e.g.:

def cube():
    for x in xrange(10):
            # draw something
            # I'm trusting some code further out will catch and display your actual error now
  • \$\begingroup\$ This won't fix the issue since as you noted, the problem is iterating out of bounds, as I had outlined in my answer that you voted down. Also, this would not help him see his actual answer; since the exception is uncaught, the script will still terminate. So, -1, if I could vote down, especially for the remakably bad form of trying to bury my earlier answer ! \$\endgroup\$
    – Bethor
    Feb 28, 2011 at 10:09
  • \$\begingroup\$ The exception from the GL stack detecting the unbalanced stack is what is stopping him seeing the root cause exception. In the same way he sees the report that he has an unbalanced stack in the terminal, he'll now see that he has an out of bounds exception. \$\endgroup\$
    – Will
    Feb 28, 2011 at 10:21
  • \$\begingroup\$ Fair enough; I'm still not sure how he's seeing a stack overflow though. The code in his pastebin raises an IndexError at the appropriate place for my install of Python 2.7 and the latest PyOpenGL and runs correctly once this is fixed. On top of that, his code does not push more than it pops, as far as I can tell from reading it. \$\endgroup\$
    – Bethor
    Feb 28, 2011 at 10:42
  • 1
    \$\begingroup\$ It depends on the OpenGL implementation; it seems obvious that his OpenGL implementation is aggressively counting in its tidy up code that is getting triggered by the exception unwinding. \$\endgroup\$
    – Will
    Feb 28, 2011 at 11:24
  • \$\begingroup\$ Good point ! The exception that triggered all though is probably still visible to the OP though, I guess he just saw the last one and didn't search for the root cause. \$\endgroup\$
    – Bethor
    Feb 28, 2011 at 11:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .