1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/Shape>
14 #include <osg/Geometry>
15
16 #include <algorithm>
17
18 using namespace osg;
19
~Shape()20 Shape::~Shape()
21 {
22 }
23
~ShapeVisitor()24 ShapeVisitor::~ShapeVisitor()
25 {
26 }
27
~ConstShapeVisitor()28 ConstShapeVisitor::~ConstShapeVisitor()
29 {
30 }
31
~Sphere()32 Sphere::~Sphere()
33 {
34 }
35
~Box()36 Box::~Box()
37 {
38 }
39
~Cone()40 Cone::~Cone()
41 {
42 }
43
~Cylinder()44 Cylinder::~Cylinder()
45 {
46 }
47
~Capsule()48 Capsule::~Capsule()
49 {
50 }
51
~InfinitePlane()52 InfinitePlane::~InfinitePlane()
53 {
54 }
55
~TriangleMesh()56 TriangleMesh::~TriangleMesh()
57 {
58 }
59
~ConvexHull()60 ConvexHull::~ConvexHull()
61 {
62 }
63
HeightField()64 HeightField::HeightField():
65 _columns(0),
66 _rows(0),
67 _origin(0.0f,0.0f,0.0f),
68 _dx(1.0f),
69 _dy(1.0f),
70 _skirtHeight(0.0f),
71 _borderWidth(0)
72 {
73 _heights = new FloatArray;
74 }
75
HeightField(const HeightField & mesh,const CopyOp & copyop)76 HeightField::HeightField(const HeightField& mesh,const CopyOp& copyop):
77 Shape(mesh,copyop),
78 _columns(mesh._columns),
79 _rows(mesh._rows),
80 _origin(mesh._origin),
81 _dx(mesh._dx),
82 _dy(mesh._dy),
83 _skirtHeight(mesh._skirtHeight),
84 _borderWidth(mesh._borderWidth),
85 _heights(new FloatArray(*mesh._heights))
86 {
87 }
88
~HeightField()89 HeightField::~HeightField()
90 {
91 }
92
93
allocate(unsigned int numColumns,unsigned int numRows)94 void HeightField::allocate(unsigned int numColumns,unsigned int numRows)
95 {
96 if (_columns!=numColumns || _rows!=numRows)
97 {
98 _heights->resize(numColumns*numRows);
99 }
100 _columns=numColumns;
101 _rows=numRows;
102 }
103
getNormal(unsigned int c,unsigned int r) const104 Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const
105 {
106 // four point normal generation.
107 float dz_dx;
108 if (c==0)
109 {
110 dz_dx = (getHeight(c+1,r)-getHeight(c,r))/getXInterval();
111 }
112 else if (c==getNumColumns()-1)
113 {
114 dz_dx = (getHeight(c,r)-getHeight(c-1,r))/getXInterval();
115 }
116 else // assume 0<c<_numColumns-1
117 {
118 dz_dx = 0.5f*(getHeight(c+1,r)-getHeight(c-1,r))/getXInterval();
119 }
120
121 float dz_dy;
122 if (r==0)
123 {
124 dz_dy = (getHeight(c,r+1)-getHeight(c,r))/getYInterval();
125 }
126 else if (r==getNumRows()-1)
127 {
128 dz_dy = (getHeight(c,r)-getHeight(c,r-1))/getYInterval();
129 }
130 else // assume 0<r<_numRows-1
131 {
132 dz_dy = 0.5f*(getHeight(c,r+1)-getHeight(c,r-1))/getYInterval();
133 }
134
135 Vec3 normal(-dz_dx,-dz_dy,1.0f);
136 normal.normalize();
137
138 return normal;
139 }
140
getHeightDelta(unsigned int c,unsigned int r) const141 Vec2 HeightField::getHeightDelta(unsigned int c,unsigned int r) const
142 {
143 // four point height generation.
144 Vec2 heightDelta;
145 if (c==0)
146 {
147 heightDelta.x() = (getHeight(c+1,r)-getHeight(c,r));
148 }
149 else if (c==getNumColumns()-1)
150 {
151 heightDelta.x() = (getHeight(c,r)-getHeight(c-1,r));
152 }
153 else // assume 0<c<_numColumns-1
154 {
155 heightDelta.x() = 0.5f*(getHeight(c+1,r)-getHeight(c-1,r));
156 }
157
158 if (r==0)
159 {
160 heightDelta.y() = (getHeight(c,r+1)-getHeight(c,r));
161 }
162 else if (r==getNumRows()-1)
163 {
164 heightDelta.y() = (getHeight(c,r)-getHeight(c,r-1));
165 }
166 else // assume 0<r<_numRows-1
167 {
168 heightDelta.y() = 0.5f*(getHeight(c,r+1)-getHeight(c,r-1));
169 }
170
171 return heightDelta;
172 }
173
~CompositeShape()174 CompositeShape::~CompositeShape()
175 {
176 }
177
178 ////////////////////////////////////////////////////////////////////////////////////////////////
179 //
180 // BuildShapeGeometryVisitor
181 //
182
183 // arbitrary minima for rows & segments
184 const unsigned int MIN_NUM_ROWS = 3;
185 const unsigned int MIN_NUM_SEGMENTS = 5;
186
BuildShapeGeometryVisitor(Geometry * geometry,const TessellationHints * hints)187 BuildShapeGeometryVisitor::BuildShapeGeometryVisitor(Geometry* geometry, const TessellationHints* hints):
188 _geometry(geometry),
189 _hints(hints)
190 {
191 _vertices = dynamic_cast<Vec3Array*>(geometry->getVertexArray());
192 _normals = dynamic_cast<Vec3Array*>(geometry->getNormalArray());
193 _texcoords = dynamic_cast<Vec2Array*>(geometry->getTexCoordArray(0));
194
195 bool requiresClearOfPrimitiveSets = false;
196
197 if (!_vertices || _vertices->getBinding()!=Array::BIND_PER_VERTEX)
198 {
199 requiresClearOfPrimitiveSets = true;
200 _vertices = new Vec3Array(Array::BIND_PER_VERTEX);
201 _geometry->setVertexArray(_vertices.get());
202 }
203
204 if (!_normals || (_normals->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_normals->size()))
205 {
206 requiresClearOfPrimitiveSets = true;
207 _normals = new Vec3Array(Array::BIND_PER_VERTEX);
208 _geometry->setNormalArray(_normals.get());
209 }
210
211 if (!_texcoords || (_texcoords->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_texcoords->size()))
212 {
213 requiresClearOfPrimitiveSets = true;
214 _texcoords = new Vec2Array(Array::BIND_PER_VERTEX);
215 _geometry->setTexCoordArray(0, _texcoords.get());
216 }
217
218 if (requiresClearOfPrimitiveSets && !_geometry->getPrimitiveSetList().empty())
219 {
220 OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor() Geometry contains compatible arrays, resetting before shape build."<<std::endl;
221 _geometry->getPrimitiveSetList().clear();
222 }
223
224 _mode = 0;
225 _start_index = 0;
226 }
227
setMatrix(const Matrixd & m)228 void BuildShapeGeometryVisitor::setMatrix(const Matrixd& m)
229 {
230 _matrix = m;
231
232 _inverse.invert(m);
233 _inverse.setTrans(0.0,0.0,0.0);
234 }
235
Vertex(const Vec3f & v)236 void BuildShapeGeometryVisitor::Vertex(const Vec3f& v)
237 {
238 _vertices->push_back(v);
239 if (_normals.valid() && _normals->size()<_vertices->size())
240 {
241 while(_normals->size()<_vertices->size()) _normals->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
242 }
243 if (_texcoords.valid() && _texcoords->size()<_vertices->size())
244 {
245 while(_texcoords->size()<_vertices->size()) _texcoords->push_back(osg::Vec2(0.0f, 0.0f));
246 }
247 }
248
249
Begin(GLenum mode)250 void BuildShapeGeometryVisitor::Begin(GLenum mode)
251 {
252 _mode = mode;
253 _start_index = _vertices->size();
254 }
255
End()256 void BuildShapeGeometryVisitor::End()
257 {
258 if (_start_index>=_vertices->size()) return;
259
260 bool smallPrimitiveSet = _vertices->size() < 65536;
261
262 // OSG_NOTICE<<"BuildShapeGeometryVisitor::End() smallPrimitiveSet = "<<smallPrimitiveSet<<std::endl;
263 if (_mode==GL_QUADS)
264 {
265 osg::ref_ptr<osg::DrawElements> primitives = smallPrimitiveSet ?
266 static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_TRIANGLES)) :
267 static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_TRIANGLES));
268
269 _geometry->addPrimitiveSet(primitives.get());
270
271 for(unsigned int i=_start_index; i<_vertices->size(); i+=4)
272 {
273 unsigned int p0 = i;
274 unsigned int p1 = i+1;
275 unsigned int p2 = i+2;
276 unsigned int p3 = i+3;
277
278 primitives->addElement(p0);
279 primitives->addElement(p1);
280 primitives->addElement(p3);
281
282 primitives->addElement(p1);
283 primitives->addElement(p2);
284 primitives->addElement(p3);
285 }
286 }
287 else if (_mode==GL_QUAD_STRIP)
288 {
289 osg::ref_ptr<osg::DrawElements> primitives = smallPrimitiveSet ?
290 static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_TRIANGLES)) :
291 static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_TRIANGLES));
292
293 _geometry->addPrimitiveSet(primitives.get());
294
295 for(unsigned int i=_start_index; i<_vertices->size()-2; i+=2)
296 {
297 unsigned int p0 = i;
298 unsigned int p1 = i+1;
299 unsigned int p2 = i+2;
300 unsigned int p3 = i+3;
301
302 primitives->addElement(p0);
303 primitives->addElement(p1);
304 primitives->addElement(p2);
305
306 primitives->addElement(p1);
307 primitives->addElement(p3);
308 primitives->addElement(p2);
309 }
310 }
311 else
312 {
313 _geometry->addPrimitiveSet(new DrawArrays(_mode, _start_index, _vertices->size()-_start_index));
314 }
315
316 for(unsigned int i=_start_index; i<_vertices->size(); ++i)
317 {
318 Vec3& v = (*_vertices)[i];
319 v = v * _matrix;
320
321 Vec3& n = (*_normals)[i];
322 n = _inverse * n;
323 n.normalize();
324 }
325
326 _vertices->dirty();
327 _normals->dirty();
328 _texcoords->dirty();
329 _geometry->dirtyGLObjects();
330
331 _start_index = _vertices->size();
332 }
333
drawCylinderBody(unsigned int numSegments,float radius,float height)334 void BuildShapeGeometryVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height)
335 {
336 const float angleDelta = 2.0f*PIf/(float)numSegments;
337 const float texCoordDelta = 1.0f/(float)numSegments;
338
339 const float r = radius;
340 const float h = height;
341
342 float basez = -h*0.5f;
343 float topz = h*0.5f;
344
345 float angle = 0.0f;
346 float texCoord = 0.0f;
347
348 bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
349 bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
350
351 // The only difference between the font & back face loops is that the
352 // normals are inverted and the order of the vertex pairs is reversed.
353 // The code is mostly duplicated in order to hoist the back/front face
354 // test out of the loop for efficiency
355
356 Begin(GL_QUAD_STRIP);
357
358 if (drawFrontFace)
359 {
360 for(unsigned int bodyi=0;
361 bodyi<numSegments;
362 ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
363 {
364 float c = cosf(angle);
365 float s = sinf(angle);
366 Vec3 n(c,s,0.0f);
367
368 Normal(n);
369 TexCoord2f(texCoord,1.0f);
370 Vertex3f(c*r,s*r,topz);
371
372 Normal(n);
373 TexCoord2f(texCoord,0.0f);
374 Vertex3f(c*r,s*r,basez);
375 }
376
377 // do last point by hand to ensure no round off errors.
378 Vec3 n(1.0f,0.0f,0.0f);
379
380 Normal(n);
381 TexCoord2f(1.0f,1.0f);
382 Vertex3f(r,0.0f,topz);
383
384 Normal(n);
385 TexCoord2f(1.0f,0.0f);
386 Vertex3f(r,0.0f,basez);
387 }
388
389 if (drawBackFace)
390 {
391 for(unsigned int bodyi=0;
392 bodyi<numSegments;
393 ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
394 {
395 float c = cosf(angle);
396 float s = sinf(angle);
397 Vec3 n(-c,-s,0.0f);
398
399 Normal(n);
400 TexCoord2f(texCoord,0.0f);
401 Vertex3f(c*r,s*r,basez);
402
403 Normal(n);
404 TexCoord2f(texCoord,1.0f);
405 Vertex3f(c*r,s*r,topz);
406 }
407
408 // do last point by hand to ensure no round off errors.
409 Vec3 n(-1.0f,0.0f,0.0f);
410
411 Normal(n);
412 TexCoord2f(1.0f,0.0f);
413 Vertex3f(r,0.0f,basez);
414
415 Normal(n);
416 TexCoord2f(1.0f,1.0f);
417 Vertex3f(r,0.0f,topz);
418 }
419
420 End();
421 }
422
423
drawHalfSphere(unsigned int numSegments,unsigned int numRows,float radius,SphereHalf which,float zOffset)424 void BuildShapeGeometryVisitor::drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset)
425 {
426 float lDelta = PIf/(float)numRows;
427 float vDelta = 1.0f/(float)numRows;
428
429 bool top = (which==SphereTopHalf);
430
431 bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
432 bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
433
434 float angleDelta = PIf*2.0f/(float)numSegments;
435 float texCoordHorzDelta = 1.0f/(float)numSegments;
436
437 float lBase=-PIf*0.5f + (top?(lDelta*(numRows/2)):0.0f);
438 float rBase=(top?(cosf(lBase)*radius):0.0f);
439 float zBase=(top?(sinf(lBase)*radius):-radius);
440 float vBase=(top?(vDelta*(numRows/2)):0.0f);
441 float nzBase=(top?(sinf(lBase)):-1.0f);
442 float nRatioBase=(top?(cosf(lBase)):0.0f);
443
444 unsigned int rowbegin = top?numRows/2:0;
445 unsigned int rowend = top?numRows:numRows/2;
446
447 for(unsigned int rowi=rowbegin; rowi<rowend; ++rowi)
448 {
449
450 float lTop = lBase+lDelta;
451 float rTop = cosf(lTop)*radius;
452 float zTop = sinf(lTop)*radius;
453 float vTop = vBase+vDelta;
454 float nzTop= sinf(lTop);
455 float nRatioTop= cosf(lTop);
456
457 Begin(GL_QUAD_STRIP);
458
459 float angle = 0.0f;
460 float texCoord = 0.0f;
461
462 // The only difference between the font & back face loops is that the
463 // normals are inverted and the order of the vertex pairs is reversed.
464 // The code is mostly duplicated in order to hoist the back/front face
465 // test out of the loop for efficiency
466
467 if (drawFrontFace) {
468 for(unsigned int topi=0; topi<numSegments;
469 ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
470 {
471
472 float c = cosf(angle);
473 float s = sinf(angle);
474
475 Normal3f(c*nRatioTop,s*nRatioTop,nzTop);
476 TexCoord2f(texCoord,vTop);
477 Vertex3f(c*rTop,s*rTop,zTop+zOffset);
478
479 Normal3f(c*nRatioBase,s*nRatioBase,nzBase);
480 TexCoord2f(texCoord,vBase);
481 Vertex3f(c*rBase,s*rBase,zBase+zOffset);
482
483 }
484
485 // do last point by hand to ensure no round off errors.
486 Normal3f(nRatioTop,0.0f,nzTop);
487 TexCoord2f(1.0f,vTop);
488 Vertex3f(rTop,0.0f,zTop+zOffset);
489
490 Normal3f(nRatioBase,0.0f,nzBase);
491 TexCoord2f(1.0f,vBase);
492 Vertex3f(rBase,0.0f,zBase+zOffset);
493 }
494
495 if (drawBackFace) {
496 for(unsigned int topi=0; topi<numSegments;
497 ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
498 {
499
500 float c = cosf(angle);
501 float s = sinf(angle);
502
503 Normal3f(-c*nRatioBase,-s*nRatioBase,-nzBase);
504 TexCoord2f(texCoord,vBase);
505 Vertex3f(c*rBase,s*rBase,zBase+zOffset);
506
507 Normal3f(-c*nRatioTop,-s*nRatioTop,-nzTop);
508 TexCoord2f(texCoord,vTop);
509 Vertex3f(c*rTop,s*rTop,zTop+zOffset);
510 }
511
512 // do last point by hand to ensure no round off errors.
513 Normal3f(-nRatioBase,0.0f,-nzBase);
514 TexCoord2f(1.0f,vBase);
515 Vertex3f(rBase,0.0f,zBase+zOffset);
516
517 Normal3f(-nRatioTop,0.0f,-nzTop);
518 TexCoord2f(1.0f,vTop);
519 Vertex3f(rTop,0.0f,zTop+zOffset);
520
521 }
522
523 End();
524
525 lBase=lTop;
526 rBase=rTop;
527 zBase=zTop;
528 vBase=vTop;
529 nzBase=nzTop;
530 nRatioBase=nRatioTop;
531
532 }
533 }
534
535
apply(const Sphere & sphere)536 void BuildShapeGeometryVisitor::apply(const Sphere& sphere)
537 {
538 bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
539 bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
540
541 setMatrix(Matrixd::translate(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z()));
542
543 unsigned int numSegments = 40;
544 unsigned int numRows = 20;
545 float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
546 if (ratio > 0.0f && ratio != 1.0f) {
547 numRows = (unsigned int) (numRows * ratio);
548 if (numRows < MIN_NUM_ROWS)
549 numRows = MIN_NUM_ROWS;
550 numSegments = (unsigned int) (numSegments * ratio);
551 if (numSegments < MIN_NUM_SEGMENTS)
552 numSegments = MIN_NUM_SEGMENTS;
553 }
554
555 float lDelta = PIf/(float)numRows;
556 float vDelta = 1.0f/(float)numRows;
557
558 float angleDelta = PIf*2.0f/(float)numSegments;
559 float texCoordHorzDelta = 1.0f/(float)numSegments;
560
561 if (drawBackFace)
562 {
563 float lBase=-PIf*0.5f;
564 float rBase=0.0f;
565 float zBase=-sphere.getRadius();
566 float vBase=0.0f;
567 float nzBase=-1.0f;
568 float nRatioBase=0.0f;
569
570 for(unsigned int rowi=0; rowi<numRows; ++rowi)
571 {
572
573 float lTop = lBase+lDelta;
574 float rTop = cosf(lTop)*sphere.getRadius();
575 float zTop = sinf(lTop)*sphere.getRadius();
576 float vTop = vBase+vDelta;
577 float nzTop= sinf(lTop);
578 float nRatioTop= cosf(lTop);
579
580 Begin(GL_QUAD_STRIP);
581
582 float angle = 0.0f;
583 float texCoord = 0.0f;
584
585 for(unsigned int topi=0; topi<numSegments;
586 ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
587 {
588
589 float c = cosf(angle);
590 float s = sinf(angle);
591
592 Normal3f(-c*nRatioBase,-s*nRatioBase,-nzBase);
593 TexCoord2f(texCoord,vBase);
594 Vertex3f(c*rBase,s*rBase,zBase);
595
596 Normal3f(-c*nRatioTop,-s*nRatioTop,-nzTop);
597
598 TexCoord2f(texCoord,vTop);
599 Vertex3f(c*rTop,s*rTop,zTop);
600
601
602 }
603
604
605 // do last point by hand to ensure no round off errors.
606 Normal3f(-nRatioBase,0.0f,-nzBase);
607 TexCoord2f(1.0f,vBase);
608 Vertex3f(rBase,0.0f,zBase);
609
610 Normal3f(-nRatioTop,0.0f,-nzTop);
611 TexCoord2f(1.0f,vTop);
612 Vertex3f(rTop,0.0f,zTop);
613
614 End();
615
616
617 lBase=lTop;
618 rBase=rTop;
619 zBase=zTop;
620 vBase=vTop;
621 nzBase=nzTop;
622 nRatioBase=nRatioTop;
623
624 }
625 }
626
627
628 if (drawFrontFace)
629 {
630 float lBase=-PIf*0.5f;
631 float rBase=0.0f;
632 float zBase=-sphere.getRadius();
633 float vBase=0.0f;
634 float nzBase=-1.0f;
635 float nRatioBase=0.0f;
636
637 for(unsigned int rowi=0; rowi<numRows; ++rowi)
638 {
639
640 float lTop = lBase+lDelta;
641 float rTop = cosf(lTop)*sphere.getRadius();
642 float zTop = sinf(lTop)*sphere.getRadius();
643 float vTop = vBase+vDelta;
644 float nzTop= sinf(lTop);
645 float nRatioTop= cosf(lTop);
646
647 Begin(GL_QUAD_STRIP);
648
649 float angle = 0.0f;
650 float texCoord = 0.0f;
651
652 for(unsigned int topi=0; topi<numSegments;
653 ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
654 {
655
656 float c = cosf(angle);
657 float s = sinf(angle);
658
659 Normal3f(c*nRatioTop,s*nRatioTop,nzTop);
660 TexCoord2f(texCoord,vTop);
661 Vertex3f(c*rTop,s*rTop,zTop);
662
663 Normal3f(c*nRatioBase,s*nRatioBase,nzBase);
664 TexCoord2f(texCoord,vBase);
665 Vertex3f(c*rBase,s*rBase,zBase);
666 }
667
668 // do last point by hand to ensure no round off errors.
669 Normal3f(nRatioTop,0.0f,nzTop);
670 TexCoord2f(1.0f,vTop);
671 Vertex3f(rTop,0.0f,zTop);
672
673 Normal3f(nRatioBase,0.0f,nzBase);
674 TexCoord2f(1.0f,vBase);
675 Vertex3f(rBase,0.0f,zBase);
676
677 End();
678
679
680 lBase=lTop;
681 rBase=rTop;
682 zBase=zTop;
683 vBase=vTop;
684 nzBase=nzTop;
685 nRatioBase=nRatioTop;
686
687 }
688 }
689
690 }
691
apply(const Box & box)692 void BuildShapeGeometryVisitor::apply(const Box& box)
693 {
694 // evaluate hints
695 bool createBody = (_hints ? _hints->getCreateBody() : true);
696 bool createTop = (_hints ? _hints->getCreateTop() : true);
697 bool createBottom = (_hints ? _hints->getCreateBottom() : true);
698
699 float dx = box.getHalfLengths().x();
700 float dy = box.getHalfLengths().y();
701 float dz = box.getHalfLengths().z();
702
703 setMatrix(box.computeRotationMatrix() * Matrixd::translate(box.getCenter()));
704
705 Begin(GL_QUADS);
706
707 if (createBody) {
708 // -ve y plane
709 Normal3f(0.0f,-1.0f,0.0f);
710 TexCoord2f(0.0f,1.0f);
711 Vertex3f(-dx,-dy,dz);
712
713 Normal3f(0.0f,-1.0f,0.0f);
714 TexCoord2f(0.0f,0.0f);
715 Vertex3f(-dx,-dy,-dz);
716
717 Normal3f(0.0f,-1.0f,0.0f);
718 TexCoord2f(1.0f,0.0f);
719 Vertex3f(dx,-dy,-dz);
720
721 Normal3f(0.0f,-1.0f,0.0f);
722 TexCoord2f(1.0f,1.0f);
723 Vertex3f(dx,-dy,dz);
724
725 // +ve y plane
726 Normal3f(0.0f,1.0f,0.0f);
727 TexCoord2f(0.0f,1.0f);
728 Vertex3f(dx,dy,dz);
729
730 Normal3f(0.0f,1.0f,0.0f);
731 TexCoord2f(0.0f,0.0f);
732 Vertex3f(dx,dy,-dz);
733
734 Normal3f(0.0f,1.0f,0.0f);
735 TexCoord2f(1.0f,0.0f);
736 Vertex3f(-dx,dy,-dz);
737
738 Normal3f(0.0f,1.0f,0.0f);
739 TexCoord2f(1.0f,1.0f);
740 Vertex3f(-dx,dy,dz);
741
742 // +ve x plane
743 Normal3f(1.0f,0.0f,0.0f);
744 TexCoord2f(0.0f,1.0f);
745 Vertex3f(dx,-dy,dz);
746
747 Normal3f(1.0f,0.0f,0.0f);
748 TexCoord2f(0.0f,0.0f);
749 Vertex3f(dx,-dy,-dz);
750
751 Normal3f(1.0f,0.0f,0.0f);
752 TexCoord2f(1.0f,0.0f);
753 Vertex3f(dx,dy,-dz);
754
755 Normal3f(1.0f,0.0f,0.0f);
756 TexCoord2f(1.0f,1.0f);
757 Vertex3f(dx,dy,dz);
758
759 // -ve x plane
760 Normal3f(-1.0f,0.0f,0.0f);
761 TexCoord2f(0.0f,1.0f);
762 Vertex3f(-dx,dy,dz);
763
764 Normal3f(-1.0f,0.0f,0.0f);
765 TexCoord2f(0.0f,0.0f);
766 Vertex3f(-dx,dy,-dz);
767
768 Normal3f(-1.0f,0.0f,0.0f);
769 TexCoord2f(1.0f,0.0f);
770 Vertex3f(-dx,-dy,-dz);
771
772 Normal3f(-1.0f,0.0f,0.0f);
773 TexCoord2f(1.0f,1.0f);
774 Vertex3f(-dx,-dy,dz);
775 }
776
777 if (createTop) {
778 // +ve z plane
779 Normal3f(0.0f,0.0f,1.0f);
780 TexCoord2f(0.0f,1.0f);
781 Vertex3f(-dx,dy,dz);
782
783 Normal3f(0.0f,0.0f,1.0f);
784 TexCoord2f(0.0f,0.0f);
785 Vertex3f(-dx,-dy,dz);
786
787 Normal3f(0.0f,0.0f,1.0f);
788 TexCoord2f(1.0f,0.0f);
789 Vertex3f(dx,-dy,dz);
790
791 Normal3f(0.0f,0.0f,1.0f);
792 TexCoord2f(1.0f,1.0f);
793 Vertex3f(dx,dy,dz);
794 }
795
796 if (createBottom) {
797 // -ve z plane
798 Normal3f(0.0f,0.0f,-1.0f);
799 TexCoord2f(0.0f,1.0f);
800 Vertex3f(dx,dy,-dz);
801
802 Normal3f(0.0f,0.0f,-1.0f);
803 TexCoord2f(0.0f,0.0f);
804 Vertex3f(dx,-dy,-dz);
805
806 Normal3f(0.0f,0.0f,-1.0f);
807 TexCoord2f(1.0f,0.0f);
808 Vertex3f(-dx,-dy,-dz);
809
810 Normal3f(0.0f,0.0f,-1.0f);
811 TexCoord2f(1.0f,1.0f);
812 Vertex3f(-dx,dy,-dz);
813 }
814
815 End();
816 }
817
apply(const Cone & cone)818 void BuildShapeGeometryVisitor::apply(const Cone& cone)
819 {
820 setMatrix(cone.computeRotationMatrix() * Matrixd::translate(cone.getCenter()));
821
822 // evaluate hints
823 bool createBody = (_hints ? _hints->getCreateBody() : true);
824 bool createBottom = (_hints ? _hints->getCreateBottom() : true);
825
826 unsigned int numSegments = 40;
827 unsigned int numRows = 10;
828 float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
829 if (ratio > 0.0f && ratio != 1.0f) {
830 numRows = (unsigned int) (numRows * ratio);
831 if (numRows < MIN_NUM_ROWS)
832 numRows = MIN_NUM_ROWS;
833 numSegments = (unsigned int) (numSegments * ratio);
834 if (numSegments < MIN_NUM_SEGMENTS)
835 numSegments = MIN_NUM_SEGMENTS;
836 }
837
838 float r = cone.getRadius();
839 float h = cone.getHeight();
840
841 float normalz = r/(sqrtf(r*r+h*h));
842 float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz));
843 normalz *= normalRatio;
844
845 float angleDelta = 2.0f*PIf/(float)numSegments;
846 float texCoordHorzDelta = 1.0/(float)numSegments;
847 float texCoordRowDelta = 1.0/(float)numRows;
848 float hDelta = cone.getHeight()/(float)numRows;
849 float rDelta = cone.getRadius()/(float)numRows;
850
851 float topz=cone.getHeight()+cone.getBaseOffset();
852 float topr=0.0f;
853 float topv=1.0f;
854 float basez=topz-hDelta;
855 float baser=rDelta;
856 float basev=topv-texCoordRowDelta;
857 float angle;
858 float texCoord;
859
860 if (createBody) {
861 for(unsigned int rowi=0; rowi<numRows;
862 ++rowi,topz=basez, basez-=hDelta, topr=baser, baser+=rDelta, topv=basev, basev-=texCoordRowDelta) {
863 // we can't use a fan for the cone top
864 // since we need different normals at the top
865 // for each face..
866 Begin(GL_QUAD_STRIP);
867
868 angle = 0.0f;
869 texCoord = 0.0f;
870 for(unsigned int topi=0; topi<numSegments;
871 ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta) {
872
873 float c = cosf(angle);
874 float s = sinf(angle);
875
876 Normal3f(c*normalRatio,s*normalRatio,normalz);
877 TexCoord2f(texCoord,topv);
878 Vertex3f(c*topr,s*topr,topz);
879
880 Normal3f(c*normalRatio,s*normalRatio,normalz);
881 TexCoord2f(texCoord,basev);
882 Vertex3f(c*baser,s*baser,basez);
883 }
884
885 // do last point by hand to ensure no round off errors.
886 Normal3f(normalRatio,0.0f,normalz);
887 TexCoord2f(1.0f,topv);
888 Vertex3f(topr,0.0f,topz);
889
890 Normal3f(normalRatio,0.0f,normalz);
891 TexCoord2f(1.0f,basev);
892 Vertex3f(baser,0.0f,basez);
893
894 End();
895 }
896 }
897
898 if (createBottom) {
899 Begin(GL_TRIANGLE_FAN);
900
901 angle = PIf*2.0f;
902 texCoord = 1.0f;
903 basez = cone.getBaseOffset();
904
905 Normal3f(0.0f,0.0f,-1.0f);
906 TexCoord2f(0.5f,0.5f);
907 Vertex3f(0.0f,0.0f,basez);
908
909 for(unsigned int bottomi=0;bottomi<numSegments;
910 ++bottomi,angle-=angleDelta,texCoord-=texCoordHorzDelta) {
911
912 float c = cosf(angle);
913 float s = sinf(angle);
914
915 Normal3f(0.0f,0.0f,-1.0f);
916 TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
917 Vertex3f(c*r,s*r,basez);
918 }
919
920 Normal3f(0.0f,0.0f,-1.0f);
921 TexCoord2f(1.0f,0.0f);
922 Vertex3f(r,0.0f,basez);
923
924 End();
925 }
926
927 }
928
apply(const Cylinder & cylinder)929 void BuildShapeGeometryVisitor::apply(const Cylinder& cylinder)
930 {
931 setMatrix(cylinder.computeRotationMatrix() * Matrixd::translate(cylinder.getCenter()));
932
933 // evaluate hints
934 bool createBody = (_hints ? _hints->getCreateBody() : true);
935 bool createTop = (_hints ? _hints->getCreateTop() : true);
936 bool createBottom = (_hints ? _hints->getCreateBottom() : true);
937
938 unsigned int numSegments = 40;
939 float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
940 if (ratio > 0.0f && ratio != 1.0f) {
941 numSegments = (unsigned int) (numSegments * ratio);
942 if (numSegments < MIN_NUM_SEGMENTS)
943 numSegments = MIN_NUM_SEGMENTS;
944 }
945
946
947 // cylinder body
948 if (createBody)
949 drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight());
950
951 float angleDelta = 2.0f*PIf/(float)numSegments;
952 float texCoordDelta = 1.0f/(float)numSegments;
953
954 float r = cylinder.getRadius();
955 float h = cylinder.getHeight();
956
957 float basez = -h*0.5f;
958 float topz = h*0.5f;
959
960 float angle = 0.0f;
961 float texCoord = 0.0f;
962
963
964 // cylinder top
965 if (createTop) {
966
967 Begin(GL_TRIANGLE_FAN);
968
969 Normal3f(0.0f,0.0f,1.0f);
970 TexCoord2f(0.5f,0.5f);
971 Vertex3f(0.0f,0.0f,topz);
972
973 angle = 0.0f;
974 texCoord = 0.0f;
975 for(unsigned int topi=0;
976 topi<numSegments;
977 ++topi,angle+=angleDelta,texCoord+=texCoordDelta)
978 {
979 float c = cosf(angle);
980 float s = sinf(angle);
981
982 Normal3f(0.0f,0.0f,1.0f);
983 TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
984 Vertex3f(c*r,s*r,topz);
985 }
986
987 Normal3f(0.0f,0.0f,1.0f);
988 TexCoord2f(1.0f,0.5f);
989 Vertex3f(r,0.0f,topz);
990
991 End();
992 }
993
994
995 // cylinder bottom
996 if (createBottom)
997 {
998 Begin(GL_TRIANGLE_FAN);
999
1000 Normal3f(0.0f,0.0f,-1.0f);
1001 TexCoord2f(0.5f,0.5f);
1002 Vertex3f(0.0f,0.0f,basez);
1003
1004 angle = PIf*2.0f;
1005 texCoord = 1.0f;
1006 for(unsigned int bottomi=0;
1007 bottomi<numSegments;
1008 ++bottomi,angle-=angleDelta,texCoord-=texCoordDelta)
1009 {
1010 float c = cosf(angle);
1011 float s = sinf(angle);
1012
1013 Normal3f(0.0f,0.0f,-1.0f);
1014 TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
1015 Vertex3f(c*r,s*r,basez);
1016 }
1017
1018 Normal3f(0.0f,0.0f,-1.0f);
1019 TexCoord2f(1.0f,0.5f);
1020 Vertex3f(r,0.0f,basez);
1021
1022 End();
1023 }
1024 }
1025
apply(const Capsule & capsule)1026 void BuildShapeGeometryVisitor::apply(const Capsule& capsule)
1027 {
1028 setMatrix(capsule.computeRotationMatrix() * Matrixd::translate(capsule.getCenter()));
1029
1030 // evaluate hints
1031 bool createBody = (_hints ? _hints->getCreateBody() : true);
1032 bool createTop = (_hints ? _hints->getCreateTop() : true);
1033 bool createBottom = (_hints ? _hints->getCreateBottom() : true);
1034
1035 unsigned int numSegments = 40;
1036 unsigned int numRows = 20;
1037 float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
1038 if (ratio > 0.0f && ratio != 1.0f) {
1039 numSegments = (unsigned int) (numSegments * ratio);
1040 if (numSegments < MIN_NUM_SEGMENTS)
1041 numSegments = MIN_NUM_SEGMENTS;
1042 numRows = (unsigned int) (numRows * ratio);
1043 if (numRows < MIN_NUM_ROWS)
1044 numRows = MIN_NUM_ROWS;
1045 }
1046
1047 // if numRows is odd the top and bottom halves of sphere won't match, so bump up to the next event numRows
1048 if ((numRows%2)!=0) ++numRows;
1049
1050 // capsule cylindrical body
1051 if (createBody)
1052 drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight());
1053
1054 // capsule top cap
1055 if (createTop)
1056 drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f);
1057
1058 // capsule bottom cap
1059 if (createBottom)
1060 drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f);
1061
1062 }
1063
apply(const InfinitePlane &)1064 void BuildShapeGeometryVisitor::apply(const InfinitePlane&)
1065 {
1066 OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor::apply(const InfinitePlane& plane) not yet implemented. "<<std::endl;
1067 }
1068
apply(const TriangleMesh & mesh)1069 void BuildShapeGeometryVisitor::apply(const TriangleMesh& mesh)
1070 {
1071 const Vec3Array* vertices = mesh.getVertices();
1072 const IndexArray* indices = mesh.getIndices();
1073
1074 if (vertices && indices)
1075 {
1076 Begin(GL_TRIANGLES);
1077
1078 for(unsigned int i=0;i+2<indices->getNumElements();i+=3)
1079 {
1080 const Vec3& v1=(*vertices)[indices->index(i)];
1081 const Vec3& v2=(*vertices)[indices->index(i+1)];
1082 const Vec3& v3=(*vertices)[indices->index(i+2)];
1083 Vec3 normal = (v2-v1)^(v3-v2);
1084 normal.normalize();
1085
1086 Normal(normal);
1087 Vertex(v1);
1088
1089 Normal(normal);
1090 Vertex(v2);
1091
1092 Normal(normal);
1093 Vertex(v3);
1094
1095 }
1096
1097 End();
1098 }
1099 }
1100
apply(const ConvexHull & hull)1101 void BuildShapeGeometryVisitor::apply(const ConvexHull& hull)
1102 {
1103 apply((const TriangleMesh&)hull);
1104 }
1105
apply(const HeightField & field)1106 void BuildShapeGeometryVisitor::apply(const HeightField& field)
1107 {
1108 if (field.getNumColumns()==0 || field.getNumRows()==0) return;
1109
1110 setMatrix(field.computeRotationMatrix() * Matrixd::translate(field.getOrigin()));
1111
1112 float dx = field.getXInterval();
1113 float dy = field.getYInterval();
1114
1115 float du = 1.0f/((float)field.getNumColumns()-1.0f);
1116 float dv = 1.0f/((float)field.getNumRows()-1.0f);
1117
1118 float vBase = 0.0f;
1119
1120 Vec3 vertTop;
1121 Vec3 normTop;
1122
1123 Vec3 vertBase;
1124 Vec3 normBase;
1125
1126 if (field.getSkirtHeight()!=0.0f)
1127 {
1128 Begin(GL_QUAD_STRIP);
1129
1130 float u = 0.0f;
1131
1132 // draw bottom skirt
1133 unsigned int col;
1134 vertTop.y() = 0.0f;
1135 for(col=0;col<field.getNumColumns();++col,u+=du)
1136 {
1137 vertTop.x() = dx*(float)col;
1138 vertTop.z() = field.getHeight(col,0);
1139 normTop.set(field.getNormal(col,0));
1140
1141 TexCoord2f(u,0.0f);
1142 Normal(normTop);
1143 Vertex(vertTop);
1144
1145 vertTop.z()-=field.getSkirtHeight();
1146
1147 TexCoord2f(u,0.0f);
1148 Normal(normTop);
1149 Vertex(vertTop);
1150 }
1151
1152 End();
1153
1154 // draw top skirt
1155 Begin(GL_QUAD_STRIP);
1156
1157 unsigned int row = field.getNumRows()-1;
1158
1159 u = 0.0f;
1160 vertTop.y() = dy*(float)(row);
1161 for(col=0;col<field.getNumColumns();++col,u+=du)
1162 {
1163 vertTop.x() = dx*(float)col;
1164 vertTop.z() = field.getHeight(col,row);
1165 normTop.set(field.getNormal(col,row));
1166
1167 TexCoord2f(u,1.0f);
1168 Normal(normTop);
1169 Vertex3f(vertTop.x(),vertTop.y(),vertTop.z()-field.getSkirtHeight());
1170
1171 //vertTop.z()-=field.getSkirtHeight();
1172
1173 TexCoord2f(u,1.0f);
1174 Normal(normTop);
1175 Vertex(vertTop);
1176 }
1177
1178 End();
1179 }
1180
1181
1182
1183 // draw each row of HeightField
1184 for(unsigned int row=0;row<field.getNumRows()-1;++row,vBase+=dv)
1185 {
1186
1187 float vTop = vBase+dv;
1188 float u = 0.0f;
1189
1190
1191 Begin(GL_QUAD_STRIP);
1192
1193 // draw skirt at beginning of this row if required.
1194 if (field.getSkirtHeight()!=0.0f)
1195 {
1196 vertTop.set(0.0f,dy*(float)(row+1),field.getHeight(0,row+1)-field.getSkirtHeight());
1197 normTop.set(field.getNormal(0,row+1));
1198
1199 vertBase.set(0.0f,dy*(float)row,field.getHeight(0,row)-field.getSkirtHeight());
1200 normBase.set(field.getNormal(0,row));
1201
1202 TexCoord2f(u,vTop);
1203 Normal(normTop);
1204 Vertex(vertTop);
1205
1206 TexCoord2f(u,vBase);
1207 Normal(normBase);
1208 Vertex(vertBase);
1209 }
1210
1211 // draw the actual row
1212 for(unsigned int col=0;col<field.getNumColumns();++col,u+=du)
1213 {
1214 vertTop.set(dx*(float)col,dy*(float)(row+1),field.getHeight(col,row+1));
1215 normTop.set(field.getNormal(col,row+1));
1216
1217 vertBase.set(dx*(float)col,dy*(float)row,field.getHeight(col,row));
1218 normBase.set(field.getNormal(col,row));
1219
1220 TexCoord2f(u,vTop);
1221 Normal(normTop);
1222 Vertex(vertTop);
1223
1224 TexCoord2f(u,vBase);
1225 Normal(normBase);
1226 Vertex(vertBase);
1227
1228 }
1229
1230 // draw skirt at end of this row if required.
1231 if (field.getSkirtHeight()!=0.0f)
1232 {
1233
1234 vertBase.z()-=field.getSkirtHeight();
1235 vertTop.z()-=field.getSkirtHeight();
1236
1237 TexCoord2f(u,vTop);
1238 Normal(normTop);
1239 Vertex(vertTop);
1240
1241 TexCoord2f(u,vBase);
1242 Normal(normBase);
1243 Vertex(vertBase);
1244 }
1245
1246 End();
1247 }
1248
1249 }
1250
apply(const CompositeShape & group)1251 void BuildShapeGeometryVisitor::apply(const CompositeShape& group)
1252 {
1253 for(unsigned int i=0;i<group.getNumChildren();++i)
1254 {
1255 group.getChild(i)->accept(*this);
1256 }
1257 }
1258
convertShapeToGeometry(const Shape & shape,const TessellationHints * hints)1259 Geometry* osg::convertShapeToGeometry(const Shape& shape, const TessellationHints* hints)
1260 {
1261 ref_ptr<Geometry> geometry = new Geometry;
1262
1263 BuildShapeGeometryVisitor buildGeometry(geometry.get(), hints);
1264 shape.accept( buildGeometry );
1265
1266 return geometry.release();
1267 }
1268
convertShapeToGeometry(const Shape & shape,const TessellationHints * hints,const Vec4 & color,Array::Binding colorBinding)1269 Geometry* osg::convertShapeToGeometry(const Shape& shape, const TessellationHints* hints, const Vec4& color, Array::Binding colorBinding)
1270 {
1271 ref_ptr<Geometry> geometry = convertShapeToGeometry(shape, hints);
1272
1273 unsigned int numColors = 0;
1274 switch(colorBinding)
1275 {
1276 case(Array::BIND_OVERALL): numColors = 1; break;
1277 case(Array::BIND_PER_VERTEX): numColors = geometry->getVertexArray()->getNumElements(); break;
1278 case(Array::BIND_PER_PRIMITIVE_SET): numColors = geometry->getPrimitiveSetList().size(); break;
1279 default: break;
1280 }
1281
1282 if (numColors>0)
1283 {
1284 ref_ptr<Vec4Array> colors = new Vec4Array(colorBinding);
1285 geometry->setColorArray(colors.get());
1286
1287 for(unsigned int i=0; i<numColors; ++i)
1288 {
1289 colors->push_back(color);
1290 }
1291 }
1292
1293 return geometry.release();
1294 }
1295