renderwobjecthierarchy.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 #include "renderworld.h"
21 #include "physphere.h"
22 #include "phyellipsoid.h"
23 #include "phybox.h"
24 #include "phycylinder.h"
25 #include "phycone.h"
26 // #include "phyheightfield.h"
27 #include "phycompoundobject.h"
28 #include "wmesh.h"
29 #include "graphicalwobject.h"
30 #include "private/renderwobjecthierarchy.h"
31 #include "logger.h"
32 #include "Newton.h"
33 
34 #include <QImage>
35 #include <QColor>
36 #include <QList>
37 #include <QVector>
38 #include <cmath>
39 
40 // These instructions are needed because QT 4.8 no longer depends on glu, so we
41 // have to include it here explicitly
42 
43 #ifdef FARSA_MAC
44 # include <GLUT/glut.h>
45 #else
46 # include <GL/glu.h>
47 #endif
48 
49 using namespace qglviewer;
50 
51 #define GLMultMatrix glMultMatrixf
52 // for double glMultMatrixd
53 
54 namespace farsa {
55 
61 public:
62  RenderGenericObject( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
63  rad = 0.02f;
64  };
65  virtual ~RenderGenericObject() { };
66  virtual void render( QGLContext* gw ) {
67  glPushMatrix();
68  container()->setupColorTexture( gw, this );
69  const wMatrix& m = obj->matrix();
70  GLMultMatrix(&m[0][0]);
71 
72  // Drawing label if we have to
73  drawLabel();
74 
75  glPopMatrix();
76  };
77  virtual void renderAABB( RenderWorld* gw ) {
78  wVector minpoint, maxpoint;
79  calculateAABB( minpoint, maxpoint, obj->matrix() );
80  gw->drawWireBox( minpoint, maxpoint );
81  };
82  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
83  wVector rds( rad, rad, rad );
84  minPoint = tm.w_pos - rds;
85  maxPoint = tm.w_pos + rds;
86  };
87 
88  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
89  dimension[0] = rad*2.0;
90  dimension[1] = rad*2.0;
91  dimension[2] = rad*2.0;
92  wVector rds = wVector( rad, rad, rad );
93  minPoint = -rds;
94  maxPoint = +rds;
95  };
96 protected:
97  real rad;
98 };
99 
100 class RenderWMesh : public RenderWObject {
101 public:
102  RenderWMesh( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
103  wmesh = (WMesh*)wobj;
104  };
105  virtual ~RenderWMesh() { };
106  virtual void render( QGLContext* gw ) {
107  glPushMatrix();
108  wMatrix m = wmesh->matrix();
109  if ( wmesh->attachedTo() ) {
110  m = m * wmesh->attachedTo()->matrix();
111  }
112  GLMultMatrix(&m[0][0]);
113  int m_numMeshes = wmesh->meshesCount();
114  WMesh::Mesh *m_pMeshes = wmesh->meshes();
115 // int m_numMaterials = wmesh->materialsCount();
116  WMesh::Material *m_pMaterials = wmesh->materials();
117 // int m_numTriangles = wmesh->trianglesCount();
118  WMesh::Triangle *m_pTriangles = wmesh->triangles();
119 // int m_numVertices = wmesh->verticesCount();
120  WMesh::Vertex *m_pVertices = wmesh->vertices();
121  for ( int i = 0; i < m_numMeshes; i++ ) {
122  int materialIndex = m_pMeshes[i].m_materialIndex;
123  if ( materialIndex >= 0 ) {
124  glMaterialfv( GL_FRONT, GL_AMBIENT, m_pMaterials[materialIndex].m_ambient );
125  glMaterialfv( GL_FRONT, GL_DIFFUSE, m_pMaterials[materialIndex].m_diffuse );
126  glMaterialfv( GL_FRONT, GL_SPECULAR, m_pMaterials[materialIndex].m_specular );
127  glMaterialfv( GL_FRONT, GL_EMISSION, m_pMaterials[materialIndex].m_emissive );
128  glMaterialf( GL_FRONT, GL_SHININESS, m_pMaterials[materialIndex].m_shininess );
129  //container()->applyTexture( gw, wmesh->texture() );
130  container()->setupColorTexture( gw, this );
131  }
132  glBegin( GL_TRIANGLES );
133  for ( int j = 0; j < m_pMeshes[i].m_numTriangles; j++ ) {
134  int triangleIndex = m_pMeshes[i].m_pTriangleIndices[j];
135  const WMesh::Triangle* pTri = &m_pTriangles[triangleIndex];
136  for ( int k = 0; k < 3; k++ ) {
137  int index = pTri->m_vertexIndices[k];
138  glNormal3fv( pTri->m_vertexNormals[k] );
139  glTexCoord2f( pTri->m_s[k], pTri->m_t[k] );
140  glVertex3fv( m_pVertices[index].m_location );
141  }
142  }
143  glEnd();
144  }
145 
146  // Drawing label if we have to
147  drawLabel();
148 
149  glPopMatrix();
150  };
151  virtual void renderAABB( RenderWorld* /*gw*/ ) {
152  };
153  virtual void calculateAABB( wVector& /*minPoint*/, wVector& /*maxPoint*/, const wMatrix /*tm*/ ) {
154  };
155  virtual void calculateOBB( wVector& /*dimension*/, wVector& /*minPoint*/, wVector& /*maxPoint*/ ) {
156  };
157 private:
158  WMesh* wmesh;
159 };
160 
161 class RenderPhyBox : public RenderWObject {
162 public:
163  RenderPhyBox( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
164  box = (PhyBox*)wobj;
165  dx = box->sideX();
166  dy = box->sideY();
167  dz = box->sideZ();
168  };
169  virtual ~RenderPhyBox() { };
170  virtual void render( QGLContext* gw ) {
171  glPushMatrix();
172  container()->setupColorTexture( gw, this );
173  const wMatrix& m = box->matrix();
174  GLMultMatrix(&m[0][0]);
175 
176  // the cube will just be drawn as six quads for the sake of simplicity
177  // for each face, we specify the quad's normal (for lighting), then
178  // specify the quad's 4 vertices and associated texture coordinates
179  glBegin(GL_QUADS);
180  float hdx = (dx/2.0);
181  float hdy = (dy/2.0);
182  float hdz = (dz/2.0);
183  // front
184  glNormal3f(0.0, 0.0, 1.0);
185  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
186  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, hdz);
187  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, hdz);
188  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, hdz);
189 
190  // back
191  glNormal3f(0.0, 0.0, -1.0);
192  glTexCoord2f(0.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
193  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
194  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
195  glTexCoord2f(0.0, 1.0); glVertex3f( hdx, hdy, -hdz);
196 
197  // top
198  glNormal3f(0.0, 1.0, 0.0);
199  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, hdy, hdz);
200  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, hdy, hdz);
201  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, -hdz);
202  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
203 
204  // bottom
205  glNormal3f(0.0, -1.0, 0.0);
206  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
207  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
208  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, -hdy, hdz);
209  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, -hdy, hdz);
210 
211  // left
212  glNormal3f(-1.0, 0.0, 0.0);
213  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
214  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
215  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, hdz);
216  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
217 
218  // right
219  glNormal3f(1.0, 0.0, 0.0);
220  glTexCoord2f(0.0, 0.0); glVertex3f( hdx, -hdy, hdz);
221  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
222  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, -hdz);
223  glTexCoord2f(0.0, 1.0); glVertex3f( hdx, hdy, hdz);
224 
225  glEnd();
226 
227  // Checking if we have to draw axis
228  if (box->localAxesDrawn()) {
229  const float radius = min(dx, min(dy, dz)) * 0.1;
230 
231  RenderWObjectContainer::drawArrow(wVector(dx, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
232  RenderWObjectContainer::drawArrow(wVector(0.0, dy, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
233  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, dz), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
234  }
235 
236  // Drawing label if we have to
237  drawLabel();
238 
239  glPopMatrix();
240  };
241  virtual void renderAABB( RenderWorld* gw ) {
242  wVector minpoint, maxpoint;
243  calculateAABB( minpoint, maxpoint, obj->matrix() );
244  gw->drawWireBox( minpoint, maxpoint );
245  };
246  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
247  real tdx = fabs(tm.x_ax[0]*dx) + fabs(tm.y_ax[0]*dy) + fabs(tm.z_ax[0]*dz);
248  real tdy = fabs(tm.x_ax[1]*dx) + fabs(tm.y_ax[1]*dy) + fabs(tm.z_ax[1]*dz);
249  real tdz = fabs(tm.x_ax[2]*dx) + fabs(tm.y_ax[2]*dy) + fabs(tm.z_ax[2]*dz);
250 
251  wVector hds( tdx/2.0, tdy/2.0, tdz/2.0 );
252  minPoint = tm.w_pos - hds;
253  maxPoint = tm.w_pos + hds;
254  };
255 
256  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
257  dimension[0] = dx;
258  dimension[1] = dy;
259  dimension[2] = dz;
260  wVector hds( dx/2.0, dy/2.0, dz/2.0 );
261  minPoint = -hds;
262  maxPoint = +hds;
263  };
264 
265 protected:
266  PhyBox* box;
267  real dx, dy, dz;
268 };
269 
271 public:
272  RenderPhySphere( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
273  sph = (PhySphere*)wobj;
274  rad = sph->radius();
275  };
276  virtual ~RenderPhySphere() { };
277  virtual void render( QGLContext* gw ) {
278  glPushMatrix();
279  GLUquadricObj *pObj;
280  container()->setupColorTexture( gw, this );
281  wMatrix mat = sph->matrix();
282 // mat.x_ax = mat.x_ax.scale( rad );
283 // mat.y_ax = mat.y_ax.scale( rad );
284 // mat.z_ax = mat.z_ax.scale( rad );
285  GLMultMatrix(&mat[0][0]);
286 
287  // Get a new Quadric off the stack
288  pObj = gluNewQuadric();
289  // Get a new Quadric off the stack
290  gluQuadricTexture(pObj, true);
291  gluSphere(pObj, rad, 20, 20);
292  gluDeleteQuadric(pObj);
293 
294  // Checking if we have to draw axis
295  if (sph->localAxesDrawn()) {
296  const float radius = rad * 0.1;
297 
298  RenderWObjectContainer::drawArrow(wVector(2.0 * rad, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
299  RenderWObjectContainer::drawArrow(wVector(0.0, 2.0 * rad, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
300  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, 2.0 * rad), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
301  }
302 
303  // Drawing label if we have to
304  drawLabel();
305 
306  glPopMatrix();
307  };
308  virtual void renderAABB( RenderWorld* gw ) {
309  wVector minpoint, maxpoint;
310  calculateAABB( minpoint, maxpoint, obj->matrix() );
311  gw->drawWireBox( minpoint, maxpoint );
312  };
313  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
314  wVector rds( rad, rad, rad );
315  minPoint = tm.w_pos - rds;
316  maxPoint = tm.w_pos + rds;
317  };
318 
319  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
320  dimension[0] = rad*2.0;
321  dimension[1] = rad*2.0;
322  dimension[2] = rad*2.0;
323  wVector rds = wVector( rad, rad, rad );
324  minPoint = -rds;
325  maxPoint = +rds;
326  };
327 protected:
328  PhySphere* sph;
329  real rad;
330 };
331 
333 public:
334  RenderPhyEllipsoid( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
335  sph = (PhyEllipsoid*)wobj;
336  radx = sph->radiusX();
337  rady = sph->radiusY();
338  radz = sph->radiusZ();
339  };
340  virtual ~RenderPhyEllipsoid() { };
341  virtual void render( QGLContext* gw ) {
342  glPushMatrix();
343  GLUquadricObj *pObj;
344  container()->setupColorTexture( gw, this );
345  wMatrix mat = sph->matrix();
346  mat.x_ax = mat.x_ax.scale( radx );
347  mat.y_ax = mat.y_ax.scale( rady );
348  mat.z_ax = mat.z_ax.scale( radz );
349  GLMultMatrix(&mat[0][0]);
350 
351  // Get a new Quadric off the stack
352  pObj = gluNewQuadric();
353  // Get a new Quadric off the stack
354  gluQuadricTexture(pObj, true);
355  gluSphere(pObj, 1, 20, 20);
356  gluDeleteQuadric(pObj);
357 
358  // Checking if we have to draw axis
359  if (sph->localAxesDrawn()) {
360  const float radius = qMax( qMax(radx, rady), radz ) * 0.1;
361 
362  RenderWObjectContainer::drawArrow(wVector(2.0 * radx, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
363  RenderWObjectContainer::drawArrow(wVector(0.0, 2.0 * rady, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
364  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, 2.0 * radz), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
365  }
366 
367  // Drawing label if we have to
368  drawLabel();
369 
370  glPopMatrix();
371  };
372  virtual void renderAABB( RenderWorld* gw ) {
373  wVector minpoint, maxpoint;
374  calculateAABB( minpoint, maxpoint, obj->matrix() );
375  gw->drawWireBox( minpoint, maxpoint );
376  };
377  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
378  wVector rds( radx, rady, radz );
379  minPoint = tm.w_pos - rds;
380  maxPoint = tm.w_pos + rds;
381  };
382 
383  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
384  dimension[0] = radx*2.0;
385  dimension[1] = rady*2.0;
386  dimension[2] = radz*2.0;
387  wVector rds = wVector( radx, rady, radz );
388  minPoint = -rds;
389  maxPoint = +rds;
390  };
391 protected:
392  PhyEllipsoid* sph;
393  real radx;
394  real rady;
395  real radz;
396 };
397 
398 // class RenderPhyCylinder : public RenderWObject {
399 // public:
400 // RenderPhyCylinder( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
401 // cil = (PhyCylinder*)wobj;
402 // rad = cil->radius();
403 // hei = cil->height();
404 // };
405 // virtual ~RenderPhyCylinder() { };
406 // virtual void render( QGLContext* gw ) {
407 // glPushMatrix();
408 // container()->setupColorTexture( gw, this );
409 //
410 // // opengl cylinder are aligned alogn the z axis, we want it along the x axis,
411 // // we create a rotation matrix to do the alignment
412 // wMatrix matrix = wMatrix::yaw( PI_GRECO * 0.5f );
413 // matrix.w_pos = matrix.rotateVector( wVector(0.0, 0.0, -hei*0.5f) );
414 // matrix = matrix * cil->matrix();
415 // GLMultMatrix(&matrix[0][0]);
416 //
417 // GLUquadricObj *pObj;
418 //
419 // // Get a new Quadric off the stack
420 // pObj = gluNewQuadric();
421 // gluQuadricTexture(pObj, true);
422 // gluCylinder(pObj, rad, rad, hei, 20, 2);
423 //
424 // // render the caps
425 // gluQuadricOrientation(pObj, GLU_INSIDE);
426 // gluDisk(pObj, 0.0f, rad, 20, 1);
427 //
428 // glTranslatef (0.0f, 0.0f, hei);
429 // gluQuadricOrientation(pObj, GLU_OUTSIDE);
430 // gluDisk(pObj, 0.0f, rad, 20, 1);
431 //
432 // gluDeleteQuadric(pObj);
433 //
434 // glPopMatrix();
435 // };
436 // virtual void renderAABB( RenderWorld* gw ) {
437 // wVector minpoint, maxpoint;
438 // calculateAABB( minpoint, maxpoint, obj->matrix() );
439 // gw->drawWireBox( minpoint, maxpoint );
440 // };
441 // virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
442 // real h2 = hei/2.0;
443 // real tdx = fabs(tm.x_ax[0]*h2) + fabs(tm.y_ax[0]*rad) + fabs(tm.z_ax[0]*rad);
444 // real tdy = fabs(tm.x_ax[1]*h2) + fabs(tm.y_ax[1]*rad) + fabs(tm.z_ax[1]*rad);
445 // real tdz = fabs(tm.x_ax[2]*h2) + fabs(tm.y_ax[2]*rad) + fabs(tm.z_ax[2]*rad);
446 // wVector hds( tdx, tdy, tdz );
447 // minPoint = tm.w_pos - hds;
448 // maxPoint = tm.w_pos + hds;
449 // };
450 //
451 // virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
452 // dimension[0] = hei;
453 // dimension[1] = rad*2.0;
454 // dimension[2] = rad*2.0;
455 // wVector rds = wVector( hei/2.0, rad, rad );
456 // minPoint = -rds;
457 // maxPoint = +rds;
458 // };
459 // protected:
460 // PhyCylinder* cil;
461 // real rad;
462 // real hei;
463 // };
464 
471 public:
480  RenderWObject(wobj, container),
481  m_cylinder(dynamic_cast<PhyCylinder*>(wobj)),
482  m_height(m_cylinder->height()),
483  m_radius(m_cylinder->radius()),
484  m_cylinderVertexes(),
485  m_cylinderNormals(),
486  m_cylinderColors(),
487  m_cylinderTextureCoords(),
488  m_upperBaseVertexes(),
489  m_upperBaseNormals(),
490  m_upperBaseColors(),
491  m_upperBaseTextureCoords(),
492  m_upperBaseSegmentsLength(),
493  m_lowerBaseVertexes(),
494  m_lowerBaseNormals(),
495  m_lowerBaseColors(),
496  m_lowerBaseTextureCoords(),
497  m_lowerBaseSegmentsLength()
498  {
499  // The cylinder representation will be updated in the first call to render()
500  }
501 
505  virtual ~RenderPhyCylinder()
506  {
507  // Nothing to do here
508  }
509 
515  virtual void render(QGLContext* gw)
516  {
517  // Checking if we have to regenerate the representation of the cylinder
518  if (m_cylinder->graphicalRepresentationNeedsUpdate(this)) {
519  updateRepresentation();
520  }
521 
522  glPushMatrix();
523  container()->setupColorTexture(gw, this);
524  GLMultMatrix(&(m_cylinder->matrix()[0][0]));
525 
526  // First drawing the cylinder. We need to enable the vertex arrays, set the
527  // starting point for vertex, normals and colors and then actually draw triangles
528  glEnableClientState(GL_NORMAL_ARRAY);
529  glEnableClientState(GL_COLOR_ARRAY);
530  glEnableClientState(GL_VERTEX_ARRAY);
531  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
532 
533  glNormalPointer(GL_FLOAT, 0, m_cylinderNormals.data());
534  glColorPointer(3, GL_FLOAT, 0, m_cylinderColors.data());
535  glVertexPointer(3, GL_FLOAT, 0, m_cylinderVertexes.data());
536  glTexCoordPointer(2, GL_FLOAT, 0, m_cylinderTextureCoords.data());
537 
538  glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cylinderVertexes.size() / 3);
539 
540  // Now drawing the upper base
541  glNormalPointer(GL_FLOAT, 0, m_upperBaseNormals.data());
542  glColorPointer(3, GL_FLOAT, 0, m_upperBaseColors.data());
543  glVertexPointer(3, GL_FLOAT, 0, m_upperBaseVertexes.data());
544  glTexCoordPointer(2, GL_FLOAT, 0, m_upperBaseTextureCoords.data());
545 
546  unsigned int startIndex = 0;
547  foreach (unsigned int curLength, m_upperBaseSegmentsLength) {
548  glDrawArrays(GL_TRIANGLE_FAN, startIndex, curLength);
549  startIndex += curLength;
550  }
551 
552  // Finally drawing the lower base
553  glNormalPointer(GL_FLOAT, 0, m_lowerBaseNormals.data());
554  glColorPointer(3, GL_FLOAT, 0, m_lowerBaseColors.data());
555  glVertexPointer(3, GL_FLOAT, 0, m_lowerBaseVertexes.data());
556  glTexCoordPointer(2, GL_FLOAT, 0, m_lowerBaseTextureCoords.data());
557 
558  startIndex = 0;
559  foreach (unsigned int curLength, m_lowerBaseSegmentsLength) {
560  glDrawArrays(GL_TRIANGLE_FAN, startIndex, curLength);
561  startIndex += curLength;
562  }
563 
564  glDisableClientState(GL_VERTEX_ARRAY);
565  glDisableClientState(GL_COLOR_ARRAY);
566  glDisableClientState(GL_NORMAL_ARRAY);
567  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
568 
569  // Checking if we have to draw axis
570  if (m_cylinder->localAxesDrawn()) {
571  const float radius = min(m_radius, m_height) * 0.1;
572 
573  RenderWObjectContainer::drawArrow(wVector(m_height, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
574  RenderWObjectContainer::drawArrow(wVector(0.0, 2.0 * m_radius, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
575  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, 2.0 * m_radius), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
576  }
577 
578  // Drawing label if we have to
579  drawLabel();
580 
581  glPopMatrix();
582  }
583 
589  virtual void renderAABB(RenderWorld* gw)
590  {
591  // Checking if we have to regenerate the representation of the cylinder
592  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
593  updateRepresentation();
594  }
595 
596  wVector minpoint, maxpoint;
597  calculateAABB(minpoint, maxpoint, obj->matrix());
598  gw->drawWireBox(minpoint, maxpoint);
599  }
600 
608  virtual void calculateAABB(wVector& minPoint, wVector& maxPoint, const wMatrix tm)
609  {
610  // Checking if we have to regenerate the representation of the cylinder
611  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
612  updateRepresentation();
613  }
614 
615  const real h2 = m_height / 2.0;
616  const real tdx = fabs(tm.x_ax[0] * h2) + fabs(tm.y_ax[0] * m_radius) + fabs(tm.z_ax[0] * m_radius);
617  const real tdy = fabs(tm.x_ax[1] * h2) + fabs(tm.y_ax[1] * m_radius) + fabs(tm.z_ax[1] * m_radius);
618  const real tdz = fabs(tm.x_ax[2] * h2) + fabs(tm.y_ax[2] * m_radius) + fabs(tm.z_ax[2] * m_radius);
619  const wVector hds(tdx, tdy, tdz);
620  minPoint = tm.w_pos - hds;
621  maxPoint = tm.w_pos + hds;
622  }
623 
631  virtual void calculateOBB(wVector& dimension, wVector& minPoint, wVector& maxPoint)
632  {
633  // Checking if we have to regenerate the representation of the cylinder
634  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
635  updateRepresentation();
636  }
637 
638  dimension[0] = m_height;
639  dimension[1] = m_radius * 2.0;
640  dimension[2] = m_radius * 2.0;
641  const wVector rds(m_height / 2.0, m_radius, m_radius);
642  minPoint = -rds;
643  maxPoint = +rds;
644  }
645 
646 protected:
652  void updateRepresentation()
653  {
654  // Some helper constants
655  const int numDivs = 20;
656  const float anglePerDiv = (2 * M_PI) / float(numDivs);
657  const float lowerBaseX = -m_height / 2.0;
658  const float upperBaseX = +m_height / 2.0;
659 
660  // Resetting all lists
661  m_cylinderVertexes.clear();
662  m_cylinderNormals.clear();
663  m_cylinderColors.clear();
664  m_cylinderTextureCoords.clear();
665  m_upperBaseVertexes.clear();
666  m_upperBaseNormals.clear();
667  m_upperBaseColors.clear();
668  m_upperBaseTextureCoords.clear();
669  m_upperBaseSegmentsLength.clear();
670  m_lowerBaseVertexes.clear();
671  m_lowerBaseNormals.clear();
672  m_lowerBaseColors.clear();
673  m_lowerBaseTextureCoords.clear();
674  m_lowerBaseSegmentsLength.clear();
675 
676  // Getting the base color of the cylinder. We use the one of the owner if we have to
677  QColor cylinderColor;
678  if (m_cylinder->useColorTextureOfOwner()) {
679  // Getting the color of the owner
680  WObject* obj = m_cylinder;
681  while (obj->useColorTextureOfOwner() && (obj->owner() != NULL)) {
682  WObject *const owner = dynamic_cast<WObject *>(obj->owner());
683  if (owner != NULL) {
684  obj = owner;
685  } else {
686  break;
687  }
688  }
689  cylinderColor = obj->color();
690  } else {
691  cylinderColor = m_cylinder->color();
692  }
693 
694  // Getting the list of colors of the cylinder. If the cylinder has only one color, we generate a list to be
695  // able to use the code below anyway. We use a temporary list because before computing all the points we
696  // generate a list which contains exactly the angular segments that will be drawn, splitting the bigger ones
697  QList<PhyCylinder::SegmentColor> tmpCylinderColors;
698  if (cylinderColor.isValid()){
699  // Single color for the whole cylinder
700  tmpCylinderColors.append(PhyCylinder::SegmentColor(SimpleInterval(-PI_GRECO, PI_GRECO), cylinderColor));
701  } else {
702  tmpCylinderColors = m_cylinder->segmentsColor();
703  }
704  // Now modifying the list to be the actual segments to draw
705  QList<PhyCylinder::SegmentColor> cylinderColors;
706  for (int i = 0; i < tmpCylinderColors.size(); ++i) {
707  if (tmpCylinderColors[i].intervals.length() < anglePerDiv) {
708  cylinderColors << tmpCylinderColors[i];
709  } else {
710  // Computing in how many parts we have to split the current segment and the length of each segment
711  const int numDivisions = int(ceil(tmpCylinderColors[i].intervals.length() / anglePerDiv));
712  if (numDivisions == 0) {
713  continue;
714  }
715  const real divisionsLength = tmpCylinderColors[i].intervals.length() / real(numDivisions);
716 
717  // If we have only one interval (it should never happend, however better safe than sorry) adding the original interval
718  if (numDivisions == 1) {
719  cylinderColors << tmpCylinderColors[i];
720  } else {
721  // Adding the first segment
722  const real firstIntervalStart = tmpCylinderColors[i].intervals.begin()->start;
723  cylinderColors << PhyCylinder::SegmentColor(SimpleInterval(firstIntervalStart, firstIntervalStart + divisionsLength), tmpCylinderColors[i].color);
724  for (int j = 1; j < numDivisions - 1; j++) {
725  const real curIntervalStart = cylinderColors.last().intervals.begin()->end;
726  cylinderColors << PhyCylinder::SegmentColor(SimpleInterval(curIntervalStart, curIntervalStart + divisionsLength), tmpCylinderColors[i].color);
727  }
728  // Just to avoid numerical problems, setting the end of the last interval to the end of the original interval
729  const real lastIntervalStart = cylinderColors.last().intervals.begin()->end;
730  const real lastIntervalEnd = tmpCylinderColors[i].intervals.begin()->end;
731  cylinderColors << PhyCylinder::SegmentColor(SimpleInterval(lastIntervalStart, lastIntervalEnd), tmpCylinderColors[i].color);
732  }
733  }
734  }
735 
736  // Adding the first two points (one on the lower base, the other on the upper base), then adding the others in the cycle.
737  {
738  const QColor color = cylinderColors[0].color;
739  const float normY = cos(-PI_GRECO);
740  const float normZ = sin(-PI_GRECO);
741  const float y = m_radius * normY;
742  const float z = m_radius * normZ;
743  m_cylinderVertexes.append(lowerBaseX);
744  m_cylinderVertexes.append(y);
745  m_cylinderVertexes.append(z);
746  m_cylinderNormals.append(0.0);
747  m_cylinderNormals.append(normY);
748  m_cylinderNormals.append(normZ);
749  m_cylinderColors.append(color.redF());
750  m_cylinderColors.append(color.greenF());
751  m_cylinderColors.append(color.blueF());
752  m_cylinderTextureCoords.append(0.0);
753  m_cylinderTextureCoords.append(0.0);
754  m_cylinderVertexes.append(upperBaseX);
755  m_cylinderVertexes.append(y);
756  m_cylinderVertexes.append(z);
757  m_cylinderNormals.append(0.0);
758  m_cylinderNormals.append(normY);
759  m_cylinderNormals.append(normZ);
760  m_cylinderColors.append(color.redF());
761  m_cylinderColors.append(color.greenF());
762  m_cylinderColors.append(color.blueF());
763  m_cylinderTextureCoords.append(1.0);
764  m_cylinderTextureCoords.append(0.0);
765  }
766  // We have to save the old color to decide when to switch
767  QColor prevColor = cylinderColors[0].color;
768  for (int i = 0; i < cylinderColors.size(); ++i) {
769  const QColor color = cylinderColors[i].color;
770 
771  if (prevColor != color) {
772  // Here we have to add the start of the interval (which is equal to the end of the previous interval).
773  // We add two points, one on the lower base, the other on the upper base
774  const real prevAngle = cylinderColors[i].intervals.begin()->start;
775  const float normY = cos(prevAngle);
776  const float normZ = sin(prevAngle);
777  const float y = m_radius * normY;
778  const float z = m_radius * normZ;
779 
780  m_cylinderVertexes.append(lowerBaseX);
781  m_cylinderVertexes.append(y);
782  m_cylinderVertexes.append(z);
783  m_cylinderNormals.append(0.0);
784  m_cylinderNormals.append(normY);
785  m_cylinderNormals.append(normZ);
786  m_cylinderColors.append(color.redF());
787  m_cylinderColors.append(color.greenF());
788  m_cylinderColors.append(color.blueF());
789  m_cylinderTextureCoords.append(0.0);
790  m_cylinderTextureCoords.append((prevAngle + PI_GRECO) / (2.0 * PI_GRECO));
791  m_cylinderVertexes.append(upperBaseX);
792  m_cylinderVertexes.append(y);
793  m_cylinderVertexes.append(z);
794  m_cylinderNormals.append(0.0);
795  m_cylinderNormals.append(normY);
796  m_cylinderNormals.append(normZ);
797  m_cylinderColors.append(color.redF());
798  m_cylinderColors.append(color.greenF());
799  m_cylinderColors.append(color.blueF());
800  m_cylinderTextureCoords.append(1.0);
801  m_cylinderTextureCoords.append((prevAngle + PI_GRECO) / (2.0 * PI_GRECO));
802  }
803 
804  const real curAngle = cylinderColors[i].intervals.begin()->end;
805  const float normY = cos(curAngle);
806  const float normZ = sin(curAngle);
807  const float y = m_radius * normY;
808  const float z = m_radius * normZ;
809 
810  // Adding two points, one on the lower base, the other on the upper base
811  m_cylinderVertexes.append(lowerBaseX);
812  m_cylinderVertexes.append(y);
813  m_cylinderVertexes.append(z);
814  m_cylinderNormals.append(0.0);
815  m_cylinderNormals.append(normY);
816  m_cylinderNormals.append(normZ);
817  m_cylinderColors.append(color.redF());
818  m_cylinderColors.append(color.greenF());
819  m_cylinderColors.append(color.blueF());
820  m_cylinderTextureCoords.append(0.0);
821  m_cylinderTextureCoords.append((curAngle + PI_GRECO) / (2.0 * PI_GRECO));
822  m_cylinderVertexes.append(upperBaseX);
823  m_cylinderVertexes.append(y);
824  m_cylinderVertexes.append(z);
825  m_cylinderNormals.append(0.0);
826  m_cylinderNormals.append(normY);
827  m_cylinderNormals.append(normZ);
828  m_cylinderColors.append(color.redF());
829  m_cylinderColors.append(color.greenF());
830  m_cylinderColors.append(color.blueF());
831  m_cylinderTextureCoords.append(1.0);
832  m_cylinderTextureCoords.append((curAngle + PI_GRECO) / (2.0 * PI_GRECO));
833 
834  prevColor = cylinderColors[i].color;
835  }
836 
837  // Now the upper base. First getting the list of colors; as for the cylinder we generate a list of
838  // colors so that the code below will work in any case and the generated list has the same angles as the
839  // one of the cylinder
840  QList<PhyCylinder::SegmentColor> upperBaseColor;
841  QColor colorForUpperBase;
842  if (cylinderColor.isValid()) {
843  // Single color for the whole cylinder
844  colorForUpperBase = cylinderColor;
845  } else if (m_cylinder->upperBaseColor().isValid()) {
846  // Single color for the whole base
847  colorForUpperBase = m_cylinder->upperBaseColor();
848  }
849  if (colorForUpperBase.isValid()) {
850  for (int i = 0; i < cylinderColors.size(); i++) {
851  PhyCylinder::SegmentColor s = cylinderColors[i];
852  s.color = colorForUpperBase;
853  upperBaseColor << s;
854  }
855  } else {
856  upperBaseColor = cylinderColors;
857  }
858 
859  // Now generating vertexes for the upper base. This variable is needed to count the number of points
860  // for each color (we have to re-add the center when changing the color)
861  unsigned int numVertexesCurSegment = 0;
862 
863  // Before entering the cycle, adding the central point (remember that we will draw this list of
864  // vertexes as a TRIANGLE_FAN)
865  {
866  const QColor color = upperBaseColor[0].color;
867  m_upperBaseVertexes.append(upperBaseX);
868  m_upperBaseVertexes.append(0.0);
869  m_upperBaseVertexes.append(0.0);
870  m_upperBaseNormals.append(1.0);
871  m_upperBaseNormals.append(0.0);
872  m_upperBaseNormals.append(0.0);
873  m_upperBaseColors.append(color.redF());
874  m_upperBaseColors.append(color.greenF());
875  m_upperBaseColors.append(color.blueF());
876  m_upperBaseTextureCoords.append(0.5);
877  m_upperBaseTextureCoords.append(0.5);
878  ++numVertexesCurSegment;
879 
880  const real curAngle = upperBaseColor[0].intervals.begin()->start;
881  const float normY = cos(curAngle);
882  const float normZ = sin(curAngle);
883  const float y = m_radius * normY;
884  const float z = m_radius * normZ;
885 
886  m_upperBaseVertexes.append(upperBaseX);
887  m_upperBaseVertexes.append(y);
888  m_upperBaseVertexes.append(z);
889  m_upperBaseNormals.append(1.0);
890  m_upperBaseNormals.append(0.0);
891  m_upperBaseNormals.append(0.0);
892  m_upperBaseColors.append(color.redF());
893  m_upperBaseColors.append(color.greenF());
894  m_upperBaseColors.append(color.blueF());
895  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
896  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
897  ++numVertexesCurSegment;
898  }
899  // We have to save the old color to decide when to switch
900  prevColor = upperBaseColor[0].color;
901  for (int i = 0; i < upperBaseColor.size(); ++i) {
902  const QColor color = upperBaseColor[i].color;
903 
904  if (prevColor != color) {
905  // Saving the number of vertex of the current segment and resetting the counter
906  m_upperBaseSegmentsLength.append(numVertexesCurSegment);
907  numVertexesCurSegment = 0;
908 
909  // Here we have to add again the center of the circle and the start of the
910  // interval (which is equal to the end of the previous interval).
911  const real prevAngle = upperBaseColor[i].intervals.begin()->start;
912  const float normY = cos(prevAngle);
913  const float normZ = sin(prevAngle);
914  const float y = m_radius * normY;
915  const float z = m_radius * normZ;
916  m_upperBaseVertexes.append(upperBaseX);
917  m_upperBaseVertexes.append(0.0);
918  m_upperBaseVertexes.append(0.0);
919  m_upperBaseNormals.append(1.0);
920  m_upperBaseNormals.append(0.0);
921  m_upperBaseNormals.append(0.0);
922  m_upperBaseColors.append(color.redF());
923  m_upperBaseColors.append(color.greenF());
924  m_upperBaseColors.append(color.blueF());
925  m_upperBaseTextureCoords.append(0.5);
926  m_upperBaseTextureCoords.append(0.5);
927  ++numVertexesCurSegment;
928  m_upperBaseVertexes.append(upperBaseX);
929  m_upperBaseVertexes.append(y);
930  m_upperBaseVertexes.append(z);
931  m_upperBaseNormals.append(1.0);
932  m_upperBaseNormals.append(0.0);
933  m_upperBaseNormals.append(0.0);
934  m_upperBaseColors.append(color.redF());
935  m_upperBaseColors.append(color.greenF());
936  m_upperBaseColors.append(color.blueF());
937  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
938  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
939  ++numVertexesCurSegment;
940  }
941 
942  const real curAngle = upperBaseColor[i].intervals.begin()->end;
943  const float normY = cos(curAngle);
944  const float normZ = sin(curAngle);
945  const float y = m_radius * normY;
946  const float z = m_radius * normZ;
947 
948  m_upperBaseVertexes.append(upperBaseX);
949  m_upperBaseVertexes.append(y);
950  m_upperBaseVertexes.append(z);
951  m_upperBaseNormals.append(1.0);
952  m_upperBaseNormals.append(0.0);
953  m_upperBaseNormals.append(0.0);
954  m_upperBaseColors.append(color.redF());
955  m_upperBaseColors.append(color.greenF());
956  m_upperBaseColors.append(color.blueF());
957  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
958  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
959  ++numVertexesCurSegment;
960 
961  prevColor = upperBaseColor[i].color;
962  }
963  // Adding the length of the last segment
964  m_upperBaseSegmentsLength.append(numVertexesCurSegment);
965 
966  // Finally the lower base. The code is exactly like the one for the upper base
967  QList<PhyCylinder::SegmentColor> lowerBaseColor;
968  QColor colorForLowerBase;
969  if (cylinderColor.isValid()) {
970  // Single color for the whole cylinder
971  colorForLowerBase = cylinderColor;
972  } else if (m_cylinder->lowerBaseColor().isValid()) {
973  // Single color for the whole base
974  colorForLowerBase = m_cylinder->lowerBaseColor();
975  }
976  if (colorForLowerBase.isValid()) {
977  for (int i = 0; i < cylinderColors.size(); i++) {
978  PhyCylinder::SegmentColor s = cylinderColors[i];
979  s.color = colorForLowerBase;
980  lowerBaseColor << s;
981  }
982  } else {
983  lowerBaseColor = cylinderColors;
984  }
985 
986  numVertexesCurSegment = 0;
987 
988  {
989  const QColor color = lowerBaseColor[0].color;
990  m_lowerBaseVertexes.append(lowerBaseX);
991  m_lowerBaseVertexes.append(0.0);
992  m_lowerBaseVertexes.append(0.0);
993  m_lowerBaseNormals.append(-1.0);
994  m_lowerBaseNormals.append(0.0);
995  m_lowerBaseNormals.append(0.0);
996  m_lowerBaseColors.append(color.redF());
997  m_lowerBaseColors.append(color.greenF());
998  m_lowerBaseColors.append(color.blueF());
999  m_lowerBaseTextureCoords.append(0.5);
1000  m_lowerBaseTextureCoords.append(0.5);
1001  ++numVertexesCurSegment;
1002 
1003  const real curAngle = lowerBaseColor[0].intervals.begin()->start;
1004  const float normY = cos(curAngle);
1005  const float normZ = sin(curAngle);
1006  const float y = m_radius * normY;
1007  const float z = m_radius * normZ;
1008 
1009  m_lowerBaseVertexes.append(lowerBaseX);
1010  m_lowerBaseVertexes.append(y);
1011  m_lowerBaseVertexes.append(z);
1012  m_lowerBaseNormals.append(-1.0);
1013  m_lowerBaseNormals.append(0.0);
1014  m_lowerBaseNormals.append(0.0);
1015  m_lowerBaseColors.append(color.redF());
1016  m_lowerBaseColors.append(color.greenF());
1017  m_lowerBaseColors.append(color.blueF());
1018  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
1019  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
1020  ++numVertexesCurSegment;
1021  }
1022  // We have to save the old color to decide when to switch
1023  prevColor = lowerBaseColor[0].color;
1024  for (int i = 0; i < lowerBaseColor.size(); ++i) {
1025  const QColor color = lowerBaseColor[i].color;
1026 
1027  if (prevColor != color) {
1028  // Saving the number of vertex of the current segment and resetting the counter
1029  m_lowerBaseSegmentsLength.append(numVertexesCurSegment);
1030  numVertexesCurSegment = 0;
1031 
1032  // Here we have to add again the center of the circle and the start of the
1033  // interval (which is equal to the end of the previous interval).
1034  const real prevAngle = lowerBaseColor[i].intervals.begin()->start;
1035  const float normY = cos(prevAngle);
1036  const float normZ = sin(prevAngle);
1037  const float y = m_radius * normY;
1038  const float z = m_radius * normZ;
1039  m_lowerBaseVertexes.append(lowerBaseX);
1040  m_lowerBaseVertexes.append(0.0);
1041  m_lowerBaseVertexes.append(0.0);
1042  m_lowerBaseNormals.append(-1.0);
1043  m_lowerBaseNormals.append(0.0);
1044  m_lowerBaseNormals.append(0.0);
1045  m_lowerBaseColors.append(color.redF());
1046  m_lowerBaseColors.append(color.greenF());
1047  m_lowerBaseColors.append(color.blueF());
1048  m_lowerBaseTextureCoords.append(0.5);
1049  m_lowerBaseTextureCoords.append(0.5);
1050  ++numVertexesCurSegment;
1051  m_lowerBaseVertexes.append(lowerBaseX);
1052  m_lowerBaseVertexes.append(y);
1053  m_lowerBaseVertexes.append(z);
1054  m_lowerBaseNormals.append(-1.0);
1055  m_lowerBaseNormals.append(0.0);
1056  m_lowerBaseNormals.append(0.0);
1057  m_lowerBaseColors.append(color.redF());
1058  m_lowerBaseColors.append(color.greenF());
1059  m_lowerBaseColors.append(color.blueF());
1060  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
1061  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
1062  ++numVertexesCurSegment;
1063  }
1064 
1065  const real curAngle = lowerBaseColor[i].intervals.begin()->end;
1066  const float normY = cos(curAngle);
1067  const float normZ = sin(curAngle);
1068  const float y = m_radius * normY;
1069  const float z = m_radius * normZ;
1070 
1071  m_lowerBaseVertexes.append(lowerBaseX);
1072  m_lowerBaseVertexes.append(y);
1073  m_lowerBaseVertexes.append(z);
1074  m_lowerBaseNormals.append(-1.0);
1075  m_lowerBaseNormals.append(0.0);
1076  m_lowerBaseNormals.append(0.0);
1077  m_lowerBaseColors.append(color.redF());
1078  m_lowerBaseColors.append(color.greenF());
1079  m_lowerBaseColors.append(color.blueF());
1080  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
1081  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
1082  ++numVertexesCurSegment;
1083 
1084  prevColor = lowerBaseColor[i].color;
1085  }
1086  // Adding the length of the last segment
1087  m_lowerBaseSegmentsLength.append(numVertexesCurSegment);
1088  }
1089 
1094 
1099 
1104 
1111  QVector<GLfloat> m_cylinderVertexes;
1112 
1118  QVector<GLfloat> m_cylinderNormals;
1119 
1125  QVector<GLfloat> m_cylinderColors;
1126 
1133  QVector<GLfloat> m_cylinderTextureCoords;
1134 
1141  QVector<GLfloat> m_upperBaseVertexes;
1142 
1148  QVector<GLfloat> m_upperBaseNormals;
1149 
1155  QVector<GLfloat> m_upperBaseColors;
1156 
1163  QVector<GLfloat> m_upperBaseTextureCoords;
1164 
1169  QVector<unsigned int> m_upperBaseSegmentsLength;
1170 
1177  QVector<GLfloat> m_lowerBaseVertexes;
1178 
1184  QVector<GLfloat> m_lowerBaseNormals;
1185 
1191  QVector<GLfloat> m_lowerBaseColors;
1192 
1199  QVector<GLfloat> m_lowerBaseTextureCoords;
1200 
1205  QVector<unsigned int> m_lowerBaseSegmentsLength;
1206 };
1207 
1209 public:
1210  RenderPhyCone( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1211  cone = (PhyCone*)wobj;
1212  rad = cone->radius();
1213  hei = cone->height();
1214  };
1215  virtual ~RenderPhyCone() { };
1216  virtual void render( QGLContext* gw ) {
1217  glPushMatrix();
1218  GLUquadricObj *pObj;
1219  container()->setupColorTexture( gw, this );
1220 
1221  // opengl cylinder are aligned alogn the z axis, we want it along the x axis,
1222  // we create a rotation matrix to do the alignment
1223  wMatrix matrix = wMatrix::yaw( PI_GRECO * 0.5 );
1224  matrix.w_pos = matrix.rotateVector( wVector(0.0, 0.0, -hei*0.5) );
1225  matrix = matrix * cone->matrix();
1226  GLMultMatrix(&matrix[0][0]);
1227 
1228  // Get a new Quadric off the stack
1229  pObj = gluNewQuadric();
1230  gluQuadricTexture(pObj, true);
1231  gluCylinder(pObj, rad, 0, hei, 20, 2);
1232 
1233  // render the caps
1234  gluQuadricOrientation(pObj, GLU_INSIDE);
1235  gluDisk(pObj, 0.0f, rad, 20, 1);
1236 
1237  gluDeleteQuadric(pObj);
1238 
1239  // Checking if we have to draw axis
1240  if (cone->localAxesDrawn()) {
1241  const float radius = min(rad, hei) * 0.1;
1242 
1243  RenderWObjectContainer::drawArrow(wVector(hei, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
1244  RenderWObjectContainer::drawArrow(wVector(0.0, 2.0 * rad, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
1245  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, 2.0 * rad), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
1246  }
1247 
1248  // Drawing label if we have to
1249  drawLabel();
1250 
1251  glPopMatrix();
1252  };
1253  virtual void renderAABB( RenderWorld* gw ) {
1254  wVector minpoint, maxpoint;
1255  calculateAABB( minpoint, maxpoint, obj->matrix() );
1256  gw->drawWireBox( minpoint, maxpoint );
1257  };
1258  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1259  real h2 = hei/2.0;
1260  real tdx = fabs(tm.x_ax[0]*h2) + fabs(tm.y_ax[0]*rad) + fabs(tm.z_ax[0]*rad);
1261  real tdy = fabs(tm.x_ax[1]*h2) + fabs(tm.y_ax[1]*rad) + fabs(tm.z_ax[1]*rad);
1262  real tdz = fabs(tm.x_ax[2]*h2) + fabs(tm.y_ax[2]*rad) + fabs(tm.z_ax[2]*rad);
1263  wVector hds( tdx, tdy, tdz );
1264  minPoint = tm.w_pos - hds;
1265  maxPoint = tm.w_pos + hds;
1266  };
1267 
1268  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1269  dimension[0] = hei;
1270  dimension[1] = rad*2.0;
1271  dimension[2] = rad*2.0;
1272  wVector rds = wVector( hei/2.0, rad, rad );
1273  minPoint = -rds;
1274  maxPoint = +rds;
1275  };
1276 protected:
1277  PhyCone* cone;
1278  real rad;
1279  real hei;
1280 };
1281 
1282 // class RenderPhyHeightField : public RenderWObject {
1283 // public:
1284 // RenderPhyHeightField( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1285 // hf = (PhyHeightField*)wobj;
1286 // dx = hf->sideX();
1287 // dy = hf->sideY();
1288 // dz = 0.01f;
1289 // };
1290 // virtual ~RenderPhyHeightField() { };
1291 // virtual void render( QGLContext* gw ) {
1292 // glPushMatrix();
1293 // container()->setupColorTexture( gw, this );
1294 // wMatrix m = hf->matrix().rotateAround( wVector(1,0,0), wVector(0,0,0), toRad(-90) );
1295 // m.w_pos[0] -= dx/2.0;
1296 // m.w_pos[1] -= dy/2.0;
1297 // GLMultMatrix(&m[0][0]);
1298 //
1299 // NewtonMesh* mesh = hf->mesh;
1300 // int stride = NewtonMeshGetVertexStrideInByte(mesh) / sizeof (double);
1301 // const double* const vertexList = NewtonMeshGetVertexArray(mesh);
1302 //
1303 // glBegin(GL_TRIANGLES);
1304 // for (void* face = NewtonMeshGetFirstFace(mesh); face; face = NewtonMeshGetNextFace(mesh, face)) {
1305 // if (!NewtonMeshIsFaceOpen (mesh, face)) {
1306 // int indices[1024];
1307 // int vertexCount = NewtonMeshGetFaceIndexCount (mesh, face);
1308 // Q_ASSERT (vertexCount < sizeof (indices)/sizeof (indices[0]));
1309 // NewtonMeshGetFaceIndices (mesh, face, indices);
1310 //
1311 // //dFloat64 normal[4];
1312 // //NewtonMeshCalculateFaceNormal (mesh, face, normal);
1313 // //glNormal3f(normal[0], normal[1], normal[2]);
1314 //
1315 // int i0 = indices[0];
1316 // int i1 = indices[1];
1317 // wVector p0 ( dFloat(vertexList[i0 * stride + 0]),
1318 // dFloat(vertexList[i0 * stride + 1]),
1319 // dFloat(vertexList[i0 * stride + 2]),
1320 // 0.0f );
1321 // wVector p1 ( dFloat(vertexList[i1 * stride + 0]),
1322 // dFloat(vertexList[i1 * stride + 1]),
1323 // dFloat(vertexList[i1 * stride + 2]),
1324 // 0.0f );
1325 // for (int i = 2; i < vertexCount; i++) {
1326 // int i2 = indices[i];
1327 // wVector p2 ( dFloat(vertexList[i2 * stride + 0]),
1328 // dFloat(vertexList[i2 * stride + 1]),
1329 // dFloat(vertexList[i2 * stride + 2]),
1330 // 0.0f );
1331 // glVertex3f(p0[0], p0[1], p0[2]);
1332 // glVertex3f(p1[0], p1[1], p1[2]);
1333 // glVertex3f(p2[0], p2[1], p2[2]);
1334 // p1 = p2;
1335 // }
1336 // }
1337 // }
1338 //
1339 // glEnd();
1340 //
1341 // glPopMatrix();
1342 // };
1343 // virtual void renderAABB( RenderWorld* gw ) {
1344 // wVector minpoint, maxpoint;
1345 // calculateAABB( minpoint, maxpoint, obj->matrix() );
1346 // gw->drawWireBox( minpoint, maxpoint );
1347 // };
1348 // virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1349 // real tdx = fabs(tm.x_ax[0]*dx) + fabs(tm.y_ax[0]*dy) + fabs(tm.z_ax[0]*dz);
1350 // real tdy = fabs(tm.x_ax[1]*dx) + fabs(tm.y_ax[1]*dy) + fabs(tm.z_ax[1]*dz);
1351 // real tdz = fabs(tm.x_ax[2]*dx) + fabs(tm.y_ax[2]*dy) + fabs(tm.z_ax[2]*dz);
1352 //
1353 // wVector hds( tdx/2.0, tdy/2.0, tdz/2.0 );
1354 // minPoint = tm.w_pos - hds;
1355 // maxPoint = tm.w_pos + hds;
1356 // };
1357 //
1358 // virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1359 // dimension[0] = dx;
1360 // dimension[1] = dy;
1361 // dimension[2] = dz;
1362 // wVector hds( dx/2.0, dy/2.0, dz/2.0 );
1363 // minPoint = -hds;
1364 // maxPoint = +hds;
1365 // };
1366 //
1367 // protected:
1368 // PhyHeightField* hf;
1369 // real dx, dy, dz;
1370 // };
1371 
1373 public:
1374  RenderCompoundObject( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1375  co = (PhyCompoundObject*)wobj;
1376  initRobjv( container );
1377  };
1378  virtual ~RenderCompoundObject() {
1379  foreach( RenderWObject* ro, robjv ) {
1380  delete ro;
1381  }
1382  };
1383  virtual void render( QGLContext* gw ) {
1384  glPushMatrix();
1385  container()->setupColorTexture( gw, this );
1386  wMatrix matrix = co->matrix();
1387  GLMultMatrix(&matrix[0][0]);
1388  foreach( RenderWObject* ro, robjv ) {
1389  ro->render( gw );
1390  }
1391 
1392  // Checking if we have to draw axis
1393  if (co->localAxesDrawn()) {
1394  // We use the dimension of the OBB as lengths of the axes
1395  wVector dimension;
1396  wVector minPoint;
1397  wVector maxPoint;
1398  calculateOBB(dimension, minPoint, maxPoint);
1399  const float radius = min(dimension.x, min(dimension.y, dimension.z)) * 0.1;
1400 
1401  RenderWObjectContainer::drawArrow(wVector(dimension.x, 0.0, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::red);
1402  RenderWObjectContainer::drawArrow(wVector(0.0, dimension.y, 0.0), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::green);
1403  RenderWObjectContainer::drawArrow(wVector(0.0, 0.0, dimension.z), wVector(0.0, 0.0, 0.0), radius, 2.0 * radius, 2.0 * radius, Qt::blue);
1404  }
1405 
1406  // Drawing label if we have to
1407  drawLabel();
1408 
1409  glPopMatrix();
1410  };
1411  virtual void renderAABB( RenderWorld* gw ) {
1412  wVector minpoint, maxpoint;
1413  calculateAABB( minpoint, maxpoint, obj->matrix() );
1414  gw->drawWireBox( minpoint, maxpoint );
1415  };
1416  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1417  robjv[0]->calculateAABB( minPoint, maxPoint, robjv[0]->object()->matrix()*tm );
1418  wVector minP, maxP;
1419  for( int i=1; i<robjv.size(); i++ ) {
1420  robjv[i]->calculateAABB( minP, maxP, robjv[i]->object()->matrix()*tm );
1421  mergeAABB( minPoint, maxPoint, minP, maxP );
1422  }
1423  };
1424  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1425  //--- the right calculation is done calculating the AABB when
1426  //--- the transformation matrix is the identity
1427  wVector minP, maxP;
1428  if ( robjv.size() == 0 ) {
1429  qWarning( "== this point should never reached: renderwobjecthierarchy.cpp:435" );
1430  return;
1431  }
1432  robjv[0]->calculateAABB( minPoint, maxPoint, robjv[0]->object()->matrix() );
1433  for( int i=1; i<robjv.size(); i++ ) {
1434  robjv[i]->calculateAABB( minP, maxP, robjv[i]->object()->matrix() );
1435  mergeAABB( minPoint, maxPoint, minP, maxP );
1436  }
1437  dimension[0] = fabs( maxPoint[0] - minPoint[0] );
1438  dimension[1] = fabs( maxPoint[1] - minPoint[1] );
1439  dimension[2] = fabs( maxPoint[2] - minPoint[2] );
1440  };
1441 protected:
1442  PhyCompoundObject* co;
1443  QVector<RenderWObject*> robjv;
1444 private:
1445  void initRobjv( RenderWObjectContainer* container ) {
1446  foreach( WObject* obj, co->bodies() ) {
1447  robjv << RenderWObjectContainer::createRenderWObjectFor( obj, container );
1448  }
1449  };
1450  void mergeAABB( wVector& minPointA, wVector& maxPointA, const wVector& minPointB, const wVector& maxPointB ) {
1451  minPointA[0] = min( minPointA[0], minPointB[0] );
1452  minPointA[1] = min( minPointA[1], minPointB[1] );
1453  minPointA[2] = min( minPointA[2], minPointB[2] );
1454  maxPointA[0] = max( maxPointA[0], maxPointB[0] );
1455  maxPointA[1] = max( maxPointA[1], maxPointB[1] );
1456  maxPointA[2] = max( maxPointA[2], maxPointB[2] );
1457  };
1458 };
1459 
1460 // This class is the renderer associated with GraphicalWObject. It simply
1461 // forwards calls to GraphicalWObject functions
1463 {
1464 public:
1466  RenderWObject(obj, rw),
1467  m_graphicalWObject(dynamic_cast<GraphicalWObject*>(obj))
1468  {
1469  }
1470 
1471  virtual ~GraphicalWObjectRenderer()
1472  {
1473  }
1474 
1475  virtual void render(QGLContext *gw)
1476  {
1477  m_graphicalWObject->updateAndRender(this, gw);
1478  }
1479 
1480  virtual void renderAABB(RenderWorld *gw)
1481  {
1482  m_graphicalWObject->updateAndRenderAABB(this, gw);
1483  }
1484 
1485  virtual void calculateAABB(wVector &minPoint, wVector &maxPoint, const wMatrix tm)
1486  {
1487  m_graphicalWObject->updateAndCalculateAABB(minPoint, maxPoint, tm);
1488  }
1489 
1490  virtual void calculateOBB(wVector &dimension, wVector &minPoint, wVector &maxPoint)
1491  {
1492  m_graphicalWObject->updateAndCalculateOBB(dimension, minPoint, maxPoint);
1493  }
1494 
1495 private:
1496  GraphicalWObject *const m_graphicalWObject;
1497 };
1498 
1499 bool RenderWObjectContainer::facInited = false;
1500 QMap<QString, WAbstractCreator*>* RenderWObjectContainer::fac;
1501 void RenderWObjectContainer::initFactory() {
1502  if ( facInited ) return;
1503 
1504  fac = new QMap<QString, WAbstractCreator*>();
1505 
1506  (*fac)["farsa::WMesh"] = new WCreator<RenderWMesh>();
1507  (*fac)["farsa::PhyBox"] = new WCreator<RenderPhyBox>();
1508  (*fac)["farsa::PhySphere"] = new WCreator<RenderPhySphere>();
1509  (*fac)["farsa::PhyEllipsoid"] = new WCreator<RenderPhyEllipsoid>();
1510  (*fac)["farsa::PhyCylinder"] = new WCreator<RenderPhyCylinder>();
1511  (*fac)["farsa::PhyCone"] = new WCreator<RenderPhyCone>();
1512 // (*fac)["farsa::PhyHeightField"] = new WCreator<RenderPhyHeightField>();
1513  (*fac)["farsa::PhyCompoundObject"] = new WCreator<RenderCompoundObject>();
1514  (*fac)["farsa::GraphicalWObject"] = new WCreator<GraphicalWObjectRenderer>();
1515 
1516  //--- FIXME a specific class should be implemented
1517  (*fac)["farsa::WObject"] = new WCreator<RenderGenericObject>();
1518  (*fac)["farsa::WorldController"] = new WCreator<RenderGenericObject>();
1519 
1520  facInited = true;
1521 }
1522 
1523 } // end namespace farsa