Work on OpenGL Example.

This commit is contained in:
David Williams 2009-04-20 21:00:28 +00:00
parent e87f84af86
commit d61827c365
3 changed files with 62 additions and 319 deletions

View File

@ -12,11 +12,11 @@ using namespace std;
OpenGLWidget::OpenGLWidget(QWidget *parent) OpenGLWidget::OpenGLWidget(QWidget *parent)
:QGLWidget(parent) :QGLWidget(parent)
,m_volData(0)
{ {
m_xRotation = 0; m_xRotation = 0;
m_yRotation = 0; m_yRotation = 0;
m_uRegionSideLength = 16.0f; m_uRegionSideLength = 16.0f;
m_distance = -g_uVolumeSideLength / 2.0f;
timer = new QTimer(this); timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update())); connect(timer, SIGNAL(timeout()), this, SLOT(update()));
@ -87,7 +87,8 @@ void OpenGLWidget::setVolume(PolyVox::Volume<PolyVox::uint8_t>* volData)
} }
} }
m_distance = m_volData->getLongestSideLength() / -2.0f; //Projection matrix is dependant on volume size, so we need to set it up again.
setupProjectionMatrix();
} }
} }
@ -124,66 +125,64 @@ void OpenGLWidget::initializeGL()
void OpenGLWidget::resizeGL(int w, int h) void OpenGLWidget::resizeGL(int w, int h)
{ {
glViewport ( 0, 0, w, h ); //Setup the viewport based on the window size
glMatrixMode ( GL_PROJECTION ); // Select The Projection Matrix glViewport(0, 0, w, h);
glLoadIdentity ( ); // Reset The Projection Matrix
float aspect = ( float ) w / ( float ) h; //Projection matrix is also dependant on the size of the current volume.
glOrtho(-m_distance*aspect, m_distance*aspect, -m_distance, m_distance, 1.0, 5000); if(m_volData)
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix {
glLoadIdentity ( ); // Reset The Model View Matrix setupProjectionMatrix();
}
} }
void OpenGLWidget::paintGL() void OpenGLWidget::paintGL()
{ {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer if(m_volData)
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix
glLoadIdentity(); // Reset The Current Modelview Matrix
//Moves the camera back so we can see the volume
glTranslatef(0.0f, 0.0f, m_distance);
//Rotate the volume by the required amount
//glRotatef(g_xRotation, 1.0f, 0.0f, 0.0f);
//glRotatef(g_yRotation, 0.0f, 1.0f, 0.0f);
;
glRotatef(m_xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(m_yRotation, 0.0f, 1.0f, 0.0f);
//Centre the volume on the origin
glTranslatef(-g_uVolumeSideLength/2,-g_uVolumeSideLength/2,-g_uVolumeSideLength/2);
for(PolyVox::uint16_t uRegionZ = 0; uRegionZ < m_uVolumeDepthInRegions; ++uRegionZ)
{ {
for(PolyVox::uint16_t uRegionY = 0; uRegionY < m_uVolumeHeightInRegions; ++uRegionY) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
{
for(PolyVox::uint16_t uRegionX = 0; uRegionX < m_uVolumeWidthInRegions; ++uRegionX)
{
Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ);
if(m_bUseOpenGLVertexBufferObjects)
{
renderRegionVertexBufferObject(m_mapOpenGLSurfacePatches[v3dRegPos]);
}
else
{
IndexedSurfacePatch* ispCurrent = m_mapIndexedSurfacePatches[v3dRegPos];
renderRegionImmediateMode(*ispCurrent);
glMatrixMode(GL_MODELVIEW); // Select The Model View Matrix
glLoadIdentity(); // Reset The Current Modelview Matrix
//Moves the camera back so we can see the volume
glTranslatef(0.0f, 0.0f, -m_volData->getDiagonalLength());
glRotatef(m_xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(m_yRotation, 0.0f, 1.0f, 0.0f);
//Centre the volume on the origin
glTranslatef(-g_uVolumeSideLength/2,-g_uVolumeSideLength/2,-g_uVolumeSideLength/2);
for(PolyVox::uint16_t uRegionZ = 0; uRegionZ < m_uVolumeDepthInRegions; ++uRegionZ)
{
for(PolyVox::uint16_t uRegionY = 0; uRegionY < m_uVolumeHeightInRegions; ++uRegionY)
{
for(PolyVox::uint16_t uRegionX = 0; uRegionX < m_uVolumeWidthInRegions; ++uRegionX)
{
Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ);
if(m_bUseOpenGLVertexBufferObjects)
{
renderRegionVertexBufferObject(m_mapOpenGLSurfacePatches[v3dRegPos]);
}
else
{
IndexedSurfacePatch* ispCurrent = m_mapIndexedSurfacePatches[v3dRegPos];
renderRegionImmediateMode(*ispCurrent);
}
} }
} }
} }
GLenum errCode;
const GLubyte *errString;
if ((errCode = glGetError()) != GL_NO_ERROR)
{
errString = gluErrorString(errCode);
cout << "OpenGL Error: " << errString << endl;
}
} }
GLenum errCode;
const GLubyte *errString;
if ((errCode = glGetError()) != GL_NO_ERROR)
{
errString = gluErrorString(errCode);
cout << "OpenGL Error: " << errString << endl;
} // Reset The Current Modelview Matrix
} }
void OpenGLWidget::mousePressEvent(QMouseEvent* event) void OpenGLWidget::mousePressEvent(QMouseEvent* event)
@ -203,5 +202,15 @@ void OpenGLWidget::mouseMoveEvent(QMouseEvent* event)
void OpenGLWidget::wheelEvent(QWheelEvent* event) void OpenGLWidget::wheelEvent(QWheelEvent* event)
{ {
m_distance += event->delta() / 120.0f; }
void OpenGLWidget::setupProjectionMatrix(void)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float frustumSize = m_volData->getDiagonalLength() / 2.0f;
float aspect = static_cast<float>(width()) / static_cast<float>(height());
glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 5000);
} }

