root/OpenSceneGraph/trunk/src/osg/ShapeDrawable.cpp @ 13041

Revision 13041, 53.9 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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/ShapeDrawable>
14#include <osg/GL>
15#include <osg/Notify>
16
17using namespace osg;
18
19// arbitrary minima for rows & segments
20const unsigned int MIN_NUM_ROWS = 3;
21const unsigned int MIN_NUM_SEGMENTS = 5;
22
23
24///////////////////////////////////////////////////////////////////////////////
25//
26// draw shape
27//
28
29class DrawShapeVisitor : public ConstShapeVisitor
30{
31    public:
32
33        DrawShapeVisitor(State& state,const TessellationHints* hints):
34            _state(state),
35            _hints(hints)
36        {
37#if 0
38            if (hints)
39            {
40                OSG_NOTICE<<"Warning: TessellationHints ignored in present osg::ShapeDrawable implementation."<<std::endl;
41            }
42#endif
43        }
44
45        virtual void apply(const Sphere&);
46        virtual void apply(const Box&);
47        virtual void apply(const Cone&);
48        virtual void apply(const Cylinder&);
49        virtual void apply(const Capsule&);
50        virtual void apply(const InfinitePlane&);
51
52        virtual void apply(const TriangleMesh&);
53        virtual void apply(const ConvexHull&);
54        virtual void apply(const HeightField&);
55
56        virtual void apply(const CompositeShape&);
57
58        State&                      _state;
59        const TessellationHints*    _hints;
60
61    protected:
62
63        DrawShapeVisitor& operator = (const DrawShapeVisitor&) { return *this; }
64
65        enum SphereHalf { SphereTopHalf, SphereBottomHalf };
66
67        // helpers for apply( Cylinder | Sphere | Capsule )
68        void drawCylinderBody(unsigned int numSegments, float radius, float height);
69        void drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset = 0.0f);
70};
71
72
73void DrawShapeVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height)
74{
75    const float angleDelta = 2.0f*osg::PI/(float)numSegments;
76    const float texCoordDelta = 1.0f/(float)numSegments;
77
78    const float r = radius;
79    const float h = height;
80
81    float basez = -h*0.5f;
82    float topz = h*0.5f;
83
84    float angle = 0.0f;
85    float texCoord = 0.0f;
86
87    bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
88    bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
89
90    // The only difference between the font & back face loops is that the
91    //  normals are inverted and the order of the vertex pairs is reversed.
92    //  The code is mostly duplicated in order to hoist the back/front face
93    //  test out of the loop for efficiency
94
95    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
96
97    gl.Begin(GL_QUAD_STRIP);
98
99    if (drawFrontFace) {
100
101      for(unsigned int bodyi=0;
102          bodyi<numSegments;
103          ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
104      {
105          float c = cosf(angle);
106          float s = sinf(angle);
107
108          gl.Normal3f(c,s,0.0f);
109
110          gl.TexCoord2f(texCoord,1.0f);
111          gl.Vertex3f(c*r,s*r,topz);
112
113          gl.TexCoord2f(texCoord,0.0f);
114          gl.Vertex3f(c*r,s*r,basez);
115      }
116
117      // do last point by hand to ensure no round off errors.
118      gl.Normal3f(1.0f,0.0f,0.0f);
119
120      gl.TexCoord2f(1.0f,1.0f);
121      gl.Vertex3f(r,0.0f,topz);
122
123      gl.TexCoord2f(1.0f,0.0f);
124      gl.Vertex3f(r,0.0f,basez);
125    }
126
127    if (drawBackFace) {
128      for(unsigned int bodyi=0;
129          bodyi<numSegments;
130          ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
131      {
132          float c = cosf(angle);
133          float s = sinf(angle);
134
135          gl.Normal3f(-c,-s,0.0f);
136
137          gl.TexCoord2f(texCoord,0.0f);
138          gl.Vertex3f(c*r,s*r,basez);
139
140          gl.TexCoord2f(texCoord,1.0f);
141          gl.Vertex3f(c*r,s*r,topz);
142      }
143
144      // do last point by hand to ensure no round off errors.
145      gl.Normal3f(-1.0f,0.0f,0.0f);
146
147      gl.TexCoord2f(1.0f,0.0f);
148      gl.Vertex3f(r,0.0f,basez);
149
150      gl.TexCoord2f(1.0f,1.0f);
151      gl.Vertex3f(r,0.0f,topz);
152    }
153
154    gl.End();
155}
156
157
158void DrawShapeVisitor::drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset)
159{
160    float lDelta = osg::PI/(float)numRows;
161    float vDelta = 1.0f/(float)numRows;
162
163    bool top = (which==SphereTopHalf);
164
165    bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
166    bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
167
168    float angleDelta = osg::PI*2.0f/(float)numSegments;
169    float texCoordHorzDelta = 1.0f/(float)numSegments;
170
171    float lBase=-osg::PI*0.5f + (top?(lDelta*(numRows/2)):0.0f);
172    float rBase=(top?(cosf(lBase)*radius):0.0f);
173    float zBase=(top?(sinf(lBase)*radius):-radius);
174    float vBase=(top?(vDelta*(numRows/2)):0.0f);
175    float nzBase=(top?(sinf(lBase)):-1.0f);
176    float nRatioBase=(top?(cosf(lBase)):0.0f);
177
178    unsigned int rowbegin = top?numRows/2:0;
179    unsigned int rowend   = top?numRows:numRows/2;
180
181    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
182
183    for(unsigned int rowi=rowbegin; rowi<rowend; ++rowi)
184    {
185
186        float lTop = lBase+lDelta;
187        float rTop = cosf(lTop)*radius;
188        float zTop = sinf(lTop)*radius;
189        float vTop = vBase+vDelta;
190        float nzTop= sinf(lTop);
191        float nRatioTop= cosf(lTop);
192
193        gl.Begin(GL_QUAD_STRIP);
194
195            float angle = 0.0f;
196            float texCoord = 0.0f;
197
198            // The only difference between the font & back face loops is that the
199            //  normals are inverted and the order of the vertex pairs is reversed.
200            //  The code is mostly duplicated in order to hoist the back/front face
201            //  test out of the loop for efficiency
202
203            if (drawFrontFace) {
204              for(unsigned int topi=0; topi<numSegments;
205                  ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
206              {
207
208                  float c = cosf(angle);
209                  float s = sinf(angle);
210
211                  gl.Normal3f(c*nRatioTop,s*nRatioTop,nzTop);
212
213                  gl.TexCoord2f(texCoord,vTop);
214                  gl.Vertex3f(c*rTop,s*rTop,zTop+zOffset);
215
216                  gl.Normal3f(c*nRatioBase,s*nRatioBase,nzBase);
217
218                  gl.TexCoord2f(texCoord,vBase);
219                  gl.Vertex3f(c*rBase,s*rBase,zBase+zOffset);
220
221              }
222
223              // do last point by hand to ensure no round off errors.
224              gl.Normal3f(nRatioTop,0.0f,nzTop);
225
226              gl.TexCoord2f(1.0f,vTop);
227              gl.Vertex3f(rTop,0.0f,zTop+zOffset);
228
229              gl.Normal3f(nRatioBase,0.0f,nzBase);
230
231              gl.TexCoord2f(1.0f,vBase);
232              gl.Vertex3f(rBase,0.0f,zBase+zOffset);
233            }
234
235          if (drawBackFace) {
236              for(unsigned int topi=0; topi<numSegments;
237                  ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
238              {
239
240                  float c = cosf(angle);
241                  float s = sinf(angle);
242
243                  gl.Normal3f(-c*nRatioBase,-s*nRatioBase,-nzBase);
244
245                  gl.TexCoord2f(texCoord,vBase);
246                  gl.Vertex3f(c*rBase,s*rBase,zBase+zOffset);
247
248                  gl.Normal3f(-c*nRatioTop,-s*nRatioTop,-nzTop);
249
250                  gl.TexCoord2f(texCoord,vTop);
251                  gl.Vertex3f(c*rTop,s*rTop,zTop+zOffset);
252              }
253
254              // do last point by hand to ensure no round off errors.
255              gl.Normal3f(-nRatioBase,0.0f,-nzBase);
256
257              gl.TexCoord2f(1.0f,vBase);
258              gl.Vertex3f(rBase,0.0f,zBase+zOffset);
259
260              gl.Normal3f(-nRatioTop,0.0f,-nzTop);
261
262              gl.TexCoord2f(1.0f,vTop);
263              gl.Vertex3f(rTop,0.0f,zTop+zOffset);
264
265          }
266
267        gl.End();
268
269        lBase=lTop;
270        rBase=rTop;
271        zBase=zTop;
272        vBase=vTop;
273        nzBase=nzTop;
274        nRatioBase=nRatioTop;
275
276    }
277}
278
279
280void DrawShapeVisitor::apply(const Sphere& sphere)
281{
282    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
283
284    gl.PushMatrix();
285
286    gl.Translated(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z());
287
288    bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
289    bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
290
291    unsigned int numSegments = 40;
292    unsigned int numRows = 20;
293    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
294    if (ratio > 0.0f && ratio != 1.0f) {
295        numRows = (unsigned int) (numRows * ratio);
296        if (numRows < MIN_NUM_ROWS)
297            numRows = MIN_NUM_ROWS;
298        numSegments = (unsigned int) (numSegments * ratio);
299        if (numSegments < MIN_NUM_SEGMENTS)
300            numSegments = MIN_NUM_SEGMENTS;
301    }
302
303    float lDelta = osg::PI/(float)numRows;
304    float vDelta = 1.0f/(float)numRows;
305
306    float angleDelta = osg::PI*2.0f/(float)numSegments;
307    float texCoordHorzDelta = 1.0f/(float)numSegments;
308
309    gl.Begin(GL_QUAD_STRIP);
310
311    if (drawBackFace)
312    {
313        float lBase=-osg::PI*0.5f;
314        float rBase=0.0f;
315        float zBase=-sphere.getRadius();
316        float vBase=0.0f;
317        float nzBase=-1.0f;
318        float nRatioBase=0.0f;
319
320        for(unsigned int rowi=0; rowi<numRows; ++rowi)
321        {
322
323            float lTop = lBase+lDelta;
324            float rTop = cosf(lTop)*sphere.getRadius();
325            float zTop = sinf(lTop)*sphere.getRadius();
326            float vTop = vBase+vDelta;
327            float nzTop= sinf(lTop);
328            float nRatioTop= cosf(lTop);
329
330            gl.Begin(GL_QUAD_STRIP);
331
332                float angle = 0.0f;
333                float texCoord = 0.0f;
334
335                for(unsigned int topi=0; topi<numSegments;
336                    ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
337                {
338
339                    float c = cosf(angle);
340                    float s = sinf(angle);
341
342                    gl.Normal3f(-c*nRatioBase,-s*nRatioBase,-nzBase);
343
344                    gl.TexCoord2f(texCoord,vBase);
345                    gl.Vertex3f(c*rBase,s*rBase,zBase);
346
347                    gl.Normal3f(-c*nRatioTop,-s*nRatioTop,-nzTop);
348
349                    gl.TexCoord2f(texCoord,vTop);
350                    gl.Vertex3f(c*rTop,s*rTop,zTop);
351
352
353                }
354
355
356                // do last point by hand to ensure no round off errors.
357                gl.Normal3f(-nRatioBase,0.0f,-nzBase);
358
359                gl.TexCoord2f(1.0f,vBase);
360                gl.Vertex3f(rBase,0.0f,zBase);
361
362                gl.Normal3f(-nRatioTop,0.0f,-nzTop);
363
364                gl.TexCoord2f(1.0f,vTop);
365                gl.Vertex3f(rTop,0.0f,zTop);
366
367            gl.End();
368
369
370            lBase=lTop;
371            rBase=rTop;
372            zBase=zTop;
373            vBase=vTop;
374            nzBase=nzTop;
375            nRatioBase=nRatioTop;
376
377        }
378    }
379
380
381    if (drawFrontFace)
382    {
383        float lBase=-osg::PI*0.5f;
384        float rBase=0.0f;
385        float zBase=-sphere.getRadius();
386        float vBase=0.0f;
387        float nzBase=-1.0f;
388        float nRatioBase=0.0f;
389
390        for(unsigned int rowi=0; rowi<numRows; ++rowi)
391        {
392
393            float lTop = lBase+lDelta;
394            float rTop = cosf(lTop)*sphere.getRadius();
395            float zTop = sinf(lTop)*sphere.getRadius();
396            float vTop = vBase+vDelta;
397            float nzTop= sinf(lTop);
398            float nRatioTop= cosf(lTop);
399
400            gl.Begin(GL_QUAD_STRIP);
401
402                float angle = 0.0f;
403                float texCoord = 0.0f;
404
405                for(unsigned int topi=0; topi<numSegments;
406                    ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
407                {
408
409                    float c = cosf(angle);
410                    float s = sinf(angle);
411
412                    gl.Normal3f(c*nRatioTop,s*nRatioTop,nzTop);
413
414                    gl.TexCoord2f(texCoord,vTop);
415                    gl.Vertex3f(c*rTop,s*rTop,zTop);
416
417                    gl.Normal3f(c*nRatioBase,s*nRatioBase,nzBase);
418
419                    gl.TexCoord2f(texCoord,vBase);
420                    gl.Vertex3f(c*rBase,s*rBase,zBase);
421
422                }
423
424                // do last point by hand to ensure no round off errors.
425                gl.Normal3f(nRatioTop,0.0f,nzTop);
426
427                gl.TexCoord2f(1.0f,vTop);
428                gl.Vertex3f(rTop,0.0f,zTop);
429
430                gl.Normal3f(nRatioBase,0.0f,nzBase);
431
432                gl.TexCoord2f(1.0f,vBase);
433                gl.Vertex3f(rBase,0.0f,zBase);
434
435            gl.End();
436
437
438            lBase=lTop;
439            rBase=rTop;
440            zBase=zTop;
441            vBase=vTop;
442            nzBase=nzTop;
443            nRatioBase=nRatioTop;
444
445        }
446    }
447
448    gl.PopMatrix();
449}
450
451void DrawShapeVisitor::apply(const Box& box)
452{
453    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
454
455    // evaluate hints
456    bool createBody = (_hints ? _hints->getCreateBody() : true);
457    bool createTop = (_hints ? _hints->getCreateTop() : true);
458    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
459
460    float dx = box.getHalfLengths().x();
461    float dy = box.getHalfLengths().y();
462    float dz = box.getHalfLengths().z();
463
464    gl.PushMatrix();
465
466    gl.Translated(box.getCenter().x(),box.getCenter().y(),box.getCenter().z());
467
468    if (!box.zeroRotation())
469    {
470        Matrixd rotation(box.computeRotationMatrix());
471        gl.MultMatrixd(rotation.ptr());
472    }
473
474    gl.Begin(GL_QUADS);
475
476    if (createBody) {
477        // -ve y plane
478        gl.Normal3f(0.0f,-1.0f,0.0f);
479
480        gl.TexCoord2f(0.0f,1.0f);
481        gl.Vertex3f(-dx,-dy,dz);
482
483        gl.TexCoord2f(0.0f,0.0f);
484        gl.Vertex3f(-dx,-dy,-dz);
485
486        gl.TexCoord2f(1.0f,0.0f);
487        gl.Vertex3f(dx,-dy,-dz);
488
489        gl.TexCoord2f(1.0f,1.0f);
490        gl.Vertex3f(dx,-dy,dz);
491
492        // +ve y plane
493        gl.Normal3f(0.0f,1.0f,0.0f);
494
495        gl.TexCoord2f(0.0f,1.0f);
496        gl.Vertex3f(dx,dy,dz);
497
498        gl.TexCoord2f(0.0f,0.0f);
499        gl.Vertex3f(dx,dy,-dz);
500
501        gl.TexCoord2f(1.0f,0.0f);
502        gl.Vertex3f(-dx,dy,-dz);
503
504        gl.TexCoord2f(1.0f,1.0f);
505        gl.Vertex3f(-dx,dy,dz);
506
507        // +ve x plane
508        gl.Normal3f(1.0f,0.0f,0.0f);
509
510        gl.TexCoord2f(0.0f,1.0f);
511        gl.Vertex3f(dx,-dy,dz);
512
513        gl.TexCoord2f(0.0f,0.0f);
514        gl.Vertex3f(dx,-dy,-dz);
515
516        gl.TexCoord2f(1.0f,0.0f);
517        gl.Vertex3f(dx,dy,-dz);
518
519        gl.TexCoord2f(1.0f,1.0f);
520        gl.Vertex3f(dx,dy,dz);
521
522        // -ve x plane
523        gl.Normal3f(-1.0f,0.0f,0.0f);
524
525        gl.TexCoord2f(0.0f,1.0f);
526        gl.Vertex3f(-dx,dy,dz);
527
528        gl.TexCoord2f(0.0f,0.0f);
529        gl.Vertex3f(-dx,dy,-dz);
530
531        gl.TexCoord2f(1.0f,0.0f);
532        gl.Vertex3f(-dx,-dy,-dz);
533
534        gl.TexCoord2f(1.0f,1.0f);
535        gl.Vertex3f(-dx,-dy,dz);
536    }
537
538    if (createTop) {
539        // +ve z plane
540        gl.Normal3f(0.0f,0.0f,1.0f);
541
542        gl.TexCoord2f(0.0f,1.0f);
543        gl.Vertex3f(-dx,dy,dz);
544
545        gl.TexCoord2f(0.0f,0.0f);
546        gl.Vertex3f(-dx,-dy,dz);
547
548        gl.TexCoord2f(1.0f,0.0f);
549        gl.Vertex3f(dx,-dy,dz);
550
551        gl.TexCoord2f(1.0f,1.0f);
552        gl.Vertex3f(dx,dy,dz);
553    }
554
555    if (createBottom) {
556        // -ve z plane
557        gl.Normal3f(0.0f,0.0f,-1.0f);
558
559        gl.TexCoord2f(0.0f,1.0f);
560        gl.Vertex3f(dx,dy,-dz);
561
562        gl.TexCoord2f(0.0f,0.0f);
563        gl.Vertex3f(dx,-dy,-dz);
564
565        gl.TexCoord2f(1.0f,0.0f);
566        gl.Vertex3f(-dx,-dy,-dz);
567
568        gl.TexCoord2f(1.0f,1.0f);
569        gl.Vertex3f(-dx,dy,-dz);
570    }
571
572    gl.End();
573
574    gl.PopMatrix();
575
576}
577
578void DrawShapeVisitor::apply(const Cone& cone)
579{
580    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
581
582    gl.PushMatrix();
583
584    gl.Translated(cone.getCenter().x(),cone.getCenter().y(),cone.getCenter().z());
585
586    if (!cone.zeroRotation())
587    {
588        Matrixd rotation(cone.computeRotationMatrix());
589        gl.MultMatrixd(rotation.ptr());
590    }
591
592    // evaluate hints
593    bool createBody = (_hints ? _hints->getCreateBody() : true);
594    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
595
596    unsigned int numSegments = 40;
597    unsigned int numRows = 10;
598    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
599    if (ratio > 0.0f && ratio != 1.0f) {
600        numRows = (unsigned int) (numRows * ratio);
601        if (numRows < MIN_NUM_ROWS)
602            numRows = MIN_NUM_ROWS;
603        numSegments = (unsigned int) (numSegments * ratio);
604        if (numSegments < MIN_NUM_SEGMENTS)
605            numSegments = MIN_NUM_SEGMENTS;
606    }
607
608    float r = cone.getRadius();
609    float h = cone.getHeight();
610
611    float normalz = r/(sqrtf(r*r+h*h));
612    float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz));
613    normalz *= normalRatio;
614
615    float angleDelta = 2.0f*osg::PI/(float)numSegments;
616    float texCoordHorzDelta = 1.0/(float)numSegments;
617    float texCoordRowDelta = 1.0/(float)numRows;
618    float hDelta = cone.getHeight()/(float)numRows;
619    float rDelta = cone.getRadius()/(float)numRows;
620
621    float topz=cone.getHeight()+cone.getBaseOffset();
622    float topr=0.0f;
623    float topv=1.0f;
624    float basez=topz-hDelta;
625    float baser=rDelta;
626    float basev=topv-texCoordRowDelta;
627    float angle;
628    float texCoord;
629
630    if (createBody) {
631        for(unsigned int rowi=0; rowi<numRows;
632            ++rowi,topz=basez, basez-=hDelta, topr=baser, baser+=rDelta, topv=basev, basev-=texCoordRowDelta) {
633                // we can't use a fan for the cone top
634                // since we need different normals at the top
635                // for each face..
636                gl.Begin(GL_QUAD_STRIP);
637
638                angle = 0.0f;
639                texCoord = 0.0f;
640                for(unsigned int topi=0; topi<numSegments;
641                    ++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta) {
642
643                    float c = cosf(angle);
644                    float s = sinf(angle);
645
646                    gl.Normal3f(c*normalRatio,s*normalRatio,normalz);
647
648                    gl.TexCoord2f(texCoord,topv);
649                    gl.Vertex3f(c*topr,s*topr,topz);
650
651                    gl.TexCoord2f(texCoord,basev);
652                    gl.Vertex3f(c*baser,s*baser,basez);
653                }
654
655                // do last point by hand to ensure no round off errors.
656                gl.Normal3f(normalRatio,0.0f,normalz);
657
658                gl.TexCoord2f(1.0f,topv);
659                gl.Vertex3f(topr,0.0f,topz);
660
661                gl.TexCoord2f(1.0f,basev);
662                gl.Vertex3f(baser,0.0f,basez);
663
664                gl.End();
665        }
666    }
667
668    if (createBottom) {
669        gl.Begin(GL_TRIANGLE_FAN);
670
671        angle = osg::PI*2.0f;
672        texCoord = 1.0f;
673        basez = cone.getBaseOffset();
674
675        gl.Normal3f(0.0f,0.0f,-1.0f);
676        gl.TexCoord2f(0.5f,0.5f);
677        gl.Vertex3f(0.0f,0.0f,basez);
678
679        for(unsigned int bottomi=0;bottomi<numSegments;
680            ++bottomi,angle-=angleDelta,texCoord-=texCoordHorzDelta) {
681
682            float c = cosf(angle);
683            float s = sinf(angle);
684
685            gl.TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
686            gl.Vertex3f(c*r,s*r,basez);
687        }
688
689        gl.TexCoord2f(1.0f,0.0f);
690        gl.Vertex3f(r,0.0f,basez);
691
692        gl.End();
693    }
694
695    gl.PopMatrix();
696}
697
698void DrawShapeVisitor::apply(const Cylinder& cylinder)
699{
700    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
701
702    gl.PushMatrix();
703
704    gl.Translated(cylinder.getCenter().x(),cylinder.getCenter().y(),cylinder.getCenter().z());
705
706    if (!cylinder.zeroRotation())
707    {
708        Matrixd rotation(cylinder.computeRotationMatrix());
709        gl.MultMatrixd(rotation.ptr());
710    }
711
712    // evaluate hints
713    bool createBody = (_hints ? _hints->getCreateBody() : true);
714    bool createTop = (_hints ? _hints->getCreateTop() : true);
715    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
716
717    unsigned int numSegments = 40;
718    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
719    if (ratio > 0.0f && ratio != 1.0f) {
720        numSegments = (unsigned int) (numSegments * ratio);
721        if (numSegments < MIN_NUM_SEGMENTS)
722            numSegments = MIN_NUM_SEGMENTS;
723    }
724
725
726    // cylinder body
727    if (createBody)
728        drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight());
729
730    float angleDelta = 2.0f*osg::PI/(float)numSegments;
731    float texCoordDelta = 1.0f/(float)numSegments;
732
733    float r = cylinder.getRadius();
734    float h = cylinder.getHeight();
735
736    float basez = -h*0.5f;
737    float topz = h*0.5f;
738
739    float angle = 0.0f;
740    float texCoord = 0.0f;
741
742    // cylinder top
743    if (createTop) {
744        gl.Begin(GL_TRIANGLE_FAN);
745
746        gl.Normal3f(0.0f,0.0f,1.0f);
747        gl.TexCoord2f(0.5f,0.5f);
748        gl.Vertex3f(0.0f,0.0f,topz);
749
750        angle = 0.0f;
751        texCoord = 0.0f;
752        for(unsigned int topi=0;
753            topi<numSegments;
754            ++topi,angle+=angleDelta,texCoord+=texCoordDelta)
755        {
756            float c = cosf(angle);
757            float s = sinf(angle);
758
759            gl.TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
760            gl.Vertex3f(c*r,s*r,topz);
761        }
762
763        gl.TexCoord2f(1.0f,0.5f);
764        gl.Vertex3f(r,0.0f,topz);
765
766        gl.End();
767    }
768
769    // cylinder bottom
770    if (createBottom)
771    {
772        gl.Begin(GL_TRIANGLE_FAN);
773
774        gl.Normal3f(0.0f,0.0f,-1.0f);
775        gl.TexCoord2f(0.5f,0.5f);
776        gl.Vertex3f(0.0f,0.0f,basez);
777
778        angle = osg::PI*2.0f;
779        texCoord = 1.0f;
780        for(unsigned int bottomi=0;
781            bottomi<numSegments;
782            ++bottomi,angle-=angleDelta,texCoord-=texCoordDelta)
783        {
784            float c = cosf(angle);
785            float s = sinf(angle);
786
787            gl.TexCoord2f(c*0.5f+0.5f,s*0.5f+0.5f);
788            gl.Vertex3f(c*r,s*r,basez);
789        }
790
791        gl.TexCoord2f(1.0f,0.5f);
792        gl.Vertex3f(r,0.0f,basez);
793
794        gl.End();
795    }
796
797    gl.PopMatrix();
798}
799
800void DrawShapeVisitor::apply(const Capsule& capsule)
801{
802    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
803
804    gl.PushMatrix();
805
806    gl.Translated(capsule.getCenter().x(),capsule.getCenter().y(),capsule.getCenter().z());
807
808    if (!capsule.zeroRotation())
809    {
810        Matrixd rotation(capsule.computeRotationMatrix());
811        gl.MultMatrixd(rotation.ptr());
812    }
813
814    // evaluate hints
815    bool createBody = (_hints ? _hints->getCreateBody() : true);
816    bool createTop = (_hints ? _hints->getCreateTop() : true);
817    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
818
819    unsigned int numSegments = 40;
820    unsigned int numRows = 20;
821    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
822    if (ratio > 0.0f && ratio != 1.0f) {
823        numSegments = (unsigned int) (numSegments * ratio);
824        if (numSegments < MIN_NUM_SEGMENTS)
825            numSegments = MIN_NUM_SEGMENTS;
826        numRows = (unsigned int) (numRows * ratio);
827        if (numRows < MIN_NUM_ROWS)
828            numRows = MIN_NUM_ROWS;
829    }
830
831
832    // capsule cylindrical body
833    if (createBody)
834        drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight());
835
836    // capsule top cap
837    if (createTop)
838        drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f);
839
840    // capsule bottom cap
841    if (createBottom)
842        drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f);
843
844    gl.PopMatrix();
845}
846
847void DrawShapeVisitor::apply(const InfinitePlane&)
848{
849    OSG_NOTICE<<"Warning: DrawShapeVisitor::apply(const InfinitePlane& plane) not yet implemented. "<<std::endl;
850}
851
852void DrawShapeVisitor::apply(const TriangleMesh& mesh)
853{
854    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
855
856    const Vec3Array* vertices = mesh.getVertices();
857    const IndexArray* indices = mesh.getIndices();
858
859     if (vertices && indices)
860     {
861        gl.Begin(GL_TRIANGLES);
862
863        for(unsigned int i=0;i+2<indices->getNumElements();i+=3)
864        {
865            const osg::Vec3& v1=(*vertices)[indices->index(i)];
866            const osg::Vec3& v2=(*vertices)[indices->index(i+1)];
867            const osg::Vec3& v3=(*vertices)[indices->index(i+2)];
868            Vec3 normal = (v2-v1)^(v3-v2);
869            normal.normalize();
870
871            gl.Normal3fv(normal.ptr());
872            gl.Vertex3fv(v1.ptr());
873            gl.Vertex3fv(v2.ptr());
874            gl.Vertex3fv(v3.ptr());
875
876        }
877
878        gl.End();
879    }
880}
881
882void DrawShapeVisitor::apply(const ConvexHull& hull)
883{
884    apply((const TriangleMesh&)hull);
885}
886
887void DrawShapeVisitor::apply(const HeightField& field)
888{
889    if (field.getNumColumns()==0 || field.getNumRows()==0) return;
890
891    GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();
892
893    gl.PushMatrix();
894
895    gl.Translated(field.getOrigin().x(),field.getOrigin().y(),field.getOrigin().z());
896
897
898    if (!field.zeroRotation())
899    {
900        Matrixd rotation(field.computeRotationMatrix());
901        gl.MultMatrixd(rotation.ptr());
902    }
903
904    float dx = field.getXInterval();
905    float dy = field.getYInterval();
906
907    float du = 1.0f/((float)field.getNumColumns()-1.0f);
908    float dv = 1.0f/((float)field.getNumRows()-1.0f);
909
910    float vBase = 0.0f;
911
912    Vec3 vertTop;
913    Vec3 normTop;
914
915    Vec3 vertBase;
916    Vec3 normBase;
917
918    if (field.getSkirtHeight()!=0.0f)
919    {
920        gl.Begin(GL_QUAD_STRIP);
921
922        float u = 0.0f;
923
924        // draw bottom skirt
925        unsigned int col;
926        vertTop.y() = 0.0f;
927        for(col=0;col<field.getNumColumns();++col,u+=du)
928        {
929            vertTop.x() = dx*(float)col;
930            vertTop.z() = field.getHeight(col,0);
931            normTop.set(field.getNormal(col,0));
932
933            gl.TexCoord2f(u,0.0f);
934            gl.Normal3fv(normTop.ptr());
935
936            gl.Vertex3fv(vertTop.ptr());
937
938            vertTop.z()-=field.getSkirtHeight();
939
940            gl.Vertex3fv(vertTop.ptr());
941        }
942
943        gl.End();
944
945        // draw top skirt
946        gl.Begin(GL_QUAD_STRIP);
947
948        unsigned int row = field.getNumRows()-1;
949
950        u = 0.0f;
951        vertTop.y() = dy*(float)(row);
952        for(col=0;col<field.getNumColumns();++col,u+=du)
953        {
954            vertTop.x() = dx*(float)col;
955            vertTop.z() = field.getHeight(col,row);
956            normTop.set(field.getNormal(col,row));
957
958            gl.TexCoord2f(u,1.0f);
959            gl.Normal3fv(normTop.ptr());
960
961            gl.Vertex3f(vertTop.x(),vertTop.y(),vertTop.z()-field.getSkirtHeight());
962
963            //vertTop.z()-=field.getSkirtHeight();
964
965            gl.Vertex3fv(vertTop.ptr());
966        }
967
968        gl.End();
969    }
970
971
972
973    // draw each row of HeightField
974    for(unsigned int row=0;row<field.getNumRows()-1;++row,vBase+=dv)
975    {
976
977        float vTop = vBase+dv;
978        float u = 0.0f;
979
980
981        gl.Begin(GL_QUAD_STRIP);
982
983        // draw skirt at beginning of this row if required.
984        if (field.getSkirtHeight()!=0.0f)
985        {
986            vertTop.set(0.0f,dy*(float)(row+1),field.getHeight(0,row+1)-field.getSkirtHeight());
987            normTop.set(field.getNormal(0,row+1));
988
989            vertBase.set(0.0f,dy*(float)row,field.getHeight(0,row)-field.getSkirtHeight());
990            normBase.set(field.getNormal(0,row));
991
992            gl.TexCoord2f(u,vTop);
993            gl.Normal3fv(normTop.ptr());
994            gl.Vertex3fv(vertTop.ptr());
995
996            gl.TexCoord2f(u,vBase);
997            gl.Normal3fv(normBase.ptr());
998            gl.Vertex3fv(vertBase.ptr());
999        }
1000
1001        // draw the actual row
1002        for(unsigned int col=0;col<field.getNumColumns();++col,u+=du)
1003        {
1004            vertTop.set(dx*(float)col,dy*(float)(row+1),field.getHeight(col,row+1));
1005            normTop.set(field.getNormal(col,row+1));
1006
1007            vertBase.set(dx*(float)col,dy*(float)row,field.getHeight(col,row));
1008            normBase.set(field.getNormal(col,row));
1009
1010            gl.TexCoord2f(u,vTop);
1011            gl.Normal3fv(normTop.ptr());
1012            gl.Vertex3fv(vertTop.ptr());
1013
1014            gl.TexCoord2f(u,vBase);
1015            gl.Normal3fv(normBase.ptr());
1016            gl.Vertex3fv(vertBase.ptr());
1017
1018        }
1019
1020        // draw skirt at end of this row if required.
1021        if (field.getSkirtHeight()!=0.0f)
1022        {
1023
1024            vertBase.z()-=field.getSkirtHeight();
1025            vertTop.z()-=field.getSkirtHeight();
1026
1027            gl.TexCoord2f(u,vTop);
1028            gl.Normal3fv(normTop.ptr());
1029            gl.Vertex3fv(vertTop.ptr());
1030
1031            gl.TexCoord2f(u,vBase);
1032            gl.Normal3fv(normBase.ptr());
1033            gl.Vertex3fv(vertBase.ptr());
1034        }
1035
1036        gl.End();
1037    }
1038
1039
1040    gl.PopMatrix();
1041
1042}
1043
1044void DrawShapeVisitor::apply(const CompositeShape& group)
1045{
1046    for(unsigned int i=0;i<group.getNumChildren();++i)
1047    {
1048        group.getChild(i)->accept(*this);
1049    }
1050}
1051
1052
1053
1054
1055///////////////////////////////////////////////////////////////////////////////
1056//
1057// Compute bounding of shape
1058//
1059
1060class ComputeBoundShapeVisitor : public ConstShapeVisitor
1061{
1062    public:
1063
1064        ComputeBoundShapeVisitor(BoundingBox& bb):_bb(bb) {}
1065
1066        virtual void apply(const Sphere&);
1067        virtual void apply(const Box&);
1068        virtual void apply(const Cone&);
1069        virtual void apply(const Cylinder&);
1070        virtual void apply(const Capsule&);
1071        virtual void apply(const InfinitePlane&);
1072
1073        virtual void apply(const TriangleMesh&);
1074        virtual void apply(const ConvexHull&);
1075        virtual void apply(const HeightField&);
1076
1077        virtual void apply(const CompositeShape&);
1078
1079        BoundingBox&    _bb;
1080
1081    protected:
1082
1083        ComputeBoundShapeVisitor& operator = (const ComputeBoundShapeVisitor&) { return *this; }
1084
1085};
1086
1087
1088void ComputeBoundShapeVisitor::apply(const Sphere& sphere)
1089{
1090    Vec3 halfLengths(sphere.getRadius(),sphere.getRadius(),sphere.getRadius());
1091    _bb.expandBy(sphere.getCenter()-halfLengths);
1092    _bb.expandBy(sphere.getCenter()+halfLengths);
1093}
1094
1095void ComputeBoundShapeVisitor::apply(const Box& box)
1096{
1097    if (box.zeroRotation())
1098    {
1099        _bb.expandBy(box.getCenter()-box.getHalfLengths());
1100        _bb.expandBy(box.getCenter()+box.getHalfLengths());
1101    }
1102    else
1103    {
1104        float x = box.getHalfLengths().x();
1105        float y = box.getHalfLengths().y();
1106        float z = box.getHalfLengths().z();
1107
1108        Vec3 base_1(Vec3(-x,-y,-z));
1109        Vec3 base_2(Vec3(x,-y,-z));
1110        Vec3 base_3(Vec3(x,y,-z));
1111        Vec3 base_4(Vec3(-x,y,-z));
1112
1113        Vec3 top_1(Vec3(-x,-y,z));
1114        Vec3 top_2(Vec3(x,-y,z));
1115        Vec3 top_3(Vec3(x,y,z));
1116        Vec3 top_4(Vec3(-x,y,z));
1117
1118        Matrix matrix = box.computeRotationMatrix();
1119        _bb.expandBy(box.getCenter()+base_1*matrix);
1120        _bb.expandBy(box.getCenter()+base_2*matrix);
1121        _bb.expandBy(box.getCenter()+base_3*matrix);
1122        _bb.expandBy(box.getCenter()+base_4*matrix);
1123
1124        _bb.expandBy(box.getCenter()+top_1*matrix);
1125        _bb.expandBy(box.getCenter()+top_2*matrix);
1126        _bb.expandBy(box.getCenter()+top_3*matrix);
1127        _bb.expandBy(box.getCenter()+top_4*matrix);
1128    }
1129}
1130
1131void ComputeBoundShapeVisitor::apply(const Cone& cone)
1132{
1133    if (cone.zeroRotation())
1134    {
1135        _bb.expandBy(cone.getCenter()+Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset()));
1136        _bb.expandBy(cone.getCenter()+Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset()));
1137
1138    }
1139    else
1140    {
1141        Vec3 top(Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset()));
1142        Vec3 base_1(Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset()));
1143        Vec3 base_2(Vec3(cone.getRadius(),-cone.getRadius(),cone.getBaseOffset()));
1144        Vec3 base_3(Vec3(cone.getRadius(),cone.getRadius(),cone.getBaseOffset()));
1145        Vec3 base_4(Vec3(-cone.getRadius(),cone.getRadius(),cone.getBaseOffset()));
1146
1147        Matrix matrix = cone.computeRotationMatrix();
1148        _bb.expandBy(cone.getCenter()+base_1*matrix);
1149        _bb.expandBy(cone.getCenter()+base_2*matrix);
1150        _bb.expandBy(cone.getCenter()+base_3*matrix);
1151        _bb.expandBy(cone.getCenter()+base_4*matrix);
1152        _bb.expandBy(cone.getCenter()+top*matrix);
1153    }
1154}
1155
1156void ComputeBoundShapeVisitor::apply(const Cylinder& cylinder)
1157{
1158    if (cylinder.zeroRotation())
1159    {
1160        Vec3 halfLengths(cylinder.getRadius(),cylinder.getRadius(),cylinder.getHeight()*0.5f);
1161        _bb.expandBy(cylinder.getCenter()-halfLengths);
1162        _bb.expandBy(cylinder.getCenter()+halfLengths);
1163
1164    }
1165    else
1166    {
1167        float r = cylinder.getRadius();
1168        float z = cylinder.getHeight()*0.5f;
1169
1170        Vec3 base_1(Vec3(-r,-r,-z));
1171        Vec3 base_2(Vec3(r,-r,-z));
1172        Vec3 base_3(Vec3(r,r,-z));
1173        Vec3 base_4(Vec3(-r,r,-z));
1174
1175        Vec3 top_1(Vec3(-r,-r,z));
1176        Vec3 top_2(Vec3(r,-r,z));
1177        Vec3 top_3(Vec3(r,r,z));
1178        Vec3 top_4(Vec3(-r,r,z));
1179
1180        Matrix matrix = cylinder.computeRotationMatrix();
1181        _bb.expandBy(cylinder.getCenter()+base_1*matrix);
1182        _bb.expandBy(cylinder.getCenter()+base_2*matrix);
1183        _bb.expandBy(cylinder.getCenter()+base_3*matrix);
1184        _bb.expandBy(cylinder.getCenter()+base_4*matrix);
1185
1186        _bb.expandBy(cylinder.getCenter()+top_1*matrix);
1187        _bb.expandBy(cylinder.getCenter()+top_2*matrix);
1188        _bb.expandBy(cylinder.getCenter()+top_3*matrix);
1189        _bb.expandBy(cylinder.getCenter()+top_4*matrix);
1190    }
1191}
1192
1193void ComputeBoundShapeVisitor::apply(const Capsule& capsule)
1194{
1195    if (capsule.zeroRotation())
1196    {
1197        Vec3 halfLengths(capsule.getRadius(),capsule.getRadius(),capsule.getHeight()*0.5f + capsule.getRadius());
1198        _bb.expandBy(capsule.getCenter()-halfLengths);
1199        _bb.expandBy(capsule.getCenter()+halfLengths);
1200
1201    }
1202    else
1203    {
1204        float r = capsule.getRadius();
1205        float z = capsule.getHeight()*0.5f + capsule.getRadius();
1206
1207        Vec3 base_1(Vec3(-r,-r,-z));
1208        Vec3 base_2(Vec3(r,-r,-z));
1209        Vec3 base_3(Vec3(r,r,-z));
1210        Vec3 base_4(Vec3(-r,r,-z));
1211
1212        Vec3 top_1(Vec3(-r,-r,z));
1213        Vec3 top_2(Vec3(r,-r,z));
1214        Vec3 top_3(Vec3(r,r,z));
1215        Vec3 top_4(Vec3(-r,r,z));
1216
1217        Matrix matrix = capsule.computeRotationMatrix();
1218        _bb.expandBy(capsule.getCenter()+base_1*matrix);
1219        _bb.expandBy(capsule.getCenter()+base_2*matrix);
1220        _bb.expandBy(capsule.getCenter()+base_3*matrix);
1221        _bb.expandBy(capsule.getCenter()+base_4*matrix);
1222
1223        _bb.expandBy(capsule.getCenter()+top_1*matrix);
1224        _bb.expandBy(capsule.getCenter()+top_2*matrix);
1225        _bb.expandBy(capsule.getCenter()+top_3*matrix);
1226        _bb.expandBy(capsule.getCenter()+top_4*matrix);
1227    }
1228}
1229
1230void ComputeBoundShapeVisitor::apply(const InfinitePlane&)
1231{
1232    // can't compute the bounding box of an infinite plane!!! :-)
1233}
1234
1235void ComputeBoundShapeVisitor::apply(const TriangleMesh& mesh)
1236{
1237    const Vec3Array* vertices = mesh.getVertices();
1238    const IndexArray* indices = mesh.getIndices();
1239
1240    if (vertices && indices)
1241    {
1242        for(unsigned int i=0;i<indices->getNumElements();++i)
1243        {
1244            const osg::Vec3& v=(*vertices)[indices->index(i)];
1245            _bb.expandBy(v);
1246        }
1247    }
1248}
1249
1250void ComputeBoundShapeVisitor::apply(const ConvexHull& hull)
1251{
1252    apply((const TriangleMesh&)hull);
1253}
1254
1255void ComputeBoundShapeVisitor::apply(const HeightField& field)
1256{
1257    float zMin=FLT_MAX;
1258    float zMax=-FLT_MAX;
1259
1260    for(unsigned int row=0;row<field.getNumRows();++row)
1261    {
1262        for(unsigned int col=0;col<field.getNumColumns();++col)
1263        {
1264            float z = field.getHeight(col,row);
1265            if (z<zMin) zMin = z;
1266            if (z>zMax) zMax = z;
1267        }
1268    }
1269
1270    if (zMin>zMax)
1271    {
1272        // no valid entries so don't reset the bounding box
1273        return;
1274    }
1275
1276
1277    if (field.zeroRotation())
1278    {
1279        _bb.expandBy(field.getOrigin()+osg::Vec3(0.0f,0.0f,zMin));
1280        _bb.expandBy(field.getOrigin()+osg::Vec3(field.getXInterval()*(field.getNumColumns()-1),field.getYInterval()*(field.getNumRows()-1),zMax));
1281    }
1282    else
1283    {
1284        float x = field.getXInterval()*(field.getNumColumns()-1);
1285        float y = field.getYInterval()*(field.getNumRows()-1);
1286
1287        Vec3 base_1(Vec3(0,0,zMin));
1288        Vec3 base_2(Vec3(x,0,zMin));
1289        Vec3 base_3(Vec3(x,y,zMin));
1290        Vec3 base_4(Vec3(0,y,zMin));
1291
1292        Vec3 top_1(Vec3(0,0,zMax));
1293        Vec3 top_2(Vec3(x,0,zMax));
1294        Vec3 top_3(Vec3(x,y,zMax));
1295        Vec3 top_4(Vec3(0,y,zMax));
1296
1297        Matrix matrix = field.computeRotationMatrix();
1298        _bb.expandBy(field.getOrigin()+base_1*matrix);
1299        _bb.expandBy(field.getOrigin()+base_2*matrix);
1300        _bb.expandBy(field.getOrigin()+base_3*matrix);
1301        _bb.expandBy(field.getOrigin()+base_4*matrix);
1302
1303        _bb.expandBy(field.getOrigin()+top_1*matrix);
1304        _bb.expandBy(field.getOrigin()+top_2*matrix);
1305        _bb.expandBy(field.getOrigin()+top_3*matrix);
1306        _bb.expandBy(field.getOrigin()+top_4*matrix);
1307    }
1308
1309}
1310
1311void ComputeBoundShapeVisitor::apply(const CompositeShape& group)
1312{
1313    for(unsigned int i=0;i<group.getNumChildren();++i)
1314    {
1315        group.getChild(i)->accept(*this);
1316    }
1317}
1318
1319
1320
1321
1322///////////////////////////////////////////////////////////////////////////////
1323//
1324// Accept a primitive functor for each of the shapes.
1325//
1326
1327class PrimitiveShapeVisitor : public ConstShapeVisitor
1328{
1329    public:
1330
1331        PrimitiveShapeVisitor(PrimitiveFunctor& functor,const TessellationHints* hints):
1332            _functor(functor),
1333            _hints(hints) {}
1334
1335        virtual void apply(const Sphere&);
1336        virtual void apply(const Box&);
1337        virtual void apply(const Cone&);
1338        virtual void apply(const Cylinder&);
1339        virtual void apply(const Capsule&);
1340        virtual void apply(const InfinitePlane&);
1341
1342        virtual void apply(const TriangleMesh&);
1343        virtual void apply(const ConvexHull&);
1344        virtual void apply(const HeightField&);
1345
1346        virtual void apply(const CompositeShape&);
1347
1348        PrimitiveFunctor& _functor;
1349        const TessellationHints*  _hints;
1350
1351    private:
1352
1353        PrimitiveShapeVisitor& operator = (const PrimitiveShapeVisitor&) { return *this; }
1354
1355        // helpers for apply( Cylinder | Sphere | Capsule )
1356        void createCylinderBody(unsigned int numSegments, float radius, float height, const osg::Matrix& matrix);
1357        void createHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, int which, float zOffset, const osg::Matrix& matrix);
1358};
1359
1360
1361
1362void PrimitiveShapeVisitor::createCylinderBody(unsigned int numSegments, float radius, float height, const osg::Matrix& matrix)
1363{
1364    const float angleDelta = 2.0f*osg::PI/(float)numSegments;
1365
1366    const float r = radius;
1367    const float h = height;
1368
1369    float basez = -h*0.5f;
1370    float topz = h*0.5f;
1371
1372    float angle = 0.0f;
1373
1374    _functor.begin(GL_QUAD_STRIP);
1375
1376        for(unsigned int bodyi=0;
1377            bodyi<numSegments;
1378            ++bodyi,angle+=angleDelta)
1379        {
1380            float c = cosf(angle);
1381            float s = sinf(angle);
1382
1383            _functor.vertex(osg::Vec3(c*r,s*r,topz) * matrix);
1384            _functor.vertex(osg::Vec3(c*r,s*r,basez) * matrix);
1385        }
1386
1387        // do last point by hand to ensure no round off errors.
1388        _functor.vertex(osg::Vec3(r,0.0f,topz) * matrix);
1389        _functor.vertex(osg::Vec3(r,0.0f,basez) * matrix);
1390
1391    _functor.end();
1392}
1393
1394
1395void PrimitiveShapeVisitor::createHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, int which, float zOffset, const osg::Matrix& matrix)
1396{
1397    float lDelta = osg::PI/(float)numRows;
1398    float vDelta = 1.0f/(float)numRows;
1399
1400    // top half is 0, bottom is 1.
1401    bool top = (which==0);
1402
1403    float angleDelta = osg::PI*2.0f/(float)numSegments;
1404
1405    float lBase=-osg::PI*0.5f + (top?(lDelta*(numRows/2)):0.0f);
1406    float rBase=(top?(cosf(lBase)*radius):0.0f);
1407    float zBase=(top?(sinf(lBase)*radius):-radius);
1408    float vBase=(top?(vDelta*(numRows/2)):0.0f);
1409
1410    unsigned int rowbegin = top?numRows/2:0;
1411    unsigned int rowend   = top?numRows:numRows/2;
1412
1413    for(unsigned int rowi=rowbegin; rowi<rowend; ++rowi)
1414    {
1415
1416        float lTop = lBase+lDelta;
1417        float rTop = cosf(lTop)*radius;
1418        float zTop = sinf(lTop)*radius;
1419        float vTop = vBase+vDelta;
1420
1421        _functor.begin(GL_QUAD_STRIP);
1422
1423            float angle = 0.0f;
1424
1425            for(unsigned int topi=0; topi<numSegments;
1426                ++topi,angle+=angleDelta)
1427            {
1428
1429                float c = cosf(angle);
1430                float s = sinf(angle);
1431
1432                _functor.vertex(osg::Vec3(c*rTop,s*rTop,zTop+zOffset) * matrix);
1433                _functor.vertex(osg::Vec3(c*rBase,s*rBase,zBase+zOffset) * matrix);
1434
1435            }
1436
1437            // do last point by hand to ensure no round off errors.
1438            _functor.vertex(osg::Vec3(rTop,0.0f,zTop+zOffset) * matrix);
1439            _functor.vertex(osg::Vec3(rBase,0.0f,zBase+zOffset) * matrix);
1440
1441        _functor.end();
1442
1443
1444        lBase=lTop;
1445        rBase=rTop;
1446        zBase=zTop;
1447        vBase=vTop;
1448    }
1449
1450}
1451
1452
1453
1454void PrimitiveShapeVisitor::apply(const Sphere& sphere)
1455{
1456
1457    float tx = sphere.getCenter().x();
1458    float ty = sphere.getCenter().y();
1459    float tz = sphere.getCenter().z();
1460
1461    unsigned int numSegments = 40;
1462    unsigned int numRows = 20;
1463    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
1464    if (ratio > 0.0f && ratio != 1.0f) {
1465        numRows = (unsigned int) (numRows * ratio);
1466        if (numRows < MIN_NUM_ROWS)
1467            numRows = MIN_NUM_ROWS;
1468        numSegments = (unsigned int) (numSegments * ratio);
1469        if (numSegments < MIN_NUM_SEGMENTS)
1470            numSegments = MIN_NUM_SEGMENTS;
1471    }
1472
1473    float lDelta = osg::PI/(float)numRows;
1474    float vDelta = 1.0f/(float)numRows;
1475
1476    float angleDelta = osg::PI*2.0f/(float)numSegments;
1477
1478    float lBase=-osg::PI*0.5f;
1479    float rBase=0.0f;
1480    float zBase=-sphere.getRadius();
1481    float vBase=0.0f;
1482
1483    for(unsigned int rowi=0;
1484        rowi<numRows;
1485        ++rowi)
1486    {
1487
1488        float lTop = lBase+lDelta;
1489        float rTop = cosf(lTop)*sphere.getRadius();
1490        float zTop = sinf(lTop)*sphere.getRadius();
1491        float vTop = vBase+vDelta;
1492
1493        _functor.begin(GL_QUAD_STRIP);
1494
1495            float angle = 0.0f;
1496
1497            for(unsigned int topi=0;
1498                topi<numSegments;
1499                ++topi,angle+=angleDelta)
1500            {
1501
1502                float c = cosf(angle);
1503                float s = sinf(angle);
1504
1505                _functor.vertex(tx+c*rTop,ty+s*rTop,tz+zTop);
1506                _functor.vertex(tx+c*rBase,ty+s*rBase,tz+zBase);
1507
1508            }
1509
1510            // do last point by hand to ensure no round off errors.
1511            _functor.vertex(tx+rTop,ty,tz+zTop);
1512            _functor.vertex(tx+rBase,ty,tz+zBase);
1513
1514        _functor.end();
1515
1516        lBase=lTop;
1517        rBase=rTop;
1518        zBase=zTop;
1519        vBase=vTop;
1520
1521    }
1522}
1523
1524void PrimitiveShapeVisitor::apply(const Box& box)
1525{
1526    // evaluate hints
1527    bool createBody = (_hints ? _hints->getCreateBody() : true);
1528    bool createTop = (_hints ? _hints->getCreateTop() : true);
1529    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
1530
1531    float x = box.getHalfLengths().x();
1532    float y = box.getHalfLengths().y();
1533    float z = box.getHalfLengths().z();
1534
1535    Vec3 base_1(-x,-y,-z);
1536    Vec3 base_2(x,-y,-z);
1537    Vec3 base_3(x,y,-z);
1538    Vec3 base_4(-x,y,-z);
1539
1540    Vec3 top_1(-x,-y,z);
1541    Vec3 top_2(x,-y,z);
1542    Vec3 top_3(x,y,z);
1543    Vec3 top_4(-x,y,z);
1544
1545    if (box.zeroRotation())
1546    {
1547        base_1 += box.getCenter();
1548        base_2 += box.getCenter();
1549        base_3 += box.getCenter();
1550        base_4 += box.getCenter();
1551
1552        top_1 += box.getCenter();
1553        top_2 += box.getCenter();
1554        top_3 += box.getCenter();
1555        top_4 += box.getCenter();
1556    }
1557    else
1558    {
1559        Matrix matrix = box.computeRotationMatrix();
1560        matrix.setTrans(box.getCenter());
1561
1562        base_1 = base_1*matrix;
1563        base_2 = base_2*matrix;
1564        base_3 = base_3*matrix;
1565        base_4 = base_4*matrix;
1566
1567        top_1 = top_1*matrix;
1568        top_2 = top_2*matrix;
1569        top_3 = top_3*matrix;
1570        top_4 = top_4*matrix;
1571    }
1572
1573    _functor.begin(GL_QUADS);
1574    if (createBody)
1575    {
1576        _functor.vertex(top_1);
1577        _functor.vertex(base_1);
1578        _functor.vertex(base_2);
1579        _functor.vertex(top_2);
1580
1581        _functor.vertex(top_2);
1582        _functor.vertex(base_2);
1583        _functor.vertex(base_3);
1584        _functor.vertex(top_3);
1585
1586        _functor.vertex(top_3);
1587        _functor.vertex(base_3);
1588        _functor.vertex(base_4);
1589        _functor.vertex(top_4);
1590
1591        _functor.vertex(top_4);
1592        _functor.vertex(base_4);
1593        _functor.vertex(base_1);
1594        _functor.vertex(top_1);
1595    }
1596
1597    if (createTop)
1598    {
1599        _functor.vertex(top_4);
1600        _functor.vertex(top_1);
1601        _functor.vertex(top_2);
1602        _functor.vertex(top_3);
1603    }
1604
1605    if (createBottom)
1606    {
1607        _functor.vertex(base_4);
1608        _functor.vertex(base_3);
1609        _functor.vertex(base_2);
1610        _functor.vertex(base_1);
1611    }
1612
1613    _functor.end();
1614
1615}
1616
1617void PrimitiveShapeVisitor::apply(const Cone& cone)
1618{
1619    // evaluate hints
1620    bool createBody = (_hints ? _hints->getCreateBody() : true);
1621    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
1622
1623    Matrix matrix = cone.computeRotationMatrix();
1624    matrix.setTrans(cone.getCenter());
1625
1626    unsigned int numSegments = 40;
1627    unsigned int numRows = 20;
1628    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
1629    if (ratio > 0.0f && ratio != 1.0f) {
1630        numRows = (unsigned int) (numRows * ratio);
1631        if (numRows < MIN_NUM_ROWS)
1632            numRows = MIN_NUM_ROWS;
1633        numSegments = (unsigned int) (numSegments * ratio);
1634        if (numSegments < MIN_NUM_SEGMENTS)
1635            numSegments = MIN_NUM_SEGMENTS;
1636    }
1637
1638    float r = cone.getRadius();
1639    float h = cone.getHeight();
1640
1641    float normalz = r/(sqrtf(r*r+h*h));
1642    float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz));
1643    normalz *= normalRatio;
1644
1645    float angleDelta = 2.0f*osg::PI/(float)numSegments;
1646    float hDelta = cone.getHeight()/(float)numRows;
1647    float rDelta = cone.getRadius()/(float)numRows;
1648
1649    float topz=cone.getHeight()+cone.getBaseOffset();
1650    float topr=0.0f;
1651    float basez=topz-hDelta;
1652    float baser=rDelta;
1653    float angle;
1654
1655    if (createBody)
1656    {
1657        for(unsigned int rowi=0;
1658            rowi<numRows;
1659            ++rowi,topz=basez, basez-=hDelta, topr=baser, baser+=rDelta)
1660        {
1661            // we can't use a fan for the cone top
1662            // since we need different normals at the top
1663            // for each face..
1664            _functor.begin(GL_QUAD_STRIP);
1665
1666                angle = 0.0f;
1667                for(unsigned int topi=0;
1668                    topi<numSegments;
1669                    ++topi,angle+=angleDelta)
1670                {
1671
1672                    float c = cosf(angle);
1673                    float s = sinf(angle);
1674
1675                    _functor.vertex(Vec3(c*topr,s*topr,topz)*matrix);
1676                    _functor.vertex(Vec3(c*baser,s*baser,basez)*matrix);
1677
1678                }
1679
1680                // do last point by hand to ensure no round off errors.
1681                _functor.vertex(Vec3(topr,0.0f,topz)*matrix);
1682                _functor.vertex(Vec3(baser,0.0f,basez)*matrix);
1683
1684            _functor.end();
1685
1686        }
1687    }
1688
1689    if (createBottom)
1690    {
1691        // we can't use a fan for the cone top
1692        // since we need different normals at the top
1693        // for each face..
1694        _functor.begin(GL_TRIANGLE_FAN);
1695
1696        angle = osg::PI*2.0f;
1697        basez = cone.getBaseOffset();
1698
1699        _functor.vertex(Vec3(0.0f,0.0f,basez)*matrix);
1700
1701        for(unsigned int bottomi=0;
1702            bottomi<numSegments;
1703            ++bottomi,angle-=angleDelta)
1704        {
1705
1706            float c = cosf(angle);
1707            float s = sinf(angle);
1708
1709            _functor.vertex(Vec3(c*r,s*r,basez)*matrix);
1710
1711        }
1712
1713        _functor.vertex(Vec3(r,0.0f,basez)*matrix);
1714
1715        _functor.end();
1716    }
1717}
1718
1719void PrimitiveShapeVisitor::apply(const Cylinder& cylinder)
1720{
1721    // evaluate hints
1722    bool createBody = (_hints ? _hints->getCreateBody() : true);
1723    bool createTop = (_hints ? _hints->getCreateTop() : true);
1724    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
1725
1726    Matrix matrix = cylinder.computeRotationMatrix();
1727    matrix.setTrans(cylinder.getCenter());
1728
1729    unsigned int numSegments = 40;
1730    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
1731    if (ratio > 0.0f && ratio != 1.0f) {
1732        numSegments = (unsigned int) (numSegments * ratio);
1733        if (numSegments < MIN_NUM_SEGMENTS)
1734            numSegments = MIN_NUM_SEGMENTS;
1735    }
1736
1737    float angleDelta = 2.0f*osg::PI/(float)numSegments;
1738
1739    float r = cylinder.getRadius();
1740    float h = cylinder.getHeight();
1741
1742    float basez = -h*0.5f;
1743    float topz = h*0.5f;
1744    float angle;
1745
1746    // cylinder body
1747    if (createBody)
1748        createCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight(), matrix);
1749
1750    // cylinder top
1751    if (createTop)
1752    {
1753        _functor.begin(GL_TRIANGLE_FAN);
1754
1755            _functor.vertex(Vec3(0.0f,0.0f,topz)*matrix);
1756
1757            angle = 0.0f;
1758            for(unsigned int topi=0;
1759                topi<numSegments;
1760                ++topi,angle+=angleDelta)
1761            {
1762
1763                float c = cosf(angle);
1764                float s = sinf(angle);
1765
1766                _functor.vertex(Vec3(c*r,s*r,topz)*matrix);
1767
1768            }
1769
1770            _functor.vertex(Vec3(r,0.0f,topz)*matrix);
1771
1772        _functor.end();
1773    }
1774
1775    // cylinder bottom
1776    if (createBottom)
1777    {
1778        _functor.begin(GL_TRIANGLE_FAN);
1779
1780            _functor.vertex(Vec3(0.0f,0.0f,basez)*matrix);
1781
1782            angle = osg::PI*2.0f;
1783            for(unsigned int bottomi=0;
1784                bottomi<numSegments;
1785                ++bottomi,angle-=angleDelta)
1786            {
1787
1788                float c = cosf(angle);
1789                float s = sinf(angle);
1790
1791                _functor.vertex(Vec3(c*r,s*r,basez)*matrix);
1792
1793            }
1794
1795            _functor.vertex(Vec3(r,0.0f,basez)*matrix);
1796
1797        _functor.end();
1798    }
1799}
1800
1801void PrimitiveShapeVisitor::apply(const Capsule& capsule)
1802{
1803    // evaluate hints
1804    bool createBody = (_hints ? _hints->getCreateBody() : true);
1805    bool createTop = (_hints ? _hints->getCreateTop() : true);
1806    bool createBottom = (_hints ? _hints->getCreateBottom() : true);
1807
1808    Matrix matrix = capsule.computeRotationMatrix();
1809    matrix.setTrans(capsule.getCenter());
1810
1811    unsigned int numSegments = 40;
1812    unsigned int numRows = 20;
1813    float ratio = (_hints ? _hints->getDetailRatio() : 1.0f);
1814    if (ratio > 0.0f && ratio != 1.0f) {
1815        numRows = (unsigned int) (numRows * ratio);
1816        if (numRows < MIN_NUM_ROWS)
1817            numRows = MIN_NUM_ROWS;
1818        numSegments = (unsigned int) (numSegments * ratio);
1819        if (numSegments < MIN_NUM_SEGMENTS)
1820            numSegments = MIN_NUM_SEGMENTS;
1821    }
1822
1823    // capsule body
1824    if (createBody)
1825        createCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight(), matrix);
1826
1827    // capsule top cap
1828    if (createTop)
1829        createHalfSphere(numSegments, numRows, capsule.getRadius(), 0, capsule.getHeight()/2.0f, matrix);
1830
1831    // capsule bottom cap
1832    if (createBottom)
1833        createHalfSphere(numSegments, numRows, capsule.getRadius(), 1, -capsule.getHeight()/2.0f, matrix);
1834
1835}
1836
1837void PrimitiveShapeVisitor::apply(const InfinitePlane&)
1838{
1839    OSG_NOTICE<<"Warning: PrimitiveShapeVisitor::apply(const InfinitePlane& plane) not yet implemented. "<<std::endl;
1840}
1841
1842void PrimitiveShapeVisitor::apply(const TriangleMesh& mesh)
1843{
1844    const Vec3Array* vertices = mesh.getVertices();
1845    const IndexArray* indices = mesh.getIndices();
1846
1847     if (vertices && indices)
1848     {
1849        _functor.begin(GL_TRIANGLES);
1850
1851        for(unsigned int i=0;i<indices->getNumElements();i+=3)
1852        {
1853            _functor.vertex((*vertices)[indices->index(i)]);
1854            _functor.vertex((*vertices)[indices->index(i+1)]);
1855            _functor.vertex((*vertices)[indices->index(i+2)]);
1856        }
1857
1858        _functor.end();
1859     }
1860
1861
1862}
1863
1864void PrimitiveShapeVisitor::apply(const ConvexHull& hull)
1865{
1866    apply((const TriangleMesh&)hull);
1867}
1868
1869void PrimitiveShapeVisitor::apply(const HeightField& field)
1870{
1871    if (field.getNumColumns()==0 || field.getNumRows()==0) return;
1872
1873    Matrix matrix = field.computeRotationMatrix();
1874    matrix.setTrans(field.getOrigin());
1875
1876    float dx = field.getXInterval();
1877    float dy = field.getYInterval();
1878
1879    for(unsigned int row=0;row<field.getNumRows()-1;++row)
1880    {
1881
1882        _functor.begin(GL_QUAD_STRIP);
1883
1884        for(unsigned int col=0;col<field.getNumColumns();++col)
1885        {
1886            Vec3 vertTop(dx*(float)col,dy*(float)(row+1),field.getHeight(col,row+1));
1887            Vec3 vertBase(dx*(float)col,dy*(float)row,field.getHeight(col,row));
1888
1889            _functor.vertex(vertTop*matrix);
1890            _functor.vertex(vertBase*matrix);
1891
1892        }
1893
1894        _functor.end();
1895    }
1896
1897}
1898
1899void PrimitiveShapeVisitor::apply(const CompositeShape& group)
1900{
1901    for(unsigned int i=0;i<group.getNumChildren();++i)
1902    {
1903        group.getChild(i)->accept(*this);
1904    }
1905}
1906
1907
1908///////////////////////////////////////////////////////////////////////////////
1909//
1910// ShapeDrawable itself..
1911//
1912
1913
1914ShapeDrawable::ShapeDrawable():
1915    _color(1.0f,1.0f,1.0f,1.0f)
1916{
1917    //setUseDisplayList(false);
1918}
1919
1920ShapeDrawable::ShapeDrawable(Shape* shape,TessellationHints* hints):
1921  _color(1.0f,1.0f,1.0f,1.0f),
1922  _tessellationHints(hints)
1923{
1924    setShape(shape);
1925    //setUseDisplayList(false);
1926}
1927
1928ShapeDrawable::ShapeDrawable(const ShapeDrawable& pg,const CopyOp& copyop):
1929    Drawable(pg,copyop),
1930    _color(pg._color),
1931    _tessellationHints(pg._tessellationHints)
1932{
1933    //setUseDisplayList(false);
1934}
1935
1936ShapeDrawable::~ShapeDrawable()
1937{
1938}
1939
1940void ShapeDrawable::setColor(const Vec4& color)
1941{
1942    if (_color!=color)
1943    {
1944        _color = color; dirtyDisplayList();
1945    }
1946}
1947
1948void ShapeDrawable::setTessellationHints(TessellationHints* hints)
1949{
1950    if (_tessellationHints!=hints)
1951    {
1952        _tessellationHints = hints;
1953        dirtyDisplayList();
1954    }
1955}
1956
1957void ShapeDrawable::drawImplementation(RenderInfo& renderInfo) const
1958{
1959    osg::State& state = *renderInfo.getState();
1960    GLBeginEndAdapter& gl = state.getGLBeginEndAdapter();
1961
1962    if (_shape.valid())
1963    {
1964        gl.Color4fv(_color.ptr());
1965
1966        DrawShapeVisitor dsv(state,_tessellationHints.get());
1967
1968        _shape->accept(dsv);
1969    }
1970}
1971
1972void ShapeDrawable::accept(ConstAttributeFunctor&) const
1973{
1974}
1975
1976void ShapeDrawable::accept(PrimitiveFunctor& pf) const
1977{
1978    if (_shape.valid())
1979    {
1980        PrimitiveShapeVisitor psv(pf,_tessellationHints.get());
1981        _shape->accept(psv);
1982    }
1983}
1984
1985
1986BoundingBox ShapeDrawable::computeBound() const
1987{
1988    BoundingBox bbox;
1989    if (_shape.valid())
1990    {
1991        ComputeBoundShapeVisitor cbsv(bbox);
1992        _shape->accept(cbsv);
1993    }
1994    return bbox;
1995}
Note: See TracBrowser for help on using the browser.