root/OpenSceneGraph/trunk/examples/osgvertexattributes/osgvertexattributes.cpp @ 13687

Revision 13574, 17.8 kB (checked in by robert, 10 hours ago)

Changed the osgUI behaviour so that events are set to be handled by Widgets that have focus even if they don't directly use them.

  • Property svn:eol-style set to native
Line 
1/* OpenSceneGraph example, osgvertexattributes.
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#include <osgUtil/ShaderGen>
20#include <osgDB/ReadFile>
21#include <osgDB/WriteFile>
22#include <osgViewer/Viewer>
23#include <osgViewer/ViewerEventHandlers>
24#include <osgGA/TrackballManipulator>
25
26class ConvertToVertexAttibArrays : public osg::NodeVisitor
27{
28    public:
29
30        typedef std::pair<unsigned int, std::string> AttributeAlias;
31
32        ConvertToVertexAttibArrays():
33            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
34        {
35            _manualVertexAliasing = false;
36
37            // mappings taken from http://www.opengl.org/registry/specs/NV/vertex_program.txt
38            _vertexAlias = AttributeAlias(0, "osg_Vertex");
39            _normalAlias = AttributeAlias(2, "osg_Normal");
40            _colorAlias = AttributeAlias(3, "osg_Color");
41            _secondaryColorAlias = AttributeAlias(4, "osg_SecondaryColor");
42            _fogCoordAlias = AttributeAlias(5, "osg_FogCoord");
43            _texCoordAlias[0] = AttributeAlias(8, "osg_MultiTexCoord0");
44            _texCoordAlias[1] = AttributeAlias(9, "osg_MultiTexCoord1");
45            _texCoordAlias[2] = AttributeAlias(10, "osg_MultiTexCoord2");
46            _texCoordAlias[3] = AttributeAlias(11, "osg_MultiTexCoord3");
47            _texCoordAlias[4] = AttributeAlias(12, "osg_MultiTexCoord4");
48            _texCoordAlias[5] = AttributeAlias(13, "osg_MultiTexCoord5");
49            _texCoordAlias[6] = AttributeAlias(14, "osg_MultiTexCoord6");
50            _texCoordAlias[7] = AttributeAlias(15, "osg_MultiTexCoord7");
51        }
52
53        void bindAttribute(osg::Program& program, const AttributeAlias& alias)
54        {
55                program.addBindAttribLocation(alias.second, alias.first);
56        }
57
58        void replaceAndBindAttrib(osg::Program& program, std::string& source, const std::string& originalStr, const AttributeAlias& alias, const std::string& declarationPrefix)
59        {
60            if (replace(source, originalStr, alias.second))
61            {
62                source.insert(0, declarationPrefix + alias.second + std::string(";\n"));
63                if (_manualVertexAliasing) bindAttribute(program, alias);
64            }
65        }
66
67        void replaceBuiltInUniform(std::string& source, const std::string& originalStr, const std::string& newStr, const std::string& declarationPrefix)
68        {
69            if (replace(source, originalStr, newStr))
70            {
71                source.insert(0, declarationPrefix + newStr + std::string(";\n"));
72            }
73        }
74
75        void convertVertexShader(osg::Program& program, osg::Shader& shader)
76        {
77            std::string source = shader.getShaderSource();
78
79            // replace ftransform as it only works with built-ins
80            replace(source, "ftransform()", "gl_ModelViewProjectionMatrix * gl_Vertex");
81
82#if 1
83            replaceAndBindAttrib(program, source, "gl_Normal", _normalAlias, "attribute vec3 ");
84            replaceAndBindAttrib(program, source, "gl_Vertex", _vertexAlias, "attribute vec4 ");
85            replaceAndBindAttrib(program, source, "gl_Color", _colorAlias, "attribute vec4 ");
86            replaceAndBindAttrib(program, source, "gl_SecondaryColor", _secondaryColorAlias, "attribute vec4 ");
87            replaceAndBindAttrib(program, source, "gl_FogCoord", _fogCoordAlias, "attribute float ");
88
89            replaceAndBindAttrib(program, source, "gl_MultiTexCoord0", _texCoordAlias[0], "attribute vec4 ");
90            replaceAndBindAttrib(program, source, "gl_MultiTexCoord1", _texCoordAlias[1], "attribute vec4 ");
91            replaceAndBindAttrib(program, source, "gl_MultiTexCoord2", _texCoordAlias[2], "attribute vec4 ");
92            replaceAndBindAttrib(program, source, "gl_MultiTexCoord3", _texCoordAlias[3], "attribute vec4 ");
93            replaceAndBindAttrib(program, source, "gl_MultiTexCoord4", _texCoordAlias[4], "attribute vec4 ");
94            replaceAndBindAttrib(program, source, "gl_MultiTexCoord5", _texCoordAlias[5], "attribute vec4 ");
95            replaceAndBindAttrib(program, source, "gl_MultiTexCoord6", _texCoordAlias[6], "attribute vec4 ");
96            replaceAndBindAttrib(program, source, "gl_MultiTexCoord7", _texCoordAlias[7], "attribute vec4 ");
97#endif
98
99#if 1
100            // replace built in uniform
101            replaceBuiltInUniform(source, "gl_ModelViewMatrix", "osg_ModeViewMatrix", "uniform mat4 ");
102            replaceBuiltInUniform(source, "gl_ModelViewProjectionMatrix", "osg_ModelViewProjectionMatrix", "uniform mat4 ");
103            replaceBuiltInUniform(source, "gl_ProjectionMatrix", "osg_ProjectionMatrix", "uniform mat4 ");
104#endif
105            shader.setShaderSource(source);
106        }
107
108        void convertFragmentShader(osg::Program& program, osg::Shader& shader)
109        {
110        }
111
112        virtual void reset()
113        {
114            _visited.clear();
115        }
116
117        void apply(osg::Node& node)
118        {
119            if (_visited.count(&node)!=0) return;
120            _visited.insert(&node);
121
122            if (node.getStateSet()) apply(*(node.getStateSet()));
123            traverse(node);
124        }
125
126        void apply(osg::Geode& geode)
127        {
128            if (_visited.count(&geode)!=0) return;
129            _visited.insert(&geode);
130
131            if (geode.getStateSet()) apply(*(geode.getStateSet()));
132
133            for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
134            {
135                if (geode.getDrawable(i)->getStateSet()) apply(*(geode.getDrawable(i)->getStateSet()));
136
137                osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
138                if (geom) apply(*geom);
139            }
140        }
141
142        bool replace(std::string& str, const std::string& original_phrase, const std::string& new_phrase)
143        {
144            bool replacedStr = false;
145            std::string::size_type pos = 0;
146            while((pos=str.find(original_phrase, pos))!=std::string::npos)
147            {
148                std::string::size_type endOfPhrasePos = pos+original_phrase.size();
149                if (endOfPhrasePos<str.size())
150                {
151                    char c = str[endOfPhrasePos];
152                    if ((c>='0' && c<='9') ||
153                        (c>='a' && c<='z') ||
154                        (c>='A' && c<='Z'))
155                    {
156                        pos = endOfPhrasePos;
157                        continue;
158                    }
159                }
160
161                replacedStr = true;
162                str.replace(pos, original_phrase.size(), new_phrase);
163            }
164            return replacedStr;
165        }
166
167        void apply(osg::Program& program, osg::Shader& shader)
168        {
169             if (_visited.count(&shader)!=0) return;
170            _visited.insert(&shader);
171
172            osg::notify(osg::NOTICE)<<"Shader "<<shader.getTypename()<<" ----before-----------"<<std::endl;
173            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
174
175            if (shader.getType()==osg::Shader::VERTEX) convertVertexShader(program, shader);
176            else if (shader.getType()==osg::Shader::FRAGMENT) convertFragmentShader(program, shader);
177
178            osg::notify(osg::NOTICE)<<"--after-----------"<<std::endl;
179            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
180            osg::notify(osg::NOTICE)<<"---------------------"<<std::endl;
181        }
182
183        void apply(osg::StateSet& stateset)
184        {
185             if (_visited.count(&stateset)!=0) return;
186            _visited.insert(&stateset);
187
188            return;
189
190            osg::notify(osg::NOTICE)<<"Found stateset "<<&stateset<<std::endl;
191            osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
192            if (program)
193            {
194                osg::notify(osg::NOTICE)<<"   Found Program "<<program<<std::endl;
195                for(unsigned int i=0; i<program->getNumShaders(); ++i)
196                {
197                    apply(*program, *(program->getShader(i)));
198                }
199
200            }
201       }
202
203        void apply(osg::Geometry& geom)
204        {
205            geom.setUseDisplayList(false);
206
207            if (!_manualVertexAliasing) return;
208
209            osg::notify(osg::NOTICE)<<"Found geometry "<<&geom<<std::endl;
210            if (geom.getVertexArray())
211            {
212                setVertexAttrib(geom, _vertexAlias, geom.getVertexArray(), false, osg::Array::BIND_PER_VERTEX);
213                geom.setVertexArray(0);
214            }
215
216            if (geom.getNormalArray())
217            {
218                setVertexAttrib(geom, _normalAlias, geom.getNormalArray(), true);
219                geom.setNormalArray(0);
220            }
221
222            if (geom.getColorArray())
223            {
224                setVertexAttrib(geom, _colorAlias, geom.getColorArray(), false);
225                geom.setColorArray(0);
226            }
227
228            if (geom.getSecondaryColorArray())
229            {
230                setVertexAttrib(geom, _secondaryColorAlias, geom.getSecondaryColorArray(), false);
231                geom.setSecondaryColorArray(0);
232            }
233
234            if (geom.getFogCoordArray())
235            {
236                // should we normalize the FogCoord array? Don't think so...
237                setVertexAttrib(geom, _fogCoordAlias, geom.getFogCoordArray(), false);
238                geom.setFogCoordArray(0);
239            }
240
241            unsigned int maxNumTexCoords = geom.getNumTexCoordArrays();
242            if (maxNumTexCoords>8)
243            {
244                osg::notify(osg::NOTICE)<<"Warning: Ignoring "<<maxNumTexCoords-8<<" texture coordinate arrays, only 8 are currently supported in vertex attribute conversion code."<<std::endl;
245                maxNumTexCoords = 8;
246            }
247            for(unsigned int i=0; i<maxNumTexCoords; ++i)
248            {
249                if (geom.getTexCoordArray(i))
250                {
251                    setVertexAttrib(geom, _texCoordAlias[i], geom.getTexCoordArray(i), false, osg::Array::BIND_PER_VERTEX);
252                    geom.setTexCoordArray(i,0);
253                }
254                else
255                {
256                    osg::notify(osg::NOTICE)<<"Found empty TexCoordArray("<<i<<")"<<std::endl;
257                }
258            }
259        }
260
261        void setVertexAttrib(osg::Geometry& geom, const AttributeAlias& alias, osg::Array* array, bool normalize, osg::Array::Binding binding = osg::Array::BIND_UNDEFINED)
262        {
263            unsigned int index = alias.first;
264            const std::string& name = alias.second;
265            array->setName(name);
266            if (binding!=osg::Array::BIND_UNDEFINED) array->setBinding(binding);
267            array->setNormalize(normalize);
268            geom.setVertexAttribArray(index, array);
269
270            osg::notify(osg::NOTICE)<<"   vertex attrib("<<name<<", index="<<index<<", normalize="<<normalize<<" binding="<<binding<<")"<<std::endl;
271        }
272
273
274        typedef std::set<osg::Object*> Visited;
275        Visited         _visited;
276
277        bool           _manualVertexAliasing;
278        AttributeAlias _vertexAlias;
279        AttributeAlias _normalAlias;
280        AttributeAlias _colorAlias;
281        AttributeAlias _secondaryColorAlias;
282        AttributeAlias _fogCoordAlias;
283        AttributeAlias _texCoordAlias[8];
284};
285
286osg::Node* createSimpleTestModel()
287{
288    osg::Group* group = new osg::Group;
289
290    osg::Geode* geode = new osg::Geode;
291    group->addChild(geode);
292
293    osg::Geometry* geometry = new osg::Geometry;
294    geode->addDrawable(geometry);
295
296    osg::Vec3Array* vertices = new osg::Vec3Array;
297    vertices->push_back(osg::Vec3(0.0,0.0,0.0));
298    vertices->push_back(osg::Vec3(0.0,0.0,1.0));
299    vertices->push_back(osg::Vec3(1.0,0.0,0.0));
300    vertices->push_back(osg::Vec3(1.0,0.0,1.0));
301    geometry->setVertexArray(vertices);
302
303    geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
304
305    char vertexShaderSource[] =
306       "void main(void)\n"
307       "{\n"
308       "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
309       "}\n";
310
311    char fragmentShaderSource[] =
312        "void main(void)\n"
313        "{\n"
314        "    gl_FragColor = vec4(1.0,1.0,0.0,1.0); \n"
315        "}\n";
316
317    osg::Program* program = new osg::Program;
318    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
319    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
320
321    geometry->getOrCreateStateSet()->setAttribute(program);
322
323    return group;
324}
325
326osg::Node* createSimpleTextureTestModel()
327{
328    osg::Group* group = new osg::Group;
329
330    osg::Geode* geode = new osg::Geode;
331    group->addChild(geode);
332
333    osg::Geometry* geometry = new osg::Geometry;
334    geode->addDrawable(geometry);
335
336    osg::Vec3Array* vertices = new osg::Vec3Array;
337    vertices->push_back(osg::Vec3(0.0,0.0,0.0));
338    vertices->push_back(osg::Vec3(0.0,0.0,1.0));
339    vertices->push_back(osg::Vec3(1.0,0.0,0.0));
340    vertices->push_back(osg::Vec3(1.0,0.0,1.0));
341    geometry->setVertexArray(vertices);
342
343    osg::Vec2Array* texcoords = new osg::Vec2Array;
344    texcoords->push_back(osg::Vec2(0.0,0.0));
345    texcoords->push_back(osg::Vec2(0.0,1.0));
346    texcoords->push_back(osg::Vec2(1.0,0.0));
347    texcoords->push_back(osg::Vec2(1.0,1.0));
348    geometry->setTexCoordArray(0, texcoords);
349
350    geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
351
352    char vertexShaderSource[] =
353       "varying vec2 texCoord;\n"
354       "void main(void)\n"
355       "{\n"
356       "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
357       "    texCoord = gl_MultiTexCoord0.xy;\n"
358       "}\n";
359
360    char fragmentShaderSource[] =
361        "varying vec2 texCoord;\n"
362        "uniform sampler2D baseTexture;\n"
363        "void main(void)\n"
364        "{\n"
365        "    gl_FragColor = texture2D(baseTexture, texCoord); \n"
366        "}\n";
367
368    osg::Program* program = new osg::Program;
369    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource));
370    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource));
371
372    osg::StateSet* stateset = geometry->getOrCreateStateSet();
373    stateset->setAttribute(program);
374
375    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
376    osg::Texture2D* texture = new osg::Texture2D(image);
377    texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
378    texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
379    stateset->setTextureAttribute(0, texture);
380
381    osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
382    stateset->addUniform(baseTextureSampler);
383
384    return group;
385}
386
387int main(int argc, char *argv[])
388{
389    // use an ArgumentParser object to manage the program arguments.
390    osg::ArgumentParser arguments(&argc,argv);
391
392    // construct the viewer.
393    osgViewer::Viewer viewer(arguments);
394
395    std::string outputFileName;
396    while (arguments.read("-o",outputFileName)) {}
397
398    osg::ref_ptr<osg::Node> loadedModel;
399
400    bool runConvertToVertexAttributes = false;
401    if (arguments.read("--simple") || arguments.read("--s"))
402    {
403        loadedModel = createSimpleTestModel();
404    }
405    else if (arguments.read("--texture") || arguments.read("-t"))
406    {
407        loadedModel = createSimpleTextureTestModel();
408    }
409    else
410    {
411        bool runShaderGen = true;
412        while (arguments.read("--shader-gen")) { runShaderGen = true; }
413        while (arguments.read("--no-shader-gen")) { runShaderGen = false; }
414
415        while (arguments.read("--vertex-attrib")) { runConvertToVertexAttributes = true; }
416        while (arguments.read("--no-vertex-attrib")) { runConvertToVertexAttributes = false; }
417
418        loadedModel = osgDB::readNodeFiles(arguments);
419        if (!loadedModel.get())
420        {
421            osg::notify(osg::NOTICE)<<"No model loaded, please specify a model filename."<<std::endl;
422            return 1;
423        }
424
425        if (runShaderGen)
426        {
427            // convert fixed function pipeline to shaders
428            osgUtil::ShaderGenVisitor sgv;
429            loadedModel->accept(sgv);
430        }
431
432        if (runConvertToVertexAttributes)
433        {
434            // find any conventional vertex, colour, normal and tex coords arrays and convert to vertex attributes
435            ConvertToVertexAttibArrays ctvaa;
436            loadedModel->accept(ctvaa);
437        }
438    }
439
440    if (!loadedModel) return 1;
441
442    if (!outputFileName.empty())
443    {
444        osgDB::writeNodeFile(*loadedModel, outputFileName);
445        return 0;
446    }
447
448    // add a viewport to the viewer and attach the scene graph.
449    viewer.setSceneData(loadedModel.get());
450
451    viewer.setCameraManipulator(new osgGA::TrackballManipulator());
452
453    // add the stats handler
454    viewer.addEventHandler(new osgViewer::StatsHandler);
455
456    viewer.realize();
457
458
459    if (runConvertToVertexAttributes)
460    {
461        // switch on the uniforms that track the modelview and projection matrices
462        osgViewer::Viewer::Windows windows;
463        viewer.getWindows(windows);
464        for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
465            itr != windows.end();
466            ++itr)
467        {
468            (*itr)->getState()->setUseModelViewAndProjectionUniforms(true);
469            (*itr)->getState()->setUseVertexAttributeAliasing(true);
470        }
471    }
472
473    return viewer.run();
474}
Note: See TracBrowser for help on using the browser.