gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r11835: Add function to Renderer API


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11835: Add function to Renderer API to render current buffer to a specified IOChannel
Date: Fri, 29 Jan 2010 10:30:10 +0100
User-agent: Bazaar (2.0.2)

------------------------------------------------------------
revno: 11835 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Fri 2010-01-29 10:30:10 +0100
message:
  Add function to Renderer API to render current buffer to a specified IOChannel
  and image format.
  
  Add ScreenShot capability to GUI base class. Currently accessible using
  Ctrl-O for spontaneous screenshots.
modified:
  backend/Renderer.h
  backend/Renderer_agg.cpp
  gui/gui.cpp
  gui/gui.h
  libbase/GnashImage.cpp
  libbase/GnashImage.h
=== modified file 'backend/Renderer.h'
--- a/backend/Renderer.h        2010-01-19 09:59:10 +0000
+++ b/backend/Renderer.h        2010-01-27 13:24:59 +0000
@@ -191,11 +191,9 @@
 /// Base class for render handlers.
 //
 /// You must define a subclass of Renderer, and pass an
-/// instance to set_Renderer() *before* any SWF parsing begins.
+/// instance to the core (RunResources) *before* any SWF parsing begins.
 ///
 /// For more info see page \ref Renderer_intro.
-/// 
-///
 class DSOEXPORT Renderer
 {
 public:
@@ -312,6 +310,24 @@
            const SWFMatrix& mat) = 0;
 
 
+    /// Draw the current rendering buffer to an image file.
+    //
+    /// Although this can be done at any time during the rendering cycle
+    /// without harmful side effects, it's advisable only to do it when 
+    /// between advance() calls, when the frame is fully renderered.
+    //
+    /// @param io       The IOChannel to write to.
+    /// @param type     The type of image output required (PNG, JPEG, GIF).
+    ///                 Note that not all FileTypes are images: rendering
+    ///                 to an FLV will not work.
+    virtual void renderToImage(boost::shared_ptr<IOChannel> /*io*/,
+        FileType /*type*/) const {
+
+        log_debug(_("Rendering to image not implemented for this "
+            "renderer"));
+    }
+        
+
     /// ==================================================================
     /// Prepare drawing area and other utilities
     /// ==================================================================

=== modified file 'backend/Renderer_agg.cpp'
--- a/backend/Renderer_agg.cpp  2010-01-19 09:59:10 +0000
+++ b/backend/Renderer_agg.cpp  2010-01-27 13:24:59 +0000
@@ -595,6 +595,21 @@
         return new agg_bitmap_info(im);
     }
 
+    virtual void renderToImage(boost::shared_ptr<IOChannel> io,
+            FileType type) const
+    {
+        log_debug("New image: %sx%s", xres, yres);
+        ImageRGBA im(xres, yres);
+        for (int x = 0; x < xres; ++x) {
+            for (int y = 0; y < yres; ++y) {
+                typename PixelFormat::color_type t = m_pixf->pixel(x, y);
+                im.setPixel(x, y, t.r, t.g, t.b, t.a);
+            }
+        }
+        
+        ImageOutput::writeImageData(type, io, im, 100);
+    }
+
     template<typename SourceFormat, typename Matrix>
     void renderVideo(GnashImage& frame, Matrix& img_mtx,
             agg::path_storage path, bool smooth)

=== modified file 'gui/gui.cpp'
--- a/gui/gui.cpp       2010-01-11 06:41:38 +0000
+++ b/gui/gui.cpp       2010-01-29 08:58:21 +0000
@@ -29,6 +29,8 @@
 #include "movie_root.h"
 #include "VM.h"
 #include "DisplayObject.h"
+#include "tu_file.h"
+#include "gnash.h"
 
 #ifdef GNASH_FPS_DEBUG
 #include "ClockTime.h"
@@ -215,13 +217,12 @@
 void
 Gui::allowScale(bool allow)
 {
-       if ( ! _stage )
-       {
+       if (!_stage) {
                log_error("Gui::allowScale called before a movie_root was 
available");
                return;
        }
 
-       if ( allow ) _stage->setStageScaleMode(movie_root::showAll);
+       if (allow) _stage->setStageScaleMode(movie_root::showAll);
        else _stage->setStageScaleMode(movie_root::noScale);
 }
 
@@ -550,10 +551,13 @@
                        }
                }
                
