Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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

share|improve this question
2  
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
1  
Why don't you ask this on Stack'Flow? –  muntoo Feb 28 '11 at 1:28

3 Answers 3

up vote 9 down vote accepted

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
    glLoadIdentity()
    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

    glLoadIdentity();
    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):
        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()
share|improve this answer
2  
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
1  
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
1  
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
share|improve this answer
    
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
1  
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

Are you sure the loop is running like so:

def cube():

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

Otherwise you get a stack of unpoped matrices

EDIT: Well, I didn't knew about indentation rules in python. My mistake.

Another note - are you sure you can access X+1 index here? positionx[x + 1]

share|improve this answer
    
It should be running like that. Gotta love Python and its whitespace-based syntax. :P –  TheBuzzSaw Feb 27 '11 at 17:30
    
This is exactly how it runs. <JustPersonalOpinion-DoNotFlame> Because it is python and python is crazy and you define { and } by tabulator. </JustPersonalOpinion-DoNotFlame> –  Notabene Feb 27 '11 at 17:32
    
The way the OP indented the loop, yes, that is basically how the loop is running. –  li.davidm Feb 27 '11 at 18:37
    
-1 Ofcourse the OP is sure his loop runs this way. Indentation is a standard feature of python and OP clearly shows this by having the statements indented properly in the code. OP is not the one who is confused on this aspect. –  5ound Feb 27 '11 at 23:47
2  
@5ound: The OP would clearly rather be writing C/JS/something than Python, and whitespace details are often lost when pasting, I think double-checking indentation is a reasonable question. –  user744 Feb 28 '11 at 1:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.