# OpenGL - Stack overflow if I do, Stack underflow if I don't!

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):
glPushMatrix()
glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
glutSolidCube(2); #draw the cube
glPopMatrix();


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():
glPopMatrix()
for x in xrange(10):
glPushMatrix()
glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
glutSolidCube(2); #draw the cube
glPopMatrix();


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!

Thanks!

EDIT:

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

• 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? – r2d2rigo Feb 27 '11 at 14:44
• 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.) – TheBuzzSaw Feb 27 '11 at 16:54
• 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. – TheBuzzSaw Feb 27 '11 at 17:07
• I deleted my answer because it contained error. I assumed something which was not true. – Notabene Feb 27 '11 at 17:14
• Why don't you ask this on Stack'Flow? – Mateen Ulhaq Feb 28 '11 at 1:28

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

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
camera()
for x in xrange(10):
glPushMatrix()
glTranslated(-positionx[x] * 10, 0, -positionz[x] * 10) #translate the cube
glutSolidCube(2) #draw the cube
glPopMatrix()
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)
if (key=='s'):
yrotrad = (yrot / 180 * 3.141592654)
xrotrad = (xrot / 180 * 3.141592654)
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):
sys.exit(0)

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

glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(500, 500)
glutInitWindowPosition (100, 100)
glutCreateWindow("A basic OpenGL Window")
init()
glutDisplayFunc(display)
glutIdleFunc(display)
glutReshapeFunc(reshape)
glutPassiveMotionFunc(mouseMovement)
#check for mouse movement
glutKeyboardFunc (keyboard)
glutMainLoop()

• 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? – Will Feb 28 '11 at 9:25
• 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... – Bethor Feb 28 '11 at 9:56
• This is actually useful - my problem wasnt – Wayne Werner Feb 28 '11 at 16:11
• 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) – Wayne Werner Feb 28 '11 at 16:23
• Lots of lots of code :) – daemonfire300 Feb 28 '11 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):
try:
glPushMatrix()
# draw something
finally:
glPopMatrix()
# I'm trusting some code further out will catch and display your actual error now

• 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 ! – Bethor Feb 28 '11 at 10:09
• 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. – Will Feb 28 '11 at 10:21
• 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. – Bethor Feb 28 '11 at 10:42
• 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. – Will Feb 28 '11 at 11:24
• 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. – Bethor Feb 28 '11 at 11:39