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

Revision 5951, 14.9 kB (checked in by robert, 8 years ago)

Added View::computeIntersections methods

  • 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            osg::notify(osg::NOTICE)<<"osgmovie - view = "<<view<<std::endl;
122            osgUtil::LineSegmentIntersector::Intersections intersections;
123            if (view && view->computeIntersections(ea.getX(), ea.getY(), nv->getNodePath().back(), intersections))
124            {
125#if 1
126                osg::notify(osg::NOTICE)<<"osgmovie - Vertex interpolation not implemented yet"<<std::endl;
127#else
128                // use the nearest intersection                 
129                const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin());
130                osg::Drawable* drawable = intersection.drawable.get();
131                osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
132                osg::Vec3Array* vertices = geometry ? dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()) : 0;
133                if (vertices)
134                {
135                    // get the vertex indices.
136                    const osgUtil::LineSegmentIntersector::Intersection::IndexList& vil = intersection.indexList;
137
138                    if (vil.size()==3)
139                    {
140                        int i1 = vil[0];
141                        int i2 = vil[1];
142                        int i3 = vil[2];
143                        osg::Vec3 v1 = (*vertices)[i1];
144                        osg::Vec3 v2 = (*vertices)[i2];
145                        osg::Vec3 v3 = (*vertices)[i3];
146                        osg::Vec3 v = intersection.localIntersectionPoint;
147                       
148                        osg::Vec3 p1 = intersection.getLocalLineSegment()->start();
149                        osg::Vec3 p2 = intersection.getLocalLineSegment()->end();
150
151                        osg::Vec3 p12 = p1-p2;
152                        osg::Vec3 v13 = v1-v3;
153                        osg::Vec3 v23 = v2-v3;
154                        osg::Vec3 p1v3 = p1-v3;
155
156                        osg::Matrix matrix(p12.x(), v13.x(), v23.x(), 0.0,
157                                           p12.y(), v13.y(), v23.y(), 0.0,
158                                           p12.z(), v13.z(), v23.z(), 0.0,
159                                           0.0,    0.0,    0.0,    1.0);
160
161                        osg::Matrix inverse;
162                        inverse.invert(matrix);
163
164                        osg::Vec3 ratio = inverse*p1v3;
165
166                        // extract the baricentric coordinates.                           
167                        float r1 = ratio.y();
168                        float r2 = ratio.z();
169                        float r3 = 1.0f-r1-r2;
170
171                        osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0;
172                        osg::Vec2Array* texcoords_Vec2Array = dynamic_cast<osg::Vec2Array*>(texcoords);
173                        if (texcoords_Vec2Array)
174                        {
175                            // we have tex coord array so now we can compute the final tex coord at the point of intersection.                               
176                            osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1];
177                            osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2];
178                            osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3];
179                            osg::Vec2 tc = tc1*r1 + tc2*r2 + tc3*r3;
180
181                            osg::notify(osg::NOTICE)<<"We hit tex coords "<<tc<<std::endl;
182
183                        }
184                    }
185                    else
186                    {
187                        osg::notify(osg::NOTICE)<<"Intersection has insufficient indices to work with";
188                    }
189
190                }
191#endif
192            }
193            else
194            {
195                osg::notify(osg::NOTICE)<<"No intersection"<<std::endl;
196            }
197            break;
198        }
199        case(osgGA::GUIEventAdapter::KEYDOWN):
200        {
201            if (ea.getKey()=='s')
202            {
203                for(ImageStreamList::iterator itr=_imageStreamList.begin();
204                    itr!=_imageStreamList.end();
205                    ++itr)
206                {
207                    std::cout<<"Play"<<std::endl;
208                     (*itr)->play();
209                }
210                return true;
211            }
212            else if (ea.getKey()=='p')
213            {
214                for(ImageStreamList::iterator itr=_imageStreamList.begin();
215                    itr!=_imageStreamList.end();
216                    ++itr)
217                {
218                    std::cout<<"Pause"<<std::endl;
219                    (*itr)->pause();
220                }
221                return true;
222            }
223            else if (ea.getKey()=='r')
224            {
225                for(ImageStreamList::iterator itr=_imageStreamList.begin();
226                    itr!=_imageStreamList.end();
227                    ++itr)
228                {
229                    std::cout<<"Restart"<<std::endl;
230                    (*itr)->rewind();
231                    (*itr)->play();
232                }
233                return true;
234            }
235            else if (ea.getKey()=='l')
236            {
237                for(ImageStreamList::iterator itr=_imageStreamList.begin();
238                    itr!=_imageStreamList.end();
239                    ++itr)
240                {
241                    if ( (*itr)->getLoopingMode() == osg::ImageStream::LOOPING)
242                    {
243                        std::cout<<"Toggle Looping Off"<<std::endl;
244                        (*itr)->setLoopingMode( osg::ImageStream::NO_LOOPING );
245                    }
246                    else
247                    {
248                        std::cout<<"Toggle Looping On"<<std::endl;
249                        (*itr)->setLoopingMode( osg::ImageStream::LOOPING );
250                    }
251                }
252                return true;
253            }
254            return false;
255        }
256
257        default:
258            return false;
259    }
260    return false;
261}
262
263void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
264{
265    usage.addKeyboardMouseBinding("p","Pause movie");
266    usage.addKeyboardMouseBinding("s","Play movie");
267    usage.addKeyboardMouseBinding("r","Restart movie");
268    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
269}
270
271
272osg::Geometry* myCreateTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle)
273{
274    if (useTextureRectangle)
275    {
276        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
277                                           osg::Vec3(width,0.0f,0.0f),
278                                           osg::Vec3(0.0f,0.0f,height),
279                                           0.0f,image->t(), image->s(),0.0f);
280
281        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
282                    new osg::TextureRectangle(image),
283                    osg::StateAttribute::ON);
284                   
285        return pictureQuad;
286    }
287    else
288    {
289        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
290                                           osg::Vec3(width,0.0f,0.0f),
291                                           osg::Vec3(0.0f,0.0f,height),
292                                           0.0f,1.0f, 1.0f,0.0f);
293                                   
294        osg::Texture2D* texture = new osg::Texture2D(image);
295        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR); 
296                                       
297        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
298                    texture,
299                    osg::StateAttribute::ON);
300
301        return pictureQuad;
302    }
303}
304
305int main(int argc, char** argv)
306{
307    // use an ArgumentParser object to manage the program arguments.
308    osg::ArgumentParser arguments(&argc,argv);
309   
310    // set up the usage document, in case we need to print out how to use this program.
311    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
312    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example demonstrates the use of ImageStream for rendering movies as textures.");
313    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
314    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
315    arguments.getApplicationUsage()->addCommandLineOption("--texture2D","Use Texture2D rather than TextureRectangle.");
316    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use shaders to post process the video.");
317   
318    bool useTextureRectangle = true;
319    bool useShader = false;
320
321    // construct the viewer.
322    osgViewer::Viewer viewer;
323   
324    while (arguments.read("--texture2D")) useTextureRectangle=false;
325    while (arguments.read("--shader")) useShader=true;
326
327    // if user request help write it out to cout.
328    if (arguments.read("-h") || arguments.read("--help"))
329    {
330        arguments.getApplicationUsage()->write(std::cout);
331        return 1;
332    }
333
334    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
335    osg::Vec3 pos(0.0f,0.0f,0.0f);
336       
337    osg::StateSet* stateset = geode->getOrCreateStateSet();
338    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
339
340    if (useShader)
341    {
342        //useTextureRectangle = false;
343       
344        static const char *shaderSourceTextureRec = {
345            "uniform vec4 cutoff_color;\n"
346            "uniform samplerRect movie_texture;\n"
347            "void main(void)\n"
348            "{\n"
349            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0]); \n"
350            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
351            "    gl_FragColor = texture_color;\n"
352            "}\n"
353        };
354
355        static const char *shaderSourceTexture2D = {
356            "uniform vec4 cutoff_color;\n"
357            "uniform sampler2D movie_texture;\n"
358            "void main(void)\n"
359            "{\n"
360            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0]); \n"
361            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
362            "    gl_FragColor = texture_color;\n"
363            "}\n"
364        };
365
366        osg::Program* program = new osg::Program;
367       
368        program->addShader(new osg::Shader(osg::Shader::FRAGMENT,
369                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D));
370
371        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f)));
372        stateset->addUniform(new osg::Uniform("movie_texture",0));
373
374        stateset->setAttribute(program);
375
376    }
377
378
379    for(int i=1;i<arguments.argc();++i)
380    {
381        if (arguments.isString(i))
382        {
383            osg::Image* image = osgDB::readImageFile(arguments[i]);
384            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image);
385            if (imagestream) imagestream->play();
386           
387            if (image)
388            {
389                geode->addDrawable(myCreateTexturedQuadGeometry(pos,image->s(),image->t(),image, useTextureRectangle));
390               
391                pos.z() += image->t()*1.5f;
392            }
393            else
394            {
395                std::cout<<"Unable to read file "<<arguments[i]<<std::endl;
396            }           
397        }
398    }
399   
400    if (geode->getNumDrawables()==0)
401    {
402        // nothing loaded.
403        arguments.getApplicationUsage()->write(std::cout);
404        return 1;
405    }
406
407    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
408    MovieEventHandler* meh = new MovieEventHandler();
409    geode->setEventCallback(meh);
410    meh->set(geode.get());
411
412    // report any errors if they have occured when parsing the program aguments.
413    if (arguments.errors())
414    {
415        arguments.writeErrorMessages(std::cout);
416        return 1;
417    }
418   
419    if (arguments.argc()<=1)
420    {
421        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
422        return 1;
423    }
424
425    // set the scene to render
426    viewer.setSceneData(geode.get());
427
428    // create the windows and run the threads.
429    return viewer.run();
430
431
432}
Note: See TracBrowser for help on using the browser.