worldsim/src/wcamera.cpp

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #ifdef FARSA_USE_YARP_AND_ICUB
00021 
00022 #include "wcamera.h"
00023 #include <QApplication>
00024 #include <QGLPixelBuffer>
00025 
00026 // These instructions are needed because QT 4.8 no longer depends on glu, so we
00027 // have to include it here explicitly
00028 #ifdef FARSA_MAC
00029 # include <GLUT/glut.h>
00030 #else
00031 # include <GL/glu.h>
00032 #endif
00033 
00034 using namespace yarp::dev;
00035 using namespace yarp::sig;
00036 using namespace yarp::os;
00037 
00038 #define GLMultMatrix glMultMatrixf
00039 // for double use #define GLMultMatrix glMultMatrixd
00040 
00041 namespace farsa {
00042 
00043 RenderCamera::RenderCamera( WCamera* wcamera, WObject* attachTo, unsigned int width, unsigned int height )
00044     : RenderWObjectContainer()/*, framev(width, height, QImage::Format_RGB32)*/ {
00045     connect( world(), SIGNAL( removedObject( WObject* ) ),
00046             this, SLOT( slotRemoveObject( WObject* ) ), Qt::DirectConnection );
00047     connect( world(), SIGNAL( addedObject( WObject* ) ),
00048             this, SLOT( slotAddObject( WObject* ) ), Qt::DirectConnection );
00049     //--- remove the attachTo WObject to renderized objects
00050     this->attachTo = attachTo;
00051     this->widthv = width;
00052     this->heightv = height;
00053     aspectRatio = 112.0f/94.0f;
00054     this->wcamera = wcamera;
00055 
00056     frameBuffer = new unsigned char[width*height*3];
00057     frameImage.setQuantum(1);
00058     frameImage.setExternal( frameBuffer, width, height );
00059     frameImage.setTopIsLowIndex( true );
00060     pbuffer = new QGLPixelBuffer( width, height );
00061     initializeGL();
00062 }
00063 
00064 RenderCamera::~RenderCamera() {
00065     delete[] frameBuffer;
00066     // I don't know why, but on some platform the following delete create a SIGSEV
00067     delete pbuffer;
00068 }
00069 
00070 void RenderCamera::moveRotatePointOfView( const wMatrix& tm ) {
00071     QMutexLocker locker(&mutex);
00072 
00073     // The translation along z is needed to avoid the camera being placed in the center of a component
00074     // of the head composite object which is inside the eye.
00075     // NOTE: The above is not very nice... Any solution better than this???
00076     eyep = tm.w_pos + tm.z_ax.scale(0.021f);
00077     atp = eyep + tm.z_ax;
00078     upv = -tm.x_ax;
00079 }
00080 
00081 void RenderCamera::initializeGL() {
00082     pbuffer->makeCurrent();
00083     glEnable(GL_LIGHT0);
00084     //glEnable(GL_LIGHTING);
00085     //glEnable(GL_COLOR_MATERIAL);
00086     glDisable(GL_LIGHTING);
00087     glDisable(GL_COLOR_MATERIAL);
00088     
00089     glEnable(GL_DEPTH_TEST);
00090     glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
00091     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00092     glViewport( 0, 0, GLint(widthv), GLint(heightv) );
00093     pbuffer->doneCurrent();
00094 }
00095 
00096 void RenderCamera::paintGL() {
00097     // Always take the resource mutex first and then our mutex to avoid deadlocks
00098     ResourcesLocker resourceLocker(this);
00099     QMutexLocker locker(&mutex);
00100 
00101     moveRotatePointOfView( wcamera->matrix() );
00102     pbuffer->makeCurrent();
00103     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00104     // GL_PROJECTION matrix
00105     glMatrixMode(GL_PROJECTION);
00106     glLoadIdentity();
00107     gluPerspective( 94.0, aspectRatio, 0.001 /*zNear*/, 1000.0 /*zFar*/ );
00108     // GL_MODELVIEW matrix
00109     glMatrixMode(GL_MODELVIEW);
00110     glLoadIdentity();
00111     gluLookAt( eyep[0], eyep[1], eyep[2], atp[0], atp[1], atp[2], upv[0], upv[1], upv[2] );
00112 
00113     //-------- Drawing SkyBox
00114     drawSkyGroundBox( (QGLContext*)(QGLContext::currentContext()) );
00115 
00116     // Render the WObject presents in the World
00117     for( int i=0; i<graphics().size(); i++ ) {
00118         RenderWObject* r = graphics()[i];
00119         if ( r->object() == attachTo ) continue;
00120         if ( r->object() == wcamera ) continue;
00121         if ( r->object()->isInvisible() ) continue;
00122         if ( r->object()->owner() ) continue;
00123         r->render( (QGLContext*)(QGLContext::currentContext()) );
00124     }
00125     glReadPixels( 0, 0, widthv, heightv, GL_RGB, GL_UNSIGNED_BYTE, frameBuffer );
00126     pbuffer->doneCurrent();
00127 }
00128 
00129 void RenderCamera::slotRemoveObject( WObject* w ) {
00130     removeObject( w );
00131 }
00132 
00133 void RenderCamera::slotAddObject( WObject* w ) {
00134     addObject( w );
00135 }
00136 
00137 bool RenderCamera::open( yarp::os::Searchable & ) {
00138     return true;
00139 }
00140 
00141 bool RenderCamera::close( ) {
00142     return true;
00143 }
00144 
00145 bool RenderCamera::configure( yarp::os::Searchable & ) {
00146     return true;
00147 }
00148 
00149 int RenderCamera::height() const {
00150     return heightv;
00151 }
00152 
00153 int RenderCamera::width() const {
00154     return widthv;
00155 }
00156     
00157 bool RenderCamera::getImage( yarp::sig::ImageOf<yarp::sig::PixelRgb>& image ) {
00158     image.setTopIsLowIndex( false );
00159     image.copy( frameImage );
00160     return true;
00161 }
00162 
00163 WCamera::WCamera( World* w, QString name, WObject* attachTo, unsigned int width, unsigned int height )
00164     : YarpObject( w, name ) {
00165     //Q_ASSERT_X( QGLPixelBuffer::hasOpenGLPbuffers(),
00166     //          "WCamera Constructor",
00167     //          "You must have a graphic card that support pbuffer OpenGL extension" );
00168     if ( !qApp ) {
00169         images = NULL;
00170     } else {
00171         images = new RenderCamera( this, attachTo, width, height );
00172         images->setWorld(w);
00173     }
00174     setColor( Qt::green );
00175     this->attachTo = attachTo;
00176     setMatrix( attachTo->matrix() );
00177     w->pushObject( this );
00178     //registerServerFrameGrabber( images, "" );
00179     porty.open( QString( "/%1/%2" ).arg( world()->name() ).arg( name ).toAscii().data() );
00180 }
00181 
00182 WCamera::WCamera( World* w, QString name, unsigned int width, unsigned int height, const wMatrix& tm )
00183     : YarpObject( w, name ) {
00184     //Q_ASSERT_X( QGLPixelBuffer::hasOpenGLPbuffers(),
00185     //          "WCamera Constructor",
00186     //          "You must have a graphic card that support pbuffer OpenGL extension" );
00187     if ( !qApp ) {
00188         images = NULL;
00189     } else {
00190         images = new RenderCamera( this, NULL, width, height );
00191         images->setWorld(w);
00192     }
00193     this->attachTo = NULL;
00194     setMatrix( tm );
00195     w->pushObject( this );
00196     //registerServerFrameGrabber( images, "" );
00197     porty.open( QString( "/%1/%2" ).arg( world()->name() ).arg( name ).toAscii().data() );
00198 }
00199 
00200 WCamera::~WCamera() {
00201     delete images;
00202 }
00203 
00204 void WCamera::preUpdate() {
00205     if ( attachTo ) {
00206         setMatrix( attachTo->matrix() );
00207     }
00208 }
00209 
00210 void WCamera::postUpdate() {
00211     if ( !images ) return;
00212     images->paintGL();
00213     ImageOf<PixelRgb>& frame = porty.prepare();
00214     images->getImage( frame );
00215     porty.write();
00216 }
00217 
00218 } // end namespace farsa
00219 
00220 #endif // FARSA_USE_YARP_AND_ICUB