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