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

Revision 13574, 31.6 kB (checked in by robert, 39 hours ago)

Fixed comment

  • 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.