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 "phybox.h"
23 #include "phycylinder.h"
24 #include "phycone.h"
25 // #include "phyheightfield.h"
26 #include "phyicub.h"
27 #include "wcamera.h"
28 #include "phycompoundobject.h"
29 #include "wmesh.h"
30 #include "graphicalwobject.h"
31 #include "private/renderwobjecthierarchy.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  };
68  virtual void renderAABB( RenderWorld* gw ) {
69  wVector minpoint, maxpoint;
70  calculateAABB( minpoint, maxpoint, obj->matrix() );
71  gw->drawWireBox( minpoint, maxpoint );
72  };
73  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
74  wVector rds( rad, rad, rad );
75  minPoint = tm.w_pos - rds;
76  maxPoint = tm.w_pos + rds;
77  };
78 
79  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
80  dimension[0] = rad*2.0;
81  dimension[1] = rad*2.0;
82  dimension[2] = rad*2.0;
83  wVector rds = wVector( rad, rad, rad );
84  minPoint = -rds;
85  maxPoint = +rds;
86  };
87 protected:
88  real rad;
89 };
90 
91 class RenderWMesh : public RenderWObject {
92 public:
93  RenderWMesh( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
94  wmesh = (WMesh*)wobj;
95  };
96  virtual ~RenderWMesh() { };
97  virtual void render( QGLContext* gw ) {
98  glPushMatrix();
99  wMatrix m = wmesh->matrix();
100  if ( wmesh->attachedTo() ) {
101  m = m * wmesh->attachedTo()->matrix();
102  }
103  GLMultMatrix(&m[0][0]);
104  int m_numMeshes = wmesh->meshesCount();
105  WMesh::Mesh *m_pMeshes = wmesh->meshes();
106 // int m_numMaterials = wmesh->materialsCount();
107  WMesh::Material *m_pMaterials = wmesh->materials();
108 // int m_numTriangles = wmesh->trianglesCount();
109  WMesh::Triangle *m_pTriangles = wmesh->triangles();
110 // int m_numVertices = wmesh->verticesCount();
111  WMesh::Vertex *m_pVertices = wmesh->vertices();
112  for ( int i = 0; i < m_numMeshes; i++ ) {
113  int materialIndex = m_pMeshes[i].m_materialIndex;
114  if ( materialIndex >= 0 ) {
115  glMaterialfv( GL_FRONT, GL_AMBIENT, m_pMaterials[materialIndex].m_ambient );
116  glMaterialfv( GL_FRONT, GL_DIFFUSE, m_pMaterials[materialIndex].m_diffuse );
117  glMaterialfv( GL_FRONT, GL_SPECULAR, m_pMaterials[materialIndex].m_specular );
118  glMaterialfv( GL_FRONT, GL_EMISSION, m_pMaterials[materialIndex].m_emissive );
119  glMaterialf( GL_FRONT, GL_SHININESS, m_pMaterials[materialIndex].m_shininess );
120  //container()->applyTexture( gw, wmesh->texture() );
121  container()->setupColorTexture( gw, this );
122  }
123  glBegin( GL_TRIANGLES );
124  for ( int j = 0; j < m_pMeshes[i].m_numTriangles; j++ ) {
125  int triangleIndex = m_pMeshes[i].m_pTriangleIndices[j];
126  const WMesh::Triangle* pTri = &m_pTriangles[triangleIndex];
127  for ( int k = 0; k < 3; k++ ) {
128  int index = pTri->m_vertexIndices[k];
129  glNormal3fv( pTri->m_vertexNormals[k] );
130  glTexCoord2f( pTri->m_s[k], pTri->m_t[k] );
131  glVertex3fv( m_pVertices[index].m_location );
132  }
133  }
134  glEnd();
135  }
136  glPopMatrix();
137  };
138  virtual void renderAABB( RenderWorld* /*gw*/ ) {
139  };
140  virtual void calculateAABB( wVector& /*minPoint*/, wVector& /*maxPoint*/, const wMatrix /*tm*/ ) {
141  };
142  virtual void calculateOBB( wVector& /*dimension*/, wVector& /*minPoint*/, wVector& /*maxPoint*/ ) {
143  };
144 private:
145  WMesh* wmesh;
146 };
147 
148 class RenderPhyBox : public RenderWObject {
149 public:
150  RenderPhyBox( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
151  box = (PhyBox*)wobj;
152  dx = box->sideX();
153  dy = box->sideY();
154  dz = box->sideZ();
155  };
156  virtual ~RenderPhyBox() { };
157  virtual void render( QGLContext* gw ) {
158  glPushMatrix();
159  container()->setupColorTexture( gw, this );
160  const wMatrix& m = box->matrix();
161  GLMultMatrix(&m[0][0]);
162 
163  // the cube will just be drawn as six quads for the sake of simplicity
164  // for each face, we specify the quad's normal (for lighting), then
165  // specify the quad's 4 vertices and associated texture coordinates
166  glBegin(GL_QUADS);
167  float hdx = (dx/2.0);
168  float hdy = (dy/2.0);
169  float hdz = (dz/2.0);
170  // front
171  glNormal3f(0.0, 0.0, 1.0);
172  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
173  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, hdz);
174  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, hdz);
175  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, hdz);
176 
177  // back
178  glNormal3f(0.0, 0.0, -1.0);
179  glTexCoord2f(0.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
180  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
181  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
182  glTexCoord2f(0.0, 1.0); glVertex3f( hdx, hdy, -hdz);
183 
184  // top
185  glNormal3f(0.0, 1.0, 0.0);
186  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, hdy, hdz);
187  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, hdy, hdz);
188  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, -hdz);
189  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
190 
191  // bottom
192  glNormal3f(0.0, -1.0, 0.0);
193  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
194  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
195  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, -hdy, hdz);
196  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, -hdy, hdz);
197 
198  // left
199  glNormal3f(-1.0, 0.0, 0.0);
200  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
201  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
202  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, hdz);
203  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
204 
205  // right
206  glNormal3f(1.0, 0.0, 0.0);
207  glTexCoord2f(0.0, 0.0); glVertex3f(hdx, -hdy, hdz);
208  glTexCoord2f(1.0, 0.0); glVertex3f(hdx, -hdy, -hdz);
209  glTexCoord2f(1.0, 1.0); glVertex3f(hdx, hdy, -hdz);
210  glTexCoord2f(0.0, 1.0); glVertex3f(hdx, hdy, hdz);
211 
212  glEnd();
213  glPopMatrix();
214  };
215  virtual void renderAABB( RenderWorld* gw ) {
216  wVector minpoint, maxpoint;
217  calculateAABB( minpoint, maxpoint, obj->matrix() );
218  gw->drawWireBox( minpoint, maxpoint );
219  };
220  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
221  real tdx = fabs(tm.x_ax[0]*dx) + fabs(tm.y_ax[0]*dy) + fabs(tm.z_ax[0]*dz);
222  real tdy = fabs(tm.x_ax[1]*dx) + fabs(tm.y_ax[1]*dy) + fabs(tm.z_ax[1]*dz);
223  real tdz = fabs(tm.x_ax[2]*dx) + fabs(tm.y_ax[2]*dy) + fabs(tm.z_ax[2]*dz);
224 
225  wVector hds( tdx/2.0, tdy/2.0, tdz/2.0 );
226  minPoint = tm.w_pos - hds;
227  maxPoint = tm.w_pos + hds;
228  };
229 
230  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
231  dimension[0] = dx;
232  dimension[1] = dy;
233  dimension[2] = dz;
234  wVector hds( dx/2.0, dy/2.0, dz/2.0 );
235  minPoint = -hds;
236  maxPoint = +hds;
237  };
238 
239 protected:
240  PhyBox* box;
241  real dx, dy, dz;
242 };
243 
245 public:
246  RenderPhySphere( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
247  sph = (PhySphere*)wobj;
248  rad = sph->radius();
249  };
250  virtual ~RenderPhySphere() { };
251  virtual void render( QGLContext* gw ) {
252  glPushMatrix();
253  GLUquadricObj *pObj;
254  container()->setupColorTexture( gw, this );
255  wMatrix mat = sph->matrix();
256  mat.x_ax = mat.x_ax.scale( rad );
257  mat.y_ax = mat.y_ax.scale( rad );
258  mat.z_ax = mat.z_ax.scale( rad );
259  GLMultMatrix(&mat[0][0]);
260 
261  // Get a new Quadric off the stack
262  pObj = gluNewQuadric();
263  // Get a new Quadric off the stack
264  gluQuadricTexture(pObj, true);
265  gluSphere(pObj, 1.0f, 20, 20);
266  gluDeleteQuadric(pObj);
267  glPopMatrix();
268  };
269  virtual void renderAABB( RenderWorld* gw ) {
270  wVector minpoint, maxpoint;
271  calculateAABB( minpoint, maxpoint, obj->matrix() );
272  gw->drawWireBox( minpoint, maxpoint );
273  };
274  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
275  wVector rds( rad, rad, rad );
276  minPoint = tm.w_pos - rds;
277  maxPoint = tm.w_pos + rds;
278  };
279 
280  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
281  dimension[0] = rad*2.0;
282  dimension[1] = rad*2.0;
283  dimension[2] = rad*2.0;
284  wVector rds = wVector( rad, rad, rad );
285  minPoint = -rds;
286  maxPoint = +rds;
287  };
288 protected:
289  PhySphere* sph;
290  real rad;
291 };
292 
293 // class RenderPhyCylinder : public RenderWObject {
294 // public:
295 // RenderPhyCylinder( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
296 // cil = (PhyCylinder*)wobj;
297 // rad = cil->radius();
298 // hei = cil->height();
299 // };
300 // virtual ~RenderPhyCylinder() { };
301 // virtual void render( QGLContext* gw ) {
302 // glPushMatrix();
303 // container()->setupColorTexture( gw, this );
304 //
305 // // opengl cylinder are aligned alogn the z axis, we want it along the x axis,
306 // // we create a rotation matrix to do the alignment
307 // wMatrix matrix = wMatrix::yaw( PI_GRECO * 0.5f );
308 // matrix.w_pos = matrix.rotateVector( wVector(0.0, 0.0, -hei*0.5f) );
309 // matrix = matrix * cil->matrix();
310 // GLMultMatrix(&matrix[0][0]);
311 //
312 // GLUquadricObj *pObj;
313 //
314 // // Get a new Quadric off the stack
315 // pObj = gluNewQuadric();
316 // gluQuadricTexture(pObj, true);
317 // gluCylinder(pObj, rad, rad, hei, 20, 2);
318 //
319 // // render the caps
320 // gluQuadricOrientation(pObj, GLU_INSIDE);
321 // gluDisk(pObj, 0.0f, rad, 20, 1);
322 //
323 // glTranslatef (0.0f, 0.0f, hei);
324 // gluQuadricOrientation(pObj, GLU_OUTSIDE);
325 // gluDisk(pObj, 0.0f, rad, 20, 1);
326 //
327 // gluDeleteQuadric(pObj);
328 //
329 // glPopMatrix();
330 // };
331 // virtual void renderAABB( RenderWorld* gw ) {
332 // wVector minpoint, maxpoint;
333 // calculateAABB( minpoint, maxpoint, obj->matrix() );
334 // gw->drawWireBox( minpoint, maxpoint );
335 // };
336 // virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
337 // real h2 = hei/2.0;
338 // real tdx = fabs(tm.x_ax[0]*h2) + fabs(tm.y_ax[0]*rad) + fabs(tm.z_ax[0]*rad);
339 // real tdy = fabs(tm.x_ax[1]*h2) + fabs(tm.y_ax[1]*rad) + fabs(tm.z_ax[1]*rad);
340 // real tdz = fabs(tm.x_ax[2]*h2) + fabs(tm.y_ax[2]*rad) + fabs(tm.z_ax[2]*rad);
341 // wVector hds( tdx, tdy, tdz );
342 // minPoint = tm.w_pos - hds;
343 // maxPoint = tm.w_pos + hds;
344 // };
345 //
346 // virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
347 // dimension[0] = hei;
348 // dimension[1] = rad*2.0;
349 // dimension[2] = rad*2.0;
350 // wVector rds = wVector( hei/2.0, rad, rad );
351 // minPoint = -rds;
352 // maxPoint = +rds;
353 // };
354 // protected:
355 // PhyCylinder* cil;
356 // real rad;
357 // real hei;
358 // };
359 
366 public:
375  RenderWObject(wobj, container),
376  m_cylinder(dynamic_cast<PhyCylinder*>(wobj)),
377  m_height(m_cylinder->height()),
378  m_radius(m_cylinder->radius()),
379  m_cylinderVertexes(),
380  m_cylinderNormals(),
381  m_cylinderColors(),
382  m_cylinderTextureCoords(),
383  m_upperBaseVertexes(),
384  m_upperBaseNormals(),
385  m_upperBaseColors(),
386  m_upperBaseTextureCoords(),
387  m_upperBaseSegmentsLength(),
388  m_lowerBaseVertexes(),
389  m_lowerBaseNormals(),
390  m_lowerBaseColors(),
391  m_lowerBaseTextureCoords(),
392  m_lowerBaseSegmentsLength()
393  {
394  // The cylinder representation will be updated in the first call to render()
395  }
396 
400  virtual ~RenderPhyCylinder()
401  {
402  // Nothing to do here
403  }
404 
410  virtual void render(QGLContext* gw)
411  {
412  // Checking if we have to regenerate the representation of the cylinder
413  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
414  updateRepresentation();
415  }
416 
417  glPushMatrix();
418  container()->setupColorTexture(gw, this);
419  GLMultMatrix(&(m_cylinder->matrix()[0][0]));
420 
421  // First drawing the cylinder. We need to enable the vertex arrays, set the
422  // starting point for vertex, normals and colors and then actually draw triangles
423  glEnableClientState(GL_NORMAL_ARRAY);
424  glEnableClientState(GL_COLOR_ARRAY);
425  glEnableClientState(GL_VERTEX_ARRAY);
426  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
427 
428  glNormalPointer(GL_FLOAT, 0, m_cylinderNormals.data());
429  glColorPointer(3, GL_FLOAT, 0, m_cylinderColors.data());
430  glVertexPointer(3, GL_FLOAT, 0, m_cylinderVertexes.data());
431  glTexCoordPointer(2, GL_FLOAT, 0, m_cylinderTextureCoords.data());
432 
433  glDrawArrays(GL_TRIANGLE_STRIP, 0, m_cylinderVertexes.size() / 3);
434 
435  // Now drawing the upper base
436  glNormalPointer(GL_FLOAT, 0, m_upperBaseNormals.data());
437  glColorPointer(3, GL_FLOAT, 0, m_upperBaseColors.data());
438  glVertexPointer(3, GL_FLOAT, 0, m_upperBaseVertexes.data());
439  glTexCoordPointer(2, GL_FLOAT, 0, m_upperBaseTextureCoords.data());
440 
441  unsigned int startIndex = 0;
442  foreach (unsigned int curLength, m_upperBaseSegmentsLength) {
443  glDrawArrays(GL_TRIANGLE_FAN, startIndex, curLength);
444  startIndex += curLength;
445  }
446 
447  // Finally drawing the lower base
448  glNormalPointer(GL_FLOAT, 0, m_lowerBaseNormals.data());
449  glColorPointer(3, GL_FLOAT, 0, m_lowerBaseColors.data());
450  glVertexPointer(3, GL_FLOAT, 0, m_lowerBaseVertexes.data());
451  glTexCoordPointer(2, GL_FLOAT, 0, m_lowerBaseTextureCoords.data());
452 
453  startIndex = 0;
454  foreach (unsigned int curLength, m_lowerBaseSegmentsLength) {
455  glDrawArrays(GL_TRIANGLE_FAN, startIndex, curLength);
456  startIndex += curLength;
457  }
458 
459  glDisableClientState(GL_VERTEX_ARRAY);
460  glDisableClientState(GL_COLOR_ARRAY);
461  glDisableClientState(GL_NORMAL_ARRAY);
462  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
463 
464  glPopMatrix();
465  }
466 
472  virtual void renderAABB(RenderWorld* gw)
473  {
474  // Checking if we have to regenerate the representation of the cylinder
475  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
476  updateRepresentation();
477  }
478 
479  wVector minpoint, maxpoint;
480  calculateAABB(minpoint, maxpoint, obj->matrix());
481  gw->drawWireBox(minpoint, maxpoint);
482  }
483 
491  virtual void calculateAABB(wVector& minPoint, wVector& maxPoint, const wMatrix tm)
492  {
493  // Checking if we have to regenerate the representation of the cylinder
494  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
495  updateRepresentation();
496  }
497 
498  const real h2 = m_height / 2.0;
499  const real tdx = fabs(tm.x_ax[0] * h2) + fabs(tm.y_ax[0] * m_radius) + fabs(tm.z_ax[0] * m_radius);
500  const real tdy = fabs(tm.x_ax[1] * h2) + fabs(tm.y_ax[1] * m_radius) + fabs(tm.z_ax[1] * m_radius);
501  const real tdz = fabs(tm.x_ax[2] * h2) + fabs(tm.y_ax[2] * m_radius) + fabs(tm.z_ax[2] * m_radius);
502  const wVector hds(tdx, tdy, tdz);
503  minPoint = tm.w_pos - hds;
504  maxPoint = tm.w_pos + hds;
505  }
506 
514  virtual void calculateOBB(wVector& dimension, wVector& minPoint, wVector& maxPoint)
515  {
516  // Checking if we have to regenerate the representation of the cylinder
517  if (m_cylinder->graphicalRepresentationNeedsUpdate()) {
518  updateRepresentation();
519  }
520 
521  dimension[0] = m_height;
522  dimension[1] = m_radius * 2.0;
523  dimension[2] = m_radius * 2.0;
524  const wVector rds(m_height / 2.0, m_radius, m_radius);
525  minPoint = -rds;
526  maxPoint = +rds;
527  }
528 
529 protected:
535  void updateRepresentation()
536  {
537  // A couple of helper constants
538  const int numDivs = 20;
539  const float anglePerDiv = (2 * M_PI) / float(numDivs);
540  const float lowerBaseX = -m_height / 2.0;
541  const float upperBaseX = +m_height / 2.0;
542 
543  // Resetting all lists
544  m_cylinderVertexes.clear();
545  m_cylinderNormals.clear();
546  m_cylinderColors.clear();
547  m_cylinderTextureCoords.clear();
548  m_upperBaseVertexes.clear();
549  m_upperBaseNormals.clear();
550  m_upperBaseColors.clear();
551  m_upperBaseTextureCoords.clear();
552  m_upperBaseSegmentsLength.clear();
553  m_lowerBaseVertexes.clear();
554  m_lowerBaseNormals.clear();
555  m_lowerBaseColors.clear();
556  m_lowerBaseTextureCoords.clear();
557  m_lowerBaseSegmentsLength.clear();
558 
559  // Getting the list of colors of the cylinder. If the cylinder has only one color, we generate a list to be
560  // able to use the code below anyway
561  QList<PhyCylinder::SegmentColor> cylinderColors;
562  if (m_cylinder->color().isValid()) {
563  // Single color for thw whole cylinder
564  cylinderColors.append(PhyCylinder::SegmentColor(0.0, m_cylinder->color()));
565  } else {
566  cylinderColors = m_cylinder->segmentsColor();
567  }
568 
569  // Now generating vertexes for the cylinder
570  float curOffset = 0.0;
571  unsigned int curSegment = 0;
572 
573  // In the exit condition of the cycle we add +anglePerDiv/2 to a full cycle to be sure to add the final point
574  // (it could be skipped because of numerical errors)
575  while (curOffset < (2.0 * M_PI + anglePerDiv / 2.0)) {
576  const float curAngle = cylinderColors[0].startingAngle + curOffset;
577 
578  if (((curSegment + 1) != cylinderColors.size()) && (cylinderColors[curSegment + 1].startingAngle < curAngle)) {
579  // Computing the two points on the color division boundary (which will then be duplicated)
580  const float normY = sin(cylinderColors[curSegment + 1].startingAngle);
581  const float normZ = cos(cylinderColors[curSegment + 1].startingAngle);
582  const float y = m_radius * normY;
583  const float z = m_radius * normZ;
584 
585  // Adding the first couple of points
586  m_cylinderVertexes.append(lowerBaseX);
587  m_cylinderVertexes.append(y);
588  m_cylinderVertexes.append(z);
589  m_cylinderNormals.append(0.0);
590  m_cylinderNormals.append(normY);
591  m_cylinderNormals.append(normZ);
592  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
593  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
594  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
595  m_cylinderTextureCoords.append(0.0);
596  m_cylinderTextureCoords.append(cylinderColors[curSegment + 1].startingAngle / (2.0 * M_PI));
597  m_cylinderVertexes.append(upperBaseX);
598  m_cylinderVertexes.append(y);
599  m_cylinderVertexes.append(z);
600  m_cylinderNormals.append(0.0);
601  m_cylinderNormals.append(normY);
602  m_cylinderNormals.append(normZ);
603  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
604  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
605  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
606  m_cylinderTextureCoords.append(1.0);
607  m_cylinderTextureCoords.append(cylinderColors[curSegment + 1].startingAngle / (2.0 * M_PI));
608 
609  // Incrementing the segment
610  ++curSegment;
611 
612  // Adding again the points (which will have the new color)
613  m_cylinderVertexes.append(lowerBaseX);
614  m_cylinderVertexes.append(y);
615  m_cylinderVertexes.append(z);
616  m_cylinderNormals.append(0.0);
617  m_cylinderNormals.append(normY);
618  m_cylinderNormals.append(normZ);
619  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
620  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
621  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
622  m_cylinderTextureCoords.append(0.0);
623  m_cylinderTextureCoords.append(cylinderColors[curSegment].startingAngle / (2.0 * M_PI));
624  m_cylinderVertexes.append(upperBaseX);
625  m_cylinderVertexes.append(y);
626  m_cylinderVertexes.append(z);
627  m_cylinderNormals.append(0.0);
628  m_cylinderNormals.append(normY);
629  m_cylinderNormals.append(normZ);
630  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
631  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
632  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
633  m_cylinderTextureCoords.append(1.0);
634  m_cylinderTextureCoords.append(cylinderColors[curSegment].startingAngle / (2.0 * M_PI));
635  }
636 
637  // Adding two points, one on the lower base, the other on the upper base
638  const float normY = sin(curAngle);
639  const float normZ = cos(curAngle);
640  const float y = m_radius * normY;
641  const float z = m_radius * normZ;
642  m_cylinderVertexes.append(lowerBaseX);
643  m_cylinderVertexes.append(y);
644  m_cylinderVertexes.append(z);
645  m_cylinderNormals.append(0.0);
646  m_cylinderNormals.append(normY);
647  m_cylinderNormals.append(normZ);
648  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
649  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
650  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
651  m_cylinderTextureCoords.append(0.0);
652  m_cylinderTextureCoords.append(curOffset / (2.0 * M_PI));
653  m_cylinderVertexes.append(upperBaseX);
654  m_cylinderVertexes.append(y);
655  m_cylinderVertexes.append(z);
656  m_cylinderNormals.append(0.0);
657  m_cylinderNormals.append(normY);
658  m_cylinderNormals.append(normZ);
659  m_cylinderColors.append(cylinderColors[curSegment].color.redF());
660  m_cylinderColors.append(cylinderColors[curSegment].color.greenF());
661  m_cylinderColors.append(cylinderColors[curSegment].color.blueF());
662  m_cylinderTextureCoords.append(1.0);
663  m_cylinderTextureCoords.append(curOffset / (2.0 * M_PI));
664 
665  curOffset += anglePerDiv;
666  }
667 
668  // Now the upper base. First getting the list of colors (as for the cylinder we generate a list of
669  // colors so that the code below will work in any case)
670  QList<PhyCylinder::SegmentColor> upperBaseColor;
671  if (m_cylinder->color().isValid()) {
672  // Single color for the whole cylinder
673  upperBaseColor.append(PhyCylinder::SegmentColor(0.0, m_cylinder->color()));
674  } else if (m_cylinder->upperBaseColor().isValid()) {
675  // Single color for the whole base
676  upperBaseColor.append(PhyCylinder::SegmentColor(0.0, m_cylinder->upperBaseColor()));
677  } else {
678  upperBaseColor = m_cylinder->segmentsColor();
679  }
680 
681  // Now generating vertexes for the upper base
682  curOffset = 0.0;
683  curSegment = 0;
684  unsigned int numVertexesCurSegment = 0;
685 
686  // In the exit condition of the cycle we add +anglePerDiv/2 to a full cycle to be sure to add the final point
687  // (it could be skipped because of numerical errors). Before entering the cycle, adding the central point (remember
688  // that we will draw this list of vertexes as a TRIANGLE_FAN)
689  m_upperBaseVertexes.append(upperBaseX);
690  m_upperBaseVertexes.append(0.0);
691  m_upperBaseVertexes.append(0.0);
692  m_upperBaseNormals.append(1.0);
693  m_upperBaseNormals.append(0.0);
694  m_upperBaseNormals.append(0.0);
695  m_upperBaseColors.append(upperBaseColor[curSegment].color.redF());
696  m_upperBaseColors.append(upperBaseColor[curSegment].color.greenF());
697  m_upperBaseColors.append(upperBaseColor[curSegment].color.blueF());
698  m_upperBaseTextureCoords.append(0.5);
699  m_upperBaseTextureCoords.append(0.5);
700  ++numVertexesCurSegment;
701  while (curOffset < (2.0 * M_PI + anglePerDiv / 2.0)) {
702  const float curAngle = upperBaseColor[0].startingAngle + curOffset;
703 
704  if (((curSegment + 1) != upperBaseColor.size()) && (upperBaseColor[curSegment + 1].startingAngle < curAngle)) {
705  // Computing the point on the color division boundary (which will then be duplicated)
706  const float normY = sin(upperBaseColor[curSegment + 1].startingAngle);
707  const float normZ = cos(upperBaseColor[curSegment + 1].startingAngle);
708  const float y = m_radius * normY;
709  const float z = m_radius * normZ;
710 
711  // Adding the first point
712  m_upperBaseVertexes.append(upperBaseX);
713  m_upperBaseVertexes.append(y);
714  m_upperBaseVertexes.append(z);
715  m_upperBaseNormals.append(1.0);
716  m_upperBaseNormals.append(0.0);
717  m_upperBaseNormals.append(0.0);
718  m_upperBaseColors.append(upperBaseColor[curSegment].color.redF());
719  m_upperBaseColors.append(upperBaseColor[curSegment].color.greenF());
720  m_upperBaseColors.append(upperBaseColor[curSegment].color.blueF());
721  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
722  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
723  ++numVertexesCurSegment;
724  m_upperBaseSegmentsLength.append(numVertexesCurSegment);
725 
726  // Incrementing the segment
727  ++curSegment;
728 
729  // Adding again the center and then the points (which will have the new color)
730  m_upperBaseVertexes.append(upperBaseX);
731  m_upperBaseVertexes.append(0.0);
732  m_upperBaseVertexes.append(0.0);
733  m_upperBaseNormals.append(1.0);
734  m_upperBaseNormals.append(0.0);
735  m_upperBaseNormals.append(0.0);
736  m_upperBaseColors.append(upperBaseColor[curSegment].color.redF());
737  m_upperBaseColors.append(upperBaseColor[curSegment].color.greenF());
738  m_upperBaseColors.append(upperBaseColor[curSegment].color.blueF());
739  m_upperBaseTextureCoords.append(0.5);
740  m_upperBaseTextureCoords.append(0.5);
741  m_upperBaseVertexes.append(upperBaseX);
742  m_upperBaseVertexes.append(y);
743  m_upperBaseVertexes.append(z);
744  m_upperBaseNormals.append(1.0);
745  m_upperBaseNormals.append(0.0);
746  m_upperBaseNormals.append(0.0);
747  m_upperBaseColors.append(upperBaseColor[curSegment].color.redF());
748  m_upperBaseColors.append(upperBaseColor[curSegment].color.greenF());
749  m_upperBaseColors.append(upperBaseColor[curSegment].color.blueF());
750  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
751  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
752  numVertexesCurSegment = 2;
753  }
754 
755  // Adding a new point points
756  const float normY = sin(curAngle);
757  const float normZ = cos(curAngle);
758  const float y = m_radius * normY;
759  const float z = m_radius * normZ;
760  m_upperBaseVertexes.append(upperBaseX);
761  m_upperBaseVertexes.append(y);
762  m_upperBaseVertexes.append(z);
763  m_upperBaseNormals.append(1.0);
764  m_upperBaseNormals.append(0.0);
765  m_upperBaseNormals.append(0.0);
766  m_upperBaseColors.append(upperBaseColor[curSegment].color.redF());
767  m_upperBaseColors.append(upperBaseColor[curSegment].color.greenF());
768  m_upperBaseColors.append(upperBaseColor[curSegment].color.blueF());
769  m_upperBaseTextureCoords.append((normY + 1.0) / 2.0);
770  m_upperBaseTextureCoords.append((normZ + 1.0) / 2.0);
771  ++numVertexesCurSegment;
772 
773  curOffset += anglePerDiv;
774  }
775  // Adding the length of the last segment
776  m_upperBaseSegmentsLength.append(numVertexesCurSegment);
777 
778  // Finally the lower base. First getting the list of colors (as for the cylinder we generate a list of
779  // colors so that the code below will work in any case)
780  QList<PhyCylinder::SegmentColor> lowerBaseColor;
781  if (m_cylinder->color().isValid()) {
782  // Single color for the whole cylinder
783  lowerBaseColor.append(PhyCylinder::SegmentColor(0.0, m_cylinder->color()));
784  } else if (m_cylinder->lowerBaseColor().isValid()) {
785  // Single color for the whole base
786  lowerBaseColor.append(PhyCylinder::SegmentColor(0.0, m_cylinder->lowerBaseColor()));
787  } else {
788  lowerBaseColor = m_cylinder->segmentsColor();
789  }
790 
791  // Now generating vertexes for the lower base
792  curOffset = 0.0;
793  curSegment = 0;
794  numVertexesCurSegment = 0;
795 
796  // In the exit condition of the cycle we add +anglePerDiv/2 to a full cycle to be sure to add the final point
797  // (it could be skipped because of numerical errors). Before entering the cycle, adding the central point (remember
798  // that we will draw this list of vertexes as a TRIANGLE_FAN)
799  m_lowerBaseVertexes.append(lowerBaseX);
800  m_lowerBaseVertexes.append(0.0);
801  m_lowerBaseVertexes.append(0.0);
802  m_lowerBaseNormals.append(-1.0);
803  m_lowerBaseNormals.append(0.0);
804  m_lowerBaseNormals.append(0.0);
805  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.redF());
806  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.greenF());
807  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.blueF());
808  m_lowerBaseTextureCoords.append(0.5);
809  m_lowerBaseTextureCoords.append(0.5);
810  ++numVertexesCurSegment;
811  while (curOffset < (2.0 * M_PI + anglePerDiv / 2.0)) {
812  const float curAngle = lowerBaseColor[0].startingAngle + curOffset;
813 
814  if (((curSegment + 1) != lowerBaseColor.size()) && (lowerBaseColor[curSegment + 1].startingAngle < curAngle)) {
815  // Computing the point on the color division boundary (which will then be duplicated)
816  const float normY = sin(lowerBaseColor[curSegment + 1].startingAngle);
817  const float normZ = cos(lowerBaseColor[curSegment + 1].startingAngle);
818  const float y = m_radius * normY;
819  const float z = m_radius * normZ;
820 
821  // Adding the first point
822  m_lowerBaseVertexes.append(lowerBaseX);
823  m_lowerBaseVertexes.append(y);
824  m_lowerBaseVertexes.append(z);
825  m_lowerBaseNormals.append(-1.0);
826  m_lowerBaseNormals.append(0.0);
827  m_lowerBaseNormals.append(0.0);
828  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.redF());
829  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.greenF());
830  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.blueF());
831  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
832  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
833  ++numVertexesCurSegment;
834  m_lowerBaseSegmentsLength.append(numVertexesCurSegment);
835 
836  // Incrementing the segment
837  ++curSegment;
838 
839  // Adding again the center and then the points (which will have the new color)
840  m_lowerBaseVertexes.append(lowerBaseX);
841  m_lowerBaseVertexes.append(0.0);
842  m_lowerBaseVertexes.append(0.0);
843  m_lowerBaseNormals.append(-1.0);
844  m_lowerBaseNormals.append(0.0);
845  m_lowerBaseNormals.append(0.0);
846  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.redF());
847  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.greenF());
848  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.blueF());
849  m_lowerBaseTextureCoords.append(0.5);
850  m_lowerBaseTextureCoords.append(0.5);
851  m_lowerBaseVertexes.append(lowerBaseX);
852  m_lowerBaseVertexes.append(y);
853  m_lowerBaseVertexes.append(z);
854  m_lowerBaseNormals.append(-1.0);
855  m_lowerBaseNormals.append(0.0);
856  m_lowerBaseNormals.append(0.0);
857  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.redF());
858  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.greenF());
859  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.blueF());
860  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
861  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
862  numVertexesCurSegment = 2;
863  }
864 
865  // Adding a new point points
866  const float normY = sin(curAngle);
867  const float normZ = cos(curAngle);
868  const float y = m_radius * normY;
869  const float z = m_radius * normZ;
870  m_lowerBaseVertexes.append(lowerBaseX);
871  m_lowerBaseVertexes.append(y);
872  m_lowerBaseVertexes.append(z);
873  m_lowerBaseNormals.append(-1.0);
874  m_lowerBaseNormals.append(0.0);
875  m_lowerBaseNormals.append(0.0);
876  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.redF());
877  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.greenF());
878  m_lowerBaseColors.append(lowerBaseColor[curSegment].color.blueF());
879  m_lowerBaseTextureCoords.append((normY + 1.0) / 2.0);
880  m_lowerBaseTextureCoords.append((normZ + 1.0) / 2.0);
881  ++numVertexesCurSegment;
882 
883  curOffset += anglePerDiv;
884  }
885  // Adding the length of the last segment
886  m_lowerBaseSegmentsLength.append(numVertexesCurSegment);
887  }
888 
893 
897  const real m_height;
898 
902  const real m_radius;
903 
910  QVector<GLfloat> m_cylinderVertexes;
911 
917  QVector<GLfloat> m_cylinderNormals;
918 
924  QVector<GLfloat> m_cylinderColors;
925 
932  QVector<GLfloat> m_cylinderTextureCoords;
933 
940  QVector<GLfloat> m_upperBaseVertexes;
941 
947  QVector<GLfloat> m_upperBaseNormals;
948 
954  QVector<GLfloat> m_upperBaseColors;
955 
962  QVector<GLfloat> m_upperBaseTextureCoords;
963 
968  QVector<unsigned int> m_upperBaseSegmentsLength;
969 
976  QVector<GLfloat> m_lowerBaseVertexes;
977 
983  QVector<GLfloat> m_lowerBaseNormals;
984 
990  QVector<GLfloat> m_lowerBaseColors;
991 
998  QVector<GLfloat> m_lowerBaseTextureCoords;
999 
1004  QVector<unsigned int> m_lowerBaseSegmentsLength;
1005 };
1006 
1008 public:
1009  RenderPhyCone( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1010  cone = (PhyCone*)wobj;
1011  rad = cone->radius();
1012  hei = cone->height();
1013  };
1014  virtual ~RenderPhyCone() { };
1015  virtual void render( QGLContext* gw ) {
1016  glPushMatrix();
1017  GLUquadricObj *pObj;
1018  container()->setupColorTexture( gw, this );
1019 
1020  // opengl cylinder are aligned alogn the z axis, we want it along the x axis,
1021  // we create a rotation matrix to do the alignment
1022  wMatrix matrix = wMatrix::yaw( PI_GRECO * 0.5 );
1023  matrix.w_pos = matrix.rotateVector( wVector(0.0, 0.0, -hei*0.5) );
1024  matrix = matrix * cone->matrix();
1025  GLMultMatrix(&matrix[0][0]);
1026 
1027  // Get a new Quadric off the stack
1028  pObj = gluNewQuadric();
1029  gluQuadricTexture(pObj, true);
1030  gluCylinder(pObj, rad, 0, hei, 20, 2);
1031 
1032  // render the caps
1033  gluQuadricOrientation(pObj, GLU_INSIDE);
1034  gluDisk(pObj, 0.0f, rad, 20, 1);
1035 
1036  gluDeleteQuadric(pObj);
1037  glPopMatrix();
1038  };
1039  virtual void renderAABB( RenderWorld* gw ) {
1040  wVector minpoint, maxpoint;
1041  calculateAABB( minpoint, maxpoint, obj->matrix() );
1042  gw->drawWireBox( minpoint, maxpoint );
1043  };
1044  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1045  real h2 = hei/2.0;
1046  real tdx = fabs(tm.x_ax[0]*h2) + fabs(tm.y_ax[0]*rad) + fabs(tm.z_ax[0]*rad);
1047  real tdy = fabs(tm.x_ax[1]*h2) + fabs(tm.y_ax[1]*rad) + fabs(tm.z_ax[1]*rad);
1048  real tdz = fabs(tm.x_ax[2]*h2) + fabs(tm.y_ax[2]*rad) + fabs(tm.z_ax[2]*rad);
1049  wVector hds( tdx, tdy, tdz );
1050  minPoint = tm.w_pos - hds;
1051  maxPoint = tm.w_pos + hds;
1052  };
1053 
1054  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1055  dimension[0] = hei;
1056  dimension[1] = rad*2.0;
1057  dimension[2] = rad*2.0;
1058  wVector rds = wVector( hei/2.0, rad, rad );
1059  minPoint = -rds;
1060  maxPoint = +rds;
1061  };
1062 protected:
1063  PhyCone* cone;
1064  real rad;
1065  real hei;
1066 };
1067 
1068 // class RenderPhyHeightField : public RenderWObject {
1069 // public:
1070 // RenderPhyHeightField( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1071 // hf = (PhyHeightField*)wobj;
1072 // dx = hf->sideX();
1073 // dy = hf->sideY();
1074 // dz = 0.01f;
1075 // };
1076 // virtual ~RenderPhyHeightField() { };
1077 // virtual void render( QGLContext* gw ) {
1078 // glPushMatrix();
1079 // container()->setupColorTexture( gw, this );
1080 // wMatrix m = hf->matrix().rotateAround( wVector(1,0,0), wVector(0,0,0), toRad(-90) );
1081 // m.w_pos[0] -= dx/2.0;
1082 // m.w_pos[1] -= dy/2.0;
1083 // GLMultMatrix(&m[0][0]);
1084 //
1085 // NewtonMesh* mesh = hf->mesh;
1086 // int stride = NewtonMeshGetVertexStrideInByte(mesh) / sizeof (double);
1087 // const double* const vertexList = NewtonMeshGetVertexArray(mesh);
1088 //
1089 // glBegin(GL_TRIANGLES);
1090 // for (void* face = NewtonMeshGetFirstFace(mesh); face; face = NewtonMeshGetNextFace(mesh, face)) {
1091 // if (!NewtonMeshIsFaceOpen (mesh, face)) {
1092 // int indices[1024];
1093 // int vertexCount = NewtonMeshGetFaceIndexCount (mesh, face);
1094 // Q_ASSERT (vertexCount < sizeof (indices)/sizeof (indices[0]));
1095 // NewtonMeshGetFaceIndices (mesh, face, indices);
1096 //
1097 // //dFloat64 normal[4];
1098 // //NewtonMeshCalculateFaceNormal (mesh, face, normal);
1099 // //glNormal3f(normal[0], normal[1], normal[2]);
1100 //
1101 // int i0 = indices[0];
1102 // int i1 = indices[1];
1103 // wVector p0 ( dFloat(vertexList[i0 * stride + 0]),
1104 // dFloat(vertexList[i0 * stride + 1]),
1105 // dFloat(vertexList[i0 * stride + 2]),
1106 // 0.0f );
1107 // wVector p1 ( dFloat(vertexList[i1 * stride + 0]),
1108 // dFloat(vertexList[i1 * stride + 1]),
1109 // dFloat(vertexList[i1 * stride + 2]),
1110 // 0.0f );
1111 // for (int i = 2; i < vertexCount; i++) {
1112 // int i2 = indices[i];
1113 // wVector p2 ( dFloat(vertexList[i2 * stride + 0]),
1114 // dFloat(vertexList[i2 * stride + 1]),
1115 // dFloat(vertexList[i2 * stride + 2]),
1116 // 0.0f );
1117 // glVertex3f(p0[0], p0[1], p0[2]);
1118 // glVertex3f(p1[0], p1[1], p1[2]);
1119 // glVertex3f(p2[0], p2[1], p2[2]);
1120 // p1 = p2;
1121 // }
1122 // }
1123 // }
1124 //
1125 // glEnd();
1126 //
1127 // glPopMatrix();
1128 // };
1129 // virtual void renderAABB( RenderWorld* gw ) {
1130 // wVector minpoint, maxpoint;
1131 // calculateAABB( minpoint, maxpoint, obj->matrix() );
1132 // gw->drawWireBox( minpoint, maxpoint );
1133 // };
1134 // virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1135 // real tdx = fabs(tm.x_ax[0]*dx) + fabs(tm.y_ax[0]*dy) + fabs(tm.z_ax[0]*dz);
1136 // real tdy = fabs(tm.x_ax[1]*dx) + fabs(tm.y_ax[1]*dy) + fabs(tm.z_ax[1]*dz);
1137 // real tdz = fabs(tm.x_ax[2]*dx) + fabs(tm.y_ax[2]*dy) + fabs(tm.z_ax[2]*dz);
1138 //
1139 // wVector hds( tdx/2.0, tdy/2.0, tdz/2.0 );
1140 // minPoint = tm.w_pos - hds;
1141 // maxPoint = tm.w_pos + hds;
1142 // };
1143 //
1144 // virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1145 // dimension[0] = dx;
1146 // dimension[1] = dy;
1147 // dimension[2] = dz;
1148 // wVector hds( dx/2.0, dy/2.0, dz/2.0 );
1149 // minPoint = -hds;
1150 // maxPoint = +hds;
1151 // };
1152 //
1153 // protected:
1154 // PhyHeightField* hf;
1155 // real dx, dy, dz;
1156 // };
1157 
1158 #ifdef FARSA_USE_YARP_AND_ICUB
1159 
1160 RenderICub::RenderICub( WObject* wobj, RenderWObjectContainer* container ) :
1161  RenderWObject( wobj, container )
1162 {
1163  icub = (PhyiCub*)wobj;
1164  icub->forceKinematicChainsUpdate(true);
1165  initRobjv(container);
1166 }
1167 
1168 RenderICub::~RenderICub()
1169 {
1170  if (icub != NULL) {
1171  icub->forceKinematicChainsUpdate(false);
1172  }
1173 }
1174 
1175 void RenderICub::render( QGLContext* gw )
1176 {
1177  // Nothing to do here, all components are rendered by their respective renderers
1178 }
1179 
1180 void RenderICub::renderAABB( RenderWorld* gw )
1181 {
1182  wVector minpoint, maxpoint;
1183  calculateAABB( minpoint, maxpoint, obj->matrix() );
1184  gw->drawWireBox( minpoint, maxpoint );
1185 }
1186 
1187 void RenderICub::calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm )
1188 {
1189  UNUSED_PARAM( tm );
1190  QList<RenderWObject*> robjs = robjv.values();
1191  robjs[0]->calculateAABB( minPoint, maxPoint, robjs[0]->object()->matrix() );
1192  wVector minP, maxP;
1193  for( int i=1; i<robjs.size(); i++ ) {
1194  robjs[i]->calculateAABB( minP, maxP, robjs[i]->object()->matrix() );
1195  mergeAABB( minPoint, maxPoint, minP, maxP );
1196  }
1197 }
1198 
1199 void RenderICub::calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint )
1200 {
1201  /* ***
1202  wVector minPoint, maxPoint;
1203  wMatrix tm = wMatrix::identity();
1204  for( int i=1; i<robjv.size(); i++ ) {
1205  robjv[i]->calculateAABB( minP, maxP, tm );
1206  mergeAABB( minPoint, maxPoint, minP, maxP );
1207  }
1208  *** */
1209  calculateAABB( minPoint, maxPoint, wMatrix::identity() );
1210  dimension[0] = fabs( maxPoint[0] - minPoint[0] );
1211  dimension[1] = fabs( maxPoint[1] - minPoint[1] );
1212  dimension[2] = fabs( maxPoint[2] - minPoint[2] );
1213 }
1214 
1215 void RenderICub::objectAlreadyDestroyed()
1216 {
1217  icub = NULL;
1218 }
1219 
1220 void RenderICub::initRobjv( RenderWObjectContainer* container )
1221 {
1222  robjv.clear();
1223  foreach( RenderWObject* wobj, container->graphics() ) {
1224  if ( wobj->object()->owner() == icub ) {
1225  robjv[wobj->object()] = wobj;
1226  }
1227  }
1228  foreach( WObject* obj, icub->leftLeg() ) {
1229  obj->setUseColorTextureOfOwner(true);
1230  }
1231  foreach( WObject* obj, icub->rightLeg() ) {
1232  obj->setUseColorTextureOfOwner(true);
1233  }
1234  foreach( WObject* obj, icub->torso() ) {
1235  obj->setUseColorTextureOfOwner(true);
1236  }
1237  foreach( WObject* obj, icub->leftArm() ) {
1238  obj->setUseColorTextureOfOwner(true);
1239  }
1240  foreach( WObject* obj, icub->rightArm() ) {
1241  obj->setUseColorTextureOfOwner(true);
1242  }
1243  int i = 0;
1244  foreach( WObject* obj, icub->headNeck() ) {
1245  //--- the eye will be displayed with the texture of the eye
1246  if ( ( i == 4 ) || ( i == 5 ) ) {
1247  obj->setUseColorTextureOfOwner(false);
1248  } else {
1249  obj->setUseColorTextureOfOwner(true);
1250  }
1251  i++;
1252  }
1253  foreach( WObject* obj, icub->covers() ) {
1254  obj->setUseColorTextureOfOwner(false);
1255  }
1256 }
1257 
1258 void RenderICub::mergeAABB( wVector& minPointA, wVector& maxPointA, const wVector& minPointB, const wVector& maxPointB )
1259 {
1260  minPointA[0] = min( minPointA[0], minPointB[0] );
1261  minPointA[1] = min( minPointA[1], minPointB[1] );
1262  minPointA[2] = min( minPointA[2], minPointB[2] );
1263  maxPointA[0] = max( maxPointA[0], maxPointB[0] );
1264  maxPointA[1] = max( maxPointA[1], maxPointB[1] );
1265  maxPointA[2] = max( maxPointA[2], maxPointB[2] );
1266 }
1267 
1268 #endif
1269 
1271 public:
1272  RenderCompoundObject( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1273  co = (PhyCompoundObject*)wobj;
1274  initRobjv( container );
1275  };
1276  virtual ~RenderCompoundObject() {
1277  foreach( RenderWObject* ro, robjv ) {
1278  delete ro;
1279  }
1280  };
1281  virtual void render( QGLContext* gw ) {
1282  glPushMatrix();
1283  container()->setupColorTexture( gw, this );
1284  wMatrix matrix = co->matrix();
1285  GLMultMatrix(&matrix[0][0]);
1286  foreach( RenderWObject* ro, robjv ) {
1287  ro->render( gw );
1288  }
1289  glPopMatrix();
1290  };
1291  virtual void renderAABB( RenderWorld* gw ) {
1292  wVector minpoint, maxpoint;
1293  calculateAABB( minpoint, maxpoint, obj->matrix() );
1294  gw->drawWireBox( minpoint, maxpoint );
1295  };
1296  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1297  robjv[0]->calculateAABB( minPoint, maxPoint, robjv[0]->object()->matrix()*tm );
1298  wVector minP, maxP;
1299  for( int i=1; i<robjv.size(); i++ ) {
1300  robjv[i]->calculateAABB( minP, maxP, robjv[i]->object()->matrix()*tm );
1301  mergeAABB( minPoint, maxPoint, minP, maxP );
1302  }
1303  };
1304  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1305  //--- the right calculation is done calculating the AABB when
1306  //--- the transformation matrix is the identity
1307  wVector minP, maxP;
1308  if ( robjv.size() == 0 ) {
1309  qWarning( "== this point should never reached: renderwobjecthierarchy.cpp:435" );
1310  return;
1311  }
1312  robjv[0]->calculateAABB( minPoint, maxPoint, robjv[0]->object()->matrix() );
1313  for( int i=1; i<robjv.size(); i++ ) {
1314  robjv[i]->calculateAABB( minP, maxP, robjv[i]->object()->matrix() );
1315  mergeAABB( minPoint, maxPoint, minP, maxP );
1316  }
1317  dimension[0] = fabs( maxPoint[0] - minPoint[0] );
1318  dimension[1] = fabs( maxPoint[1] - minPoint[1] );
1319  dimension[2] = fabs( maxPoint[2] - minPoint[2] );
1320  };
1321 protected:
1322  PhyCompoundObject* co;
1323  QVector<RenderWObject*> robjv;
1324 private:
1325  void initRobjv( RenderWObjectContainer* container ) {
1326  foreach( WObject* obj, co->bodies() ) {
1327  robjv << RenderWObjectContainer::createRenderWObjectFor( obj, container );
1328  }
1329  };
1330  void mergeAABB( wVector& minPointA, wVector& maxPointA, const wVector& minPointB, const wVector& maxPointB ) {
1331  minPointA[0] = min( minPointA[0], minPointB[0] );
1332  minPointA[1] = min( minPointA[1], minPointB[1] );
1333  minPointA[2] = min( minPointA[2], minPointB[2] );
1334  maxPointA[0] = max( maxPointA[0], maxPointB[0] );
1335  maxPointA[1] = max( maxPointA[1], maxPointB[1] );
1336  maxPointA[2] = max( maxPointA[2], maxPointB[2] );
1337  };
1338 };
1339 
1340 #ifdef FARSA_USE_YARP_AND_ICUB
1341 
1343 public:
1344  RenderWCamera( WObject* wobj, RenderWObjectContainer* container ) : RenderWObject( wobj, container ) {
1345  wcam = (WCamera*)(wobj);
1346  dx = 0.015f;
1347  dy = 0.01f;
1348  dz = 0.025f;
1349  };
1350  virtual ~RenderWCamera() { };
1351  virtual void render( QGLContext* gw ) {
1352  if ( wcam->attachedTo() != NULL ) return;
1353  glPushMatrix();
1354  container()->setupColorTexture( gw, this );
1355  const wMatrix& m = wcam->matrix();
1356  GLMultMatrix(&m[0][0]);
1357  // the cube will just be drawn as six quads for the sake of simplicity
1358  // for each face, we specify the quad's normal (for lighting), then
1359  // specify the quad's 4 vertices and associated texture coordinates
1360  glBegin(GL_QUADS);
1361  float hdx = (dx/2.0);
1362  float hdy = (dy/2.0);
1363  float hdz = (dz/2.0);
1364  // front
1365  glNormal3f(0.0, 0.0, 1.0);
1366  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
1367  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, hdz);
1368  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, hdz);
1369  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, hdz);
1370  // back
1371  glNormal3f(0.0, 0.0, -1.0);
1372  glTexCoord2f(0.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
1373  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
1374  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
1375  glTexCoord2f(0.0, 1.0); glVertex3f( hdx, hdy, -hdz);
1376  // top
1377  glNormal3f(0.0, 1.0, 0.0);
1378  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, hdy, hdz);
1379  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, hdy, hdz);
1380  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, hdy, -hdz);
1381  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
1382  // bottom
1383  glNormal3f(0.0, -1.0, 0.0);
1384  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
1385  glTexCoord2f(1.0, 0.0); glVertex3f( hdx, -hdy, -hdz);
1386  glTexCoord2f(1.0, 1.0); glVertex3f( hdx, -hdy, hdz);
1387  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, -hdy, hdz);
1388  // left
1389  glNormal3f(-1.0, 0.0, 0.0);
1390  glTexCoord2f(0.0, 0.0); glVertex3f(-hdx, -hdy, -hdz);
1391  glTexCoord2f(1.0, 0.0); glVertex3f(-hdx, -hdy, hdz);
1392  glTexCoord2f(1.0, 1.0); glVertex3f(-hdx, hdy, hdz);
1393  glTexCoord2f(0.0, 1.0); glVertex3f(-hdx, hdy, -hdz);
1394  // right
1395  glNormal3f(1.0, 0.0, 0.0);
1396  glTexCoord2f(0.0, 0.0); glVertex3f(hdx, -hdy, hdz);
1397  glTexCoord2f(1.0, 0.0); glVertex3f(hdx, -hdy, -hdz);
1398  glTexCoord2f(1.0, 1.0); glVertex3f(hdx, hdy, -hdz);
1399  glTexCoord2f(0.0, 1.0); glVertex3f(hdx, hdy, hdz);
1400  glEnd();
1401 
1402  //--- some fancy stuff for understanding the orientation of camera
1403  container()->drawCylinder( wVector(0,1,0), wVector(-hdx-0.006f,0,hdz-0.006f), 0.004f, 0.008f );
1404  container()->drawCylinder( wVector(0,1,0), wVector(-hdx,0,-hdz), 0.004f, 0.008f );
1405  container()->drawCylinder( wVector(0,0,1), wVector(0,0.0,hdz+0.003f), 0.006f, 0.004f );
1406  glPopMatrix();
1407  };
1408  virtual void renderAABB( RenderWorld* gw ) {
1409  wVector minpoint, maxpoint;
1410  calculateAABB( minpoint, maxpoint, obj->matrix() );
1411  gw->drawWireBox( minpoint, maxpoint );
1412  };
1413  virtual void calculateAABB( wVector& minPoint, wVector& maxPoint, const wMatrix tm ) {
1414  real tdx = fabs(tm.x_ax[0]*dx) + fabs(tm.y_ax[0]*dy) + fabs(tm.z_ax[0]*dz);
1415  real tdy = fabs(tm.x_ax[1]*dx) + fabs(tm.y_ax[1]*dy) + fabs(tm.z_ax[1]*dz);
1416  real tdz = fabs(tm.x_ax[2]*dx) + fabs(tm.y_ax[2]*dy) + fabs(tm.z_ax[2]*dz);
1417  wVector hds( tdx/2.0, tdy/2.0, tdz/2.0 );
1418  minPoint = tm.w_pos - hds;
1419  maxPoint = tm.w_pos + hds;
1420  };
1421  virtual void calculateOBB( wVector& dimension, wVector& minPoint, wVector& maxPoint ) {
1422  dimension[0] = dx;
1423  dimension[1] = dy;
1424  dimension[2] = dz;
1425  wVector hds( dx/2.0, dy/2.0, dz/2.0 );
1426  minPoint = -hds;
1427  maxPoint = +hds;
1428  };
1429 protected:
1430  WCamera* wcam;
1431  real dx, dy, dz;
1432 };
1433 
1434 #endif // FARSA_USE_YARP_AND_ICUB
1435 
1436 // This class is the renderer associated with GraphicalWObject. It simply
1437 // forwards calls to GraphicalWObject functions
1439 {
1440 public:
1442  RenderWObject(obj, rw),
1443  m_graphicalWObject(dynamic_cast<GraphicalWObject*>(obj))
1444  {
1445  }
1446 
1447  virtual ~GraphicalWObjectRenderer()
1448  {
1449  }
1450 
1451  virtual void render(QGLContext *gw)
1452  {
1453  m_graphicalWObject->updateAndRender(this, gw);
1454  }
1455 
1456  virtual void renderAABB(RenderWorld *gw)
1457  {
1458  m_graphicalWObject->updateAndRenderAABB(this, gw);
1459  }
1460 
1461  virtual void calculateAABB(wVector &minPoint, wVector &maxPoint, const wMatrix tm)
1462  {
1463  m_graphicalWObject->updateAndCalculateAABB(minPoint, maxPoint, tm);
1464  }
1465 
1466  virtual void calculateOBB(wVector &dimension, wVector &minPoint, wVector &maxPoint)
1467  {
1468  m_graphicalWObject->updateAndCalculateOBB(dimension, minPoint, maxPoint);
1469  }
1470 
1471 private:
1472  GraphicalWObject *const m_graphicalWObject;
1473 };
1474 
1475 bool RenderWObjectContainer::facInited = false;
1476 QMap<QString, WAbstractCreator*>* RenderWObjectContainer::fac;
1477 void RenderWObjectContainer::initFactory() {
1478  if ( facInited ) return;
1479 
1480  fac = new QMap<QString, WAbstractCreator*>();
1481 
1482  (*fac)["farsa::WMesh"] = new WCreator<RenderWMesh>();
1483  (*fac)["farsa::PhyBox"] = new WCreator<RenderPhyBox>();
1484  (*fac)["farsa::PhySphere"] = new WCreator<RenderPhySphere>();
1485  (*fac)["farsa::PhyCylinder"] = new WCreator<RenderPhyCylinder>();
1486  (*fac)["farsa::PhyCone"] = new WCreator<RenderPhyCone>();
1487 // (*fac)["farsa::PhyHeightField"] = new WCreator<RenderPhyHeightField>();
1488  (*fac)["farsa::PhyCompoundObject"] = new WCreator<RenderCompoundObject>();
1489 #ifdef FARSA_USE_YARP_AND_ICUB
1490  (*fac)["farsa::WCamera"] = new WCreator<RenderWCamera>();
1491  (*fac)[PhyiCub::staticMetaObject.className()] = new WCreator<RenderICub>();
1492 #endif
1493  (*fac)["farsa::GraphicalWObject"] = new WCreator<GraphicalWObjectRenderer>();
1494 
1495  //--- FIXME a specific class should be implemented
1496  (*fac)["farsa::WObject"] = new WCreator<RenderGenericObject>();
1497  (*fac)["farsa::WorldController"] = new WCreator<RenderGenericObject>();
1498 
1499  facInited = true;
1500 }
1501 
1502 } // end namespace farsa