-               if (modifier & gnash::key::GNASH_MOD_CONTROL)
-               {
-                       switch(k)
+               if (modifier & gnash::key::GNASH_MOD_CONTROL) {
+                       switch (k)
                        {
+                case gnash::key::o:
+                case gnash::key::O:
+                    takeScreenShot();
+                    break;
                                case gnash::key::r:
                                case gnash::key::R:
                                        restart();
@@ -583,28 +587,27 @@
                                case gnash::key::MINUS:
                                {
                                        // Max interval allowed: 1 second (1FPS)
-                                       unsigned int ni = std::min(_interval+2, 
1000u);
+                                       const size_t ni = 
std::min<size_t>(_interval + 2, 1000u);
                                        setInterval(ni);
                                        break;
                 }
                                case gnash::key::PLUS:
                                {
                                        // Min interval allowed: 1/100 second 
(100FPS)
-                                       unsigned int ni = std::max(_interval-2, 
10u);
+                                       const size_t ni = 
std::max<size_t>(_interval - 2, 10u);
                                        setInterval(ni);
                                        break;
                                 }
                                case gnash::key::EQUALS:
                                {
-                                       if ( _stage )
-                                       {
-                                               float fps = _stage->frameRate();
+                                       if (_stage) {
+                                               const float fps = 
_stage->frameRate();
                                                // Min interval allowed: 1/100 
second (100FPS)
-                                               unsigned int ni = 1000.0/fps;
+                                               const size_t ni = 1000.0/fps;
                                                setInterval(ni);
                                        }
                                        break;
-                                }
+                }
                                default:
                                        break;
                        }
@@ -613,16 +616,15 @@
                        if ( _keyboardMouseMovements )
                        {
                                int step = _keyboardMouseMovementsStep; 
-                               if (modifier & gnash::key::GNASH_MOD_SHIFT) 
step*=5; // x5 if SHIFT is pressed
-                               switch(k)
+                // x5 if SHIFT is pressed
+                               if (modifier & gnash::key::GNASH_MOD_SHIFT) 
step *= 5; 
+                               switch (k)
                                {
                                        case gnash::key::UP:
                                        {
                                                int newx = _xpointer;
                                                int newy = _ypointer-step;
-                                               //log_debug("(theoretically) 
From %d,%d to %d,%d (step %d)", _xpointer, _ypointer, newx, newy, step);
                                                if ( newy < 0 ) newy=0;
-                                               //log_debug("From %d,%d to 
%d,%d", _xpointer, _ypointer, newx, newy);
                                                notify_mouse_moved(newx, newy);
                                                break;
                                        }
@@ -630,9 +632,7 @@
                                        {
                                                int newx = _xpointer;
                                                int newy = _ypointer+step;
-                                               //log_debug("(theoretically) 
From %d,%d to %d,%d (step %d)", _xpointer, _ypointer, newx, newy, step);
                                                if ( newy >= _height ) newy = 
_height-1;
-                                               //log_debug("From %d,%d to 
%d,%d", _xpointer, _ypointer, newx, newy);
                                                notify_mouse_moved(newx, newy);
                                                break;
                                        }
@@ -640,19 +640,15 @@
                                        {
                                                int newx = _xpointer-step;
                                                int newy = _ypointer;
-                                               //log_debug("(theoretically) 
From %d,%d to %d,%d (step %d)", _xpointer, _ypointer, newx, newy, step);
                                                if ( newx < 0 ) newx = 0;
-                                               //log_debug("From %d,%d to 
%d,%d", _xpointer, _ypointer, newx, newy);
                                                notify_mouse_moved(newx, newy);
                                                break;
                                        }
                                        case gnash::key::RIGHT:
                                        {
-                                               int newy = _ypointer;
-                                               int newx = _xpointer+step;
-                                               //log_debug("(theoretically) 
From %d,%d to %d,%d (step %d)", _xpointer, _ypointer, newx, newy, step);
+                                               const int newy = _ypointer;
+                                               int newx = _xpointer + step;
                                                if ( newx >= _width ) newx = 
_width-1;
-                                               //log_debug("From %d,%d to 
%d,%d", _xpointer, _ypointer, newx, newy);
                                                notify_mouse_moved(newx, newy);
                                                break;
                                        }
@@ -664,12 +660,11 @@
                }
        }
 
-    if ( ! _started ) return;
-
-    if ( _stopped ) return;
-
-       if ( _stage->notify_key_event(k, pressed) )
-       {
+    if (!_started) return;
+
+    if (_stopped) return;
+
+       if (_stage->notify_key_event(k, pressed)) {
                // any action triggered by the
                // event required screen refresh
                display(_stage);
@@ -872,27 +867,25 @@
 void
 Gui::pause()
 {
-    if ( _stopped )
-    {
+    if (_stopped) {
         play();
-    }
-    else
-    {
-        // TODO: call stop() instead ?
-        // The only thing I see is that ::stop exits full-screen,
-        // but I'm not sure that's intended behaviour
-
-        // @todo since we registered the sound handler, shouldn't we know
-        //       already what it is ?!
-       sound::sound_handler* s = _stage->runResources().soundHandler();
-       if ( s ) s->pause();
-        _stopped = true;
-
-        log_debug("Pausing virtual clock");
-        _virtualClock.pause();
-
-        stopHook();
-    }
+        return;
+    }
+
+    // TODO: call stop() instead ?
+    // The only thing I see is that ::stop exits full-screen,
+    // but I'm not sure that's intended behaviour
+
+    // @todo since we registered the sound handler, shouldn't we know
+    //       already what it is ?!
+    sound::sound_handler* s = _stage->runResources().soundHandler();
+    if (s) s->pause();
+    _stopped = true;
+
+    log_debug("Pausing virtual clock");
+    _virtualClock.pause();
+
+    stopHook();
 }
 
 void
@@ -928,34 +921,34 @@
 bool
 Gui::advanceMovie()
 {
-
-       if ( isStopped() ) return true;
-
-    if ( ! _started ) start();
-  
-
+       if (isStopped()) return true;
+
+    if (!_started) start();
 
        gnash::movie_root* m = _stage;
        
 // Define REVIEW_ALL_FRAMES to have *all* frames
-// consequencially displaied. Useful for debugging.
+// consequentially displayed. Useful for debugging.
 //#define REVIEW_ALL_FRAMES 1
 
 #ifndef REVIEW_ALL_FRAMES
        // Advance movie by one frame
        bool advanced = m->advance();
 #else
-       size_t cur_frame = m->getRootMovie()->get_current_frame();
-       size_t tot_frames = m->getRootMovie()->get_frame_count();
-       bool advanced = m->advance();
-       m->getRootMovie.ensureFrameLoaded(tot_frames);
-       m->goto_frame(cur_frame+1);
+       const size_t cur_frame = m->getRootMovie()->get_current_frame();
+       const size_t tot_frames = m->getRootMovie()->get_frame_count();
+       const bool advanced = m->advance();
+       
+    m->getRootMovie.ensureFrameLoaded(tot_frames);
+       m->goto_frame(cur_frame + 1);
     m->set_play_state(gnash::MovieClip::PLAYSTATE_PLAY);
        log_debug(_("Frame %d"), m->get_current_frame());
 #endif
+    
 
 #ifdef GNASH_FPS_DEBUG
-       if ( advanced ) fpsCounterTick(); // will be a no-op if 
fps_timer_interval is zero
+    // will be a no-op if fps_timer_interval is zero
+       if (advanced) fpsCounterTick(); 
 #endif
 
 
@@ -967,10 +960,10 @@
 #ifdef SKIP_RENDERING_IF_LATE
     // We want to skip rendering IFF it's time to advance again.
     // We'll ask the stage about it
-    if ( _stage->timeToNextFrame() <= 0 )
-    {
-        if ( doDisplay ) // or should it be if advanced ?
-        {
+    if (_stage->timeToNextFrame() <= 0) {
+
+        // or should it be if advanced ?
+        if (doDisplay) {
             // TODO: take note of a frame drop (count them)
             //log_debug("Frame rendering dropped due to being late");
 #ifdef GNASH_FPS_DEBUG
@@ -983,26 +976,49 @@
 
        if (doDisplay) display(m);
 
-       if ( ! loops() )
-       {
+       if (!loops()) {
                size_t curframe = m->get_current_frame(); // can be 0 on 
malformed SWF
                const gnash::MovieClip& si = m->getRootMovie();
-               if (curframe + 1 >= si.get_frame_count())
-               {
+               if (curframe + 1 >= si.get_frame_count()) {
                        quit(); 
                }
        }
 
-    /// Quit if we've reached the advance limit.
-    if (_maxAdvances && advanced && (_advances++ > _maxAdvances))
-    {
-        quit();
+    if (_screenShotter.get()) {
+        _screenShotter->screenShot(_advances);
+    }
+
+    // Only increment advances and check for exit condition when we've
+    // really changed frame.
+    if (advanced) {
+
+        /// Quit if we've reached the frame advance limit.
+        if (_maxAdvances && (_advances > _maxAdvances)) {
+            quit();
+        }
+        ++_advances;
     }
 
        return true;
 }
 
 void
+Gui::takeScreenShot()
+{
+    if (!_screenShotter.get()) {
+        // If no ScreenShotter exists, none was requested at startup.
+        URL url(_runResources.baseURL());
+        std::string::size_type p = url.path().rfind('/');
+        const std::string& name = (p == std::string::npos) ? url.path() :
+            url.path().substr(p + 1);
+        const std::string& filename = "screenshot-" + name;
+        _screenShotter.reset(new ScreenShotter(_renderer, filename));
+    }
+    assert (_screenShotter.get());
+    _screenShotter->now();
+}
+
+void
 Gui::setCursor(gnash_cursor_type /*newcursor*/)
 {
 }
@@ -1243,15 +1259,15 @@
 bool
 Gui::yesno(const std::string& question)
 {
-    log_error("This gui didn't override 'yesno', assuming 'yes' answer to 
question: %s", question);
+    log_error("This gui didn't override 'yesno', assuming 'yes' answer to "
+            "question: %s", question);
     return true;
 }
 
 void
 Gui::setQuality(Quality q)
 {
-       if ( ! _stage )
-       {
+       if (!_stage) {
                log_error("Gui::setQuality called before a movie_root was 
available");
                return;
        }
@@ -1261,13 +1277,32 @@
 Quality
 Gui::getQuality() const
 {
-       if ( ! _stage )
-       {
+       if (!_stage) {
                log_error("Gui::getQuality called before a movie_root was 
available");
-               return QUALITY_HIGH; // just a guess..
+        // just a guess..
+               return QUALITY_HIGH;
        }
     return _stage->getQuality();
 }
 
+void
+ScreenShotter::screenShot(size_t frameAdvance)
+{
+    if (_immediate) {
+        // Spontaneous screenshots always have the frame number appended.
+        std::ostringstream ss;
+        ss << _fileName << "-" << frameAdvance;
+        FILE* f = std::fopen(ss.str().c_str(), "wb");
+        if (f) {
+            boost::shared_ptr<IOChannel> t(new tu_file(f, true));
+            _renderer->renderToImage(t, GNASH_FILETYPE_PNG);
+        }
+        else {
+            log_error("Failed to open screenshot file \"%s\"!", _fileName);
+        }
+        _immediate = false;
+    }
+}
+
 // end of namespace
 }

=== modified file 'gui/gui.h'
--- a/gui/gui.h 2010-01-11 06:41:38 +0000
+++ b/gui/gui.h 2010-01-29 08:58:21 +0000
@@ -68,9 +68,7 @@
     class movie_definition;
 }
 
-namespace gnash
-{
-
+namespace gnash {
 
 /// Enumerates mouse cursor types.
 enum gnash_cursor_type {
@@ -79,6 +77,44 @@
   CURSOR_INPUT
 };
 
+/// Handles screen dumps.
+class ScreenShotter
+{
+public:
+
+    /// Create a ScreenShotter with renderer and output name.
+    ScreenShotter(boost::shared_ptr<Renderer> r, const std::string& fileName)
+        :
+        _renderer(r),
+        _immediate(false),
+        _fileName(fileName)
+    {}
+
+    /// Take a screenshot at the next possible moment.
+    void now() {
+        _immediate = true;
+    }
+
+    /// Takes a screenshot if required.
+    //
+    /// Called on each advance.
+    //
+    /// @param frameAdvance     used to check whether a screenshot is required
+    ///                         as well as to construct the filename.
+    void screenShot(size_t frameAdvance);
+
+private:
+
+    boost::shared_ptr<Renderer> _renderer;
+
+    /// If true, the next call to screenshot will take a screenshot
+    bool _immediate;
+
+    /// Name used to generate output file.
+    const std::string _fileName;
+
+};
+
 /// Parent class from which all GUI implementations will depend.
 class Gui {
 
@@ -243,8 +279,7 @@
     bool advanceMovie();
 
     /// Convenience static wrapper around advanceMovie for callbacks happiness.
-    static bool advance_movie(Gui* gui)
-    {
+    static bool advance_movie(Gui* gui) {
         return gui->advanceMovie();
     }
 
@@ -317,13 +352,16 @@
     bool isStopped() const { return _stopped; }
     
     /// Whether gnash is is running as a plugin
-    bool isPlugin() const { return (( _xid )); }
+    bool isPlugin() const { return ((_xid)); }
+
+    /// Take a screenshot now!
+    void takeScreenShot();
 
     /// Set the maximum number of frame advances before Gnash exits.
     void setMaxAdvances(unsigned long ul) { if (ul) _maxAdvances = ul; }
     
     void showUpdatedRegions(bool x) { _showUpdatedRegions = x; }
-    bool showUpdatedRegions() { return _showUpdatedRegions; }
+    bool showUpdatedRegions() const { return _showUpdatedRegions; }
 
     /// Instruct the core to restart the movie and
     /// set state to play(). This does not change pause
@@ -468,16 +506,16 @@
 private:
 
     /// Width of a window pixel, in stage pseudopixel units.
-    float           _xscale;
+    float _xscale;
 
     /// Height of a window pixel, in stage pseudopixel units.
-    float           _yscale;
+    float _yscale;
 
     /// Window pixel X offset of stage origin
-    boost::int32_t   _xoffset;
+    boost::int32_t _xoffset;
 
     /// Window pixel Y offset of stage origin
-    boost::int32_t   _yoffset;
+    boost::int32_t _yoffset;
 
     bool display(movie_root* m);
     
@@ -519,10 +557,10 @@
     movie_root* _stage;
 
     /// True if the application has been put into "stop" mode
-    bool            _stopped;
+    bool _stopped;
 
     /// True if the application didn't start yet
-    bool            _started;
+    bool _started;
 
     /// If true, updated regions (invalidated ranges) are visibly outlined.
     bool _showUpdatedRegions;
@@ -530,6 +568,9 @@
     SystemClock _systemClock;
     InterruptableVirtualClock _virtualClock;
     
+    /// Checked on each advance for screenshot activity if it exists.
+    boost::scoped_ptr<ScreenShotter> _screenShotter;
+
 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS 
        int _xpointer;
        int _ypointer;

=== modified file 'libbase/GnashImage.cpp'
--- a/libbase/GnashImage.cpp    2010-01-18 07:20:07 +0000
+++ b/libbase/GnashImage.cpp    2010-01-27 13:24:59 +0000
@@ -75,7 +75,7 @@
     assert(pitch >= width);
 }
 
-void GnashImage::update(boost::uint8_t* data)
+void GnashImage::update(const boost::uint8_t* data)
 {
     std::memcpy(this->data(), data, _size);
 }

=== modified file 'libbase/GnashImage.h'
--- a/libbase/GnashImage.h      2010-01-25 18:52:20 +0000
+++ b/libbase/GnashImage.h      2010-01-27 13:24:59 +0000
@@ -139,7 +139,7 @@
     ///
     /// @param data buffer to copy data from.
     ///
-    void update(boost::uint8_t* data);
+    void update(const boost::uint8_t* data);
 
     /// Copy image data from another image data
     //


reply via email to

[Prev in Thread] Current Thread [Next in Thread]