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

Revision 13376, 25.3 kB (checked in by robert, 4 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

  • 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/StateSetManipulator>
38#include <osgGA/EventVisitor>
39
40#include <iostream>
41
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::observer_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            }
108        }
109
110        ImageStreamList& _imageStreamList;
111
112    protected:
113
114        FindImageStreamsVisitor& operator = (const FindImageStreamsVisitor&) { return *this; }
115
116    };
117
118
119    bool            _trackMouse;
120    ImageStreamList _imageStreamList;
121    unsigned int    _seekIncr;
122
123};
124
125
126
127void MovieEventHandler::set(osg::Node* node)
128{
129    _imageStreamList.clear();
130    if (node)
131    {
132        FindImageStreamsVisitor fisv(_imageStreamList);
133        node->accept(fisv);
134    }
135}
136
137
138bool MovieEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv)
139{
140    switch(ea.getEventType())
141    {
142        case(osgGA::GUIEventAdapter::MOVE):
143        case(osgGA::GUIEventAdapter::PUSH):
144        case(osgGA::GUIEventAdapter::RELEASE):
145        {
146            if (_trackMouse)
147            {
148                osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
149                osgUtil::LineSegmentIntersector::Intersections intersections;
150                bool foundIntersection = view==0 ? false :
151                    (nv==0 ? view->computeIntersections(ea, intersections) :
152                             view->computeIntersections(ea, nv->getNodePath(), intersections));
153
154                if (foundIntersection)
155                {
156
157                    // use the nearest intersection
158                    const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin());
159                    osg::Drawable* drawable = intersection.drawable.get();
160                    osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
161                    osg::Vec3Array* vertices = geometry ? dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()) : 0;
162                    if (vertices)
163                    {
164                        // get the vertex indices.
165                        const osgUtil::LineSegmentIntersector::Intersection::IndexList& indices = intersection.indexList;
166                        const osgUtil::LineSegmentIntersector::Intersection::RatioList& ratios = intersection.ratioList;
167
168                        if (indices.size()==3 && ratios.size()==3)
169                        {
170                            unsigned int i1 = indices[0];
171                            unsigned int i2 = indices[1];
172                            unsigned int i3 = indices[2];
173
174                            float r1 = ratios[0];
175                            float r2 = ratios[1];
176                            float r3 = ratios[2];
177
178                            osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0;
179                            osg::Vec2Array* texcoords_Vec2Array = dynamic_cast<osg::Vec2Array*>(texcoords);
180                            if (texcoords_Vec2Array)
181                            {
182                                // we have tex coord array so now we can compute the final tex coord at the point of intersection.
183                                osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1];
184                                osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2];
185                                osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3];
186                                osg::Vec2 tc = tc1*r1 + tc2*r2 + tc3*r3;
187
188                                osg::notify(osg::NOTICE)<<"We hit tex coords "<<tc<<std::endl;
189
190                            }
191                        }
192                        else
193                        {
194                            osg::notify(osg::NOTICE)<<"Intersection has insufficient indices to work with";
195                        }
196
197                    }
198                }
199                else
200                {
201                    osg::notify(osg::NOTICE)<<"No intersection"<<std::endl;
202                }
203            }
204            break;
205        }
206        case(osgGA::GUIEventAdapter::KEYDOWN):
207        {
208            if (ea.getKey()=='p')
209            {
210                for(ImageStreamList::iterator itr=_imageStreamList.begin();
211                    itr!=_imageStreamList.end();
212                    ++itr)
213                {
214                    osg::ImageStream::StreamStatus playToggle = (*itr)->getStatus();
215                    if (playToggle != osg::ImageStream::PLAYING)
216                    {
217                        std::cout<< (*itr).get() << " Play"<<std::endl;
218                        (*itr)->play();
219                    }
220                    else
221                    {
222                        // playing, so pause
223                        std::cout<< (*itr).get() << " Pause"<<std::endl;
224                        (*itr)->pause();
225                    }
226                }
227                return true;
228            }
229            else if (ea.getKey()=='r')
230            {
231                for(ImageStreamList::iterator itr=_imageStreamList.begin();
232                    itr!=_imageStreamList.end();
233                    ++itr)
234                {
235                    std::cout<< (*itr).get() << " Restart"<<std::endl;
236                    (*itr)->rewind();
237                    (*itr)->play();
238                }
239                return true;
240            }
241            else if (ea.getKey()=='>')
242            {
243                for(ImageStreamList::iterator itr=_imageStreamList.begin();
244                    itr!=_imageStreamList.end();
245                    ++itr)
246                {
247                    std::cout<<"Seeking"<<std::endl;
248                    if(_seekIncr > 3) _seekIncr = 0;
249                    double length = (*itr)->getLength();
250                    double t_pos = (length/4.0f)*_seekIncr;
251                    //(*itr)->rewind();
252                    (*itr)->seek(t_pos);
253                    (*itr)->play();
254                    _seekIncr++;
255                }
256                return true;
257            }
258            else if (ea.getKey()=='L')
259            {
260                for(ImageStreamList::iterator itr=_imageStreamList.begin();
261                    itr!=_imageStreamList.end();
262                    ++itr)
263                {
264                    if ( (*itr)->getLoopingMode() == osg::ImageStream::LOOPING)
265                    {
266                        std::cout<< (*itr).get() << " Toggle Looping Off"<<std::endl;
267                        (*itr)->setLoopingMode( osg::ImageStream::NO_LOOPING );
268                    }
269                    else
270                    {
271                        std::cout<< (*itr).get() << " Toggle Looping On"<<std::endl;
272                        (*itr)->setLoopingMode( osg::ImageStream::LOOPING );
273                    }
274                }
275                return true;
276            }
277            else if (ea.getKey()=='+')
278            {
279                for(ImageStreamList::iterator itr=_imageStreamList.begin();
280                    itr!=_imageStreamList.end();
281                    ++itr)
282                {
283                    double tm = (*itr)->getTimeMultiplier();
284                    tm += 0.1;
285                    (*itr)->setTimeMultiplier(tm);
286                    std::cout << (*itr).get() << " Increase speed rate "<< (*itr)->getTimeMultiplier() << std::endl;
287                }
288                return true;
289            }
290            else if (ea.getKey()=='-')
291            {
292                for(ImageStreamList::iterator itr=_imageStreamList.begin();
293                    itr!=_imageStreamList.end();
294                    ++itr)
295                {
296                    double tm = (*itr)->getTimeMultiplier();
297                    tm -= 0.1;
298                    (*itr)->setTimeMultiplier(tm);
299                    std::cout << (*itr).get() << " Decrease speed rate "<< (*itr)->getTimeMultiplier() << std::endl;
300                }
301                return true;
302            }
303            else if (ea.getKey()=='o')
304            {
305                for(ImageStreamList::iterator itr=_imageStreamList.begin();
306                    itr!=_imageStreamList.end();
307                    ++itr)
308                {
309                    std::cout<< (*itr).get() << " Frame rate  "<< (*itr)->getFrameRate() <<std::endl;
310                }
311                return true;
312            }
313            return false;
314        }
315
316        default:
317            return false;
318    }
319    return false;
320}
321
322void MovieEventHandler::getUsage(osg::ApplicationUsage& usage) const
323{
324    usage.addKeyboardMouseBinding("p","Play/Pause movie");
325    usage.addKeyboardMouseBinding("r","Restart movie");
326    usage.addKeyboardMouseBinding("l","Toggle looping of movie");
327    usage.addKeyboardMouseBinding("+","Increase speed of movie");
328    usage.addKeyboardMouseBinding("-","Decrease speed of movie");
329    usage.addKeyboardMouseBinding("o","Display frame rate of movie");
330    usage.addKeyboardMouseBinding(">","Advance the movie using seek");
331}
332
333
334osg::Geometry* myCreateTexturedQuadGeometry(const osg::Vec3& pos,float width,float height, osg::Image* image, bool useTextureRectangle, bool xyPlane, bool option_flip)
335{
336    bool flip = image->getOrigin()==osg::Image::TOP_LEFT;
337    if (option_flip) flip = !flip;
338
339    if (useTextureRectangle)
340    {
341        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
342                                           osg::Vec3(width,0.0f,0.0f),
343                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height),
344                                           0.0f, flip ? image->t() : 0.0, image->s(), flip ? 0.0 : image->t());
345
346        osg::TextureRectangle* texture = new osg::TextureRectangle(image);
347        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
348        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
349
350
351        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
352                                                                        texture,
353                                                                        osg::StateAttribute::ON);
354
355        return pictureQuad;
356    }
357    else
358    {
359        osg::Geometry* pictureQuad = osg::createTexturedQuadGeometry(pos,
360                                           osg::Vec3(width,0.0f,0.0f),
361                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height),
362                                           0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f);
363
364        osg::Texture2D* texture = new osg::Texture2D(image);
365        texture->setResizeNonPowerOfTwoHint(false);
366        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
367        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
368        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
369
370
371        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
372                    texture,
373                    osg::StateAttribute::ON);
374
375        return pictureQuad;
376    }
377}
378
379#if USE_SDL
380
381class SDLAudioSink : public osg::AudioSink
382{
383    public:
384
385        SDLAudioSink(osg::AudioStream* audioStream):
386            _started(false),
387            _paused(false),
388            _audioStream(audioStream) {}
389
390        ~SDLAudioSink();
391
392        virtual void play();
393        virtual void pause();
394        virtual void stop();
395
396        virtual bool playing() const { return _started && !_paused; }
397
398
399        bool                                _started;
400        bool                                _paused;
401        osg::observer_ptr<osg::AudioStream> _audioStream;
402};
403
404#endif
405
406int main(int argc, char** argv)
407{
408    // use an ArgumentParser object to manage the program arguments.
409    osg::ArgumentParser arguments(&argc,argv);
410
411    // set up the usage document, in case we need to print out how to use this program.
412    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
413    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" example demonstrates the use of ImageStream for rendering movies as textures.");
414    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
415    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
416    arguments.getApplicationUsage()->addCommandLineOption("--texture2D","Use Texture2D rather than TextureRectangle.");
417    arguments.getApplicationUsage()->addCommandLineOption("--shader","Use shaders to post process the video.");
418    arguments.getApplicationUsage()->addCommandLineOption("--interactive","Use camera manipulator to allow movement around movie.");
419    arguments.getApplicationUsage()->addCommandLineOption("--flip","Flip the movie so top becomes bottom.");
420#if defined(WIN32) || defined(__APPLE__)
421    arguments.getApplicationUsage()->addCommandLineOption("--devices","Print the Video input capability via QuickTime and exit.");
422#endif
423
424    bool useTextureRectangle = true;
425    bool useShader = false;
426
427    // construct the viewer.
428    osgViewer::Viewer viewer(arguments);
429
430    if (arguments.argc()<=1)
431    {
432        arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
433        return 1;
434    }
435
436#if defined(WIN32) || defined(__APPLE__)
437    // if user requests devices video capability.
438    if (arguments.read("-devices") || arguments.read("--devices"))
439    {
440        // Force load QuickTime plugin, probe video capability, exit
441        osgDB::readImageFile("devices.live");
442        return 1;
443    }
444#endif
445
446    while (arguments.read("--texture2D")) useTextureRectangle=false;
447    while (arguments.read("--shader")) useShader=true;
448
449    bool mouseTracking = false;
450    while (arguments.read("--mouse")) mouseTracking=true;
451
452
453    // if user request help write it out to cout.
454    if (arguments.read("-h") || arguments.read("--help"))
455    {
456        arguments.getApplicationUsage()->write(std::cout);
457        return 1;
458    }
459
460    bool fullscreen = !arguments.read("--interactive");
461    bool flip = arguments.read("--flip");
462
463    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
464
465    osg::StateSet* stateset = geode->getOrCreateStateSet();
466    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
467
468    if (useShader)
469    {
470        //useTextureRectangle = false;
471
472        static const char *shaderSourceTextureRec = {
473            "uniform vec4 cutoff_color;\n"
474            "uniform samplerRect movie_texture;\n"
475            "void main(void)\n"
476            "{\n"
477            "    vec4 texture_color = textureRect(movie_texture, gl_TexCoord[0].st); \n"
478            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
479            "    gl_FragColor = texture_color;\n"
480            "}\n"
481        };
482
483        static const char *shaderSourceTexture2D = {
484            "uniform vec4 cutoff_color;\n"
485            "uniform sampler2D movie_texture;\n"
486            "void main(void)\n"
487            "{\n"
488            "    vec4 texture_color = texture2D(movie_texture, gl_TexCoord[0].st); \n"
489            "    if (all(lessThanEqual(texture_color,cutoff_color))) discard; \n"
490            "    gl_FragColor = texture_color;\n"
491            "}\n"
492        };
493
494        osg::Program* program = new osg::Program;
495
496        program->addShader(new osg::Shader(osg::Shader::FRAGMENT,
497                                           useTextureRectangle ? shaderSourceTextureRec : shaderSourceTexture2D));
498
499        stateset->addUniform(new osg::Uniform("cutoff_color",osg::Vec4(0.1f,0.1f,0.1f,1.0f)));
500        stateset->addUniform(new osg::Uniform("movie_texture",0));
501
502        stateset->setAttribute(program);
503
504    }
505
506    osg::Vec3 pos(0.0f,0.0f,0.0f);
507    osg::Vec3 topleft = pos;
508    osg::Vec3 bottomright = pos;
509
510    bool xyPlane = fullscreen;
511   
512    bool useAudioSink = false;
513    while(arguments.read("--audio")) { useAudioSink = true; }
514   
515#if USE_SDL
516    unsigned int numAudioStreamsEnabled = 0;
517#endif
518
519    for(int i=1;i<arguments.argc();++i)
520    {
521        if (arguments.isString(i))
522        {
523            osg::Image* image = osgDB::readImageFile(arguments[i]);
524            osg::ImageStream* imagestream = dynamic_cast<osg::ImageStream*>(image);
525            if (imagestream)
526            {
527                osg::ImageStream::AudioStreams& audioStreams = imagestream->getAudioStreams();
528                if (useAudioSink && !audioStreams.empty())
529                {
530                    osg::AudioStream* audioStream = audioStreams[0].get();
531                    osg::notify(osg::NOTICE)<<"AudioStream read ["<<audioStream->getName()<<"]"<<std::endl;
532#if USE_SDL
533                    if (numAudioStreamsEnabled==0)
534                    {
535                        audioStream->setAudioSink(new SDLAudioSink(audioStream));
536                       
537                        ++numAudioStreamsEnabled;
538                    }
539#endif
540                }
541
542
543                imagestream->play();
544            }
545
546            if (image)
547            {
548                osg::notify(osg::NOTICE)<<"image->s()"<<image->s()<<" image-t()="<<image->t()<<" aspectRatio="<<image->getPixelAspectRatio()<<std::endl;
549
550                float width = image->s() * image->getPixelAspectRatio();
551                float height = image->t();
552
553                osg::ref_ptr<osg::Drawable> drawable = myCreateTexturedQuadGeometry(pos, width, height,image, useTextureRectangle, xyPlane, flip);
554               
555                if (image->isImageTranslucent())
556                {
557                    osg::notify(osg::NOTICE)<<"Transparent movie, enabling blending."<<std::endl;
558
559                    drawable->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
560                    drawable->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
561                }
562
563                geode->addDrawable(drawable.get());
564
565                bottomright = pos + osg::Vec3(width,height,0.0f);
566
567                if (xyPlane) pos.y() += height*1.05f;
568                else pos.z() += height*1.05f;
569            }
570            else
571            {
572                std::cout<<"Unable to read file "<<arguments[i]<<std::endl;
573            }
574        }
575    }
576
577    // set the scene to render
578    viewer.setSceneData(geode.get());
579
580    if (viewer.getSceneData()==0)
581    {
582        arguments.getApplicationUsage()->write(std::cout);
583        return 1;
584    }
585
586    // pass the model to the MovieEventHandler so it can pick out ImageStream's to manipulate.
587    MovieEventHandler* meh = new MovieEventHandler();
588    meh->setMouseTracking( mouseTracking );
589    meh->set( viewer.getSceneData() );
590    viewer.addEventHandler( meh );
591
592    viewer.addEventHandler( new osgViewer::StatsHandler );
593    viewer.addEventHandler( new osgGA::StateSetManipulator( viewer.getCamera()->getOrCreateStateSet() ) );
594    viewer.addEventHandler( new osgViewer::WindowSizeHandler );
595
596    // add the record camera path handler
597    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
598
599    // report any errors if they have occurred when parsing the program arguments.
600    if (arguments.errors())
601    {
602        arguments.writeErrorMessages(std::cout);
603        return 1;
604    }
605
606    if (fullscreen)
607    {
608        viewer.realize();
609       
610        viewer.getCamera()->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
611
612        float screenAspectRatio = 1280.0f/1024.0f;
613
614        osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
615        if (wsi)
616        {
617            unsigned int width, height;
618            wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);
619           
620            screenAspectRatio = float(width) / float(height);
621        }
622       
623        float modelAspectRatio = (bottomright.x()-topleft.x())/(bottomright.y()-topleft.y());
624       
625        viewer.getCamera()->setViewMatrix(osg::Matrix::identity());
626
627
628        osg::Vec3 center = (bottomright + topleft)*0.5f;
629        osg::Vec3 dx(bottomright.x()-center.x(), 0.0f, 0.0f);
630        osg::Vec3 dy(0.0f, topleft.y()-center.y(), 0.0f);
631
632        float ratio = modelAspectRatio/screenAspectRatio;
633
634        if (ratio>1.0f)
635        {
636            // use model width as the control on model size.
637            bottomright = center + dx - dy * ratio;
638            topleft = center - dx + dy * ratio;
639        }
640        else
641        {
642            // use model height as the control on model size.
643            bottomright = center + dx / ratio - dy;
644            topleft = center - dx / ratio + dy;
645        }
646
647        viewer.getCamera()->setProjectionMatrixAsOrtho2D(topleft.x(),bottomright.x(),topleft.y(),bottomright.y());
648
649        while(!viewer.done())
650        {
651            viewer.frame();
652        }
653        return 0;
654    }
655    else
656    {
657        // create the windows and run the threads.
658        return viewer.run();
659    }
660}
661
662#if USE_SDL
663
664#include "SDL.h"
665
666static void soundReadCallback(void * user_data, uint8_t * data, int datalen)
667{
668    SDLAudioSink * sink = reinterpret_cast<SDLAudioSink*>(user_data);
669    osg::ref_ptr<osg::AudioStream> as = sink->_audioStream.get();
670    if (as.valid())
671    {
672        as->consumeAudioBuffer(data, datalen);
673    }
674}
675
676SDLAudioSink::~SDLAudioSink()
677{
678    stop();
679}
680
681void SDLAudioSink::play()
682{
683    if (_started)
684    {
685        if (_paused)
686        {
687            SDL_PauseAudio(0);
688            _paused = false;
689        }
690        return;
691    }
692
693    _started = true;
694    _paused = false;
695
696    osg::notify(osg::NOTICE)<<"SDLAudioSink()::startPlaying()"<<std::endl;
697
698    osg::notify(osg::NOTICE)<<"  audioFrequency()="<<_audioStream->audioFrequency()<<std::endl;
699    osg::notify(osg::NOTICE)<<"  audioNbChannels()="<<_audioStream->audioNbChannels()<<std::endl;
700    osg::notify(osg::NOTICE)<<"  audioSampleFormat()="<<_audioStream->audioSampleFormat()<<std::endl;
701
702    SDL_AudioSpec specs = { 0 };
703    SDL_AudioSpec wanted_specs = { 0 };
704
705    wanted_specs.freq = _audioStream->audioFrequency();
706    wanted_specs.format = AUDIO_S16SYS;
707    wanted_specs.channels = _audioStream->audioNbChannels();
708    wanted_specs.silence = 0;
709    wanted_specs.samples = 1024;
710    wanted_specs.callback = soundReadCallback;
711    wanted_specs.userdata = this;
712
713    if (SDL_OpenAudio(&wanted_specs, &specs) < 0)
714        throw "SDL_OpenAudio() failed (" + std::string(SDL_GetError()) + ")";
715
716    SDL_PauseAudio(0);
717
718}
719
720void SDLAudioSink::pause()
721{
722    if (_started)
723    {
724        SDL_PauseAudio(1);
725        _paused = true;
726    }
727}
728
729void SDLAudioSink::stop()
730{
731    if (_started)
732    {
733        if (!_paused) SDL_PauseAudio(1);
734        SDL_CloseAudio();
735
736        osg::notify(osg::NOTICE)<<"~SDLAudioSink() destructor, but still playing"<<std::endl;
737    }
738}
739
740#endif
Note: See TracBrowser for help on using the browser.