[Top][All Lists]
[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
//
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/trunk r11835: Add function to Renderer API to render current buffer to a specified IOChannel,
Benjamin Wolsey <=