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 <osgUtil/SceneGraphBuilder>
14 
15 #include <osg/Notify>
16 #include <osg/io_utils>
17 
18 #include <osg/PrimitiveSet>
19 #include <osg/Texture>
20 #include <osg/AlphaFunc>
21 #include <osg/BlendFunc>
22 #include <osg/LineStipple>
23 #include <osg/Depth>
24 #include <osg/CullFace>
25 #include <osg/FrontFace>
26 #include <osg/LineWidth>
27 #include <osg/Point>
28 #include <osg/PolygonMode>
29 #include <osg/PolygonOffset>
30 #include <osg/PolygonStipple>
31 #include <osg/ShadeModel>
32 #include <osg/ShapeDrawable>
33 
34 using namespace osgUtil;
35 
SceneGraphBuilder()36 SceneGraphBuilder::SceneGraphBuilder():
37     _statesetAssigned(false),
38     _normalSet(false),
39     _normal(0.0f,0.0f,1.0f),
40     _colorSet(false),
41     _color(1.0f,1.0f,1.0f,1.0f),
42     _maxNumTexCoordComponents(0),
43     _texCoord(0.f,0.0f,0.0f,1.0f),
44     _primitiveMode(0)
45 {
46 }
47 
48 
49 ///////////////////////////////////////////////////////////////////////////////////////////
50 //
51 // OpenGL 1.0 building methods
52 //
PushMatrix()53 void SceneGraphBuilder::PushMatrix()
54 {
55     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
56     else _matrixStack.push_back(_matrixStack.back());
57 }
58 
PopMatrix()59 void SceneGraphBuilder::PopMatrix()
60 {
61     if (!_matrixStack.empty()) _matrixStack.pop_back();
62 
63     matrixChanged();
64 }
65 
LoadIdentity()66 void SceneGraphBuilder::LoadIdentity()
67 {
68     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
69     _matrixStack.back().makeIdentity();
70 
71     matrixChanged();
72 }
73 
LoadMatrixd(const GLdouble * m)74 void SceneGraphBuilder::LoadMatrixd(const GLdouble* m)
75 {
76     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
77     _matrixStack.back().set(m);
78 
79     matrixChanged();
80 }
81 
MultMatrixd(const GLdouble * m)82 void SceneGraphBuilder::MultMatrixd(const GLdouble* m)
83 {
84     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
85     _matrixStack.back().preMult(osg::Matrixd(m));
86 
87     matrixChanged();
88 }
89 
Translated(GLdouble x,GLdouble y,GLdouble z)90 void SceneGraphBuilder::Translated(GLdouble x, GLdouble y, GLdouble z)
91 {
92     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
93     _matrixStack.back().preMultTranslate(osg::Vec3d(x,y,z));
94 
95     matrixChanged();
96 }
97 
Scaled(GLdouble x,GLdouble y,GLdouble z)98 void SceneGraphBuilder::Scaled(GLdouble x, GLdouble y, GLdouble z)
99 {
100     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
101     _matrixStack.back().preMultScale(osg::Vec3d(x,y,z));
102 
103     matrixChanged();
104 }
105 
Rotated(GLdouble angle,GLdouble x,GLdouble y,GLdouble z)106 void SceneGraphBuilder::Rotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
107 {
108     if (_matrixStack.empty()) _matrixStack.push_back(osg::Matrixd());
109     _matrixStack.back().preMultRotate(osg::Quat(osg::inDegrees(angle),osg::Vec3d(x,y,z)));
110 
111     matrixChanged();
112 }
113 
BlendFunc(GLenum srcFactor,GLenum dstFactor)114 void SceneGraphBuilder::BlendFunc(GLenum srcFactor, GLenum dstFactor)
115 {
116     addAttribute(new osg::BlendFunc(srcFactor, dstFactor));
117 }
118 
CullFace(GLenum mode)119 void SceneGraphBuilder::CullFace(GLenum mode)
120 {
121     addAttribute(new osg::CullFace(osg::CullFace::Mode(mode)));
122 }
123 
DepthFunc(GLenum mode)124 void SceneGraphBuilder::DepthFunc(GLenum mode)
125 {
126     addAttribute(new osg::Depth(osg::Depth::Function(mode)));
127 }
128 
FrontFace(GLenum mode)129 void SceneGraphBuilder::FrontFace(GLenum mode)
130 {
131     addAttribute(new osg::FrontFace(osg::FrontFace::Mode(mode)));
132 }
133 
LineStipple(GLint factor,GLushort pattern)134 void SceneGraphBuilder::LineStipple(GLint factor, GLushort pattern)
135 {
136     addAttribute(new osg::LineStipple(factor, pattern));
137 }
138 
LineWidth(GLfloat lineWidth)139 void SceneGraphBuilder::LineWidth(GLfloat lineWidth)
140 {
141     addAttribute(new osg::LineWidth(lineWidth));
142 }
143 
PointSize(GLfloat pointSize)144 void SceneGraphBuilder::PointSize(GLfloat pointSize)
145 {
146     addAttribute(new osg::Point(pointSize));
147 }
148 
PolygonMode(GLenum face,GLenum mode)149 void SceneGraphBuilder::PolygonMode(GLenum face, GLenum mode)
150 {
151     addAttribute(new osg::PolygonMode(osg::PolygonMode::Face(face),osg::PolygonMode::Mode(mode)));
152 }
153 
PolygonOffset(GLfloat factor,GLfloat units)154 void SceneGraphBuilder::PolygonOffset(GLfloat factor, GLfloat units)
155 {
156     addAttribute(new osg::PolygonOffset(factor,units));
157 }
158 
PolygonStipple(const GLubyte * mask)159 void SceneGraphBuilder::PolygonStipple(const GLubyte* mask)
160 {
161     addAttribute(new osg::PolygonStipple(mask));
162 }
163 
ShadeModel(GLenum mode)164 void SceneGraphBuilder::ShadeModel(GLenum mode)
165 {
166     addAttribute(new osg::ShadeModel(osg::ShadeModel::Mode(mode)));
167 }
Enable(GLenum mode)168 void SceneGraphBuilder::Enable(GLenum mode)
169 {
170     addMode(mode, true);
171 }
172 
Disable(GLenum mode)173 void SceneGraphBuilder::Disable(GLenum mode)
174 {
175     addMode(mode, false);
176 }
177 
Color4f(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)178 void SceneGraphBuilder::Color4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
179 {
180     _normalSet = true;
181     _color.set(red,green,blue,alpha);
182 }
183 
Normal3f(GLfloat x,GLfloat y,GLfloat z)184 void SceneGraphBuilder::Normal3f(GLfloat x, GLfloat y, GLfloat z)
185 {
186     _normalSet = true;
187     _normal.set(x,y,z);
188 }
189 
TexCoord1f(GLfloat x)190 void SceneGraphBuilder::TexCoord1f(GLfloat x)
191 {
192     _maxNumTexCoordComponents = 1;
193     _texCoord.set(x,0.0f,0.0f,1.0f);
194 }
195 
TexCoord2f(GLfloat x,GLfloat y)196 void SceneGraphBuilder::TexCoord2f(GLfloat x, GLfloat y)
197 {
198     _maxNumTexCoordComponents = 2;
199     _texCoord.set(x,y,0.0f,1.0f);
200 }
201 
TexCoord3f(GLfloat x,GLfloat y,GLfloat z)202 void SceneGraphBuilder::TexCoord3f(GLfloat x, GLfloat y, GLfloat z)
203 {
204     _maxNumTexCoordComponents = 3;
205     _texCoord.set(x,y,z,1.0);
206 }
207 
TexCoord4f(GLfloat x,GLfloat y,GLfloat z,GLfloat w)208 void SceneGraphBuilder::TexCoord4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
209 {
210     _maxNumTexCoordComponents = 4;
211     _texCoord.set(x,y,z,w);
212 }
213 
Vertex3f(GLfloat x,GLfloat y,GLfloat z)214 void SceneGraphBuilder::Vertex3f(GLfloat x, GLfloat y, GLfloat z)
215 {
216     osg::Vec3 vertex(x,y,z);
217 
218     vertex = vertex * _matrixStack.back();
219 
220     if (_vertices.valid()) _vertices->push_back(vertex);
221     if (_normal.valid()) _normals->push_back(_normal);
222     if (_colors.valid()) _colors->push_back(_color);
223     if (_texCoords.valid()) _texCoords->push_back(_texCoord);
224 }
225 
Begin(GLenum mode)226 void SceneGraphBuilder::Begin(GLenum mode)
227 {
228     // reset geometry
229     _primitiveMode = mode;
230     _vertices = new osg::Vec3Array;
231 
232     _normalSet = false;
233     _normals = new osg::Vec3Array;
234 
235     _colorSet = false;
236     _colors = new osg::Vec4Array;
237 
238     _maxNumTexCoordComponents = 0;
239     _texCoords = new osg::Vec4Array;
240 
241 }
242 
End()243 void SceneGraphBuilder::End()
244 {
245     allocateGeometry();
246 
247     _geometry->setVertexArray(_vertices.get());
248 
249     if (_colorSet)
250     {
251          _geometry->setColorArray(_colors.get(), osg::Array::BIND_PER_VERTEX);
252     }
253     else
254     {
255          osg::Vec4Array* colors = new osg::Vec4Array;
256          colors->push_back(_color);
257 
258          _geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
259     }
260 
261     if (_normalSet)
262     {
263          _geometry->setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX);
264     }
265     else
266     {
267          _geometry->setNormalArray(NULL, osg::Array::BIND_OFF);
268     }
269 
270     if (_maxNumTexCoordComponents==1)
271     {
272         // convert Vec4Array into FloatArray
273         osg::FloatArray* texCoords = new osg::FloatArray;
274         for(osg::Vec4Array::iterator itr = _texCoords->begin();
275             itr != _texCoords->end();
276             ++itr)
277         {
278             texCoords->push_back(itr->x());
279         }
280          _geometry->setTexCoordArray(0, texCoords);
281     }
282     if (_maxNumTexCoordComponents==2)
283     {
284         // convert Vec4Array into FloatArray
285         osg::Vec2Array* texCoords = new osg::Vec2Array;
286         for(osg::Vec4Array::iterator itr = _texCoords->begin();
287             itr != _texCoords->end();
288             ++itr)
289         {
290             texCoords->push_back(osg::Vec2(itr->x(),itr->y()));
291         }
292          _geometry->setTexCoordArray(0, texCoords);
293     }
294     if (_maxNumTexCoordComponents==3)
295     {
296         // convert Vec4Array into FloatArray
297         osg::Vec3Array* texCoords = new osg::Vec3Array;
298         for(osg::Vec4Array::iterator itr = _texCoords->begin();
299             itr != _texCoords->end();
300             ++itr)
301         {
302             texCoords->push_back(osg::Vec3(itr->x(),itr->y(), itr->z()));
303         }
304          _geometry->setTexCoordArray(0, texCoords);
305     }
306     else if (_maxNumTexCoordComponents==4)
307     {
308          _geometry->setTexCoordArray(0, _texCoords.get());
309     }
310 
311     _geometry->addPrimitiveSet(new osg::DrawArrays(_primitiveMode, 0, _vertices->size()));
312 
313     completeGeometry();
314 }
315 
316 ///////////////////////////////////////////////////////////////////////////////////////////
317 //
318 //  GLU style building methods
319 //
QuadricDrawStyle(GLenum aDrawStyle)320 void SceneGraphBuilder::QuadricDrawStyle(GLenum aDrawStyle)
321 {
322     _quadricState._drawStyle = aDrawStyle;
323 }
324 
QuadricNormals(GLenum aNormals)325 void SceneGraphBuilder::QuadricNormals(GLenum aNormals)
326 {
327     _quadricState._normals = aNormals;
328 }
329 
QuadricOrientation(GLenum aOrientation)330 void SceneGraphBuilder::QuadricOrientation(GLenum aOrientation)
331 {
332     _quadricState._orientation = aOrientation;
333 }
334 
QuadricTexture(GLboolean aTexture)335 void SceneGraphBuilder::QuadricTexture(GLboolean aTexture)
336 {
337     _quadricState._texture = aTexture;
338 }
339 
Cylinder(GLfloat aBase,GLfloat aTop,GLfloat aHeight,GLint aSlices,GLint aStacks)340 void SceneGraphBuilder::Cylinder(GLfloat        aBase,
341                              GLfloat        aTop,
342                              GLfloat        aHeight,
343                              GLint          aSlices,
344                              GLint          aStacks)
345 {
346     OSG_NOTICE<<"SceneGraphBuilder::Cylinder("<<aBase<<", "<<aTop<<", "<<aHeight<<", "<<aSlices<<", "<<aStacks<<") not implemented yet"<<std::endl;
347 }
348 
Disk(GLfloat,GLfloat outer,GLint slices,GLint)349 void SceneGraphBuilder::Disk(GLfloat        /*inner*/,
350                              GLfloat        outer,
351                              GLint          slices,
352                              GLint          /*loops*/)
353 {
354     double angle = 0.0;
355     double delta = 2.0*osg::PI/double(slices-1);
356 
357     if (_quadricState._normals!=GLU_NONE) Normal3f(0.0f,0.0f,1.0f);
358 
359     switch(_quadricState._drawStyle)
360     {
361         case(GLU_POINT):
362         {
363             Begin(GL_POINTS);
364             if (_quadricState._texture) TexCoord2f(0.5f,0.5f);
365             Vertex3f(0.0f, 0.0f, 0.0f);
366             for(GLint i=0; i<slices; ++i, angle += delta)
367             {
368                 if (_quadricState._texture) TexCoord2f(GLfloat(sin(angle)*0.5+0.5), GLfloat(cos(angle)*0.5+0.5));
369                 Vertex3f(outer*GLfloat(sin(angle)), outer*GLfloat(cos(angle)), 0.0f);
370             }
371             End();
372             break;
373         }
374         case(GLU_LINE):
375         {
376             Begin(GL_LINE_LOOP);
377             for(GLint i=0; i<slices; ++i, angle += delta)
378             {
379                 if (_quadricState._texture) TexCoord2f(GLfloat(sin(angle)*0.5+0.5), GLfloat(cos(angle)*0.5+0.5));
380                 Vertex3f(outer*GLfloat(sin(angle)), outer*GLfloat(cos(angle)), 0.0f);
381             }
382             End();
383             break;
384         }
385         case(GLU_FILL):
386         {
387             Begin(GL_TRIANGLE_FAN);
388             if (_quadricState._texture) TexCoord2f(0.5f,0.5f);
389             Vertex3f(0.0f, 0.0f, 0.0f);
390             for(GLint i=0; i<slices; ++i, angle += delta)
391             {
392                 if (_quadricState._texture) TexCoord2f(GLfloat(sin(angle)*0.5+0.5), GLfloat(cos(angle)*0.5+0.5));
393                 Vertex3f(outer*GLfloat(sin(angle)), outer*GLfloat(cos(angle)), 0.0f);
394             }
395             End();
396             break;
397         }
398         case(GLU_SILHOUETTE):
399         {
400             Begin(GL_LINE_LOOP);
401             for(GLint i=0; i<slices; ++i, angle += delta)
402             {
403                 if (_quadricState._texture) TexCoord2f(GLfloat(sin(angle)*0.5+0.5), GLfloat(cos(angle)*0.5+0.5));
404                 Vertex3f(outer*GLfloat(sin(angle)), outer*GLfloat(cos(angle)), 0.0f);
405             }
406             End();
407             break;
408         }
409     }
410 }
411 
PartialDisk(GLfloat inner,GLfloat outer,GLint slices,GLint loops,GLfloat start,GLfloat sweep)412 void SceneGraphBuilder::PartialDisk(GLfloat        inner,
413                                     GLfloat        outer,
414                                     GLint          slices,
415                                     GLint          loops,
416                                     GLfloat        start,
417                                     GLfloat        sweep)
418 {
419     OSG_NOTICE<<"SceneGraphBuilder::PartialDisk("<<inner<<", "<<outer<<", "<<slices<<", "<<loops<<", "<<start<<", "<<sweep<<") not implemented yet."<<std::endl;
420     OSG_NOTICE<<"   quadric("<<_quadricState._drawStyle<<", "<<_quadricState._normals<<", "<<_quadricState._orientation<<", "<<_quadricState._texture<<std::endl;
421 }
422 
Sphere(GLfloat radius,GLint,GLint)423 void SceneGraphBuilder::Sphere(GLfloat        radius,
424                                GLint          /*slices*/,
425                                GLint          /*stacks*/)
426 {
427     addShape(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f), radius));
428 }
429 
430 
431 ///////////////////////////////////////////////////////////////////////////////////////////
432 //
433 //  General scene graph building methods
434 //
435 
getScene()436 osg::Node* SceneGraphBuilder::getScene()
437 {
438     if (_group.valid() && _group->getNumChildren()>0) return _group.get();
439     else if (_transform.valid() && _transform->getNumChildren()>0) return _transform.get();
440     else if (_geode.valid() && _geode->getNumDrawables()>0) return _geode.get();
441 
442     return 0;
443 }
444 
takeScene()445 osg::Node* SceneGraphBuilder::takeScene()
446 {
447     osg::ref_ptr<osg::Node> node;
448 
449     if (_group.valid() && _group->getNumChildren()>0) node = _group.get();
450     else if (_transform.valid() && _transform->getNumChildren()>0) node = _transform.get();
451     else if (_geode.valid() && _geode->getNumDrawables()>0) node = _geode.get();
452 
453     // reset all the pointers to properly release the scene graph
454     _geometry = 0;
455     _geode = 0;
456     _transform = 0;
457     _group = 0;
458 
459     return node.release();
460 }
461 
matrixChanged()462 void SceneGraphBuilder::matrixChanged()
463 {
464 }
465 
addAttribute(osg::StateAttribute * attribute)466 void SceneGraphBuilder::addAttribute(osg::StateAttribute* attribute)
467 {
468     allocateStateSet();
469     _stateset->setAttribute(attribute);
470 }
471 
addMode(GLenum mode,bool enabled)472 void SceneGraphBuilder::addMode(GLenum mode, bool enabled)
473 {
474     allocateStateSet();
475     _stateset->setMode(mode, enabled ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
476 }
477 
478 
addTextureAttribute(unsigned int unit,osg::StateAttribute * attribute)479 void SceneGraphBuilder::addTextureAttribute(unsigned int unit, osg::StateAttribute* attribute)
480 {
481     allocateStateSet();
482     _stateset->setTextureAttribute(unit, attribute);
483 }
484 
addTextureMode(unsigned int unit,GLenum mode,bool enabled)485 void SceneGraphBuilder::addTextureMode(unsigned int unit, GLenum mode, bool enabled)
486 {
487     allocateStateSet();
488     _stateset->setTextureMode(unit, mode, enabled ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
489 }
490 
addShape(osg::Shape * shape)491 void SceneGraphBuilder::addShape(osg::Shape* shape)
492 {
493     osg::ShapeDrawable* sd = new osg::ShapeDrawable(shape);
494     sd->setColor(_color);
495 
496     addDrawable(sd);
497 }
498 
addDrawable(osg::Drawable * drawable)499 void SceneGraphBuilder::addDrawable(osg::Drawable* drawable)
500 {
501     if (!_geode) _geode = new osg::Geode;
502 
503     if (_stateset.valid())
504     {
505         drawable->setStateSet(_stateset.get());
506         _statesetAssigned = true;
507     }
508 
509     _geode->addDrawable(drawable);
510 }
511 
allocateStateSet()512 void SceneGraphBuilder::allocateStateSet()
513 {
514     if (_statesetAssigned)
515     {
516         _stateset = dynamic_cast<osg::StateSet*>(_stateset->clone(osg::CopyOp::SHALLOW_COPY));
517         _statesetAssigned = false;
518     }
519 
520     if (!_stateset) _stateset = new osg::StateSet;
521 }
522 
allocateGeometry()523 void SceneGraphBuilder::allocateGeometry()
524 {
525     if (!_geometry)
526     {
527         _geometry = new osg::Geometry;
528     }
529 }
530 
completeGeometry()531 void SceneGraphBuilder::completeGeometry()
532 {
533     if (_geometry.valid()) addDrawable(_geometry.get());
534     _geometry = 0;
535 }
536