OpenGLCanvas.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   OpenGLCanvas.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Matthew Jacobs (jacobs.mh@gmail.com)
00005    @date   Fall 2008
00006    
00007    @brief
00008       Provides an OpenGL rendering view
00009    <!-------------------------------------------------------------------->**/
00010 
00011 #include "OpenGLCanvas.h"
00012 #include "Gui.h"
00013 
00014 #include <milton.h>
00015 #include <QtGui>
00016 
00017 OpenGLCanvas::OpenGLCanvas(bool defaultInteractionListeners, 
00018                            Gui *gui, unsigned width, unsigned height)
00019    : QGLWidget(QGLFormat(QGL::SampleBuffers)), Canvas(gui, width, height), m_drawMode(MODE_SOLID)
00020 {
00021    _init(defaultInteractionListeners);
00022 }
00023 
00024 OpenGLCanvas::OpenGLCanvas(Gui *gui, unsigned width, unsigned height)
00025    : QGLWidget(QGLFormat(QGL::SampleBuffers)), Canvas(gui, width, height), m_drawMode(MODE_SOLID)
00026 {
00027    _init(true);
00028 }
00029 
00030 OpenGLCanvas::~OpenGLCanvas()
00031 { }
00032 
00033 void OpenGLCanvas::init() {
00034    if (!m_initted) {
00035       if (NULL == m_renderer) {
00036          Scene *scene = new Scene(MaterialList(), new ShapeSet(false));
00037          m_renderer   = new OpenGLRenderer(new ThinLensCamera(), scene);
00038       }
00039       
00040       Canvas::init();
00041    }
00042 }
00043 
00044 bool OpenGLCanvas::save(const char *fileName) {
00045    // technical Qt note:
00046    //    renderPixmap creates a new, temporary GL context and renders this 
00047    // OpenGLCanvas in that new context. this 'flushPreview' flag denotes to 
00048    // Milton shapes / objects that prior display lists, textures, etc. have 
00049    // been invalidated (because they don't cross over between GL contexts), 
00050    // and therefore need to be recreated before using them; otherwise, 
00051    // attempting to use a previously-compiled display list, for example, 
00052    // would silently fail within renderPixmap.
00053    ResourceManager::insert<bool>("flushPreview", true);
00054    const QPixmap &temp = renderPixmap();
00055    ResourceManager::insert<bool>("flushPreview", false);
00056    
00057    return temp.save(QString(fileName), NULL, -1);
00058 }
00059 
00060 
00061 void OpenGLCanvas::lightOn(int light) {
00062    ASSERT(light >= 0 && light < 8);
00063    glEnable(GL_LIGHT0 + light);
00064 }
00065 
00066 void OpenGLCanvas::lightOff(int light) {
00067    ASSERT(light >= 0 && light < 8);
00068    glDisable(GL_LIGHT0 + light);
00069 }
00070 
00071 void OpenGLCanvas::lightPos(int light, float x, float y, float z) {
00072    ASSERT(light >= 0 && light < 8);
00073    GLfloat pos[4] = {x, y, z, 1};
00074    
00075    glPushMatrix();
00076    glLoadIdentity();
00077    glLightfv(GL_LIGHT0+light, GL_POSITION, pos);
00078    glPopMatrix();
00079 }
00080 
00081 void OpenGLCanvas::lightColor(int light, float r, float g, float b) {
00082    ASSERT(light >= 0 && light < 8);
00083    GLfloat color[4] = { r, g, b, 1};
00084    
00085    glLightfv(GL_LIGHT0+light, GL_DIFFUSE, color);
00086    glLightfv(GL_LIGHT0+light, GL_SPECULAR, color);
00087 }
00088 
00089 void OpenGLCanvas::lightFunc(int light, float a, float b, float c) {
00090    ASSERT(light >= 0 && light < 8);
00091    
00092    glLightf(GL_LIGHT0 + light, GL_CONSTANT_ATTENUATION, a);
00093    glLightf(GL_LIGHT0 + light, GL_LINEAR_ATTENUATION, b);
00094    glLightf(GL_LIGHT0 + light, GL_QUADRATIC_ATTENUATION, c);
00095 }
00096 
00097 
00098 bool OpenGLCanvas::supportsOpenGL() const {
00099    return true;
00100 }
00101 
00102 
00103 void OpenGLCanvas::mousePressEvent(QMouseEvent *e) {
00104    mousePressed(e);
00105 }
00106 
00107 void OpenGLCanvas::mouseReleaseEvent(QMouseEvent *e) {
00108    mouseReleased(e);
00109 }
00110 
00111 void OpenGLCanvas::mouseMoveEvent(QMouseEvent *e) {
00112    mouseMoved(e);
00113 }
00114 
00115 void OpenGLCanvas::keyPressEvent(QKeyEvent *e) {
00116    keyPressed(e);
00117 }
00118 
00119 void OpenGLCanvas::keyReleaseEvent(QKeyEvent *e) {
00120    keyReleased(e);
00121 }
00122 
00123 
00124 QSize OpenGLCanvas::sizeHint() const {
00125    return QSize(m_width, m_height);
00126 }
00127 
00128 QSize OpenGLCanvas::minimumSize() const {
00129    return sizeHint();
00130 }
00131 
00132 QSize OpenGLCanvas::maximumSize() const {
00133    return sizeHint();
00134 }
00135 
00136 
00137 void OpenGLCanvas::initializeGL() {
00138    qglClearColor(Qt::black);
00139    
00140    glShadeModel(GL_SMOOTH);
00141    glDisable(GL_DITHER);
00142    glDisable(GL_NORMALIZE);
00143    glEnable(GL_DEPTH_TEST);
00144    
00145    glEnable(GL_LIGHTING);
00146    for(int i = 8; i--;) {
00147       glDisable(GL_LIGHT0+i);
00148       lightFunc(i, 0, .5, .2);
00149    }
00150    
00151    glColorMaterial(GL_FRONT, GL_DIFFUSE);
00152    glEnable(GL_MULTISAMPLE);
00153    glEnable(GL_CULL_FACE);
00154    
00155    setDrawMode(m_drawMode);
00156 }
00157 
00158 void OpenGLCanvas::redraw() {
00159    update();
00160 }
00161 
00162 void OpenGLCanvas::paintEvent(QPaintEvent *e) {
00163    int err;
00164    if ((err = glGetError()) != GL_NO_ERROR) {
00165       cerr << "GL is in an error state before call to paintGL()" << endl;
00166       cerr << "(Error: " << gluErrorString(err) << ")\n";
00167       assert(0);
00168    }
00169    
00170    glMatrixMode(GL_MODELVIEW);
00171    glPushMatrix();
00172    
00173    { // reset lighting
00174       glEnable(GL_LIGHTING);
00175       for(int i = 8; i--;) {
00176          glDisable(GL_LIGHT0 + i);
00177          lightFunc(i, .5, .2, 0);
00178       }
00179       
00180       glColorMaterial(GL_FRONT, GL_DIFFUSE);
00181       glEnable(GL_COLOR_MATERIAL);
00182       
00183       if (ResourceManager::getValue<bool>("enableDefaultLighting", true)) {
00184          const real_t p = 4.5;
00185          unsigned index = 0;
00186          
00187          for(int dim = 3; dim--;) {
00188             real_t pos[3] = { 1, 1, 1 };
00189             
00190             for(real_t sign = -1; sign <= 1; sign += 2) {
00191                pos[dim] = sign * p;
00192                pos[(dim + 1) % 3] *= (dim + 1);
00193                pos[(dim + 2) % 3] *= (dim + 1);
00194                
00195                lightOn(index);
00196                lightPos(index, pos[0], pos[1], pos[2]);
00197                lightFunc(index, .5, (2-sign)/4.0, 0);
00198                
00199                const real_t power = 1;
00200                lightColor(index, power, power, power);
00201                
00202                ++index;
00203             }
00204          }
00205          
00206          lightOn(index);
00207          lightPos(index, 2, 2, 2);
00208          lightFunc(index, 1, .3, 0);
00209          lightColor(index, 1, 1, 1);
00210          ++index;
00211          
00212          // attempt to place a light at the center of the scene's bounding box
00213          if (m_renderer) {
00214             Scene *scene = m_renderer->getScene();
00215             
00216             if (scene) {
00217                ShapeSet *shapes = scene->getShapes();
00218                
00219                if (shapes) {
00220                   const Point3 &p = shapes->getAABB().getCenter();
00221                   
00222                   lightOn(index);
00223                   lightPos(index, p[0], p[1], p[2]);
00224                   lightFunc(index, .5, 0, 0);
00225                   lightColor(index, 1, 1, 1);
00226                }
00227             }
00228          }
00229       }
00230    }
00231    
00232    int oldDrawMode = m_drawMode;
00233    if (m_renderer && m_renderer->supportsOpenGL())
00234       m_renderer->render();
00235    
00236    /* Notify all listeners of the paintGL event */
00237    ListenerListIter iter;
00238    
00239    for(iter = m_interactionListeners.begin(); iter != m_interactionListeners.end(); iter++) {
00240       (*iter)->paintGL();
00241    }
00242    
00243    glMatrixMode(GL_MODELVIEW);
00244    glPopMatrix();
00245    
00246    setDrawMode(oldDrawMode);
00247    
00248    /* Notify all listeners of the paint event */
00249    QPainter painter(this);
00250    painter.setRenderHint(QPainter::Antialiasing);
00251    
00252    for(iter = m_interactionListeners.begin(); iter != m_interactionListeners.end(); iter++) {
00253       (*iter)->paint(&painter);
00254    }
00255    
00256    if ((err = glGetError()) != GL_NO_ERROR) {
00257       cerr << "GL is in an error state after call to paintGL()" << endl;
00258       cerr << "(Error: " << gluErrorString(err) << ")\n";
00259       assert(0);
00260    }
00261 }
00262 
00263 void OpenGLCanvas::resizeGL(int width, int height) {
00264    glViewport(0, 0, width, height);
00265 }
00266 
00267 void OpenGLCanvas::setDrawMode(int style) {
00268    makeCurrent();
00269    
00270    if (style == MODE_WIREFRAME)
00271       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00272    else // MODE_SOLID
00273       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00274    
00275    m_drawMode = style;
00276 }
00277 
00278 
00279 void OpenGLCanvas::_init(bool defaultInteractionListeners) {
00280    _setupQWidget();
00281    
00282    if (defaultInteractionListeners) {
00283       registerInteractionListener(new CameraUIListener(this));
00284    }
00285 }
00286 
00287 void OpenGLCanvas::_setupQWidget() {
00288    // minor optimization: tell Qt that we'll be painting our own background
00289    setAutoFillBackground(false);
00290    setAttribute(Qt::WA_NoSystemBackground);
00291    setFocusPolicy(Qt::StrongFocus);
00292    
00293    if (layout() != NULL)
00294       layout()->setSizeConstraint(QLayout::SetFixedSize);
00295    
00296    setMouseTracking(true);
00297    setFixedSize(m_width, m_height);
00298    
00299    // display a message if OpenGL is not supported
00300    // (over remote login, for example)
00301    if (!QGLFormat::hasOpenGL()) {
00302       dprintf("\nERROR: OpenGL not supported on this device!\n"
00303               "\t(OpenGLCanvas is invalid)\n\n");
00304    }
00305 }
00306 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6