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