root/OpenSceneGraph/trunk/src/osgUtil/SceneGraphBuilder.cpp @ 8868

Revision 8868, 14.7 kB (checked in by robert, 6 years ago)

From Mathias Froehlich, "This is a generic optimization that does not depend on any cpu or instruction
set.

The optimization is based on the observation that matrix matrix multiplication
with a dense matrix 4x4 is 43 Operations whereas multiplication with a
transform, or scale matrix is only 4
2 operations. Which is a gain of a
*FACTOR*4* for these special cases.
The change implements these special cases, provides a unit test for these
implementation and converts uses of the expensiver dense matrix matrix
routine with the specialized versions.

Depending on the transform nodes in the scenegraph this change gives a
noticable improovement.
For example the osgforest code using the MatrixTransform? is about 20% slower
than the same codepath using the PositionAttitudeTransform? instead of the
MatrixTransform? with this patch applied.

If I remember right, the sse type optimizations did *not* provide a factor 4
improovement. Also these changes are totally independent of any cpu or
instruction set architecture. So I would prefer to have this current kind of
change instead of some hand coded and cpu dependent assembly stuff. If we
need that hand tuned stuff, these can go on top of this changes which must
provide than hand optimized additional variants for the specialized versions
to give a even better result in the end.

An other change included here is a change to rotation matrix from quaterion
code. There is a sqrt call which couold be optimized away. Since we divide in
effect by sqrt(length)*sqrt(length) which is just length ...
"

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