wcamera.cpp
1 /********************************************************************************
2  * WorldSim -- library for robot simulations *
3  * Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the Free Software *
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
18  ********************************************************************************/
19 
20 #ifdef FARSA_USE_YARP_AND_ICUB
21 
22 #include "wcamera.h"
23 #include <QApplication>
24 #include <QGLPixelBuffer>
25 
26 // These instructions are needed because QT 4.8 no longer depends on glu, so we
27 // have to include it here explicitly
28 #ifdef FARSA_MAC
29 # include <GLUT/glut.h>
30 #else
31 # include <GL/glu.h>
32 #endif
33 
34 using namespace yarp::dev;
35 using namespace yarp::sig;
36 using namespace yarp::os;
37 
38 #define GLMultMatrix glMultMatrixf
39 // for double use #define GLMultMatrix glMultMatrixd
40 
41 namespace farsa {
42 
43 RenderCamera::RenderCamera( WCamera* wcamera, WObject* attachTo, unsigned int width, unsigned int height )
44  : RenderWObjectContainer()/*, framev(width, height, QImage::Format_RGB32)*/ {
45  connect( world(), SIGNAL( removedObject( WObject* ) ),
46  this, SLOT( slotRemoveObject( WObject* ) ), Qt::DirectConnection );
47  connect( world(), SIGNAL( addedObject( WObject* ) ),
48  this, SLOT( slotAddObject( WObject* ) ), Qt::DirectConnection );
49  //--- remove the attachTo WObject to renderized objects
50  this->attachTo = attachTo;
51  this->widthv = width;
52  this->heightv = height;
53  aspectRatio = 112.0f/94.0f;
54  this->wcamera = wcamera;
55 
56  frameBuffer = new unsigned char[width*height*3];
57  frameImage.setQuantum(1);
58  frameImage.setExternal( frameBuffer, width, height );
59  frameImage.setTopIsLowIndex( true );
60  pbuffer = new QGLPixelBuffer( width, height );
61  initializeGL();
62 }
63 
64 RenderCamera::~RenderCamera() {
65  delete[] frameBuffer;
66  // I don't know why, but on some platform the following delete create a SIGSEV
67  delete pbuffer;
68 }
69 
71  QMutexLocker locker(&mutex);
72 
73  // The translation along z is needed to avoid the camera being placed in the center of a component
74  // of the head composite object which is inside the eye.
75  // NOTE: The above is not very nice... Any solution better than this???
76  eyep = tm.w_pos + tm.z_ax.scale(0.021f);
77  atp = eyep + tm.z_ax;
78  upv = -tm.x_ax;
79 }
80 
82  pbuffer->makeCurrent();
83  glEnable(GL_LIGHT0);
84  //glEnable(GL_LIGHTING);
85  //glEnable(GL_COLOR_MATERIAL);
86  glDisable(GL_LIGHTING);
87  glDisable(GL_COLOR_MATERIAL);
88 
89  glEnable(GL_DEPTH_TEST);
90  glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
91  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
92  glViewport( 0, 0, GLint(widthv), GLint(heightv) );
93  pbuffer->doneCurrent();
94 }
95 
97  // Always take the resource mutex first and then our mutex to avoid deadlocks
98  ResourcesLocker resourceLocker(this);
99  QMutexLocker locker(&mutex);
100 
101  moveRotatePointOfView( wcamera->matrix() );
102  pbuffer->makeCurrent();
103  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
104  // GL_PROJECTION matrix
105  glMatrixMode(GL_PROJECTION);
106  glLoadIdentity();
107  gluPerspective( 94.0, aspectRatio, 0.001 /*zNear*/, 1000.0 /*zFar*/ );
108  // GL_MODELVIEW matrix
109  glMatrixMode(GL_MODELVIEW);
110  glLoadIdentity();
111  gluLookAt( eyep[0], eyep[1], eyep[2], atp[0], atp[1], atp[2], upv[0], upv[1], upv[2] );
112 
113  //-------- Drawing SkyBox
114  drawSkyGroundBox( (QGLContext*)(QGLContext::currentContext()) );
115 
116  // Render the WObject presents in the World
117  for( int i=0; i<graphics().size(); i++ ) {
118  RenderWObject* r = graphics()[i];
119  if ( r->object() == attachTo ) continue;
120  if ( r->object() == wcamera ) continue;
121  if ( r->object()->isInvisible() ) continue;
122  if ( r->object()->owner() ) continue;
123  r->render( (QGLContext*)(QGLContext::currentContext()) );
124  }
125  glReadPixels( 0, 0, widthv, heightv, GL_RGB, GL_UNSIGNED_BYTE, frameBuffer );
126  pbuffer->doneCurrent();
127 }
128 
129 void RenderCamera::slotRemoveObject( WObject* w ) {
130  removeObject( w );
131 }
132 
133 void RenderCamera::slotAddObject( WObject* w ) {
134  addObject( w );
135 }
136 
137 bool RenderCamera::open( yarp::os::Searchable & ) {
138  return true;
139 }
140 
142  return true;
143 }
144 
145 bool RenderCamera::configure( yarp::os::Searchable & ) {
146  return true;
147 }
148 
149 int RenderCamera::height() const {
150  return heightv;
151 }
152 
153 int RenderCamera::width() const {
154  return widthv;
155 }
156 
157 bool RenderCamera::getImage( yarp::sig::ImageOf<yarp::sig::PixelRgb>& image ) {
158  image.setTopIsLowIndex( false );
159  image.copy( frameImage );
160  return true;
161 }
162 
163 WCamera::WCamera( World* w, QString name, WObject* attachTo, unsigned int width, unsigned int height )
164  : YarpObject( w, name ) {
165  //Q_ASSERT_X( QGLPixelBuffer::hasOpenGLPbuffers(),
166  // "WCamera Constructor",
167  // "You must have a graphic card that support pbuffer OpenGL extension" );
168  if ( !qApp ) {
169  images = NULL;
170  } else {
171  images = new RenderCamera( this, attachTo, width, height );
172  images->setWorld(w);
173  }
174  setColor( Qt::green );
175  this->attachTo = attachTo;
176  setMatrix( attachTo->matrix() );
177  w->pushObject( this );
178  //registerServerFrameGrabber( images, "" );
179  porty.open( QString( "/%1/%2" ).arg( world()->name() ).arg( name ).toAscii().data() );
180 }
181 
182 WCamera::WCamera( World* w, QString name, unsigned int width, unsigned int height, const wMatrix& tm )
183  : YarpObject( w, name ) {
184  //Q_ASSERT_X( QGLPixelBuffer::hasOpenGLPbuffers(),
185  // "WCamera Constructor",
186  // "You must have a graphic card that support pbuffer OpenGL extension" );
187  if ( !qApp ) {
188  images = NULL;
189  } else {
190  images = new RenderCamera( this, NULL, width, height );
191  images->setWorld(w);
192  }
193  this->attachTo = NULL;
194  setMatrix( tm );
195  w->pushObject( this );
196  //registerServerFrameGrabber( images, "" );
197  porty.open( QString( "/%1/%2" ).arg( world()->name() ).arg( name ).toAscii().data() );
198 }
199 
201  delete images;
202 }
203 
205  if ( attachTo ) {
206  setMatrix( attachTo->matrix() );
207  }
208 }
209 
211  if ( !images ) return;
212  images->paintGL();
213  ImageOf<PixelRgb>& frame = porty.prepare();
214  images->getImage( frame );
215  porty.write();
216 }
217 
218 } // end namespace farsa
219 
220 #endif // FARSA_USE_YARP_AND_ICUB