/****************************************************************************
** $Id: qt/glbox.cpp   3.3.6   edited Aug 31 2005 $
**
** Copyright (C) 1992-2005 Trolltech AS.  All rights reserved.
**
** This file is part of an example program for Qt.  This example
** program may be used, distributed and modified without limitation.
**
*****************************************************************************/

/****************************************************************************
**
** This is a simple QGLWidget displaying a box
**
** The OpenGL code is mostly borrowed from Brian Pauls "spin" example
** in the Mesa distribution
**
****************************************************************************/

#include "glbox.h"

// Initialize static class variables:

// Shared display list id:
GLuint GLBox::sharedDisplayList = 0;

// Counter keeping track of number of GLBox instances sharing 
// the display list, so that the last instance can delete it:
int GLBox::sharedListUsers = 0;


/*!
  Create a GLBox widget
*/

GLBox::GLBox( QWidget* parent, const char* name, const QGLWidget* shareWidget )
    : QGLWidget( parent, name, shareWidget )
{
    xRot = yRot = zRot = 0.0;		// default object rotation
    scale = 1.0;			// default object scale
    object = 0;
    localDisplayList = 0;
}


/*!
  Set up the OpenGL rendering state. Robustly access shared display list.
*/

void GLBox::initializeGL()
{
    // Let OpenGL clear to black
    qglClearColor( black ); 

    glEnable(GL_DEPTH_TEST);

    if ( sharedListUsers == 0 ) {	// No shared list has been made yet
	sharedDisplayList = makeObject();	// Make one
	object = sharedDisplayList;		// Use it
	sharedListUsers++;				// Keep reference count
	qDebug( "GLBox %s created shared display list.", name() );
    }
    else {				// There is a shared diplay list
	if ( isSharing() ) {		// Can we access it?
	    object = sharedDisplayList;		// Yes, use it
	    sharedListUsers++;			// Keep reference count
	    qDebug( "GLBox %s uses shared display list.", name() );
	}
	else {				
	    localDisplayList = makeObject();	// No, roll our own
	    object = localDisplayList;		// and use that
	    qDebug( "GLBox %s uses private display list.", name() );
	}
    }
}



/*!
  Release allocated resources
*/

GLBox::~GLBox()
{
    makeCurrent();				// We're going to do gl calls
    if ( localDisplayList != 0 ) {		// Did we make our own?
	glDeleteLists( localDisplayList, 1 );	// Yes, delete it
	qDebug( "GLBox %s deleted private display list.", name() );
    }
    else {
	sharedListUsers--;	// No, we used the shared one; keep refcount
	if ( sharedListUsers == 0 ) { 			// Any sharers left?
	    glDeleteLists( sharedDisplayList, 1 );	// No, delete it
	    sharedDisplayList = 0;
	    qDebug( "GLBox %s deleted shared display list.", name() );
	}
    }
}


/*!
  Paint the box. The actual openGL commands for drawing the box are
  performed here.
*/

void GLBox::paintGL()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef( 0.0, 0.0, -3.0 );
    glScalef( scale, scale, scale );

    glRotatef( xRot, 1.0, 0.0, 0.0 ); 
    glRotatef( yRot, 0.0, 1.0, 0.0 ); 
    glRotatef( zRot, 0.0, 0.0, 1.0 );

    glCallList( object );
}




/*!
  Set up the OpenGL view port, matrix mode, etc.
*/

void GLBox::resizeGL( int w, int h )
{
    glViewport( 0, 0, (GLint)w, (GLint)h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10.0);
}


/*!
  Generate an OpenGL display list for the object to be shown, i.e. the box
*/

GLuint GLBox::makeObject()
{
    GLuint list;

    list = glGenLists( 1 );

    glNewList( list, GL_COMPILE );

    glBegin(GL_QUADS);
    /* Front face */
    qglColor( green );
    glVertex3f(-1.0, 1.0, 1.0);
    glVertex3f(1.0, 1.0, 1.0);
    glVertex3f(1.0, -1.0, 1.0);
    glVertex3f(-1.0, -1.0, 1.0);
    /* Back face */
    qglColor( yellow );
    glVertex3f(-1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, -1.0, -1.0);
    glVertex3f(-1.0, -1.0, -1.0);
    /* Top side face */
    qglColor( blue );
    glVertex3f(-1.0, 1.0, 1.0);
    glVertex3f(1.0, 1.0, 1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(-1.0, 1.0, -1.0);
    /* Bottom side face */
    qglColor( red );
    glVertex3f(-1.0, -1.0, 1.0);
    glVertex3f(1.0, -1.0, 1.0);
    glVertex3f(1.0, -1.0, -1.0);
    glVertex3f(-1.0, -1.0, -1.0);
    glEnd();
    glEndList();

    return list;
}


/*!
  Set the rotation angle of the object to \e degrees around the X axis.
*/

void GLBox::setXRotation( int degrees )
{
    xRot = (GLfloat)(degrees % 360);
    updateGL();
}


/*!
  Set the rotation angle of the object to \e degrees around the Y axis.
*/

void GLBox::setYRotation( int degrees )
{
    yRot = (GLfloat)(degrees % 360);
    updateGL();
}


/*!
  Set the rotation angle of the object to \e degrees around the Z axis.
*/

void GLBox::setZRotation( int degrees )
{
    zRot = (GLfloat)(degrees % 360);
    updateGL();
}
