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
14#ifndef OSGUTIL_Tessellator
15#define OSGUTIL_Tessellator
16
17#include <osg/Geometry>
18
19#include <osgUtil/Export>
20
21#include <osg/GLU>
22
23#include <vector>
24
25#ifndef CALLBACK
26    /* Win32 calling conventions. (or a least that's what the GLUT example tess.c uses.)*/
27    #define CALLBACK
28#endif
29
30namespace osgUtil {
31
32/** Originally a simple class for tessellating a single polygon boundary.
33  * Using old style glu tessellation functions for portability.
34  * Upgraded Jan 2004 to use the modern glu tessellation functions.*/
35
36class OSGUTIL_EXPORT Tessellator : public osg::Referenced
37{
38    public:
39
40        Tessellator();
41        ~Tessellator();
42
43        /** The winding rule, see red book ch 11. */
44        enum WindingType{
45            TESS_WINDING_ODD          = GLU_TESS_WINDING_ODD,
46            TESS_WINDING_NONZERO      = GLU_TESS_WINDING_NONZERO,
47            TESS_WINDING_POSITIVE     = GLU_TESS_WINDING_POSITIVE,
48            TESS_WINDING_NEGATIVE     = GLU_TESS_WINDING_NEGATIVE,
49            TESS_WINDING_ABS_GEQ_TWO  = GLU_TESS_WINDING_ABS_GEQ_TWO
50        } ;
51
52        /** we interpret all contours in the geometry as a single set to be tessellated or
53         * each separate drawable's contours needs to be tessellated. */
54        enum TessellationType {
55            TESS_TYPE_GEOMETRY, // tessellate everything in the geometry object
56            TESS_TYPE_DRAWABLE, // tessellate each polygon, triangles & quads drawables in geometry separately
57            TESS_TYPE_POLYGONS // tessellate ONLY polygon drawables in geometry separately
58        };
59
60        /** Set and get tessellation request boundary only on/off */
61        void setBoundaryOnly (const bool tt) { _boundaryOnly=tt;}
62        inline bool getBoundaryOnly ( ) { return _boundaryOnly;}
63
64        /** Set and get tessellation windong rule */
65        void setWindingType (const WindingType wt) { _wtype=wt;}
66        inline WindingType getWindingType ( ) { return _wtype;}
67
68        /** Set and get tessellation type */
69        void setTessellationType (const TessellationType tt) { _ttype=tt;}
70        inline TessellationType getTessellationType ( ) { return _ttype;}
71
72        /** Change the contours lists of the geometry into tessellated primitives (the
73          * list of primitives in the original geometry is stored in the Tessellator for
74          * possible re-use.
75          * The name remains retessellatePolygons although it now handles trifans, strips, quads etc.
76          * as well as Polygons so as to not break old codes relying on this function name. */
77        void retessellatePolygons(osg::Geometry &cxgeom);
78
79        /** Define the normal to the tessellated polygon - this provides a hint how to
80         *  tessellate the contours; see gluTessNormal in red book or man pages.
81         *  GWM July 2005. Can improve teselation
82         *  "For example, if you know that all polygons lie in the x-y plane,
83         *   call gluTessNormal(tess, 0.0, 0.0, 1.0) before rendering any polygons."
84         */
85        void setTessellationNormal(const osg::Vec3 norm) { tessNormal=norm;}
86
87        osg::Geometry::PrimitiveSetList  getContours() { return _Contours;}
88
89        struct Prim : public osg::Referenced
90        {
91            Prim(GLenum mode):_mode(mode) {}
92
93            typedef std::vector<osg::Vec3*> VecList;
94
95            GLenum  _mode;
96            VecList _vertices;
97        };
98
99        virtual void beginTessellation();
100
101        void beginContour();
102
103        /** Add a vertex to the current contour, see gluTessVertex for details.
104        * Note the vertex pointer is returned at the end of tessellation and
105        * must not be left dangling or be overwritten until all results are
106        * collected.
107        */
108        void addVertex(osg::Vec3* vertex);
109
110        void endContour();
111
112        void endTessellation();
113
114        typedef std::vector< osg::ref_ptr<Prim> > PrimList;
115
116        PrimList& getPrimList() { return _primList; }
117
118        void reset();
119
120    protected:
121
122        /** remove unused parts of the array, eg for when retessellating
123         * tessellation can introduce extra vertices for concave or crossing boundaries,
124         * these will leak memory if not removed when retessellating. */
125        void reduceArray(osg::Array * cold, const unsigned int nnu);
126
127        void collectTessellation(osg::Geometry &cxgeom, unsigned int originalIndex);
128
129        typedef std::map<osg::Vec3*,unsigned int> VertexPtrToIndexMap;
130        void addContour(GLenum  mode, unsigned int first, unsigned int last, osg::Vec3Array* vertices);
131        void addContour(osg::PrimitiveSet* primitive, osg::Vec3Array* vertices);
132        void handleNewVertices(osg::Geometry& geom,VertexPtrToIndexMap &vertexPtrToIndexMap);
133
134        void begin(GLenum mode);
135        void vertex(osg::Vec3* vertex);
136        void combine(osg::Vec3* vertex,void* vertex_data[4],GLfloat weight[4]);
137        void end();
138        void error(GLenum errorCode);
139
140
141        static void CALLBACK beginCallback(GLenum which, void* userData);
142        static void CALLBACK vertexCallback(GLvoid *data, void* userData);
143        static void CALLBACK combineCallback(GLdouble coords[3], void* vertex_data[4],
144                              GLfloat weight[4], void** outData,
145                              void* useData);
146        static void CALLBACK endCallback(void* userData);
147        static void CALLBACK errorCallback(GLenum errorCode, void* userData);
148
149
150        struct Vec3d
151        {
152            double _v[3];
153        };
154
155
156        struct NewVertex
157        {
158
159            NewVertex():
160                _vpos(0),
161                _f1(0),
162                _v1(0),
163                _f2(0),
164                _v2(0),
165                _f3(0),
166                _v3(0),
167                _f4(0),
168                _v4(0) {}
169
170            NewVertex(const NewVertex& nv):
171                _vpos(nv._vpos),
172                _f1(nv._f1),
173                _v1(nv._v1),
174                _f2(nv._f2),
175                _v2(nv._v2),
176                _f3(nv._f3),
177                _v3(nv._v3),
178                _f4(nv._f4),
179                _v4(nv._v4) {}
180
181            NewVertex(osg::Vec3* vx,
182                      float f1,osg::Vec3* v1,
183                      float f2,osg::Vec3* v2,
184                      float f3,osg::Vec3* v3,
185                      float f4,osg::Vec3* v4):
186                _vpos(vx),
187                _f1(f1),
188                _v1(v1),
189                _f2(f2),
190                _v2(v2),
191                _f3(f3),
192                _v3(v3),
193                _f4(f4),
194                _v4(v4) {}
195
196            osg::Vec3  *_vpos; // added gwm Jan 2004 the vertex coords s.t. NewVertex can be used in a std::vector
197
198            float       _f1;
199            osg::Vec3*  _v1;
200
201            float       _f2;
202            osg::Vec3*  _v2;
203
204            float       _f3;
205            osg::Vec3*  _v3;
206
207            float       _f4;
208            osg::Vec3*  _v4;
209
210        };
211
212        //change NewVertexList from std::map<osg::Vec3*,NewVertex> NewVertexList;
213        // because this has undefined order of insertion for new vertices.
214        // which occasionally corrupted the texture mapping.
215        typedef std::vector<NewVertex> NewVertexList;
216        typedef std::vector<Vec3d*> Vec3dList;
217
218        osg::GLUtesselator*  _tobj;
219
220        PrimList        _primList;
221        Vec3dList       _coordData;
222        NewVertexList   _newVertexList;
223        GLenum          _errorCode;
224
225        /** winding rule, which parts will become solid */
226        WindingType _wtype;
227
228        /** tessellation rule, which parts will become solid */
229        TessellationType _ttype;
230
231        bool _boundaryOnly; // see gluTessProperty - if true: make the boundary edges only.
232
233        /** number of vertices that are part of the 'original' set of contours */
234        unsigned int _numberVerts;
235
236        /** List of primitives that define the contours */
237        osg::Geometry::PrimitiveSetList                _Contours;
238
239        /** count number of primitives in a geometry to get right no. of norms/colurs etc for per_primitive attributes. */
240        unsigned int _index;
241
242        /** the gluTessNormal for tessellation hint */
243        osg::Vec3 tessNormal;
244
245        /** count of number of extra primitives added */
246        unsigned int _extraPrimitives;
247};
248
249}
250
251#endif
252