View File

@ -37,12 +37,12 @@ class OpenGLWidget : public QGLWidget
void paintGL(); void paintGL();
private: private:
void setupProjectionMatrix(void);
QPoint m_LastFrameMousePos; QPoint m_LastFrameMousePos;
QPoint m_CurrentMousePos; QPoint m_CurrentMousePos;
int m_xRotation; int m_xRotation;
int m_yRotation; int m_yRotation;
float m_distance;
QTimer *timer; QTimer *timer;

View File

@ -79,269 +79,3 @@ int main(int argc, char *argv[])
return app.exec(); return app.exec();
} }
#ifdef USING_GLUT
#ifdef WIN32
#include "glew/glew.h"
#else
#include <gl/gl.h> // The GL Header File
#endif
#include <gl/glut.h> // The GL Utility Toolkit (Glut) Header]
#include <iostream>
//Some namespaces we need
using namespace std;
using namespace PolyVox;
using namespace std;
//Global variables are easier for demonstration purposes, especially
//as I'm not sure how/if I can pass variables to the GLUT functions.
//Global variables are denoted by the 'g_' prefix
const uint16_t g_uVolumeSideLength = 256;
const uint16_t g_uRegionSideLength = 16;
const uint16_t g_uVolumeSideLengthInRegions = g_uVolumeSideLength / g_uRegionSideLength;
int g_xRotation = 0.0f;
int g_yRotation = 0.0f;
int g_xOld = 0;
int g_yOld = 0;
int g_frameCounter = 0;
bool g_bUseOpenGLVertexBufferObjects;
//Creates a volume 128x128x128
Volume<uint8_t> g_volData(g_uVolumeSideLength);
//Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region
OpenGLSurfacePatch g_openGLSurfacePatches[g_uVolumeSideLengthInRegions][g_uVolumeSideLengthInRegions][g_uVolumeSideLengthInRegions];
IndexedSurfacePatch* g_indexedSurfacePatches[g_uVolumeSideLengthInRegions][g_uVolumeSideLengthInRegions][g_uVolumeSideLengthInRegions];
void timerFunc(int value)
{
cout << "FPS = " << g_frameCounter << endl;
g_frameCounter = 0;
glutTimerFunc(1000, timerFunc, 0);
}
void init ( GLvoid ) // Create Some Everyday Functions
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glEnable ( GL_COLOR_MATERIAL );
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
}
void display ( void ) // Create The Display Function
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix
glLoadIdentity(); // Reset The Current Modelview Matrix
//Moves the camera back so we can see the volume
glTranslatef(0.0f, 0.0f, -100.0f);
//Rotate the volume by the required amount
glRotatef(g_xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(g_yRotation, 0.0f, 1.0f, 0.0f);
//Centre the volume on the origin
glTranslatef(-g_uVolumeSideLength/2,-g_uVolumeSideLength/2,-g_uVolumeSideLength/2);
for(uint16_t uRegionZ = 0; uRegionZ < g_uVolumeSideLengthInRegions; ++uRegionZ)
{
for(uint16_t uRegionY = 0; uRegionY < g_uVolumeSideLengthInRegions; ++uRegionY)
{
for(uint16_t uRegionX = 0; uRegionX < g_uVolumeSideLengthInRegions; ++uRegionX)
{
if(g_bUseOpenGLVertexBufferObjects)
{
renderRegionVertexBufferObject(g_openGLSurfacePatches[uRegionX][uRegionY][uRegionZ]);
}
else
{
IndexedSurfacePatch* ispCurrent = g_indexedSurfacePatches[uRegionX][uRegionY][uRegionZ];
renderRegionImmediateMode(*ispCurrent);
}
}
}
}
GLenum errCode;
const GLubyte *errString;
if ((errCode = glGetError()) != GL_NO_ERROR)
{
errString = gluErrorString(errCode);
cout << "OpenGL Error: " << errString << endl;
}
g_frameCounter++;
glutSwapBuffers ( );
// Swap The Buffers To Not Be Left With A Clear Screen
}
void idle()
{
glutPostRedisplay();
}
void reshape ( int w, int h ) // Create The Reshape Function (the viewport)
{
glViewport ( 0, 0, w, h );
glMatrixMode ( GL_PROJECTION ); // Select The Projection Matrix
glLoadIdentity ( ); // Reset The Projection Matrix
if ( h==0 ) // Calculate The Aspect Ratio Of The Window
gluPerspective ( 80, ( float ) w, 1.0, 5000.0 );
else
gluPerspective ( 80, ( float ) w / ( float ) h, 1.0, 5000.0 );
glMatrixMode ( GL_MODELVIEW ); // Select The Model View Matrix
glLoadIdentity ( ); // Reset The Model View Matrix
}
void keyboard ( unsigned char key, int x, int y ) // Create Keyboard Function
{
switch ( key ) {
case 27: // When Escape Is Pressed...
exit ( 0 ); // Exit The Program
break; // Ready For Next Case
default: // Now Wrap It Up
break;
}
}
void motion(int x, int y)
{
glMatrixMode(GL_MODELVIEW);
int xDiff = x - g_xOld;
int yDiff = y - g_yOld;
g_xOld = x;
g_yOld = y;
g_xRotation += xDiff;
g_yRotation += yDiff;
}
void arrow_keys ( int a_keys, int x, int y ) // Create Special Function (required for arrow keys)
{
switch ( a_keys ) {
case GLUT_KEY_UP: // When Up Arrow Is Pressed...
glutFullScreen ( ); // Go Into Full Screen Mode
break;
case GLUT_KEY_DOWN: // When Down Arrow Is Pressed...
glutReshapeWindow ( 500, 500 ); // Go Into A 500 By 500 Window
break;
default:
break;
}
}
void main ( int argc, char** argv ) // Create Main Function For Bringing It All Together
{
g_bUseOpenGLVertexBufferObjects = true;
glutInit ( &argc, argv ); // Erm Just Write It =)
glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE ); // Display Mode
glutInitWindowSize ( 500, 500 ); // If glutFullScreen wasn't called this is the window size
glutCreateWindow ( "PolyVox OpenGL Example" ); // Window Title (argv[0] for current directory as title)
glutMotionFunc(motion);
glutDisplayFunc ( display ); // Matching Earlier Functions To Their Counterparts
glutReshapeFunc ( reshape );
glutKeyboardFunc ( keyboard );
glutSpecialFunc ( arrow_keys );
glutTimerFunc(1000, timerFunc, 0);
glutIdleFunc(idle);
if(g_bUseOpenGLVertexBufferObjects)
{
#ifdef WIN32
//If we are on Windows we will need GLEW to access recent OpenGL functionality
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
cout << "Error: " << glewGetErrorString(err) << endl;
}
#endif
}
//Make our volume contain a sphere in the center.
uint16_t minPos = 0;
uint16_t midPos = g_volData.getSideLength() / 2;
uint16_t maxPos = g_volData.getSideLength() - 1;
createCubeInVolume(g_volData, Vector3DUint16(minPos, minPos, minPos), Vector3DUint16(maxPos, maxPos, maxPos), 0);
createSphereInVolume(g_volData, 50.0f, 5);
createSphereInVolume(g_volData, 40.0f, 4);
createSphereInVolume(g_volData, 30.0f, 3);
createSphereInVolume(g_volData, 20.0f, 2);
createSphereInVolume(g_volData, 10.0f, 1);
createCubeInVolume(g_volData, Vector3DUint16(minPos, minPos, minPos), Vector3DUint16(midPos-1, midPos-1, midPos-1), 0);
createCubeInVolume(g_volData, Vector3DUint16(midPos+1, midPos+1, minPos), Vector3DUint16(maxPos, maxPos, midPos-1), 0);
createCubeInVolume(g_volData, Vector3DUint16(midPos+1, minPos, midPos+1), Vector3DUint16(maxPos, midPos-1, maxPos), 0);
createCubeInVolume(g_volData, Vector3DUint16(minPos, midPos+1, midPos+1), Vector3DUint16(midPos-1, maxPos, maxPos), 0);
//Our volume is broken down into cuboid regions, and we create one mesh for each region.
//This three-level for loop iterates over each region.
for(uint16_t uRegionZ = 0; uRegionZ < g_uVolumeSideLengthInRegions; ++uRegionZ)
{
for(uint16_t uRegionY = 0; uRegionY < g_uVolumeSideLengthInRegions; ++uRegionY)
{
for(uint16_t uRegionX = 0; uRegionX < g_uVolumeSideLengthInRegions; ++uRegionX)
{
//Create a new surface patch (which is basiaclly the PolyVox term for a mesh).
IndexedSurfacePatch* ispCurrent = new IndexedSurfacePatch();
//Compute the extents of the current region
//FIXME - This is a little complex? PolyVox could
//provide more functions for dealing with regions?
uint16_t regionStartX = uRegionX * g_uRegionSideLength;
uint16_t regionStartY = uRegionY * g_uRegionSideLength;
uint16_t regionStartZ = uRegionZ * g_uRegionSideLength;
uint16_t regionEndX = regionStartX + g_uRegionSideLength + 1; //Why do we need the '+1' here?
uint16_t regionEndY = regionStartY + g_uRegionSideLength + 1; //Why do we need the '+1' here?
uint16_t regionEndZ = regionStartZ + g_uRegionSideLength + 1; //Why do we need the '+1' here?
Vector3DInt32 regLowerCorner(regionStartX, regionStartY, regionStartZ);
Vector3DInt32 regUpperCorner(regionEndX, regionEndY, regionEndZ);
//Extract the surface for this region
extractReferenceSurface(&g_volData, Region(regLowerCorner, regUpperCorner), ispCurrent);
if(g_bUseOpenGLVertexBufferObjects)
{
g_openGLSurfacePatches[uRegionX][uRegionY][uRegionZ] = BuildOpenGLSurfacePatch(*ispCurrent);
}
else
{
g_indexedSurfacePatches[uRegionX][uRegionY][uRegionZ] = ispCurrent;
}
//delete ispCurrent;
}
}
}
init ();
glutMainLoop ( ); // Initialize The Main Loop
}
#endif //USING_GLUT