root/OpenSceneGraph/trunk/examples/osgtessellate/osgtessellate.cpp @ 13640

Revision 13574, 31.6 kB (checked in by robert, 16 minutes ago)

From Paul Martz, fixed placement of OpenGL header so that it gets generated and placed in the build directory as per the Config file

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgtessellate.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19/* osgTessellator
20 * - this Tessellator is an extension of the basic one - rather than tessellating
21 * individual polygons, we tessellate the entire geode with multiple contours.
22 * allows for overlapping contours etc.
23 * the Tessellator has new member fuinctions
24 setTessellationType(osgUtil::Tessellator::TESS_TYPE_xxx);
25    tscx->setBoundaryOnly(bool);
26    tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_xxx);
27 * for winding rules: See the red book chap 13.
28 */
29
30#include <osgDB/ReadFile>
31#include <osgUtil/Optimizer>
32#include <osgViewer/Viewer>
33#include <osg/Projection>
34#include <osg/MatrixTransform>
35
36#include <osgText/Text>
37
38#include <osgUtil/Tessellator> // to tessellate multiple contours
39
40
41class tessellateDemoGeometry : public osg::Geometry, public osgUtil::Tessellator {
42    // We add the Tessellator to the geometry because we want to access the
43    // tessellatable contours again;  you can apply a Tessellator to a Geometry
44    // to produce exactly a required tessellation once only, and then
45    // the contours could be discarded since the geometry does not need to be retessellated.
46public:
47    tessellateDemoGeometry() {};
48
49protected:
50    virtual ~tessellateDemoGeometry() {};
51};
52
53osg::Geometry *makePolsTwo (void)
54{
55    // an example of using current geometry contours to create next tessellation
56    // this polygon disappears once the contour rules make no polygons.
57    tessellateDemoGeometry *gtess= new tessellateDemoGeometry;
58    int i;
59    osg::Vec3Array *coords = new osg::Vec3Array;
60    osg::Vec3Array *nrms = new osg::Vec3Array;
61    osg::Vec2Array *tcs = new osg::Vec2Array;
62    osg::Vec3 nrm(0,-1,0);
63    static GLdouble quadstrip[8][3] =
64    { { 1900.0, 1130.0, 0.0 },
65      { 2100.0, 1130.0, 0.0 },
66      { 1900.0, 1350.0, 0.0 },
67      { 1950.0, 1350.0, 0.0 },
68      { 1900.0, 1550.0, 0.0 },
69      { 2000.0, 1550.0, 0.0 },
70      { 1900.0, 1750.0, 0.0 },
71      { 2400.0, 1750.0, 0.0 } };
72    static GLdouble innerquadstrip[8][3] =
73    { { 2000.0, 1230.0, 0.0 },
74      { 2050.0, 1230.0, 0.0 },
75      { 1920.0, 1350.0, 0.0 },
76      { 1940.0, 1350.0, 0.0 },
77      { 1920.0, 1550.0, 0.0 },
78      { 1980.0, 1550.0, 0.0 },
79      { 2000.0, 1650.0, 0.0 },
80      { 2400.0, 1650.0, 0.0 } };
81
82    // add one large quadstrip
83    for (i = 0; i < 8; i++)
84    {
85        coords->push_back(osg::Vec3(quadstrip[i][0],quadstrip[i][2],quadstrip[i][1]));
86        tcs->push_back(osg::Vec2(quadstrip[i][0],quadstrip[i][1])/200.0);
87        nrms->push_back(nrm);
88    }
89    for (i = 0; i < 8; i++) {
90        coords->push_back(osg::Vec3(innerquadstrip[i][0],innerquadstrip[i][2],innerquadstrip[i][1]));
91        tcs->push_back(osg::Vec2(innerquadstrip[i][0],innerquadstrip[i][1])/200.0);
92        nrms->push_back(nrm);
93    }
94    gtess->setVertexArray(coords);
95    gtess->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
96    gtess->setTexCoordArray(0,tcs);
97
98    // demonstrate that the Tessellator makes textured tessellations
99    osg::StateSet* stateset = new osg::StateSet();
100
101    osg::Image* image = osgDB::readImageFile("Cubemap_snow/posy.jpg");
102    if (image)
103    {
104        osg::Texture2D* texture = new osg::Texture2D;
105        texture->setImage(image);
106        texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
107        texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
108        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
109    }
110    gtess->setStateSet( stateset );
111
112    int nstart=0;
113    // The derived class tessellateDemoGeometry retains the original contours for re-use.
114    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nstart,8));nstart+=8;
115    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nstart,8));nstart+=8;
116
117    gtess->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
118    gtess->setBoundaryOnly(true);
119    gtess->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO); // so that first change in wind type makes the commonest tessellation - ODD.
120
121    return gtess;
122}
123
124osg::Geometry *makeSideWall (const float xpos)
125{
126    // demonstrate making a rectangular 'wall' with 2 holes in it.
127    osg::Geometry *gtess= new osg::Geometry;
128    int i;
129    osg::Vec3Array *coords = new osg::Vec3Array;
130    osg::Vec3Array *nrms = new osg::Vec3Array;
131    osg::Vec2Array *tcs = new osg::Vec2Array;
132    osg::Vec3 nrm(-1,0,0);
133    // front wall
134    static GLdouble wall[4][2] =
135    { { 1130.0, 0.0 },
136      { 1130.0, 300.0 } ,
137      { 1340.0,300.0 },
138      { 1340.0,0.0 } };
139
140    gtess->setVertexArray(coords);
141    gtess->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
142    gtess->setTexCoordArray(0,tcs);
143
144    for (i = 0; i < 4; i++) {
145        coords->push_back(osg::Vec3(xpos,wall[i][1],wall[i][0]));
146        tcs->push_back(osg::Vec2(wall[i][1],wall[i][0])/100.0);
147        nrms->push_back(nrm);
148    }
149    int nstart=0;
150
151    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,4));nstart+=4;
152    for (i = 0; i < 24; i++) { // make an ellipse hole
153        float y=150+50*cos(i*2*osg::PI/24.0);
154        float z=1300+30* sin(i*2*osg::PI/24.0);
155        coords->push_back(osg::Vec3(xpos,y,z));
156        tcs->push_back(osg::Vec2(y,z)/100.0);
157        nrms->push_back(nrm);
158    }
159    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,24));nstart+=24;
160    for (i = 0; i < 5; i++) { // make a pentagonal hole
161        float y=150+50*cos(i*2*osg::PI/5.0);
162        float z=1200+40* sin(i*2*osg::PI/5.0);
163        coords->push_back(osg::Vec3(xpos,y,z));
164        tcs->push_back(osg::Vec2(y,z)/100.0);
165        nrms->push_back(nrm);
166    }
167    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,5));nstart+=5;
168
169    // demonstrate that the Tessellator makes textured tessellations
170    osg::StateSet* stateset = new osg::StateSet();
171
172    osg::Image* image = osgDB::readImageFile("Cubemap_snow/posx.jpg");
173    if (image)
174    {
175        osg::Texture2D* texture = new osg::Texture2D;
176        texture->setImage(image);
177        texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
178        texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
179        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
180    }
181    gtess->setStateSet( stateset );
182
183
184    osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator; // the v1.2 multi-contour Tessellator.
185    // we use the geometry primitives to describe the contours which are tessellated.
186    // Winding odd means leave hole in surface where there are 2,4,6... contours circling the point.
187    tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
188    tscx->setBoundaryOnly(false);
189    tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD); // so that first change in wind type makes the commonest tessellation - ODD.
190
191    tscx->retessellatePolygons(*gtess);
192
193    return gtess;
194}
195
196osg::Geometry *makeFrontWall (const float zpos) {
197    // an example of using one tessellation to make a 'house' wall
198    // describe the wall as a pentagon, then door & 4 windows are further contours
199    // tessellate the set of contours to make a 'house wall' from the Boolean-like operations.
200    int nstart=0; // counts vertices used for the geometry primitives
201
202    osg::Geometry *gtess= new osg::Geometry;
203    int i;
204    osg::Vec3Array *coords = new osg::Vec3Array;
205    osg::Vec3Array *nrms = new osg::Vec3Array;
206    osg::Vec2Array *tcs = new osg::Vec2Array;
207    osg::Vec3 nrm(0,-1,0);
208    // front wall
209    static GLdouble wall[5][2] =
210    { { 2200.0, 1130.0 },
211      { 2600.0, 1130.0 },
212      { 2600.0, 1340.0 },
213      { 2400.0, 1440.0 },
214      { 2200.0, 1340.0 } };
215
216    static GLdouble door[4][2] =
217    { { 2360.0, 1130.0 },
218      { 2440.0, 1130.0 },
219      { 2440.0, 1230.0 },
220      { 2360.0, 1230.0 } };
221
222    static GLdouble windows[16][2] =
223    { { 2240.0, 1180.0 },
224      { 2330.0, 1180.0 },
225      { 2330.0, 1220.0 },
226      { 2240.0, 1220.0 },
227      { 2460.0, 1180.0 },
228      { 2560.0, 1180.0 },
229      { 2560.0, 1220.0 },
230      { 2460.0, 1220.0 },
231      { 2240.0, 1280.0 },
232      { 2330.0, 1280.0 },
233      { 2330.0, 1320.0 },
234      { 2240.0, 1320.0 },
235      { 2460.0, 1280.0 },
236      { 2560.0, 1280.0 },
237      { 2560.0, 1320.0 },
238      { 2460.0, 1320.0 } };
239
240    gtess->setVertexArray(coords);
241    gtess->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
242    gtess->setTexCoordArray(0,tcs);
243
244    // add one large pentagon -the wall
245    for (i = 0; i < 5; i++) {
246        coords->push_back(osg::Vec3(wall[i][0],zpos,wall[i][1]));
247        tcs->push_back(osg::Vec2(wall[i][0],wall[i][1])/100.0);
248        nrms->push_back(nrm);
249    }
250    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,5));nstart+=5;
251    // add first hole, a door
252    for (i = 0; i < 4; i++) {
253        coords->push_back(osg::Vec3(door[i][0],zpos,door[i][1]));
254        tcs->push_back(osg::Vec2(door[i][0],door[i][1])/100.0);
255        nrms->push_back(nrm);
256    }
257    // and windows
258    for (i = 0; i < 16; i++) {
259        coords->push_back(osg::Vec3(windows[i][0],zpos,windows[i][1]));
260        tcs->push_back(osg::Vec2(windows[i][0],windows[i][1])/100.0);
261        nrms->push_back(nrm);
262    }
263    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,20));nstart+=20;
264
265    // demonstrate that the Tessellator makes textured tessellations
266    osg::StateSet* stateset = new osg::StateSet();
267
268    osg::Image* image = osgDB::readImageFile("Cubemap_snow/posy.jpg");
269    if (image)
270    {
271        osg::Texture2D* texture = new osg::Texture2D;
272        texture->setImage(image);
273        texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
274        texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
275        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
276    }
277    gtess->setStateSet( stateset );
278
279    // We use a Tessellator to produce the tessellation required once only
280    // and the contours are discarded.
281    osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator; // the v1.2 multi-contour Tessellator.
282    tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
283    tscx->setBoundaryOnly(false);
284    tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD); // so that first change in wind type makes the commonest tessellation - ODD.
285
286    tscx->retessellatePolygons(*gtess);
287
288    return gtess;
289}
290osg::Geode *makeHouse (void) {
291    osg::Geode *gd = new osg::Geode;
292    gd->addDrawable(makeFrontWall(0.0));
293    gd->addDrawable(makeFrontWall(300.0));
294    gd->addDrawable(makeSideWall(2200.0));
295    gd->addDrawable(makeSideWall(2600.0));
296    return gd;
297}
298osg::Geometry *makePols (void) {
299    tessellateDemoGeometry *gtess= new tessellateDemoGeometry;
300    int i;
301    osg::Vec3Array *coords = new osg::Vec3Array;
302    osg::Vec3Array *nrms = new osg::Vec3Array;
303    osg::Vec2Array *tcs = new osg::Vec2Array;
304    osg::Vec3 nrm(0,-1,0);
305    // coordinates from red book code but shifted by 1000 & 2000 for alternate Tessellatory things.
306    static GLdouble rects[12][3] =
307    { { 50.0, 50.0, 0.0 },
308      { 300.0, 50.0, 0.0 },
309      { 300.0, 300.0, 0.0 },
310      { 50.0, 300.0, 0.0 },
311      { 100.0, 100.0, 0.0 },
312      { 250.0, 100.0, 0.0 },
313      { 250.0, 250.0, 0.0 },
314      { 100.0, 250.0, 0.0 },
315      { 150.0, 150.0, 0.0 },
316      { 200.0, 150.0, 0.0 },
317      { 200.0, 200.0, 0.0 },
318      { 150.0, 200.0, 0.0 } };
319
320    static GLdouble rectsMidanti[12][3] = // the centre 2 contours are traversed opposite order to outer contour.
321    { { 1050.0, 50.0, 0.0 },
322      { 1300.0, 50.0, 0.0 },
323      { 1300.0, 300.0, 0.0 },
324      { 1050.0, 300.0, 0.0 },
325      { 1250.0, 100.0, 0.0 },
326      { 1100.0, 100.0, 0.0 },
327      { 1100.0, 250.0, 0.0 },
328      { 1250.0, 250.0, 0.0 },
329      { 1200.0, 150.0, 0.0 },
330      { 1150.0, 150.0, 0.0 },
331      { 1150.0, 200.0, 0.0 },
332      { 1200.0, 200.0, 0.0 } };
333    static GLdouble spiral[16][3] = // shift by 1000; nb the order of vertices is reversed from that of the red book
334    { { 3400.0, 250.0, 0.0 },
335      { 3400.0, 50.0, 0.0 },
336      { 3050.0, 50.0, 0.0 },
337      { 3050.0, 400.0, 0.0 },
338      { 3350.0, 400.0, 0.0 },
339      { 3350.0, 100.0, 0.0 },
340      { 3100.0, 100.0, 0.0 },
341      { 3100.0, 350.0, 0.0 },
342      { 3300.0, 350.0, 0.0 },
343      { 3300.0, 150.0, 0.0 },
344      { 3150.0, 150.0, 0.0 },
345      { 3150.0, 300.0, 0.0 },
346      { 3250.0, 300.0, 0.0 },
347      { 3250.0, 200.0, 0.0 },
348      { 3200.0, 200.0, 0.0 },
349      { 3200.0, 250.0, 0.0 }
350    };
351    static GLdouble quad1[4][3] = // shift by 2000 for next 3 things
352    { { 2050.0, 150.0, 0.0 },
353      { 2350.0, 150.0, 0.0 },
354      { 2350.0, 200.0, 0.0 },
355      { 2050.0, 200.0, 0.0 }
356    };
357    static GLdouble quad2[4][3] =
358    { { 2100.0, 100.0, 0.0 },
359      { 2300.0, 100.0, 0.0 },
360      { 2300.0, 350.0, 0.0 },
361      { 2100.0, 350.0, 0.0 }
362    };
363    static GLdouble tri[3][3] =
364    { { 2200.0, 50.0, 0.0 },
365      { 2250.0, 300.0, 0.0 },
366      { 2150.0, 300.0, 0.0 }
367    };
368    static GLdouble quad3[4][3] =
369    { { 100.0, 1100.0, 0.0 },
370      { 1300.0, 1100.0, 0.0 },
371      { 1300.0, 2350.0, 0.0 },
372      { 100.0, 2350.0, 0.0}
373    };
374    static GLdouble quadstrip[8][3] =
375    { { 900.0, 1130.0, 0.0 },
376      { 1100.0, 1130.0, 0.0 },
377      { 900.0, 1350.0, 0.0 },
378      { 950.0, 1350.0, 0.0 },
379      { 900.0, 1550.0, 0.0 },
380      { 1000.0, 1550.0, 0.0 },
381      { 900.0, 1750.0, 0.0 },
382      { 1400.0, 1750.0, 0.0 }
383    };
384
385    for (i = 0; i < 12; i++) {
386        coords->push_back(osg::Vec3(rects[i][0],rects[i][2],rects[i][1]));
387        tcs->push_back(osg::Vec2(rects[i][0],rects[i][1])/200.0);
388        nrms->push_back(nrm);
389    }
390    for (i = 0; i < 12; i++) {
391        coords->push_back(osg::Vec3(rectsMidanti[i][0],rectsMidanti[i][2],rectsMidanti[i][1]));
392        tcs->push_back(osg::Vec2(rectsMidanti[i][0],rectsMidanti[i][1])/200.0);
393        nrms->push_back(nrm);
394    }
395    for (i = 0; i < 16; i++) { // and reverse spiral to make same as that of red book ch 11
396        coords->push_back(osg::Vec3(spiral[15-i][0],spiral[15-i][2],spiral[15-i][1]));
397        tcs->push_back(osg::Vec2(spiral[15-i][0],spiral[15-i][1])/200.0);
398        nrms->push_back(nrm);
399    }
400    for (i = 0; i < 4; i++) {
401        coords->push_back(osg::Vec3(quad1[i][0],quad1[i][2],quad1[i][1]));
402        tcs->push_back(osg::Vec2(quad1[i][0],quad1[i][1])/200.0);
403        nrms->push_back(nrm);
404    }
405    for (i = 0; i < 4; i++) {
406        coords->push_back(osg::Vec3(quad2[i][0],quad2[i][2],quad2[i][1]));
407        tcs->push_back(osg::Vec2(quad2[i][0],quad2[i][1])/200.0);
408        nrms->push_back(nrm);
409    }
410    for (i = 0; i < 3; i++) {
411        coords->push_back(osg::Vec3(tri[i][0],tri[i][2],tri[i][1]));
412        tcs->push_back(osg::Vec2(tri[i][0],tri[i][1])/200.0);
413        nrms->push_back(nrm);
414    }
415    // add one large quad with multiple holes
416    for (i = 0; i < 4; i++) {
417        coords->push_back(osg::Vec3(quad3[i][0],quad3[i][2],quad3[i][1]));
418        tcs->push_back(osg::Vec2(quad3[i][0],quad3[i][1])/200.0);
419        nrms->push_back(nrm);
420    }
421    {
422        osg::Vec3 centre(300,0,1500);
423        for (i = 0; i < 18; i++) {
424            osg::Vec3 rim=centre+osg::Vec3(-cos(osg::DegreesToRadians((float)i*20.0)),0.0,sin(osg::DegreesToRadians((float)i*20.0)))*150.0;
425            coords->push_back(rim);
426            tcs->push_back(osg::Vec2(rim.x(),rim.z())/200.0);
427            nrms->push_back(nrm);
428        }
429    }
430    {
431        osg::Vec3 centre(400,0,1800);
432        for (i = 0; i < 18; i++) {
433            osg::Vec3 rim=centre+osg::Vec3(-cos(osg::DegreesToRadians((float)i*15.0)),0.0,sin(osg::DegreesToRadians((float)i*15.0)))*250.0;
434            coords->push_back(rim);
435            tcs->push_back(osg::Vec2(rim.x(),rim.z())/200.0);
436            nrms->push_back(nrm);
437        }
438    }
439    {
440        osg::Vec3 centre(600,0,1400);
441        for (i = 0; i < 18; i++) {
442            osg::Vec3 rim=centre+osg::Vec3(-cos(osg::DegreesToRadians((float)i*12.0)),0.0,sin(osg::DegreesToRadians((float)i*12.0)))*250.0;
443            coords->push_back(rim);
444            tcs->push_back(osg::Vec2(rim.x(),rim.z())/200.0);
445            nrms->push_back(nrm);
446        }
447    }
448    // add one large quadstrip
449    for (i = 0; i < 8; i++) {
450        coords->push_back(osg::Vec3(quadstrip[i][0],quadstrip[i][2],quadstrip[i][1]));
451        tcs->push_back(osg::Vec2(quadstrip[i][0],quadstrip[i][1])/200.0);
452        nrms->push_back(nrm);
453    }
454    gtess->setVertexArray(coords);
455    gtess->setNormalArray(nrms, osg::Array::BIND_PER_VERTEX);
456    gtess->setTexCoordArray(0,tcs);
457
458    // demonstrate that the Tessellator makes textured tessellations
459    osg::StateSet* stateset = new osg::StateSet();
460
461    osg::Image* image = osgDB::readImageFile("Cubemap_snow/posz.jpg");
462    if (image)
463    {
464        osg::Texture2D* texture = new osg::Texture2D;
465        texture->setImage(image);
466        texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
467        texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
468        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
469    }
470    gtess->setStateSet( stateset );
471
472    int nstart=0;
473    // the contours accepoted are polygons; quads & tris. Trifans can bve added later.
474    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,12));nstart+=12;
475    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,12));nstart+=12;
476    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,16));nstart+=16;
477    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,4));nstart+=4;
478    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,nstart,4));nstart+=4;
479    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,nstart,3));nstart+=3;
480    // A rectabngle with multiple holes
481    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,nstart,4));nstart+=4;
482    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,nstart,18));nstart+=18;
483    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,18));nstart+=18;
484    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart,18));nstart+=18;
485    // test for quad strip
486    gtess->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP,nstart,8));nstart+=8;
487
488    // We need to access the tessellatable contours again to demonstrate all types of tessellation.
489    // I could add the Tessellator to the geometry as userdata, but here
490    // I use the derived tessellateDemoGeometry to hold both the drawable geode and the original contours.
491
492    gtess->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
493    gtess->setBoundaryOnly(true);
494    gtess->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO); // so that first change in wind type makes the commonest tessellation - ODD.
495
496    return gtess;
497}
498osg::Node* createHUD()
499{ // add a string reporting the type of winding rule tessellation applied
500    osg::Geode* geode = new osg::Geode();
501
502    std::string timesFont("fonts/arial.ttf");
503
504    // turn lighting off for the text and disable depth test to ensure its always ontop.
505    osg::StateSet* stateset = geode->getOrCreateStateSet();
506    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
507
508    // Disable depth test, and make sure that the hud is drawn after everything
509    // else so that it always appears ontop.
510    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
511    stateset->setRenderBinDetails(11,"RenderBin");
512
513    osg::Vec3 position(150.0f,900.0f,0.0f);
514    osg::Vec3 delta(0.0f,-30.0f,0.0f);
515
516    {
517        osgText::Text* text = new  osgText::Text;
518        geode->addDrawable( text );
519
520        text->setFont(timesFont);
521        text->setPosition(position);
522        text->setText("Tessellation example - no tessellation (use 'W' wireframe to visualise)");
523        text->setColor(osg::Vec4(1.0,1.0,0.8,1.0));
524        position += delta;
525
526    }
527    {
528        osgText::Text* text = new  osgText::Text;
529        geode->addDrawable( text );
530
531        text->setFont(timesFont);
532        text->setPosition(position);
533        text->setText("Press 'n' to use an alternative tessellation.");
534
535    }
536
537    // create the hud.
538    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
539    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
540    modelview_abs->setMatrix(osg::Matrix::identity());
541    modelview_abs->addChild(geode);
542
543    osg::Projection* projection = new osg::Projection;
544    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
545    projection->addChild(modelview_abs);
546
547    return projection;
548
549}
550
551
552osg::Group *makeTessellateExample (void) {
553    osg::Group *grp=new osg::Group;
554    osg::Geode *gd=new osg::Geode;
555    gd->addDrawable(makePols());
556    gd->addDrawable(makePolsTwo());
557    grp->addChild(gd);
558
559    grp->addChild(makeHouse());
560
561    return grp;
562}
563
564class setTessellateVisitor : public osg::NodeVisitor
565{ // searches a loaded model tree for tessellatable geometries.
566    // used with any database model which has a renderGroup (Geode) named 'tessellate'
567    // or you can force a type of tess with special names or a sub-class of Geode could have extra information
568    // of course you can use any name to detect what is to be tessellated!
569    // all the polygons within the specific node are deemed to be contours, so
570    // any tessellation can be requested.
571public:
572
573    setTessellateVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {
574    }
575    virtual void apply(osg::Geode& geode) {
576        if (geode.getName().compare(0,9,"tessellate")==0) {
577            for(unsigned int i=0;i<geode.getNumDrawables();++i)
578            {
579                osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
580                if (geom) {
581                    osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator();
582                    if (tscx.valid()) {
583                        tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
584                        if (geode.getName()== "tessellate") {
585                            // add a Tessellator so that this geom is retessellated when N is pressed
586                            tscx->setBoundaryOnly(true);
587                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO); // so that first change in wind type makes the commonest tessellation - ODD.
588                            geom->setUserData(tscx.get());
589                        } else if (geode.getName()== "tessellate odd") {
590                            // OR you can just apply the Tessellator once only, using these different types
591                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD); // commonest tessellation - ODD.
592                            tscx->retessellatePolygons(*geom);
593                        } else if (geode.getName()== "tessellate odd bound") {
594                            tscx->setBoundaryOnly(true);
595                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD); // tessellation - ODD, only show boundary.
596                            tscx->retessellatePolygons(*geom);
597                        } else if (geode.getName()== "tessellate positive") {
598                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE); // tessellation - pos.
599                            tscx->retessellatePolygons(*geom);
600                        } else if (geode.getName()== "tessellate positive bound") {
601                            tscx->setBoundaryOnly(true);
602                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE);
603                            tscx->retessellatePolygons(*geom);
604                        } else if (geode.getName()== "tessellate negative") {
605                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NEGATIVE);
606                            tscx->retessellatePolygons(*geom);
607                        } else if (geode.getName()== "tessellate negative bound") {
608                            tscx->setBoundaryOnly(true);
609                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NEGATIVE);
610                            tscx->retessellatePolygons(*geom);
611                        } else if (geode.getName()== "tessellate nonzero") {
612                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NONZERO);
613                            tscx->retessellatePolygons(*geom);
614                        } else if (geode.getName()== "tessellate nonzero bound") {
615                            tscx->setBoundaryOnly(true);
616                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_NONZERO);
617                            tscx->retessellatePolygons(*geom);
618                        } else if (geode.getName()== "tessellate geq2") {
619                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO);
620                            tscx->retessellatePolygons(*geom);
621                        } else if (geode.getName()== "tessellate geq2 bound") {
622                            tscx->setBoundaryOnly(true);
623                            tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO);
624                            tscx->retessellatePolygons(*geom);
625                        }
626                    }
627                }
628            }
629        }
630    }
631};
632
633class cxTessellateVisitor : public osg::NodeVisitor
634{ // special to this demo, traverses SG and finds nodes which have been tessellated
635    // for test/demo purposes these nodes are of type tessellateDemoGeometry
636    // but you could store the Tessellator as UserData or however you like.
637    // the Tessellator holds copies of the original contours used in the tessellation
638    // In this visitor, I reuse the contours to make a different type of tessellation.
639public:
640
641    cxTessellateVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {
642    }
643    virtual void apply(osg::Geode& geode) {
644
645        for(unsigned int i=0;i<geode.getNumDrawables();++i)
646        {
647            tessellateDemoGeometry *geom=dynamic_cast<tessellateDemoGeometry*>(geode.getDrawable(i));
648            if (geom) {
649                if (!geom->getBoundaryOnly()) { // turn on bounds only
650                    // NB this shows only the true boundary of the curves, no internal edges
651                    geom->setBoundaryOnly(true);
652
653                } else { // change to next type of tessellation...
654                    geom->setBoundaryOnly(false);
655                    switch (geom->getWindingType()) {
656                    case         osgUtil::Tessellator::TESS_WINDING_ODD:
657                        geom->setWindingType(osgUtil::Tessellator::TESS_WINDING_NONZERO);
658                        break;
659                    case    osgUtil::Tessellator::TESS_WINDING_NONZERO:
660                        geom->setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE);
661                        break;
662                    case    osgUtil::Tessellator::TESS_WINDING_POSITIVE:
663                        geom->setWindingType( osgUtil::Tessellator::TESS_WINDING_NEGATIVE);
664                        break;
665                    case    osgUtil::Tessellator::TESS_WINDING_NEGATIVE:
666                        geom->setWindingType( osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO);
667                        break;
668                    case    osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO:
669                        geom->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD);
670                        break;
671                    }
672                }
673
674                switch (geom->getWindingType()) { // a text to be added to the scene.
675                case         osgUtil::Tessellator::TESS_WINDING_ODD:
676                    str="TESS_WINDING_ODD";
677                    break;
678                case    osgUtil::Tessellator::TESS_WINDING_NONZERO:
679                    str="TESS_WINDING_NONZERO";
680                    break;
681                case    osgUtil::Tessellator::TESS_WINDING_POSITIVE:
682                    str="TESS_WINDING_POSITIVE";
683                    break;
684                case    osgUtil::Tessellator::TESS_WINDING_NEGATIVE:
685                    str="TESS_WINDING_NEGATIVE";
686                    break;
687                case    osgUtil::Tessellator::TESS_WINDING_ABS_GEQ_TWO:
688                    str="TESS_WINDING_ABS_GEQ_TWO";
689                    break;
690                }
691                if (geom->getBoundaryOnly()) str += " Boundary";
692
693                geom->retessellatePolygons(*geom);
694            }
695            osgText::Text* txt = dynamic_cast<osgText::Text*>(geode.getDrawable(i));
696            if (txt) {
697                const osg::Vec4& ct=txt->getColor(); // pick the text to be changed by its color
698                if (ct.z()<0.9) {
699                    txt->setText(str.c_str());
700                }
701            }
702        }
703        traverse(geode);
704    }
705
706    std::string str; // a label for on screen display
707};
708
709class KeyboardEventHandler : public osgGA::GUIEventHandler
710{ // extra event handler traps 'n' key to re-tessellate any tessellated geodes.
711public:
712
713    KeyboardEventHandler(osg::Node *nd):
714        _scene(nd) {}
715
716        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&)
717        {
718            switch(ea.getEventType())
719            {
720                case(osgGA::GUIEventAdapter::KEYDOWN):
721                {
722                    if (_scene && ea.getKey()=='n')
723                    {
724                        // re-tessellate the scene graph.
725                        // the same contours are re-tessellated using a new method. Old contours
726                        // & tessellation type are held internally in the derived Geode class tessellateDemoGeometry.
727                        cxTessellateVisitor tsv;
728                        _scene->accept(tsv);
729                       return true;
730                    }
731                    break;
732                }
733                default:
734                    break;
735            }
736            return false;
737        }
738
739        osg::Node *_scene;
740
741};
742
743
744int main( int argc, char **argv )
745{
746    // use an ArgumentParser object to manage the program arguments.
747    osg::ArgumentParser arguments(&argc,argv);
748
749    // construct the viewer.
750    osgViewer::Viewer viewer;
751
752    // read the scene from the list of file specified commandline args.
753    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
754
755    // if no model has been successfully loaded report failure.
756    if (!loadedModel)
757    {
758        loadedModel=makeTessellateExample();
759
760    } else { // if there is a loaded model:
761
762        // tessellate by searching for geode called tessellate & tessellate it
763        setTessellateVisitor tsv;
764        loadedModel->accept(tsv);
765
766    }
767
768    // create the hud.
769    osg::Group *gload= dynamic_cast<osg::Group *> (loadedModel.get());
770    gload->addChild(createHUD());
771
772
773    osgUtil::Optimizer optimizer;
774    optimizer.optimize(loadedModel.get() );
775
776    // set the scene to render
777    viewer.setSceneData(loadedModel.get());
778
779    // add event handler for keyboard 'n' to retessellate
780    viewer.addEventHandler(new KeyboardEventHandler(loadedModel.get()));
781
782    return viewer.run();
783}
Note: See TracBrowser for help on using the browser.