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

Revision 7477, 16.7 kB (checked in by robert, 7 years ago)

Removed all dome distortion correction code as this is now part of the core osgViewer.

Added viewer mode where movies are made fullscreen. One can use the old interactive
camera mode by using --interactive parameter on the command line.

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