Developer Documentation
GLPrimitives.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44  * $Revision$ *
45  * $LastChangedBy$ *
46  * $Date$ *
47  * *
48  \*===========================================================================*/
49 
50 #include <ACG/GL/acg_glew.hh>
51 
52 #include "GLPrimitives.hh"
53 #include <ACG/GL/IRenderer.hh>
54 
55 
56 namespace ACG {
57 
58 //========================================================================
59 // GLPrimitive base class
60 //========================================================================
61 
62 GLPrimitive::GLPrimitive() :
63  vboDataInvalid_(true),
64  normalOrientation_(OUTSIDE),
65  numTris_(0),
66  numLines_(0),
67  vboData_(0),
68  curTriPtr_(0),
69  vbo_(0)
70 {
71 
72  vertexDecl_.addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION);
73  vertexDecl_.addElement(GL_FLOAT, 3, VERTEX_USAGE_NORMAL);
74  vertexDecl_.addElement(GL_FLOAT, 2, VERTEX_USAGE_TEXCOORD);
75 }
76 
77 //------------------------------------------------------------------------
78 
79 GLPrimitive::~GLPrimitive()
80 {
81  if (vbo_)
82  glDeleteBuffers(1, &vbo_);
83 
84  delete[] vboData_;
85 }
86 
87 //------------------------------------------------------------------------
88 
89 void GLPrimitive::addTriangleToVBO(const ACG::Vec3f* _p, const ACG::Vec3f* _n, const ACG::Vec2f* _tex)
90 {
91  if (!numTris_ || vboDataInvalid_)
92  numTris_ = getNumTriangles();
93 
94  if (!numTris_)
95  return;
96 
97  assert(numLines_ == 0);
98 
99 
100  if (!vboData_)
101  vboData_ = new float[8 * 3 * numTris_];
102 
103  if (curTriPtr_ == numTris_)
104  return;
105 
106  float* pTri = &vboData_[0] + (curTriPtr_++) * 3 * 8;
107 
108  // copy triangle
109  for (int i = 0; i < 3; ++i) {
110  for (int k = 0; k < 3; ++k)
111  *(pTri++) = _p[i][k];
112 
113  for (int k = 0; k < 3; ++k)
114  *(pTri++) = _n[i][k];
115 
116  for (int k = 0; k < 2; ++k)
117  *(pTri++) = _tex[i][k];
118  }
119 }
120 
121 
122 void GLPrimitive::addLineToVBO( const ACG::Vec3f* _p, const ACG::Vec3f* _n, const ACG::Vec2f* _tex )
123 {
124  if (!numLines_ || vboDataInvalid_)
125  numLines_ = getNumLines();
126 
127  if (!numLines_)
128  return;
129 
130  assert(numTris_ == 0);
131 
132  if (!vboData_)
133  vboData_ = new float[8 * 2 * numLines_];
134 
135  if (curTriPtr_ == numLines_)
136  return;
137 
138  float* pLine = &vboData_[0] + (curTriPtr_++) * 2 * 8;
139 
140  // copy line segment
141  for (int i = 0; i < 2; ++i) {
142  for (int k = 0; k < 3; ++k)
143  *(pLine++) = _p[i][k];
144 
145  for (int k = 0; k < 3; ++k)
146  *(pLine++) = _n[i][k];
147 
148  for (int k = 0; k < 2; ++k)
149  *(pLine++) = _tex[i][k];
150  }
151 }
152 
153 
154 //------------------------------------------------------------------------
155 
156 void GLPrimitive::bindVBO()
157 {
158  if (checkVBO())
159  {
160  glBindBuffer(GL_ARRAY_BUFFER, vbo_);
161 
162  glVertexPointer(3, GL_FLOAT, 32, 0);
163  glEnableClientState(GL_VERTEX_ARRAY);
164 
165  glNormalPointer(GL_FLOAT, 32, (GLvoid*) 12);
166  glEnableClientState(GL_NORMAL_ARRAY);
167 
168  glClientActiveTexture(GL_TEXTURE0);
169  glTexCoordPointer(2, GL_FLOAT, 32, (GLvoid*) 24);
170  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
171  }
172 }
173 
174 //------------------------------------------------------------------------
175 
176 
177 bool GLPrimitive::checkVBO()
178 {
179  // create vbo if not done yet
180  // update vbo data and upload to gpu if needed
181  // return false iff vbo empty
182 
183  const int bufSize = numTris_ ? numTris_ * 3 * 8 * 4 : numLines_ * 2 * 8 * 4;
184 
185  if (!vbo_) {
186  if (!vboData_ || (!numTris_ && !numLines_) || (numTris_ && numLines_))
187  return false;
188 
189  // create vbo
190  glGenBuffers(1, &vbo_);
191  glBindBuffer(GL_ARRAY_BUFFER, vbo_);
192  glBufferData(GL_ARRAY_BUFFER, bufSize, vboData_, GL_STATIC_DRAW);
193 
194  delete[] vboData_;
195  vboData_ = 0;
196  } else if (vboDataInvalid_) {
197  updateVBOData();
198  glBindBuffer(GL_ARRAY_BUFFER, vbo_);
199  glBufferData(GL_ARRAY_BUFFER, bufSize, vboData_, GL_STATIC_DRAW);
200  vboDataInvalid_ = false;
201  }
202 
203  return true;
204 }
205 
206 //------------------------------------------------------------------------
207 
208 void GLPrimitive::unBindVBO()
209 {
210  glBindBuffer(GL_ARRAY_BUFFER, 0);
211  glDisableClientState(GL_VERTEX_ARRAY);
212  glDisableClientState(GL_NORMAL_ARRAY);
213  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
214 }
215 
216 //------------------------------------------------------------------------
217 
218 void GLPrimitive::draw_primitive()
219 {
220  bindVBO();
221 
222  if (numTris_)
223  glDrawArrays(GL_TRIANGLES, 0, numTris_ * 3);
224  else
225  glDrawArrays(GL_LINES, 0, numLines_ * 2);
226 
227  unBindVBO();
228 }
229 
230 //------------------------------------------------------------------------
231 
232 void GLPrimitive::addToRenderer_primitive( class IRenderer* _renderer, RenderObject* _ro )
233 {
234  if (checkVBO())
235  {
236  _ro->vertexBuffer = vbo_;
237  _ro->vertexDecl = &vertexDecl_;
238 
239  if (numTris_)
240  _ro->glDrawArrays(GL_TRIANGLES, 0, numTris_ * 3);
241  else
242  _ro->glDrawArrays(GL_LINES, 0, numLines_ * 2);
243 
244  _renderer->addRenderObject(_ro);
245  }
246 }
247 
248 //------------------------------------------------------------------------
249 
250 void GLPrimitive::updateVBOData() {
251  curTriPtr_ = 0;
252 
253  if (vboData_) {
254  delete[] vboData_;
255  vboData_ = 0;
256  }
257 
258  updateVBO();
259 }
260 
261 //------------------------------------------------------------------------
262 
263 unsigned int GLPrimitive::getVBO()
264 {
265  return checkVBO() ? vbo_ : 0;
266 }
267 
268 const VertexDeclaration* GLPrimitive::getVertexDecl() const
269 {
270  return &vertexDecl_;
271 }
272 
273 //========================================================================
274 // GLSphere
275 //========================================================================
276 
277 
278 
279 GLSphere::GLSphere(int _slices, int _stacks) :
280  slices_(_slices),
281  stacks_(_stacks)
282 {
283  updateVBO();
284 }
285 
286 //------------------------------------------------------------------------
287 
288 GLSphere::~GLSphere()
289 {
290 
291 }
292 
293 //------------------------------------------------------------------------
294 
295 void GLSphere::draw(GLState& _state, float _radius, const ACG::Vec3f& _center)
296 {
297  _state.push_modelview_matrix();
298 
299  _state.translate(ACG::Vec3d(_center));
300  _state.scale(_radius, _radius, _radius);
301 
302  GLPrimitive::draw_primitive();
303 
304  _state.pop_modelview_matrix();
305 }
306 
307 //------------------------------------------------------------------------
308 
309 void GLSphere::addToRenderer( IRenderer* _renderer, const RenderObject* _base, float _radius, const ACG::Vec3f& _center /*= ACG::Vec3f(0.0f, 0.0f, 0.0f)*/ )
310 {
311  RenderObject ro = *_base;
312 
313  ro.modelview.translate(ACG::Vec3d(_center));
314  ro.modelview.scale((double)_radius, (double)_radius, (double)_radius);
315 
316  GLPrimitive::addToRenderer_primitive(_renderer, &ro);
317 }
318 
319 
320 //------------------------------------------------------------------------
321 
322 int GLSphere::getNumTriangles()
323 {
324  return 2 * slices_ + (stacks_ - 2) * slices_ * 2;
325 }
326 
327 //------------------------------------------------------------------------
328 
329 void GLSphere::updateVBO()
330 {
331  for (int sl = 0; sl < slices_; ++sl) {
332  // top triangle:
333  {
334  int st = 0;
335  addTriangle(0, st, sl + 1, st + 1, sl, st + 1);
336  }
337  // middle quads:
338  for (int st = 1; st < stacks_ - 1; ++st) {
339  addTriangle(sl, st, sl + 1, st, sl, st + 1);
340  addTriangle(sl + 1, st, sl + 1, st + 1, sl, st + 1);
341  }
342  // bottom triangle:
343  {
344  addTriangle(0, stacks_, sl, stacks_ - 1, sl + 1, stacks_ - 1);
345  }
346  }
347 }
348 
349 //------------------------------------------------------------------------
350 
351 void GLSphere::addTriangle(int sl0, int st0, int sl1, int st1, int sl2, int st2)
352 {
353  ACG::Vec3f p[3];
354  ACG::Vec3f n[3];
355  ACG::Vec2f tex[3];
356 
357  n[0] = p[0] = positionOnSphere(sl0, st0);
358  n[1] = p[1] = positionOnSphere(sl1, st1);
359  n[2] = p[2] = positionOnSphere(sl2, st2);
360  n[0].normalize();
361  n[1].normalize();
362  n[2].normalize();
363  tex[0] = texCoordOnSphere(sl0, st0);
364  tex[1] = texCoordOnSphere(sl1, st1);
365  tex[2] = texCoordOnSphere(sl2, st2);
366 
367  addTriangleToVBO(p, n, tex);
368 }
369 
370 //------------------------------------------------------------------------
371 
372 ACG::Vec3f GLSphere::positionOnSphere(int _sliceNumber, int _stackNumber)
373 {
374  ACG::Vec3f position;
375 
376  double alpha = (M_PI / double(stacks_)) * double(_stackNumber);
377  double beta = ((2.0 * M_PI) / double(slices_)) * double(_sliceNumber);
378 
379  double ringRadius = sin(alpha);
380  position[0] = sin(beta) * ringRadius;
381  position[1] = cos(beta) * ringRadius;
382  position[2] = cos(alpha);
383 
384  return position;
385 }
386 
387 //------------------------------------------------------------------------
388 
389 ACG::Vec2f GLSphere::texCoordOnSphere(int _sliceNumber, int _stackNumber)
390 {
391  ACG::Vec2f texCoord;
392 
393  double alpha = (M_PI / double(stacks_)) * double(_stackNumber);
394  texCoord[0] = double(_sliceNumber) / double(slices_);
395  texCoord[1] = 0.5 * (cos(alpha) + 1.0);
396 
397  return texCoord;
398 }
399 
400 //========================================================================
401 // GLCone
402 //========================================================================
403 
404 GLCone::GLCone(int _slices, int _stacks, float _bottomRadius, float _topRadius, bool _bottomCap, bool _topCap) :
405  slices_(_slices),
406  stacks_(_stacks),
407  bottomRadius_(_bottomRadius),
408  topRadius_(_topRadius),
409  bottomCap_(_bottomCap),
410  topCap_(_topCap)
411 {
412  updateVBO();
413 }
414 
415 //------------------------------------------------------------------------
416 
417 GLCone::~GLCone()
418 {
419 
420 }
421 
422 //------------------------------------------------------------------------
423 
424 void GLCone::setBottomRadius(float _bottomRadius) {
425  if (bottomRadius_ != _bottomRadius)
426  vboDataInvalid_ = true;
427  bottomRadius_ = _bottomRadius;
428 }
429 
430 //------------------------------------------------------------------------
431 
432 void GLCone::setTopRadius(float _topRadius) {
433  if (topRadius_ != _topRadius)
434  vboDataInvalid_ = true;
435  topRadius_ = _topRadius;
436 }
437 
438 //------------------------------------------------------------------------
439 
440 void GLCone::setNormalOrientation(NormalOrientation orientation) {
441  if (normalOrientation_ != orientation)
442  vboDataInvalid_ = true;
443  normalOrientation_ = orientation;
444 }
445 
446 //------------------------------------------------------------------------
447 
448 void GLCone::draw(GLState& _state, float _height, const ACG::Vec3f& _center, ACG::Vec3f _upDir)
449 {
450 // ACG::mat4 mWorld = ACG::translate(ACG::mat4(1.0f), _center);
451 
452  _state.push_modelview_matrix();
453 
454  // translate
455  _state.translate(ACG::Vec3d(_center));
456 
457  _upDir.normalize();
458 
459  // compute rotation matrix mAlign
460  // such that vBindDir rotates to _upDir
461  ACG::GLMatrixd mAlign;
462  mAlign.identity();
463 
464  ACG::Vec3f vBindDir(0.0f, 0.0f, 1.0f);
465 
466  ACG::Vec3f vRotAxis = OpenMesh::cross(_upDir, vBindDir);
467  vRotAxis.normalize();
468 
469  ACG::Vec3f vUp = OpenMesh::cross(_upDir, vRotAxis);
470 
471  // rotate
472  for (int i = 0; i < 3; ++i) {
473  mAlign(i, 0) = vRotAxis[i];
474  mAlign(i, 1) = vUp[i];
475  mAlign(i, 2) = _upDir[i];
476  }
477 
478  ACG::Vec3f vDelta = vBindDir - _upDir;
479  if ( fabsf(OpenMesh::dot(vDelta, vDelta)) < 1e-3f)
480  mAlign.identity();
481 
482  // scale
483  mAlign.scale(1.0, 1.0, _height);
484 
485  ACG::GLMatrixd mAlignInv(mAlign);
486  mAlignInv.invert();
487 
488  _state.mult_matrix(mAlign, mAlignInv);
489 
490  GLPrimitive::draw_primitive();
491 
492  _state.pop_modelview_matrix();
493 }
494 
495 //------------------------------------------------------------------------
496 
497 
498 void GLCone::addToRenderer(IRenderer* _renderer,
499  const RenderObject* _base,
500  float _height,
501  const ACG::Vec3f& _center,
502  ACG::Vec3f _upDir,
503  float _radiusScale)
504 {
505  RenderObject ro = *_base;
506 
507  // translate
508  ro.modelview.translate(ACG::Vec3d(_center));
509 
510  _upDir.normalize();
511 
512  // compute rotation matrix mAlign
513  // such that vBindDir rotates to _upDir
514  ACG::GLMatrixf mAlign;
515  mAlign.identity();
516 
517  ACG::Vec3f vBindDir(0.0f, 0.0f, 1.0f);
518 
519  ACG::Vec3f vRotAxis = OpenMesh::cross(_upDir, vBindDir);
520  vRotAxis.normalize();
521 
522  ACG::Vec3f vUp = OpenMesh::cross(_upDir, vRotAxis);
523 
524  // rotate
525  for (int i = 0; i < 3; ++i) {
526  mAlign(i, 0) = vRotAxis[i];
527  mAlign(i, 1) = vUp[i];
528  mAlign(i, 2) = _upDir[i];
529  }
530 
531  ACG::Vec3f vDelta = vBindDir - _upDir;
532  if ( fabsf(OpenMesh::dot(vDelta, vDelta)) < 1e-3f)
533  mAlign.identity();
534 
535  // scale
536  mAlign.scale(_radiusScale, _radiusScale, _height);
537 
538  ro.modelview *= mAlign;
539 
540  GLPrimitive::addToRenderer_primitive(_renderer, &ro);
541 }
542 
543 //------------------------------------------------------------------------
544 
545 int GLCone::getNumTriangles()
546 {
547  int numTris = stacks_ * slices_ * 2;
548 
549  if (bottomCap_)
550  numTris += slices_;
551  if (topCap_)
552  numTris += slices_;
553 
554  return numTris;
555 }
556 
557 //------------------------------------------------------------------------
558 
559 ACG::Vec3f GLCone::positionOnCone(int _sliceNumber, int _stackNumber)
560 {
561  ACG::Vec3f position;
562 
563  double beta = ((2.0 * M_PI) / slices_) * _sliceNumber;
564 
565  double relativeHeight = _stackNumber / (double) stacks_;
566  double ringRadius = (1.0 - relativeHeight) * bottomRadius_ + relativeHeight * topRadius_;
567  position[0] = sin(beta) * ringRadius;
568  position[1] = cos(beta) * ringRadius;
569  position[2] = relativeHeight;
570 
571  return position;
572 }
573 
574 //------------------------------------------------------------------------
575 
576 ACG::Vec2f GLCone::texCoordOnCone(int _sliceNumber, int _stackNumber)
577 {
578  ACG::Vec2f texCoord;
579 
580  texCoord[0] = _sliceNumber / (double) slices_;
581  texCoord[1] = _stackNumber / (double) stacks_;
582 
583  return texCoord;
584 }
585 
586 //------------------------------------------------------------------------
587 
588 ACG::Vec3f GLCone::normalOnCone(int _sliceNumber, int _stackNumber)
589 {
590  ACG::Vec3f normal;
591 
592  double beta = ((2.0 * M_PI) / slices_) * _sliceNumber;
593  double relativeHeight = _stackNumber / (double) stacks_;
594  double ringRadius = (1.0 - relativeHeight) * bottomRadius_ + relativeHeight * topRadius_;
595 
596  normal[0] = sin(beta) * ringRadius;
597  normal[1] = cos(beta) * ringRadius;
598  normal[2] = (bottomRadius_ - topRadius_);
599 
600  normal.normalize();
601  return normal;
602 }
603 
604 //------------------------------------------------------------------------
605 
606 void GLCone::addTriangle(int sl0, int st0, int sl1, int st1, int sl2, int st2)
607 {
608  ACG::Vec3f p[3];
609  ACG::Vec3f n[3];
610  ACG::Vec2f tex[3];
611 
612  p[0] = positionOnCone(sl0, st0);
613  p[1] = positionOnCone(sl1, st1);
614  p[2] = positionOnCone(sl2, st2);
615  if (normalOrientation_ == OUTSIDE) {
616  n[0] = normalOnCone(sl0, st0);
617  n[1] = normalOnCone(sl1, st1);
618  n[2] = normalOnCone(sl2, st2);
619  } else if (normalOrientation_ == INSIDE) {
620  n[0] = -normalOnCone(sl0, st0);
621  n[1] = -normalOnCone(sl1, st1);
622  n[2] = -normalOnCone(sl2, st2);
623  }
624  tex[0] = texCoordOnCone(sl0, st0);
625  tex[1] = texCoordOnCone(sl1, st1);
626  tex[2] = texCoordOnCone(sl2, st2);
627 
628  addTriangleToVBO(p, n, tex);
629 }
630 
631 //------------------------------------------------------------------------
632 
633 void GLCone::updateVBO()
634 {
635  for (int sl = 0; sl < slices_; ++sl) {
636  // top triangle:
637  if (topCap_) {
638  ACG::Vec3f p[3];
639  ACG::Vec3f n[3];
640  ACG::Vec2f tex[3];
641 
642  p[0] = ACG::Vec3f(0.0, 0.0, 1.0);
643  p[1] = positionOnCone(sl + 1, stacks_);
644  p[2] = positionOnCone(sl, stacks_);
645  if (normalOrientation_ == OUTSIDE) {
646  n[0] = ACG::Vec3f(0.0, 0.0, 1.0);
647  n[1] = ACG::Vec3f(0.0, 0.0, 1.0);
648  n[2] = ACG::Vec3f(0.0, 0.0, 1.0);
649  } else if (normalOrientation_ == INSIDE) {
650  n[0] = ACG::Vec3f(0.0, 0.0, -1.0);
651  n[1] = ACG::Vec3f(0.0, 0.0, -1.0);
652  n[2] = ACG::Vec3f(0.0, 0.0, -1.0);
653  }
654 
655  tex[0] = ACG::Vec2f(0.5, 0.5);
656  double beta = ((2.0 * M_PI) / slices_) * (sl + 1);
657  tex[1] = ACG::Vec2f(sin(beta), cos(beta));
658  beta = ((2.0 * M_PI) / slices_) * (sl);
659  tex[2] = ACG::Vec2f(sin(beta), cos(beta));
660 
661  addTriangleToVBO(p, n, tex);
662  }
663  // middle quads:
664  for (int st = 0; st < stacks_; ++st) {
665  addTriangle(sl, st, sl, st + 1, sl + 1, st);
666  addTriangle(sl + 1, st, sl, st + 1, sl + 1, st + 1);
667  }
668  // bottom triangle:
669  if (bottomCap_) {
670  ACG::Vec3f p[3];
671  ACG::Vec3f n[3];
672  ACG::Vec2f tex[3];
673 
674  p[0] = ACG::Vec3f(0.0, 0.0, 0.0);
675  p[1] = positionOnCone(sl, 0);
676  p[2] = positionOnCone(sl + 1, 0);
677  if (normalOrientation_ == OUTSIDE) {
678  n[0] = ACG::Vec3f(0.0, 0.0, -1.0);
679  n[1] = ACG::Vec3f(0.0, 0.0, -1.0);
680  n[2] = ACG::Vec3f(0.0, 0.0, -1.0);
681  } else if (normalOrientation_ == INSIDE) {
682  n[0] = ACG::Vec3f(0.0, 0.0, 1.0);
683  n[1] = ACG::Vec3f(0.0, 0.0, 1.0);
684  n[2] = ACG::Vec3f(0.0, 0.0, 1.0);
685  }
686 
687  tex[0] = ACG::Vec2f(0.5, 0.5);
688  double beta = ((2.0 * M_PI) / slices_) * (sl);
689  tex[1] = ACG::Vec2f(sin(beta), cos(beta));
690  beta = ((2.0 * M_PI) / slices_) * (sl + 1);
691  tex[2] = ACG::Vec2f(sin(beta), cos(beta));
692 
693  addTriangleToVBO(p, n, tex);
694  }
695  }
696 }
697 
698 //========================================================================
699 // GLCylinder
700 //========================================================================
701 
702 GLCylinder::GLCylinder(int _slices, int _stacks, float _radius, bool _bottomCap, bool _topCap) :
703  GLCone(_slices, _stacks, _radius, _radius, _bottomCap, _topCap)
704 {
705 }
706 
707 //========================================================================
708 // GLPartialDisk
709 //========================================================================
710 
719 GLPartialDisk::GLPartialDisk(int _slices, int _loops, float _innerRadius, float _outerRadius, float _startAngle, float _sweepAngle) :
720  slices_(_slices),
721  loops_(_loops),
722  innerRadius_(_innerRadius),
723  outerRadius_(_outerRadius),
724  startAngle_(_startAngle),
725  sweepAngle_(_sweepAngle)
726 {
727  updateVBO();
728 }
729 
730 //------------------------------------------------------------------------
731 
732 void GLPartialDisk::setInnerRadius(float _innerRadius) {
733  if (innerRadius_ != _innerRadius)
734  vboDataInvalid_ = true;
735  innerRadius_ = _innerRadius;
736 }
737 
738 //------------------------------------------------------------------------
739 
740 void GLPartialDisk::setOuterRadius(float _outerRadius) {
741  if (outerRadius_ != _outerRadius)
742  vboDataInvalid_ = true;
743  outerRadius_ = _outerRadius;
744 }
745 
746 //------------------------------------------------------------------------
747 
748 int GLPartialDisk::getNumTriangles() {
749  return slices_ * (loops_+1) * 2;
750 }
751 
752 //------------------------------------------------------------------------
753 
754 void GLPartialDisk::updateVBO() {
755  assert(slices_ >= 2);
756  assert(loops_ >= 1);
757  assert(outerRadius_ > 0.0f);
758  assert(innerRadius_ >= 0.0f);
759  assert(innerRadius_ < outerRadius_);
760 
761  if (sweepAngle_ < -360.0f)
762  sweepAngle_ = 360.0f;
763  if (sweepAngle_ > 360.0f)
764  sweepAngle_ = 360.0f;
765  if (sweepAngle_ < 0) {
766  startAngle_ += sweepAngle_;
767  sweepAngle_ = -sweepAngle_;
768  }
769 
770  float* sinCache = new float[slices_+1];
771  float* cosCache = new float[slices_+1];
772 
773  // precompute all sine and cosine that are needed
774  float angleOffsetRadian = startAngle_ * M_PI / 180.0f;
775  float sweepAngleRadian = sweepAngle_ * M_PI / 180.0f;
776  for (int i = 0; i < slices_+1; ++i) {
777  float angle = angleOffsetRadian + sweepAngleRadian * i/slices_;
778  sinCache[i] = sin(angle);
779  cosCache[i] = cos(angle);
780  }
781 
782  // iterate over loops (starting from the inner most) to generate triangles
783  float deltaRadius = outerRadius_ - innerRadius_;
784  for (int i = loops_+1; i > 0; --i) {
785 
786  // for each slice generate two triangles
787  for (int j = 0; j < slices_; ++j) {
788 
789  ACG::Vec3f p[3];
790  ACG::Vec3f n[3];
791  ACG::Vec2f tex[3];
792  ACG::Vec3f p2[3];
793  ACG::Vec3f n2[3];
794  ACG::Vec2f tex2[3];
795 
796  // radius of the loop nearer to the center of the disk
797  float innerRadius = outerRadius_ - deltaRadius * ((float) i / (loops_ + 1));
798  // radius of the loop further from the center of the disk
799  float outerRadius = outerRadius_ - deltaRadius * ((float) (i - 1) / (loops_ + 1));
800 
801  // first triangle:
802  // 1 2
803  //
804  // 0
805  // vertices
806  p[0] = ACG::Vec3f(innerRadius * sinCache[j], innerRadius * cosCache[j], 0.0f);
807  p[1] = ACG::Vec3f(outerRadius * sinCache[j], outerRadius * cosCache[j], 0.0f);
808  p[2] = ACG::Vec3f(outerRadius * sinCache[j+1], outerRadius * cosCache[j+1], 0.0f);
809  // normals
810  n[0] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
811  n[1] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
812  n[2] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
813  // TODO: proper texture coordinates
814  tex[0] = ACG::Vec2f(0.0f, 0.0f);
815  tex[1] = ACG::Vec2f(0.0f, 0.0f);
816  tex[2] = ACG::Vec2f(0.0f, 0.0f);
817 
818  addTriangleToVBO(p, n, tex);
819 
820  // second triangle:
821  // x 1
822  //
823  // 0 2
824  // vertices
825  p2[0] = ACG::Vec3f(innerRadius * sinCache[j], innerRadius * cosCache[j], 0.0f);
826  p2[1] = ACG::Vec3f(outerRadius * sinCache[j+1], outerRadius * cosCache[j+1], 0.0f);
827  p2[2] = ACG::Vec3f(innerRadius * sinCache[j+1], innerRadius * cosCache[j+1], 0.0f);
828  // normals
829  n2[0] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
830  n2[1] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
831  n2[2] = ACG::Vec3f(0.0f, 0.0f, 1.0f);
832  // TODO: proper texture coordinates
833  tex2[0] = ACG::Vec2f(0.0f, 0.0f);
834  tex2[1] = ACG::Vec2f(0.0f, 0.0f);
835  tex2[2] = ACG::Vec2f(0.0f, 0.0f);
836 
837  addTriangleToVBO(p2, n2, tex2);
838 
839  }
840  }
841 
842  delete[] sinCache;
843  delete[] cosCache;
844 }
845 
846 //------------------------------------------------------------------------
847 
848 void GLPartialDisk::draw( GLState& _state, const ACG::Vec3f& _center, ACG::Vec3f _upDir) {
849  _state.push_modelview_matrix();
850 
851  // translate
852  _state.translate(ACG::Vec3d(_center));
853 
854  _upDir.normalize();
855 
856  // compute rotation matrix mAlign
857  // such that vBindDir rotates to _upDir
858  ACG::GLMatrixd mAlign;
859  mAlign.identity();
860 
861  ACG::Vec3f vBindDir(0.0f, 0.0f, 1.0f);
862 
863  ACG::Vec3f vRotAxis = OpenMesh::cross(_upDir, vBindDir);
864  vRotAxis.normalize();
865 
866  ACG::Vec3f vUp = OpenMesh::cross(_upDir, vRotAxis);
867 
868  // rotate
869  for (int i = 0; i < 3; ++i) {
870  mAlign(i, 0) = vRotAxis[i];
871  mAlign(i, 1) = vUp[i];
872  mAlign(i, 2) = _upDir[i];
873  }
874 
875  ACG::Vec3f vDelta = vBindDir - _upDir;
876  if ( fabsf(OpenMesh::dot(vDelta, vDelta)) < 1e-3f)
877  mAlign.identity();
878 
879  ACG::GLMatrixd mAlignInv(mAlign);
880  mAlignInv.invert();
881 
882  _state.mult_matrix(mAlign, mAlignInv);
883 
884  GLPrimitive::draw_primitive();
885 
886  _state.pop_modelview_matrix();
887 }
888 
889 //========================================================================
890 // GLDisk
891 //========================================================================
892 
899 GLDisk::GLDisk(int _slices, int _loops, float _innerRadius, float _outerRadius) :
900  GLPartialDisk(_slices, _loops, _innerRadius, _outerRadius, 0.0f, 360.0f)
901 {
902 }
903 
904 
905 //========================================================================
906 // GLBox
907 //========================================================================
908 
909 GLBox::GLBox()
910 {
911  updateVBO();
912 }
913 
914 GLBox::~GLBox()
915 {
916 }
917 
918 int GLBox::getNumTriangles()
919 {
920  return 12;
921 }
922 
923 //------------------------------------------------------------------------
924 
925 void GLBox::updateVBO()
926 {
927  static const Vec3f pos[8] =
928  {
929  Vec3f(-0.5f,-0.5f,0.5f), Vec3f(-0.5f,-0.5f,-0.5f), Vec3f(0.5f,-0.5f,-0.5f),
930  Vec3f(0.5f,-0.5f,0.5f), Vec3f(-0.5f,0.5f,0.5f), Vec3f(0.5f,0.5f,0.5f),
931  Vec3f(0.5f,0.5f,-0.5f), Vec3f(-0.5f,0.5f,-0.5f)
932  };
933 
934  static const Vec3f norm[6] =
935  {
936  Vec3f(0.0f,-1.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f),
937  Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), Vec3f(-1.0f,0.0f,0.0f)
938  };
939 
940  static const Vec2f texc[4] =
941  {
942  Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f), Vec2f(0.0f,0.0f)
943  };
944 
945  // tri: p,p,p ,n,n,n ,t,t,t
946  static const int tris[12][9] =
947  {
948  {0,1,2 ,0,0,0 ,0,1,2}, {2,3,0 ,0,0,0 ,2,3,0}, {4,5,6 ,1,1,1 ,3,0,1},
949  {6,7,4 ,1,1,1 ,1,2,3}, {0,3,5 ,2,2,2 ,3,0,1}, {5,4,0 ,2,2,2 ,1,2,3},
950  {3,2,6 ,3,3,3 ,3,0,1}, {6,5,3 ,3,3,3 ,1,2,3}, {2,1,7 ,4,4,4 ,3,0,1},
951  {7,6,2 ,4,4,4 ,1,2,3}, {1,0,4 ,5,5,5 ,3,0,1}, {4,7,1 ,5,5,5 ,1,2,3}
952  };
953 
954  for (int i = 0; i < 12; ++i)
955  {
956  Vec3f triPos[3] = { pos[tris[i][0]], pos[tris[i][1]], pos[tris[i][2]] };
957  Vec3f triNorm[3] = { norm[tris[i][3]], norm[tris[i][4]], norm[tris[i][5]] };
958  Vec2f triTexc[3] = { texc[tris[i][6]], texc[tris[i][7]], texc[tris[i][8]] };
959 
960  addTriangleToVBO(triPos, triNorm, triTexc);
961  }
962 }
963 
964 //------------------------------------------------------------------------
965 
966 GLLineBox::GLLineBox()
967 {
968  updateVBO();
969 }
970 
971 GLLineBox::~GLLineBox()
972 {
973 }
974 
975 //------------------------------------------------------------------------
976 
977 int GLLineBox::getNumTriangles()
978 {
979  return 0;
980 }
981 
982 int GLLineBox::getNumLines()
983 {
984  return 12;
985 }
986 
987 //------------------------------------------------------------------------
988 
989 void GLLineBox::updateVBO()
990 {
991  static const Vec3f pos[8] =
992  {
993  Vec3f(-0.5f,-0.5f,0.5f), Vec3f(-0.5f,-0.5f,-0.5f), Vec3f(0.5f,-0.5f,-0.5f),
994  Vec3f(0.5f,-0.5f,0.5f), Vec3f(-0.5f,0.5f,0.5f), Vec3f(0.5f,0.5f,0.5f),
995  Vec3f(0.5f,0.5f,-0.5f), Vec3f(-0.5f,0.5f,-0.5f)
996  };
997 
998  static const Vec3f norm[6] =
999  {
1000  Vec3f(0.0f,-1.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f),
1001  Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), Vec3f(-1.0f,0.0f,0.0f)
1002  };
1003 
1004  static const Vec2f texc[4] =
1005  {
1006  Vec2f(1.0f,0.0f), Vec2f(1.0f,1.0f), Vec2f(0.0f,1.0f), Vec2f(0.0f,0.0f)
1007  };
1008 
1009  // line: p,p ,n,n ,t,t
1010  static const int lines[12][6] =
1011  {
1012  {1,2, 0,0, 0,3}, {0,3, 0,0, 0,3}, {4,5, 0,0, 0,3}, {7,6, 0,0, 0,3},
1013  {1,7, 0,0, 0,3}, {0,4, 0,0, 0,3}, {2,6, 0,0, 0,3}, {3,5, 0,0, 0,3},
1014  {1,0, 0,0, 0,3}, {2,3, 0,0, 0,3}, {7,4, 0,0, 0,3}, {6,5, 0,0, 0,3}
1015  };
1016 
1017  for (int i = 0; i < 12; ++i)
1018  {
1019  Vec3f p[2] = { pos[lines[i][0]], pos[lines[i][1]]};
1020  Vec3f n[2] = { norm[lines[i][2]], norm[lines[i][3]]};
1021  Vec2f t[2] = { texc[lines[i][4]], texc[lines[i][5]]};
1022 
1023  addLineToVBO(p, n, t);
1024  }
1025 }
1026 
1027 //------------------------------------------------------------------------
1028 
1029 }
VectorT< float, 2 > Vec2f
Definition: VectorT.hh:108
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1006
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:125
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:531
void mult_matrix(const GLMatrixd &_m, const GLMatrixd &_inv_m, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply by a given transformation matrix
Definition: GLState.cc:612
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
GLPartialDisk(int _slices, int _loops, float _innerRadius, float _outerRadius, float _startAngle, float _sweepAngle)
void scale(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with scaling matrix (x,y,z)
Definition: GLMatrixT.cc:81
GLDisk(int _slices, int _loops, float _innerRadius, float _outerRadius)
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1022
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:428
bool invert()
matrix inversion (returns true on success)
Definition: Matrix4x4T.cc:297
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
osg::Vec3f cross(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.