root/OpenSceneGraph/trunk/examples/osgmovie/osgmovie.cpp @ 5953

Revision 5953, 13.8 kB (checked in by robert, 7 years ago)

Added support for vertex ratios into LineSegmentIntersector?.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// -*-c++-*-
2
3#include <osgViewer/Viewer>
4
5#include <osgDB/ReadFile>
6
7#include <osg/Geode>
8#include <osg/Geometry>
9#include <osg/StateSet>
10#include <osg/Material>
11#include <osg/Texture2D>
12#include <osg/TextureRectangle>
13#include <osg/TexMat>
14#include <osg/CullFace>
15#include <osg/ImageStream>
16#include <osg/io_utils>
17
18#include <osgGA/TrackballManipulator>
19#include <osgGA/EventVisitor>
20
21#include <iostream>
22
23osg::ImageStream* s_imageStream = 0;
24class MovieEventHandler : public osgGA::GUIEventHandler
25{
26public:
27
28    MovieEventHandler() {}
29   
30    void set(osg::Node* node);
31
32    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv);
33   
34    virtual void getUsage(osg::ApplicationUsage& usage) const;
35
36    typedef std::vector< osg::ref_ptr<osg::ImageStream> > ImageStreamList;
37
38protected:
39
40    virtual ~MovieEventHandler() {}
41
42    class FindImageStreamsVisitor : public osg::NodeVisitor
43    {
44    public:
45        FindImageStreamsVisitor(ImageStreamList& imageStreamList):
46            _imageStreamList(imageStreamList) {}
47           
48        virtual void apply(osg::Geode& geode)
49        {
50            apply(geode.getStateSet());
51
52            for(unsigned int i=0;i<geode.getNumDrawables();++i)
53            {
54                apply(geode.getDrawable(i)->getStateSet());
55            }
56       
57            traverse(geode);
58        }
59
60        virtual void apply(osg::Node& node)
61        {
62            apply(node.getStateSet());
63            traverse(node);
64        }
65       
66        inline void apply(osg::StateSet* stateset)
67        {
68            if (!stateset) return;
69           
70            osg::StateAttribute* attr = stateset->getTextureAttribute(0,osg::StateAttribute::TEXTURE);
71            if (attr)
72            {
73                osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(attr);
74                if (texture2D) apply(dynamic_cast<osg::ImageStream*>(texture2D->getImage()));
75
76                osg::TextureRectangle* textureRec = dynamic_cast<osg::TextureRectangle*>(attr);
77                if (textureRec) apply(dynamic_cast<osg::ImageStream*>(textureRec->getImage()));
78            }
79        }
80       
81        inline void apply(osg::ImageStream* imagestream)
82        {
83            if (imagestream)
84            {
85                _imageStreamList.push_back(imagestream);
86                s_imageStream = imagestream;
87            }
88        }
89       
90        ImageStreamList& _imageStreamList;
91    };
92
93
94    ImageStreamList _imageStreamList;
95   
96};
97
98
99
100void MovieEventHandler::set(osg::Node* node)
101{
102    _imageStreamList.clear();
103    if (node)
104    {
105        FindImageStreamsVisitor fisv(_imageStreamList);
106        node->accept(fisv);
107    }
108}
109
110
111bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
112{
113    switch(ea.getEventType())
114    {
115        case(osgGA::GUIEventAdapter::MOVE):
116        case(osgGA::GUIEventAdapter::PUSH):
117        case(osgGA::GUIEventAdapter::RELEASE):
118        {
119
120            osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
121            osgUtil::LineSegmentIntersector::Intersections intersections;
122            if (view && view->computeIntersections(ea.getX(), ea.getY(), nv->getNodePath(), intersections))
123            {
124
125                // use the nearest intersection                 
126                const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin());
127                osg::Drawable* drawable = intersection.drawable.get();
128                osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
129                osg::Vec3Array* vertices = geometry ? dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()) : 0;
130                if (vertices)
131                {
132                    // get the vertex indices.
133                    const osgUtil::LineSegmentIntersector::Intersection::IndexList& indices = intersection.indexList;
134                    const osgUtil::LineSegmentIntersector::Intersection::RatioList& ratios = intersection.ratioList;
135
136                    if (indices.size()==3 && ratios.size()==3)
137                    {
138                        unsigned int i1 = indices[0];
139                        unsigned int i2 = indices[1];
140                        unsigned int i3 = indices[2];
141
142                        float r1 = ratios[0];
143                        float r2 = ratios[1];
144                        float r3 = ratios[2];
145
146                        osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0;
147                        osg::Vec2Array* texcoords_Vec2Array = dynamic_cast<osg::Vec2Array*>(texcoords);
148                        if (texcoords_Vec2Array)
149                        {
150                            // we have tex coord array so now we can compute the final tex coord at the point of intersection.                               
151                            osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1];
152                            osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2];
153                            osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3];
154                            osg::Vec2 tc = tc1*r1 + tc2*r2 + tc3*r3;
155
156                            osg::notify(osg::NOTICE)<<"We hit tex coords "<<tc<<std::endl;
157
158                        }
159                    }
160                    else
161                    {
162                        osg::notify(osg::NOTICE)<<"Intersection has insufficient indices to work with";
163                    }
164
165                }
166            }
167            else
168            {
169                osg::notify(osg::NOTICE)<<"No intersection"<<std::endl;
170            }
171            break;
172        }
173        case(osgGA::GUIEventAdapter::KEYDOWN):
174        {
175            if (ea.getKey()=='s')
176            {
177                for(ImageStreamList::iterator itr=_imageStreamList.begin();
178                    itr!=_imageStreamList.end();
179                    ++itr)
180                {
181                    std::cout<<"Play"<<std::endl;
182                     (*itr)->play();
183                }
184                return true;
185            }
186            else if (ea.getKey()=='p')
187            {
188                for(ImageStreamList::iterator itr=_imageStreamList.begin();
189                    itr!=_imageStreamList.end();
190                    ++itr)
191                {
192                    std::cout<<"Pause"<<std::endl;
193                    (*itr)->pause();
194                }
195                return true;
196            }
197            else if (ea.getKey()=='r')
198            {
199                for(ImageStreamList::iterator itr=_imageStreamList.begin();
200                    itr!=_imageStreamList.end();
201                    ++itr)
202                {
203                    std::cout<<"Restart"<<std::endl;
204                    (*itr)->rewind();
205                    (*itr)->play();
206                }
207                return true;
208            }
209            else if (ea.getKey()=='l')
210            {
211                for(ImageStreamList::iterator itr=_imageStreamList.begin();
212                    itr!=_imageStreamList.end();
213                    ++itr)
214                {
215                    if ( (*itr)->getLoopingMode() == osg::ImageStream::LOOPING)
216                    {
217                        std::cout<<"Toggle Looping Off"<<std::endl;
218                        (*itr)->setLoopingMode( osg::ImageStream::NO_LOOPING );
219                    }
220                    else
221                    {
222                        std::cout<<"Toggle Looping On"<<std::endl;
223                        (*itr)->setLoopingMode( osg::ImageStream::LOOPING );
224                    }
225                }
226                return true;
227            }
228            return false;
229        }
230
231        default:
232            return false;
233    }
234    return false;
235}
236
237void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
238{
239    usage.addKeyboardMouseBinding("p","Pause movie");
240    usage.addKeyboardMouseBinding("s","Play movie");
241    usage.addKeyboardMouseBinding("r","Restart movie");
242    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
243}
244
245
246osg::Geometry* myCreateTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle)
247{
248    if (useTextureRectangle)
249    {
250        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
251                                           osg::Vec3(width,0.0f,0.0f),
252                                           osg::Vec3(0.0f,0.0f,height),
253                                           0.0f,image->t(), image->s(),0.0f);
254
255        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
256                    new osg::TextureRectangle(image),
257                    osg::StateAttribute::ON);
258                   
259        return pictureQuad;
260    }
261    else
262    {
263        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
264                                           osg::Vec3(width,0.0f,0.0f),
265                                           osg::Vec3(0.0f,0.0f,height),
266                                           0.0f,1.0f, 1.0f,0.0f);
267                                   
268        osg::Texture2D* texture = new osg::Texture2D(image);
269        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); 
270                                       
271        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
272                    texture,
273                    osg::StateAttribute::ON);
274
275        return pictureQuad;
276    }
277}
278
279int main(int argc, char** argv)
280{
281    // use an ArgumentParser object to manage the program arguments.
282    osg::ArgumentParser arguments(&argc,argv);
283   
284    // set up the usage document, in case we need to print out how to use this program.
285    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
286    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example demonstrates the use of ImageStream for rendering movies as textures.");
287    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
288    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
289    arguments.getApplicationUsage()->addCommandLineOption("--texture2D","Use Texture2D rather than TextureRectangle.");
290    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use shaders to post process the video.");
291   
292    bool useTextureRectangle = true;
293    bool useShader = false;
294
295    // construct the viewer.
296    osgViewer::Viewer viewer;
297   
298    while (arguments.read("--texture2D")) useTextureRectangle=false;
299    while (arguments.read("--shader")) useShader=true;
300
301    // if user request help write it out to cout.
302    if (arguments.read("-h") || arguments.read("--help"))
303    {
304        arguments.getApplicationUsage()->write(std::cout);
305        return 1;
306    }
307
308    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
309    osg::Vec3 pos(0.0f,0.0f,0.0f);
310       
311    osg::StateSet* stateset = geode->getOrCreateStateSet();
312    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
313
314    if (useShader)
315    {
316        //useTextureRectangle = false;
317       
318        static const char *shaderSourceTextureRec = {
319            "uniform vec4 cutoff_color;\n"
320            "uniform samplerRect movie_texture;\n"
321            "void main(void)\n"
322            "{\n"
323            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n"
324            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
325            "    gl_FragColor = texture_color;\n"
326            "}\n"
327        };
328
329        static const char *shaderSourceTexture2D = {
330            "uniform vec4 cutoff_color;\n"
331            "uniform sampler2D movie_texture;\n"
332            "void main(void)\n"
333            "{\n"
334            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n"
335            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
336            "    gl_FragColor = texture_color;\n"
337            "}\n"
338        };
339
340        osg::Program* program = new osg::Program;
341       
342        program->addShader(new osg::Shader(osg::Shader::FRAGMENT,
343                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D));
344
345        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f)));
346        stateset->addUniform(new osg::Uniform("movie_texture",0));
347
348        stateset->setAttribute(program);
349
350    }
351
352
353    for(int i=1;i<arguments.argc();++i)
354    {
355        if (arguments.isString(i))
356        {
357            osg::Image* image = osgDB::readImageFile(arguments[i]);
358            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image);
359            if (imagestream) imagestream->play();
360           
361            if (image)
362            {
363                geode->addDrawable(myCreateTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle));
364               
365                pos.z() += image->t()*1.5f;
366            }
367            else
368            {
369                std::cout<<"Unable to read file "<<arguments[i]<<std::endl;
370            }           
371        }
372    }
373   
374    if (geode->getNumDrawables()==0)
375    {
376        // nothing loaded.
377        arguments.getApplicationUsage()->write(std::cout);
378        return 1;
379    }
380
381    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
382    MovieEventHandler* meh = new MovieEventHandler();
383    geode->setEventCallback(meh);
384    meh->set(geode.get());
385
386    // report any errors if they have occured when parsing the program aguments.
387    if (arguments.errors())
388    {
389        arguments.writeErrorMessages(std::cout);
390        return 1;
391    }
392   
393    if (arguments.argc()<=1)
394    {
395        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
396        return 1;
397    }
398
399    // set the scene to render
400    viewer.setSceneData(geode.get());
401
402    // create the windows and run the threads.
403    return viewer.run();
404
405
406}
Note: See TracBrowser for help on using the browser.