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

Revision 10620, 12.8 kB (checked in by robert, 5 years ago)

Added use of binding of vertex attributes to names

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
24class ConvertToVertexAttibArrays : public osg::NodeVisitor
25{
26    public:
27
28        typedef std::pair<unsigned int, std::string> AttributeAlias;
29
30        ConvertToVertexAttibArrays():
31            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
32        {
33            // mappings taken from http://www.opengl.org/registry/specs/NV/vertex_program.txt
34            _vertexAlias = AttributeAlias(0, "osg_Vertex");
35            _normalAlias = AttributeAlias(2, "osg_Normal");
36            _colorAlias = AttributeAlias(3, "osg_Color");
37            _secondaryColorAlias = AttributeAlias(4, "osg_SecondaryColor");
38            _fogCoordAlias = AttributeAlias(5, "osg_FogCoord");
39            _texCoordAlias[0] = AttributeAlias(8, "osg_MultiTexCoord0");
40            _texCoordAlias[1] = AttributeAlias(9, "osg_MultiTexCoord1");
41            _texCoordAlias[2] = AttributeAlias(10, "osg_MultiTexCoord2");
42            _texCoordAlias[3] = AttributeAlias(11, "osg_MultiTexCoord3");
43            _texCoordAlias[4] = AttributeAlias(12, "osg_MultiTexCoord4");
44            _texCoordAlias[5] = AttributeAlias(13, "osg_MultiTexCoord5");
45            _texCoordAlias[6] = AttributeAlias(14, "osg_MultiTexCoord6");
46            _texCoordAlias[7] = AttributeAlias(15, "osg_MultiTexCoord7");
47        }
48
49        void bindAttribute(osg::Program& program, const AttributeAlias& alias)
50        {
51                program.addBindAttribLocation(alias.second, alias.first);
52        }
53
54        void replaceAndBind(osg::Program& program, std::string& source, const std::string& originalStr, const AttributeAlias& alias, const std::string& declarationPrefix)
55        {
56            if (replace(source, originalStr, alias.second))
57            {
58                source.insert(0, declarationPrefix + alias.second + std::string(";\n"));
59                bindAttribute(program, alias);
60            }
61        }
62
63        void convertVertexShader(osg::Program& program, osg::Shader& shader)
64        {
65            std::string source = shader.getShaderSource();
66
67            // replace ftransform as it only works with built-ins
68            replace(source, "ftransform()", "gl_ModelViewProjectionMatrix * gl_Vertex");
69
70            replaceAndBind(program, source, "gl_Normal", _normalAlias, "attribute vec3 ");
71            replaceAndBind(program, source, "gl_Vertex", _vertexAlias, "attribute vec4 ");
72            replaceAndBind(program, source, "gl_Color", _colorAlias, "attribute vec4 ");
73            replaceAndBind(program, source, "gl_SecondaryColor", _secondaryColorAlias, "attribute vec4 ");
74            replaceAndBind(program, source, "gl_FogCoord", _fogCoordAlias, "attribute float ");
75
76            replaceAndBind(program, source, "gl_MultiTexCoord0", _texCoordAlias[0], "attribute vec4 ");
77            replaceAndBind(program, source, "gl_MultiTexCoord1", _texCoordAlias[1], "attribute vec4 ");
78            replaceAndBind(program, source, "gl_MultiTexCoord2", _texCoordAlias[2], "attribute vec4 ");
79            replaceAndBind(program, source, "gl_MultiTexCoord3", _texCoordAlias[3], "attribute vec4 ");
80            replaceAndBind(program, source, "gl_MultiTexCoord4", _texCoordAlias[4], "attribute vec4 ");
81            replaceAndBind(program, source, "gl_MultiTexCoord5", _texCoordAlias[5], "attribute vec4 ");
82            replaceAndBind(program, source, "gl_MultiTexCoord6", _texCoordAlias[6], "attribute vec4 ");
83            replaceAndBind(program, source, "gl_MultiTexCoord7", _texCoordAlias[7], "attribute vec4 ");
84
85
86#if 0
87            // replace the modelview and project matrices
88            replace(source, "gl_ModelViewMatrix", "osg_ModeViewMatrix");
89            replace(source, "gl_ModelViewProjectionMatrix", "osg_ModelViewProjectionMatrix");
90            replace(source, "gl_ProjectionMatrix", "osg_ProjectionMatrix");
91#endif
92            shader.setShaderSource(source);
93        }
94
95        void convertFragmentShader(osg::Program& program, osg::Shader& shader)
96        {
97        }
98
99        virtual void reset()
100        {
101            _visited.clear();
102        }
103
104        void apply(osg::Node& node)
105        {
106            if (_visited.count(&node)!=0) return;
107            _visited.insert(&node);
108
109            if (node.getStateSet()) apply(*(node.getStateSet()));
110            traverse(node);
111        }
112
113        void apply(osg::Geode& geode)
114        {
115            if (_visited.count(&geode)!=0) return;
116            _visited.insert(&geode);
117
118            if (geode.getStateSet()) apply(*(geode.getStateSet()));
119
120            for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
121            {
122                if (geode.getDrawable(i)->getStateSet()) apply(*(geode.getDrawable(i)->getStateSet()));
123
124                osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
125                if (geom) apply(*geom);
126            }
127        }
128
129        bool replace(std::string& str, const std::string& original_phrase, const std::string& new_phrase)
130        {
131            bool replacedStr = false;
132            std::string::size_type pos = 0;
133            while((pos=str.find(original_phrase, pos))!=std::string::npos)
134            {
135                std::string::size_type endOfPhrasePos = pos+original_phrase.size();
136                if (endOfPhrasePos<str.size())
137                {
138                    char c = str[endOfPhrasePos];
139                    if ((c>='0' && c<='9') ||
140                        (c>='a' && c<='z') ||
141                        (c>='A' && c<='Z'))
142                    {
143                        pos = endOfPhrasePos;
144                        continue;
145                    }
146                }
147
148                replacedStr = true;
149                str.replace(pos, original_phrase.size(), new_phrase);
150            }
151            return replacedStr;
152        }
153
154        void apply(osg::Program& program, osg::Shader& shader)
155        {
156             if (_visited.count(&shader)!=0) return;
157            _visited.insert(&shader);
158
159            osg::notify(osg::NOTICE)<<"Shader "<<shader.getTypename()<<" ----before-----------"<<std::endl;
160            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
161
162            if (shader.getType()==osg::Shader::VERTEX) convertVertexShader(program, shader);
163            else if (shader.getType()==osg::Shader::FRAGMENT) convertFragmentShader(program, shader);
164
165            osg::notify(osg::NOTICE)<<"--after-----------"<<std::endl;
166            osg::notify(osg::NOTICE)<<shader.getShaderSource()<<std::endl;
167            osg::notify(osg::NOTICE)<<"---------------------"<<std::endl;
168        }
169
170        void apply(osg::StateSet& stateset)
171        {
172             if (_visited.count(&stateset)!=0) return;
173            _visited.insert(&stateset);
174
175            osg::notify(osg::NOTICE)<<"Found stateset "<<&stateset<<std::endl;
176            osg::Program* program = dynamic_cast<osg::Program*>(stateset.getAttribute(osg::StateAttribute::PROGRAM));
177            if (program)
178            {
179                osg::notify(osg::NOTICE)<<"   Found Program "<<program<<std::endl;
180                for(unsigned int i=0; i<program->getNumShaders(); ++i)
181                {
182                    apply(*program, *(program->getShader(i)));
183                }
184
185            }
186       }
187
188        void apply(osg::Geometry& geom)
189        {
190            geom.setUseDisplayList(false);
191
192            osg::notify(osg::NOTICE)<<"Found geometry "<<&geom<<std::endl;
193            if (geom.getVertexArray())
194            {
195                setVertexAttrib(geom, _vertexAlias, geom.getVertexArray(), false, osg::Geometry::BIND_PER_VERTEX);
196                geom.setVertexArray(0);
197            }
198
199            if (geom.getNormalArray())
200            {
201                setVertexAttrib(geom, _normalAlias, geom.getNormalArray(), false, geom.getNormalBinding());
202                geom.setNormalArray(0);
203            }
204
205            if (geom.getColorArray())
206            {
207                setVertexAttrib(geom, _colorAlias, geom.getColorArray(), false, geom.getColorBinding());
208                geom.setColorArray(0);
209            }
210
211            if (geom.getSecondaryColorArray())
212            {
213                setVertexAttrib(geom, _secondaryColorAlias, geom.getSecondaryColorArray(), false, geom.getSecondaryColorBinding());
214                geom.setSecondaryColorArray(0);
215            }
216
217            if (geom.getFogCoordArray())
218            {
219                // should we normalize the FogCoord array? Don't think so...
220                setVertexAttrib(geom, _fogCoordAlias, geom.getFogCoordArray(), false, geom.getSecondaryColorBinding());
221                geom.setFogCoordArray(0);
222            }
223
224            unsigned int maxNumTexCoords = geom.getNumTexCoordArrays();
225            if (maxNumTexCoords>8)
226            {
227                osg::notify(osg::NOTICE)<<"Warning: Ignoring "<<maxNumTexCoords-8<<" texture coordinate arrays, only 8 are currently supported in vertex attribute conversion code."<<std::endl;
228                maxNumTexCoords = 8;
229            }
230            for(unsigned int i=0; i<maxNumTexCoords; ++i)
231            {
232                if (geom.getTexCoordArray(i))
233                {
234                    setVertexAttrib(geom, _texCoordAlias[i], geom.getTexCoordArray(i), false, osg::Geometry::BIND_PER_VERTEX);
235                    geom.setTexCoordArray(i,0);
236                }
237                else
238                {
239                    osg::notify(osg::NOTICE)<<"Found empty TexCoordArray("<<i<<")"<<std::endl;
240                }
241            }
242        }
243
244        void setVertexAttrib(osg::Geometry& geom, const AttributeAlias& alias, osg::Array* array, bool normalize, osg::Geometry::AttributeBinding binding)
245        {
246            unsigned int index = alias.first;
247            const std::string& name = alias.second;
248            array->setName(name);
249            geom.setVertexAttribArray(index, array);
250            geom.setVertexAttribNormalize(index, normalize);
251            geom.setVertexAttribBinding(index, binding);
252
253            osg::notify(osg::NOTICE)<<"   vertex attrib("<<name<<", index="<<index<<", normalize="<<normalize<<" binding="<<binding<<")"<<std::endl;
254        }
255
256
257        typedef std::set<osg::Object*> Visited;
258        Visited         _visited;
259
260        AttributeAlias _vertexAlias;
261        AttributeAlias _normalAlias;
262        AttributeAlias _colorAlias;
263        AttributeAlias _secondaryColorAlias;
264        AttributeAlias _fogCoordAlias;
265        AttributeAlias _texCoordAlias[8];
266};
267
268
269
270int main(int argc, char *argv[])
271{
272    // use an ArgumentParser object to manage the program arguments.
273    osg::ArgumentParser arguments(&argc,argv);
274
275    // construct the viewer.
276    osgViewer::Viewer viewer(arguments);
277
278    std::string outputFileName;
279    while (arguments.read("-o",outputFileName)) {}
280
281    bool runShaderGen = true;
282    while (arguments.read("--shader-gen")) { runShaderGen = true; }
283    while (arguments.read("--no-shader-gen")) { runShaderGen = false; }
284
285    bool runConvertToVertexAttributes = true;
286    while (arguments.read("--vertex-attrib")) { runConvertToVertexAttributes = true; }
287    while (arguments.read("--no-vertex-attrib")) { runConvertToVertexAttributes = false; }
288
289    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
290    if (!loadedModel.get())
291    {
292        osg::notify(osg::NOTICE)<<"No model loaded, please specify a model filename."<<std::endl;
293        return 1;
294    }
295
296    if (runShaderGen)
297    {
298        // convert fixed function pipeline to shaders
299        osgUtil::ShaderGenVisitor sgv;
300        loadedModel->accept(sgv);
301    }
302
303    if (runConvertToVertexAttributes)
304    {
305        // find any conventional vertex, colour, normal and tex coords arrays and convert to vertex attributes
306        ConvertToVertexAttibArrays ctvaa;
307        loadedModel->accept(ctvaa);
308    }
309
310    if (!outputFileName.empty())
311    {
312        osgDB::writeNodeFile(*loadedModel, outputFileName);
313        return 0;
314    }
315
316    // add a viewport to the viewer and attach the scene graph.
317    viewer.setSceneData(loadedModel.get());
318
319    return viewer.run();
320}
Note: See TracBrowser for help on using the browser.