1 /****************************************************************************
2 * VCGLib                                                            o o     *
3 * Visual and Computer Graphics Library                            o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2004-2016                                           \/)\/    *
6 * Visual Computing Lab                                            /\/|      *
7 * ISTI - Italian National Research Council                           |      *
8 *                                                                    \      *
9 * All rights reserved.                                                      *
10 *                                                                           *
11 * This program is free software; you can redistribute it and/or modify      *
12 * it under the terms of the GNU General Public License as published by      *
13 * the Free Software Foundation; either version 2 of the License, or         *
14 * (at your option) any later version.                                       *
15 *                                                                           *
16 * This program is distributed in the hope that it will be useful,           *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
20 * for more details.                                                         *
21 *                                                                           *
22 ****************************************************************************/
23 #ifndef __VCGLIB_GLU_TESSELATOR_H
24 #define __VCGLIB_GLU_TESSELATOR_H
25 #include <vcg/space/point2.h>
26 #include <vector>
27 
28 #ifndef GL_VERSION_1_1
29 #error "Please include OpenGL before including this file"
30 #endif
31 
32 
33 // The inclusion of glu should be always safe (if someone has already included gl stuff).
34 #ifndef GLU_VERSIONS
35 #ifdef __APPLE__
36 #include <OpenGL/glu.h>
37 #else
38 #ifdef _WIN32
39   #include <windows.h>
40 #endif
41 #include <GL/glu.h>
42 #endif
43 #endif
44 
45 #ifndef CALLBACK
46 #ifdef _WIN32
47 #define CALLBACK __stdcall
48 #else
49 #define CALLBACK
50 #endif
51 #endif
52 
53 namespace vcg
54 {
55 
56 class glu_tesselator
57 {
58     public:
59 
60         typedef glu_tesselator this_type;
61 
62         /*
63             Works with Point2 and Point3;
64 
65             sample usage:
66 
67             // tesselation input: each outline represents a polygon contour
68             std::vector< std::vector<point_type> > outlines = ...;
69 
70             // tesselation output (triangles indices)
71             std::vector<int> indices;
72 
73             // compute triangles indices
74             glu_tesselator::tesselate(outlines, indices);
75 
76             // unroll input contours points
77             std::vector<point_type> points;
78 
79             for (size_t i=0; i<outlines.size(); ++i)
80             {
81                 for (size_t j=0; j<outlines[i].size(); ++j)
82                 {
83                     points.push_back(outlines[i][j]);
84                 }
85             }
86             // or simply call glu_tesselator::unroll(outlines, points);
87 
88             // create triangles
89             for (size_t i=0; i<indices.size(); i+=3)
90             {
91                 create_triangle(
92                     points[ indices[i+0] ],
93                     points[ indices[i+1] ],
94                     points[ indices[i+2] ]);
95             }
96         */
97 
98         template <class point_type>
unroll(const std::vector<std::vector<point_type>> & outlines,std::vector<point_type> & points)99         static inline void unroll(const std::vector< std::vector<point_type> > & outlines, std::vector<point_type> & points)
100         {
101             for (size_t i=0; i<outlines.size(); ++i)
102             {
103                 for (size_t j=0; j<outlines[i].size(); ++j)
104                 {
105                     points.push_back(outlines[i][j]);
106                 }
107             }
108         }
109 
110         template <class point_type>
tesselate(const std::vector<std::vector<point_type>> & outlines,std::vector<int> & indices)111         static inline void tesselate(const std::vector< std::vector<point_type> > & outlines, std::vector<int> & indices)
112         {
113             tess_prim_data_vec t_data;
114 
115             this_type::do_tesselation(outlines, t_data);
116 
117             //int k = 0;
118             for (size_t i=0; i<t_data.size(); ++i)
119             {
120                 const size_t st = t_data[i].indices.size();
121                 if (st < 3) continue;
122 
123                 switch (t_data[i].type)
124                 {
125                     case GL_TRIANGLES:
126                         for (size_t j=0; j<st; ++j)
127                         {
128                             indices.push_back(t_data[i].indices[j]);
129                         }
130                         break;
131 
132                     case GL_TRIANGLE_STRIP:
133                         {
134                         int i0 = t_data[i].indices[0];
135                         int i1 = t_data[i].indices[1];
136 
137                         bool ccw = true;
138 
139                         for (size_t j=2; j<st; ++j)
140                         {
141                             const int i2 = t_data[i].indices[j];
142 
143                             indices.push_back(i0);
144                             indices.push_back(i1);
145                             indices.push_back(i2);
146 
147                             if (ccw) i0 = i2;
148                             else     i1 = i2;
149 
150                             ccw = !ccw;
151                         }																	}
152                         break;
153 
154                     case GL_TRIANGLE_FAN:
155                         {
156                         const int first = t_data[i].indices[0];
157                         int prev = t_data[i].indices[1];
158 
159                         for (size_t j=2; j<st; ++j)
160                         {
161                             const int curr = t_data[i].indices[j];
162 
163                             indices.push_back(first);
164                             indices.push_back(prev);
165                             indices.push_back(curr);
166 
167                             prev = curr;
168                         }
169                         }
170                         break;
171 
172                     default:
173                         break;
174                 }
175             }
176         }
177 
178     protected:
179 
180         class tess_prim_data
181         {
182             public:
183 
184                 typedef tess_prim_data this_type;
185 
186                 GLenum type;
187                 std::vector<int> indices;
188 
tess_prim_data(void)189                 tess_prim_data(void) { }
tess_prim_data(GLenum t)190                 tess_prim_data(GLenum t) : type(t) { }
191         };
192 
193         typedef std::vector<tess_prim_data> tess_prim_data_vec;
194 
begin_cb(GLenum type,void * polygon_data)195         static void CALLBACK begin_cb(GLenum type, void * polygon_data)
196         {
197             tess_prim_data_vec * t_data = (tess_prim_data_vec *)polygon_data;
198             t_data->push_back(tess_prim_data(type));
199         }
200 
end_cb(void * polygon_data)201         static void CALLBACK end_cb(void * polygon_data)
202         {
203             (void)polygon_data;
204         }
205 
vertex_cb(void * vertex_data,void * polygon_data)206         static void CALLBACK vertex_cb(void * vertex_data, void * polygon_data)
207         {
208             tess_prim_data_vec * t_data = (tess_prim_data_vec *)polygon_data;
209             t_data->back().indices.push_back((int)((size_t)vertex_data));
210         }
211 
212         template <class point_type>
do_tesselation(const std::vector<std::vector<point_type>> & outlines,tess_prim_data_vec & t_data)213         static void do_tesselation(const std::vector< std::vector<point_type> > & outlines, tess_prim_data_vec & t_data)
214         {
215             GLUtesselator * tess = gluNewTess();
216 //#ifdef __APPLE__
217 //			gluTessCallback(tess, GLU_TESS_BEGIN_DATA,  (GLvoid (CALLBACK *)(...))(this_type::begin_cb));
218 //			gluTessCallback(tess, GLU_TESS_END_DATA,    (GLvoid (CALLBACK *)(...))(this_type::end_cb));
219 //			gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (CALLBACK *)(...))(this_type::vertex_cb));
220 //#else
221             gluTessCallback(tess, GLU_TESS_BEGIN_DATA,  (GLvoid (CALLBACK *)())(this_type::begin_cb));
222             gluTessCallback(tess, GLU_TESS_END_DATA,    (GLvoid (CALLBACK *)())(this_type::end_cb));
223             gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (CALLBACK *)())(this_type::vertex_cb));
224 //#endif
225             void * polygon_data = (void *)(&t_data);
226 
227             GLdouble vertex[3];
228 
229             size_t k = 0;
230             gluTessBeginPolygon(tess, polygon_data);
231             for (size_t i=0; i<outlines.size(); ++i)
232             {
233                 gluTessBeginContour(tess);
234                 for (size_t j=0; j<outlines[i].size(); ++j)
235                 {
236                     this_type::get_position(outlines[i][j], vertex);
237                     gluTessVertex(tess, vertex, (void *)k);
238                     ++k;
239                 }
240                 gluTessEndContour(tess);
241             }
242             gluTessEndPolygon(tess);
243 
244             gluDeleteTess(tess);
245         }
246 
247         template <class scalar_type>
get_position(const vcg::Point2<scalar_type> & p,GLdouble * d)248         static inline void get_position(const vcg::Point2<scalar_type> & p, GLdouble * d)
249         {
250             d[0] = (GLdouble)(p[0]);
251             d[1] = (GLdouble)(p[1]);
252             d[2] = (GLdouble)(0);
253         }
254 
255         template <class scalar_type>
get_position(const vcg::Point3<scalar_type> & p,GLdouble * d)256         static inline void get_position(const vcg::Point3<scalar_type> & p, GLdouble * d)
257         {
258             d[0] = (GLdouble)(p[0]);
259             d[1] = (GLdouble)(p[1]);
260             d[2] = (GLdouble)(p[2]);
261         }
262 };
263 
264 } // end namespace vcg
265 
266 #endif // __VCGLIB_GLU_TESSELATOR_H
267