Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

GlPipe.cpp

Go to the documentation of this file.
00001 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00002  *
00003  * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum, Christopher Just,
00007  *   Patrick Hartling, Kevin Meinert,
00008  *   Carolina Cruz-Neira, Albert Baker
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Library General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Library General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Library General Public
00021  * License along with this library; if not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023  * Boston, MA 02111-1307, USA.
00024  *
00025  * -----------------------------------------------------------------
00026  * File:          $RCSfile: GlPipe.cpp,v $
00027  * Date modified: $Date: 2003/12/31 23:25:42 $
00028  * Version:       $Revision: 1.88 $
00029  * -----------------------------------------------------------------
00030  *
00031  *************** <auto-copyright.pl END do not edit this line> ***************/
00032 
00033 #include <vrj/vrjConfig.h>
00034 
00035 #include <vpr/vpr.h>
00036 
00037 #ifdef VPR_OS_Darwin
00038 #   include <OpenGL/gl.h>
00039 #else
00040 #   include <GL/gl.h>
00041 #endif
00042 
00043 #include <vrj/Kernel/Kernel.h>
00044 #include <vrj/Draw/OGL/GlPipe.h>
00045 #include <vrj/Draw/OGL/GlApp.h>
00046 #include <vpr/Thread/Thread.h>
00047 #include <vpr/Sync/Guard.h>
00048 #include <vrj/Util/Debug.h>
00049 
00050 #include <vrj/Display/SurfaceViewport.h>
00051 #include <vrj/Display/SimViewport.h>
00052 #include <vrj/Draw/OGL/GlSimInterface.h>
00053 #include <boost/concept_check.hpp>
00054 
00055 namespace vrj
00056 {
00057 
00058 
00063 int GlPipe::start()
00064 {
00065     vprASSERT(mThreadRunning == false);        // We should not be running yet
00066 
00067     // Create a new thread to call the control loop
00068     vpr::ThreadMemberFunctor<GlPipe>* memberFunctor =
00069          new vpr::ThreadMemberFunctor<GlPipe>(this, &GlPipe::controlLoop, NULL);
00070 
00071     mActiveThread = new vpr::Thread(memberFunctor);
00072 
00073     vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00074        << "vjGlPipe::start: Started control loop. " << mActiveThread
00075        << std::endl << vprDEBUG_FLUSH;
00076     return 1;        // XXX: Is this always true?
00077 }
00078 
00083 void GlPipe::triggerRender()
00084 {
00085    //vprASSERT(mThreadRunning == true);      // We must be running
00086    while(!mThreadRunning)
00087    {
00088       vprDEBUG(vrjDBG_DRAW_MGR,vprDBG_HVERB_LVL) << "Waiting in for thread to start triggerRender.\n" << vprDEBUG_FLUSH;
00089       vpr::Thread::yield();
00090    }
00091 
00092    renderTriggerSema.release();
00093 }
00094 
00099 void GlPipe::completeRender()
00100 {
00101    vprASSERT(mThreadRunning == true);      // We must be running
00102 
00103    renderCompleteSema.acquire();
00104 }
00105 
00107 void GlPipe::triggerSwap()
00108 {
00109    vprASSERT(mThreadRunning == true);
00110    swapTriggerSema.release();
00111 }
00112 
00114 void GlPipe::completeSwap()
00115 {
00116    vprASSERT(mThreadRunning == true);
00117    swapCompleteSema.acquire();
00118 }
00119 
00120 
00125 void GlPipe::addWindow(GlWindow* win)
00126 {
00127    vpr::Guard<vpr::Mutex> guardNew(mNewWinLock);       // Protect the data
00128    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00129       << "vjGlPipe::addWindow: Pipe: " << mPipeNum
00130       << " adding window (to new wins):\n" << win
00131       << std::endl << vprDEBUG_FLUSH;
00132    mNewWins.push_back(win);
00133 }
00134 
00139 void GlPipe::removeWindow(GlWindow* win)
00140 {
00141    vpr::Guard<vpr::Mutex> guardClosing(mClosingWinLock);
00142    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL)
00143       << "vjGlPipe:: removeWindow: Pipe: " << mPipeNum
00144       << " window added to closingWins.\n" << win
00145       << std::endl << vprDEBUG_FLUSH;
00146    mClosingWins.push_back(win);
00147 }
00148 
00149 
00150 // The main loop routine
00151 // while running <br>
00152 // - Check for windows to open/close <br>
00153 // - Wait for render signal <br>
00154 // - Render all the windows <br>
00155 // - Signal render completed <br>
00156 // - Wait for swap signal <br>
00157 // - Swap all windows <br>
00158 // - Signal swap completed <br>
00159 //
00160 void GlPipe::controlLoop(void* nullParam)
00161 {
00162    boost::ignore_unused_variable_warning(nullParam);
00163    mThreadRunning = true;     // We are running so set flag
00164    // Loop until flag set
00165    while (!controlExit)
00166    {
00167       checkForWindowsToClose();  // Checks for closing windows
00168       checkForNewWindows();      // Checks for new windows to open
00169 
00170       // --- handle EVENTS for the windows --- //
00171       // XXX: This may have to be here because of need to get open window event (Win32)
00172       // otherwise I would like to move it to being after the swap to get better performance
00173       {
00174          for(unsigned int winId=0;winId<mOpenWins.size();winId++)
00175             mOpenWins[winId]->checkEvents();
00176       }
00177 
00178       // --- RENDER the windows ---- //
00179       {
00180          renderTriggerSema.acquire();
00181 
00182          GlApp* the_app = glManager->getApp();
00183 
00184          // --- pipe PRE-draw function ---- //
00185          the_app->pipePreDraw();      // Can't get a context since I may not be guaranteed a window
00186 
00187          // Render the windows
00188          for (unsigned int winId=0;winId < mOpenWins.size();winId++) {
00189             renderWindow(mOpenWins[winId]);
00190          }
00191          renderCompleteSema.release();
00192       }
00193 
00194       // ----- SWAP the windows ------ //
00195       {
00196          swapTriggerSema.acquire();
00197 
00198          // Swap all the windows
00199          for(unsigned int winId=0;winId < mOpenWins.size();winId++)
00200          {
00201             swapWindowBuffers(mOpenWins[winId]);
00202          }
00203 
00204          swapCompleteSema.release();
00205       }
00206    }
00207 
00208    mThreadRunning = false;     // We are not running
00209 }
00210 
00217 void GlPipe::checkForWindowsToClose()
00218 {
00219    if(mClosingWins.size() > 0)   // If there are windows to close
00220    {
00221       vpr::Guard<vpr::Mutex> guardClosing(mClosingWinLock);
00222       vpr::Guard<vpr::Mutex> guardNew(mNewWinLock);
00223       vpr::Guard<vpr::Mutex> guardOpen(mOpenWinLock);
00224 
00225       for(unsigned int i=0;i<mClosingWins.size();i++)
00226       {
00227          GlWindow* win = mClosingWins[i];
00228 
00229          // Call contextClose
00230          GlApp* the_app = glManager->getApp();               // Get application for easy access
00231          //Display* the_display = win->getDisplay();         // Get the display for easy access
00232          glManager->setCurrentContext(win->getId());        // Set TS data of context id
00233          glManager->currentUserData()->setUser(NULL);       // Set user data
00234          glManager->currentUserData()->setProjection(NULL);
00235          glManager->currentUserData()->setViewport(NULL);   // Set vp data
00236          glManager->currentUserData()->setGlWindow(win);    // Set the gl window
00237 
00238          win->makeCurrent();              // Make the context current
00239          the_app->contextClose();          // Call context close function
00240 
00241          // Close the window
00242          win->close();
00243 
00244          // Remove it from the lists
00245          mNewWins.erase(std::remove(mNewWins.begin(), mNewWins.end(), win), mNewWins.end());
00246          mOpenWins.erase(std::remove(mOpenWins.begin(), mOpenWins.end(), win), mOpenWins.end());
00247 
00248          // Delete the window
00249          delete win;
00250          mClosingWins[i] = NULL;
00251       }
00252 
00253       mClosingWins.erase(mClosingWins.begin(), mClosingWins.end());
00254       vprASSERT(mClosingWins.size() == 0);;
00255    }
00256 }
00257 
00262 void GlPipe::checkForNewWindows()
00263 {
00264    if (mNewWins.size() > 0)  // If there are new windows added
00265    {
00266       vpr::Guard<vpr::Mutex> guardNew(mNewWinLock);
00267       vpr::Guard<vpr::Mutex> guardOpen(mOpenWinLock);
00268 
00269       for (unsigned int winNum=0; winNum<mNewWins.size(); winNum++)
00270       {
00271           if (mNewWins[winNum]->open())
00272           {
00273               mNewWins[winNum]->makeCurrent();
00274               vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00275                  << "vrj::GlPipe::checkForNewWindows(): Just opened window: "
00276                  << mNewWins[winNum]->getDisplay()->getName() << std::endl
00277                  << *(mNewWins[winNum]) << std::endl << vprDEBUG_FLUSH;
00278               mNewWins[winNum]->finishSetup();        // Complete any window open stuff
00279               mOpenWins.push_back(mNewWins[winNum]);
00280           } else {
00281               vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00282                  << clrOutBOLD(clrRED,"ERROR:") << "vjGlPipe::checkForNewWindows: Failed to open window: "
00283                  << mNewWins[winNum]->getDisplay()->getName().c_str()
00284                  << std::endl << vprDEBUG_FLUSH;
00285               // XXX: We should handle this error more gracefully
00286           }   // Done
00287       }
00288 
00289       mNewWins.erase(mNewWins.begin(), mNewWins.end());
00290       vprASSERT(mNewWins.size() == 0);
00291    }
00292 }
00293 
00298 void GlPipe::renderWindow(GlWindow* win)
00299 {
00300    float vp_ox, vp_oy, vp_sx, vp_sy;            // Viewport origin and size
00301    Viewport::View  view;                      // The view for the active viewport
00302 
00303    GlApp* the_app = glManager->getApp();       // Get application for easy access
00304    Display* the_display = win->getDisplay();   // Get the display for easy access
00305 
00306    // Update the projections for the display using the current app's scale factor
00307    // NOTE: This relies upon no other thread trying to update this display at the same time
00308    float scale_factor = the_app->getDrawScaleFactor();
00309    the_display->updateProjections(scale_factor);
00310 
00311    glManager->setCurrentContext(win->getId());     // Set TSS data of context id
00312 
00313    vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_HVERB_LVL)
00314       << "vjGlPipe::renderWindow: Set context to: "
00315       << GlDrawManager::instance()->getCurrentContext()
00316       << std::endl << vprDEBUG_FLUSH;
00317 
00318    // --- SET CONTEXT --- //
00319    win->makeCurrent();
00320 
00321    // VIEWPORT cleaning
00322    if(win->hasDirtyViewport())
00323    {
00324       win->updateViewport();
00325    }
00326 
00327    // CONTEXT INIT(): Check if we need to call contextInit()
00328    // - Must call when context is new OR application is new
00329    if(win->hasDirtyContext())
00330    {
00331          // Have dirty context
00332       glManager->currentUserData()->setUser(NULL);         // Set user data
00333       glManager->currentUserData()->setProjection(NULL);
00334       glManager->currentUserData()->setViewport(NULL);     // Set vp data
00335       glManager->currentUserData()->setGlWindow(win);      // Set the gl window
00336 
00337       the_app->contextInit();              // Call context init function
00338       win->setDirtyContext(false);        // All clean now
00339    }
00340 
00341    // BUFFER PRE DRAW: Check if we need to clear stereo buffers
00342    if(win->isStereo())
00343    {
00344       win->setViewBuffer(Viewport::RIGHT_EYE);
00345       the_app->bufferPreDraw();
00346       win->setViewBuffer(Viewport::LEFT_EYE);
00347       the_app->bufferPreDraw();
00348    }
00349    else
00350    {
00351       the_app->bufferPreDraw();
00352    }
00353 
00354    the_app->contextPreDraw();                 // Do any context pre-drawing
00355 
00356    // --- FOR EACH VIEWPORT -- //
00357    Viewport* viewport = NULL;
00358    unsigned num_vps = the_display->getNumViewports();
00359    for(unsigned vp_num=0; vp_num < num_vps; vp_num++)
00360    {
00361       viewport = the_display->getViewport(vp_num);
00362 
00363       // Should viewport be rendered???
00364       if(viewport->isActive())
00365       {
00366          view = viewport->getView();
00367 
00368          // Set the glViewport to draw within
00369          viewport->getOriginAndSize(vp_ox, vp_oy, vp_sx, vp_sy);
00370          win->setViewport(vp_ox, vp_oy, vp_sx, vp_sy);
00371 
00372          // Set user information
00373          glManager->currentUserData()->setUser(viewport->getUser());       // Set user data
00374          glManager->currentUserData()->setViewport(viewport);              // Set the viewport
00375          glManager->currentUserData()->setGlWindow(win);                   // Set the gl window
00376 
00377          // ---- SURFACE & Simulator --- //
00378          // if (viewport->isSurface())
00379          {
00380             SimViewport*      sim_vp(NULL);
00381             GlSimInterface*   draw_sim_i(NULL);
00382 
00383             if(viewport->isSimulator())
00384             {
00385                sim_vp = dynamic_cast<SimViewport*>(viewport);
00386                vprASSERT(NULL != sim_vp);
00387                draw_sim_i = dynamic_cast<GlSimInterface*>(sim_vp->getDrawSimInterface());
00388             }
00389 
00390             if((Viewport::STEREO == view) || (Viewport::LEFT_EYE == view))      // LEFT EYE
00391             {
00392                win->setViewBuffer(Viewport::LEFT_EYE);
00393                win->setProjection(viewport->getLeftProj());
00394                glManager->currentUserData()->setProjection(viewport->getLeftProj());
00395 
00396                the_app->draw();
00397 
00398                if(NULL != draw_sim_i)
00399                {
00400                   draw_sim_i->draw(scale_factor);
00401                }
00402             }
00403             if ((Viewport::STEREO == view) || (Viewport::RIGHT_EYE == view))    // RIGHT EYE
00404             {
00405                win->setViewBuffer(Viewport::RIGHT_EYE);
00406                win->setProjection(viewport->getRightProj());
00407                glManager->currentUserData()->setProjection(viewport->getRightProj());
00408 
00409                the_app->draw();
00410 
00411                if(NULL != draw_sim_i)
00412                {
00413                   draw_sim_i->draw(scale_factor);
00414                }
00415             }
00416          }
00417       }  // should viewport be rendered
00418    }     // for each viewport
00419 
00420    // -- Post context stuff --- //
00421    the_app->contextPostDraw();
00422 }
00423 
00428 void GlPipe::swapWindowBuffers(GlWindow* win)
00429 {
00430    win->makeCurrent();           // Set correct context
00431    win->swapBuffers();           // Implicitly calls a glFlush
00432 }
00433 
00434 }

Generated on Sun May 2 15:10:17 2004 for VR Juggler by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002