1 // gui.cpp: Top level GUI for SWF player, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 Free Software Foundation, Inc
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "gnashconfig.h"
29 #include <boost/assign/list_of.hpp>
31 #include "MovieClip.h"
33 #include "sound_handler.h"
34 #include "movie_root.h"
36 #include "DisplayObject.h"
37 #include "GnashEnums.h"
38 #include "RunResources.h"
39 #include "StreamProvider.h"
40 #include "ScreenShotter.h"
42 #ifdef GNASH_FPS_DEBUG
43 #include "ClockTime.h"
44 #include <boost/format.hpp>
47 /// Define this to make sure each frame is fully rendered from ground up
48 /// even if no motion has been detected in the movie.
49 //#define FORCE_REDRAW 1
51 /// Define this if you want to debug the *detection* of region updates only.
52 /// This will disable region updates for the backend (GUI+renderer) completely
53 /// so that only the last region (red frame) will be visible. However, this
54 /// slows down rendering as each frame is fully re-rendered. If you want to
55 /// debug the GUI part, however (see if blitting the region works), then you
56 /// probably won't define this.
57 #ifndef DISABLE_REGION_UPDATES_DEBUGGING
58 //#define REGION_UPDATES_DEBUGGING_FULL_REDRAW 1
61 #ifndef DISABLE_REGION_UPDATES_DEBUGGING
62 // a runtime check would make the { x; } block conditionally executed
63 #define IF_DEBUG_REGION_UPDATES(x) { if (_showUpdatedRegions) { x } }
65 #define IF_DEBUG_REGION_UPDATES(x)
68 // Define this to have gnash print the mouse pointer coordinates
69 // as the mouse moves. See also ENABLE_KEYBOARD_MOUSE_MOVEMENTS
70 // to have more control over mouse pointer.
72 //#define DEBUG_MOUSE_COORDINATES 1
78 Display(Gui
& g
, movie_root
& r
) : _g(g
), _r(r
) {}
79 void operator()() const {
80 InvalidatedRanges world_ranges
;
81 world_ranges
.setWorld();
82 _g
.setInvalidatedRegions(world_ranges
);
90 Gui::Gui(RunResources
& r
) :
106 #ifdef GNASH_FPS_DEBUG
108 ,fps_counter_total(0)
110 ,fps_timer_interval(0.0)
117 ,_showUpdatedRegions(false)
119 // NOTE: it's important that _systemClock is constructed
120 // before and destroyed after _virtualClock !
122 ,_virtualClock(_systemClock
)
123 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS
126 ,_keyboardMouseMovements(true) // TODO: base default on gnashrc or always false and provide menu item to toggle
127 ,_keyboardMouseMovementsStep(1)
133 Gui::Gui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
)
148 _xoffset(0), // TODO: x and y offset will need update !
150 #ifdef GNASH_FPS_DEBUG
152 ,fps_counter_total(0)
154 ,fps_timer_interval(0.0)
161 ,_showUpdatedRegions(false)
163 // NOTE: it's important that _systemClock is constructed
164 // before and destroyed after _virtualClock !
166 ,_virtualClock(_systemClock
)
167 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS
170 ,_keyboardMouseMovements(true) // TODO: base default on gnashrc or always false and provide menu item to toggle
171 ,_keyboardMouseMovementsStep(1)
178 if ( _movieDef
.get() ) {
179 log_debug("~Gui - _movieDef refcount: %d", _movieDef
->get_ref_count());
182 #ifdef GNASH_FPS_DEBUG
183 if ( fps_timer_interval
) {
184 std::cerr
<< "Total frame advances/drops: "
185 << fps_counter_total
<< "/" << frames_dropped
<< std::endl
;
191 Gui::setClipboard(const std::string
&)
193 LOG_ONCE(log_unimpl(_("Clipboard not yet supported in this GUI")));
199 log_unimpl(_("Fullscreen not yet supported in this GUI"));
203 Gui::resizeWindow(int /*width*/, int /*height*/)
205 log_unimpl(_("Window resize not yet supported in this GUI"));
209 Gui::unsetFullscreen()
211 log_unimpl(_("Fullscreen not yet supported in this GUI"));
217 // Take a screenshot of the last frame if required.
218 if (_screenShotter
.get() && _renderer
.get()) {
219 Display
dis(*this, *_stage
);
220 _screenShotter
->last(*_renderer
, &dis
);
229 LOG_ONCE(log_unimpl(_("Menu show/hide not yet supported in this GUI")));
233 Gui::showMouse(bool /* show */)
235 LOG_ONCE(log_unimpl(_("Mouse show/hide not yet supported in this GUI")));
240 Gui::showMenu(bool /* show */)
242 LOG_ONCE(log_unimpl(_("Menu show/hide not yet supported in this GUI")));
246 Gui::allowScale(bool allow
)
249 log_error("Gui::allowScale called before a movie_root was available");
253 if (allow
) _stage
->setStageScaleMode(movie_root::SCALEMODE_SHOWALL
);
254 else _stage
->setStageScaleMode(movie_root::SCALEMODE_NOSCALE
);
258 Gui::toggleFullscreen()
260 /// Sends request to Gnash core to change display state.
262 _stage
->setStageDisplayState(movie_root::DISPLAYSTATE_NORMAL
);
264 _stage
->setStageDisplayState(movie_root::DISPLAYSTATE_FULLSCREEN
);
277 Gui::updateStageMatrix()
280 // When VM initializes, we'll get a call to resize_view, which
281 // would call us again.
282 log_error(_("Can't update stage matrix till VM is initialized"));
286 assert(_stage
); // when VM is initialized this should hold
288 float swfwidth
= _movieDef
->get_width_pixels();
289 float swfheight
= _movieDef
->get_height_pixels();
292 movie_root::ScaleMode scaleMode
= _stage
->getStageScaleMode();
295 case movie_root::SCALEMODE_NOSCALE
:
296 _xscale
= _yscale
= 1.0f
;
299 case movie_root::SCALEMODE_SHOWALL
:
300 // set new scale value ( user-pixel / pseudo-pixel ). Do
301 // not divide by zero, or we end up with an invalid
302 // stage matrix that returns nan values.
303 _xscale
= (swfwidth
== 0.0f
) ? 1.0f
: _width
/ swfwidth
;
304 _yscale
= (swfheight
== 0.0f
) ? 1.0f
: _height
/ swfheight
;
306 // Scale proportionally, using smallest scale
307 if (_xscale
< _yscale
) {
309 } else if (_yscale
< _xscale
) {
314 case movie_root::SCALEMODE_NOBORDER
:
315 // set new scale value ( user-pixel / pseudo-pixel )
316 _xscale
= (swfwidth
== 0.0f
) ? 1.0f
: _width
/ swfwidth
;
317 _yscale
= (swfheight
== 0.0f
) ? 1.0f
: _height
/ swfheight
;
319 // Scale proportionally, using biggest scale
320 if (_xscale
> _yscale
) {
322 } else if (_yscale
> _xscale
) {
327 case movie_root::SCALEMODE_EXACTFIT
:
328 // NOTE: changing aspect ratio is valid!
329 _xscale
= (swfwidth
== 0.0f
) ? 1.0f
: _width
/ swfwidth
;
330 _yscale
= (swfheight
== 0.0f
) ? 1.0f
: _height
/ swfheight
;
334 log_error(_("Invalid scaleMode %d"), scaleMode
);
342 movie_root::StageAlign align
= _stage
->getStageAlignment();
343 movie_root::StageHorizontalAlign halign
= align
.first
;
344 movie_root::StageVerticalAlign valign
= align
.second
;
346 // Handle horizontal alignment
348 case movie_root::STAGE_H_ALIGN_L
:
350 // _xoffset=0 is fine
354 case movie_root::STAGE_H_ALIGN_R
:
357 float defWidth
= swfwidth
*= _xscale
;
358 float diffWidth
= _width
-defWidth
;
359 _xoffset
= diffWidth
;
363 case movie_root::STAGE_V_ALIGN_C
:
366 float defWidth
= swfwidth
*= _xscale
;
367 float diffWidth
= _width
-defWidth
;
368 _xoffset
= diffWidth
/2.0;
374 log_error(_("Invalid horizontal align %d"), valign
);
379 // Handle vertical alignment
381 case movie_root::STAGE_V_ALIGN_T
:
383 // _yoffset=0 is fine
387 case movie_root::STAGE_V_ALIGN_B
:
389 float defHeight
= swfheight
*= _yscale
;
390 float diffHeight
= _height
-defHeight
;
391 _yoffset
= diffHeight
;
395 case movie_root::STAGE_V_ALIGN_C
:
397 float defHeight
= swfheight
*= _yscale
;
398 float diffHeight
= _height
-defHeight
;
399 _yoffset
= diffHeight
/2.0;
405 log_error(_("Invalid vertical align %d"), valign
);
410 //log_debug("updateStageMatrix: scaleMode:%d, valign:%d, halign:%d",
411 //scaleMode, valign, halign);
413 // TODO: have a generic set_matrix ?
414 if (_renderer
.get()) {
415 _renderer
->set_scale(_xscale
, _yscale
);
416 _renderer
->set_translation(_xoffset
, _yoffset
);
418 //log_debug("updateStageMatrix: could not signal updated stage
419 //matrix to renderer (no renderer registered)");
423 //_redraw_flag |= (_width!=width) || (_height!=height);
424 _redraw_flag
= true; // this fixes bug #21971
429 Gui::resize_view(int width
, int height
)
431 GNASH_REPORT_FUNCTION
;
436 if (_stage
&& _started
) {
437 _stage
->setDimensions(width
, height
);
442 _validbounds
.setTo(0, 0, _width
, _height
);
446 if ( _stage
&& _started
) {
456 // @todo since we registered the sound handler, shouldn't we know
457 // already what it is ?!
458 sound::sound_handler
* s
= _stage
->runResources().soundHandler();
462 if (s
->is_muted()) s
->unmute();
468 Gui::notifyMouseMove(int ux
, int uy
)
470 movie_root
* m
= _stage
;
472 if ( ! _started
) return;
474 if ( _stopped
) return;
476 // A stage pseudopixel is user pixel / _xscale wide
477 boost::int32_t x
= (ux
-_xoffset
) / _xscale
;
479 // A stage pseudopixel is user pixel / _xscale high
480 boost::int32_t y
= (uy
-_yoffset
) / _yscale
;
482 #ifdef DEBUG_MOUSE_COORDINATES
483 log_debug("mouse @ %d,%d", x
, y
);
486 if ( m
->mouseMoved(x
, y
) ) {
487 // any action triggered by the
488 // event required screen refresh
492 DisplayObject
* activeEntity
= m
->getActiveEntityUnderPointer();
493 if ( activeEntity
) {
494 if ( activeEntity
->isSelectableTextField() ) {
495 setCursor(CURSOR_INPUT
);
496 } else if ( activeEntity
->allowHandCursor() ) {
497 setCursor(CURSOR_HAND
);
499 setCursor(CURSOR_NORMAL
);
502 setCursor(CURSOR_NORMAL
);
505 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS
514 Gui::notifyMouseWheel(int delta
)
516 movie_root
* m
= _stage
;
519 if (!_started
) return;
520 if (_stopped
) return;
522 if (m
->mouseWheel(delta
)) {
523 // any action triggered by the
524 // event required screen refresh
530 Gui::notifyMouseClick(bool mouse_pressed
)
532 movie_root
* m
= _stage
;
535 if (!_started
) return;
536 if (_stopped
) return;
538 if (m
->mouseClick(mouse_pressed
)) {
539 // any action triggered by the
540 // event required screen refresh
548 movie_root
* m
= _stage
;
550 if ( ! _started
) return;
559 Gui::notify_key_event(gnash::key::code k
, int modifier
, bool pressed
)
562 // Handle GUI shortcuts
564 if (k
== gnash::key::ESCAPE
) {
565 if (isFullscreen()) {
566 _stage
->setStageDisplayState(movie_root::DISPLAYSTATE_NORMAL
);
570 if (modifier
& gnash::key::GNASH_MOD_CONTROL
) {
600 showUpdatedRegions(!showUpdatedRegions());
602 case gnash::key::MINUS
:
604 // Max interval allowed: 1 second (1FPS)
605 const size_t ni
= std::min
<size_t>(_interval
+ 2, 1000u);
609 case gnash::key::PLUS
:
611 // Min interval allowed: 1/100 second (100FPS)
612 const size_t ni
= std::max
<size_t>(_interval
- 2, 10u);
616 case gnash::key::EQUALS
:
619 const float fps
= _stage
->getRootMovie().frameRate();
620 // Min interval allowed: 1/100 second (100FPS)
621 const size_t ni
= 1000.0/fps
;
630 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS
631 if ( _keyboardMouseMovements
) {
632 int step
= _keyboardMouseMovementsStep
;
633 // x5 if SHIFT is pressed
634 if (modifier
& gnash::key::GNASH_MOD_SHIFT
) step
*= 5;
638 int newx
= _xpointer
;
639 int newy
= _ypointer
-step
;
640 if ( newy
< 0 ) newy
=0;
641 notifyMouseMove(newx
, newy
);
644 case gnash::key::DOWN
:
646 int newx
= _xpointer
;
647 int newy
= _ypointer
+step
;
648 if ( newy
>= _height
) newy
= _height
-1;
649 notifyMouseMove(newx
, newy
);
652 case gnash::key::LEFT
:
654 int newx
= _xpointer
-step
;
655 int newy
= _ypointer
;
656 if ( newx
< 0 ) newx
= 0;
657 notifyMouseMove(newx
, newy
);
660 case gnash::key::RIGHT
:
662 const int newy
= _ypointer
;
663 int newx
= _xpointer
+ step
;
664 if ( newx
>= _width
) newx
= _width
-1;
665 notifyMouseMove(newx
, newy
);
672 #endif // ENABLE_KEYBOARD_MOUSE_MOVEMENTS
676 if (!_started
) return;
678 if (_stopped
) return;
680 if (_stage
->keyEvent(k
, pressed
)) {
681 // any action triggered by the
682 // event required screen refresh
689 Gui::display(movie_root
* m
)
691 assert(m
== _stage
); // why taking this arg ??
695 InvalidatedRanges changed_ranges
;
698 // Should the frame be rendered completely, even if it did not change?
702 redraw_flag
= _redraw_flag
|| want_redraw();
705 // reset class member if we do a redraw now
706 if (redraw_flag
) _redraw_flag
=false;
708 // Find out the surrounding frame of all characters which
709 // have been updated. This just checks what region of the stage has changed
710 // due to ActionScript code, the timeline or user events. The GUI can still
711 // choose to render a different part of the stage.
715 // choose snapping ranges factor
716 changed_ranges
.setSnapFactor(1.3f
);
718 // Use multi ranges only when GUI/Renderer supports it
719 // (Useless CPU overhead, otherwise)
720 changed_ranges
.setSingleMode(!want_multiple_regions());
722 // scan through all sprites to compute invalidated bounds
723 m
->add_invalidated_bounds(changed_ranges
, false);
725 // grow ranges by a 2 pixels to avoid anti-aliasing issues
726 changed_ranges
.growBy(40.0f
/ _xscale
);
729 changed_ranges
.combineRanges();
732 // TODO: Remove this and want_redraw to avoid confusion!?
734 changed_ranges
.setWorld();
738 // This is a good place to inspect the invalidated bounds state. Enable
739 // the following block (and parts of it) if you need to.
742 // This may print a huge amount of information, but is useful to analyze
743 // the (visible) object structure of the movie and the flags of the
744 // characters. For example, a characters should have set the
745 // m_child_invalidated flag if at least one of it's childs has the
746 // invalidated flag set.
747 log_debug("DUMPING CHARACTER TREE");
750 InfoTree::iterator top
= tr
.begin();
751 _stage
->getMovieInfo(tr
, top
);
753 for (InfoTree::iterator i
= tr
.begin(), e
= tr
.end();
755 std::cout
<< std::string(tr
.depth(i
) * 2, ' ') << i
->first
<< ": " <<
756 i
->second
<< std::endl
;
760 // less verbose, and often necessary: see the exact coordinates of the
761 // invalidated bounds (mainly to see if it's NULL or something else).
762 std::cout
<< "Calculated changed ranges: " << changed_ranges
<< "\n";
766 // Avoid drawing of stopped movies
767 if ( ! changed_ranges
.isNull() ) { // use 'else'?
768 // Tell the GUI(!) that we only need to update this
769 // region. Note the GUI can do whatever it wants with
770 // this information. It may simply ignore the bounds
771 // (which will normally lead into a complete redraw),
772 // or it may extend or shrink the bounds as it likes. So,
773 // by calling set_invalidated_bounds we have no guarantee
774 // that only this part of the stage is rendered again.
775 #ifdef REGION_UPDATES_DEBUGGING_FULL_REDRAW
776 // redraw the full screen so that only the
777 // *new* invalidated region is visible
779 InvalidatedRanges world_ranges
;
780 world_ranges
.setWorld();
781 setInvalidatedRegions(world_ranges
);
783 setInvalidatedRegions(changed_ranges
);
786 // TODO: should this be called even if we're late ?
789 // Render the frame, if not late.
790 // It's up to the GUI/renderer combination
791 // to do any clipping, if desired.
794 // show invalidated region using a red rectangle
795 // (Flash debug style)
796 IF_DEBUG_REGION_UPDATES (
797 if (_renderer
.get() && !changed_ranges
.isWorld()) {
798 for (size_t rno
= 0; rno
< changed_ranges
.size(); rno
++) {
799 const geometry::Range2d
<int>& bounds
=
800 changed_ranges
.getRange(rno
);
802 float xmin
= bounds
.getMinX();
803 float xmax
= bounds
.getMaxX();
804 float ymin
= bounds
.getMinY();
805 float ymax
= bounds
.getMaxY();
807 const std::vector
<point
> box
= boost::assign::list_of
813 _renderer
->draw_poly(box
, rgba(0,0,0,0), rgba(255,0,0,255),
820 // show frame on screen
830 if ( ! _stopped
) return;
837 // @todo since we registered the sound handler, shouldn't we know
838 // already what it is ?!
839 sound::sound_handler
* s
= _stage
->runResources().soundHandler();
840 if ( s
) s
->unpause();
842 // log_debug("Starting virtual clock");
843 _virtualClock
.resume();
852 // _stage must be registered before this is called.
855 if ( _stopped
) return;
856 if ( isFullscreen() ) unsetFullscreen();
860 // @todo since we registered the sound handler, shouldn't we know
861 // already what it is ?!
862 sound::sound_handler
* s
= _stage
->runResources().soundHandler();
865 // log_debug("Pausing virtual clock");
866 _virtualClock
.pause();
879 // TODO: call stop() instead ?
880 // The only thing I see is that ::stop exits full-screen,
881 // but I'm not sure that's intended behaviour
883 // @todo since we registered the sound handler, shouldn't we know
884 // already what it is ?!
885 sound::sound_handler
* s
= _stage
->runResources().soundHandler();
889 // log_debug("Pausing virtual clock");
890 _virtualClock
.pause();
898 assert ( ! _started
);
900 log_error(_("Gui is in stop mode, won't start application"));
904 // Initializes the stage with a Movie and the passed flash vars.
905 _stage
->init(_movieDef
.get(), _flashVars
);
907 bool background
= true; // ??
908 _stage
->set_background_alpha(background
? 1.0f
: 0.05f
);
910 // to properly update stageMatrix if scaling is given
911 resize_view(_width
, _height
);
913 // @todo since we registered the sound handler, shouldn't we know
914 // already what it is ?!
915 sound::sound_handler
* s
= _stage
->runResources().soundHandler();
917 if ( ! _audioDump
.empty() ) {
918 s
->setAudioDump(_audioDump
);
924 // log_debug("Starting virtual clock");
925 _virtualClock
.resume();
930 Gui::advanceMovie(bool doDisplay
)
940 Display
dis(*this, *_stage
);
941 gnash::movie_root
* m
= _stage
;
943 // Define REVIEW_ALL_FRAMES to have *all* frames
944 // consequentially displayed. Useful for debugging.
945 //#define REVIEW_ALL_FRAMES 1
947 #ifndef REVIEW_ALL_FRAMES
948 // Advance movie by one frame
949 const bool advanced
= m
->advance();
951 const size_t cur_frame
= m
->getRootMovie().get_current_frame();
952 const size_t tot_frames
= m
->getRootMovie().get_frame_count();
953 const bool advanced
= m
->advance();
955 m
->getRootMovie().ensureFrameLoaded(tot_frames
);
956 m
->goto_frame(cur_frame
+ 1);
957 m
->getRootMovie().setPlayState(gnash::MovieClip::PLAYSTATE_PLAY
);
958 // log_debug("Frame %d", m->getRootMovie().get_current_frame());
961 #ifdef GNASH_FPS_DEBUG
962 // will be a no-op if fps_timer_interval is zero
968 if (doDisplay
&& visible()) {
973 // can be 0 on malformed SWF
974 const size_t curframe
= m
->getRootMovie().get_current_frame();
975 const MovieClip
& si
= m
->getRootMovie();
976 if (curframe
+ 1 >= si
.get_frame_count()) {
981 if (_screenShotter
.get() && _renderer
.get()) {
982 _screenShotter
->screenShot(*_renderer
, _advances
, doDisplay
? 0 : &dis
);
985 // Only increment advances and check for exit condition when we've
986 // really changed frame.
988 /// Quit if we've reached the frame advance limit.
989 if (_maxAdvances
&& (_advances
> _maxAdvances
)) {
999 Gui::setScreenShotter(std::auto_ptr
<ScreenShotter
> ss
)
1001 _screenShotter
.reset(ss
.release());
1005 Gui::takeScreenShot()
1007 if (!_screenShotter
.get()) {
1008 // If no ScreenShotter exists, none was requested at startup.
1009 // We use a default filename pattern.
1010 URL
url(_runResources
.streamProvider().baseURL());
1011 std::string::size_type p
= url
.path().rfind('/');
1012 const std::string
& name
= (p
== std::string::npos
) ? url
.path() :
1013 url
.path().substr(p
+ 1);
1014 const std::string
& filename
= "screenshot-" + name
+ "-%f";
1015 _screenShotter
.reset(new ScreenShotter(filename
, GNASH_FILETYPE_PNG
));
1017 assert (_screenShotter
.get());
1018 _screenShotter
->now();
1022 Gui::setCursor(gnash_cursor_type
/*newcursor*/)
1034 Gui::setInvalidatedRegion(const SWFRect
& /*bounds*/)
1040 Gui::setInvalidatedRegions(const InvalidatedRanges
& ranges
)
1042 // fallback to single regions
1043 geometry::Range2d
<int> full
= ranges
.getFullArea();
1047 if (full
.isFinite()) {
1048 bounds
= SWFRect(full
.getMinX(), full
.getMinY(),
1049 full
.getMaxX(), full
.getMaxY());
1051 else if (full
.isWorld()) {
1055 setInvalidatedRegion(bounds
);
1060 std::auto_ptr
<movie_root::InfoTree
>
1061 Gui::getMovieInfo() const
1063 std::auto_ptr
<movie_root::InfoTree
> tr
;
1069 tr
.reset(new movie_root::InfoTree());
1071 // Top nodes for the tree:
1072 // 1. VM information
1073 // 2. "Stage" information
1076 movie_root::InfoTree::iterator topIter
= tr
->begin();
1077 movie_root::InfoTree::iterator firstLevelIter
;
1079 VM
& vm
= _stage
->getVM();
1081 std::ostringstream os
;
1086 os
<< "SWF " << vm
.getSWFVersion();
1087 topIter
= tr
->insert(topIter
, std::make_pair("Root SWF version", os
.str()));
1089 // This short-cut is to avoid a bug in movie_root's getMovieInfo,
1090 // which relies on the availability of a _rootMovie for doing
1091 // it's work, while we don't set it if we didn't start..
1094 topIter
= tr
->insert(topIter
, std::make_pair("Stage properties",
1095 "not constructed yet"));
1099 movie_root
& stage
= vm
.getRoot();
1100 stage
.getMovieInfo(*tr
, topIter
);
1105 topIter
= tr
->insert(topIter
, std::make_pair("Mouse Entities", ""));
1107 const DisplayObject
* ch
;
1108 ch
= stage
.getActiveEntityUnderPointer();
1110 std::stringstream ss
;
1111 ss
<< ch
->getTarget() << " (" + typeName(*ch
)
1112 << " - depth:" << ch
->get_depth()
1113 << " - useHandCursor:" << ch
->allowHandCursor()
1115 firstLevelIter
= tr
->append_child(topIter
,
1116 std::make_pair("Active entity under mouse pointer", ss
.str()));
1119 ch
= stage
.getEntityUnderPointer();
1121 std::stringstream ss
;
1122 ss
<< ch
->getTarget() << " (" + typeName(*ch
)
1123 << " - depth:" << ch
->get_depth()
1125 firstLevelIter
= tr
->append_child(topIter
,
1126 std::make_pair("Topmost entity under mouse pointer", ss
.str()));
1129 ch
= stage
.getDraggingCharacter();
1131 std::stringstream ss
;
1132 ss
<< ch
->getTarget() << " (" + typeName(*ch
)
1133 << " - depth:" << ch
->get_depth() << ")";
1134 firstLevelIter
= tr
->append_child(topIter
,
1135 std::make_pair("Dragging character: ", ss
.str()));
1141 topIter
= tr
->insert(topIter
, std::make_pair("GC Statistics", ""));
1142 GC::CollectablesCount cc
;
1143 _stage
->gc().countCollectables(cc
);
1145 const std::string lbl
= "GC managed ";
1146 for (GC::CollectablesCount::iterator i
=cc
.begin(), e
=cc
.end(); i
!=e
; ++i
) {
1147 const std::string
& typ
= i
->first
;
1148 std::ostringstream ss
;
1150 firstLevelIter
= tr
->append_child(topIter
,
1151 std::make_pair(lbl
+ typ
, ss
.str()));
1154 tr
->sort(firstLevelIter
.begin(), firstLevelIter
.end());
1161 #ifdef GNASH_FPS_DEBUG
1163 Gui::fpsCounterTick()
1166 // increment this *before* the early return so that
1167 // frame count on exit is still valid
1168 ++fps_counter_total
;
1170 if (! fps_timer_interval
) {
1174 boost::uint64_t current_timer
= clocktime::getTicks();
1176 // TODO: keep fps_timer_interval in milliseconds to avoid the multiplication
1177 // at each fpsCounterTick call...
1178 boost::uint64_t interval_ms
= (boost::uint64_t)(fps_timer_interval
* 1000.0);
1180 if (fps_counter_total
==1) {
1181 fps_timer
= current_timer
;
1182 fps_start_timer
= current_timer
;
1187 if (current_timer
- fps_timer
>= interval_ms
) {
1189 float secs
= (current_timer
- fps_timer
) / 1000.0;
1190 float secs_total
= (current_timer
- fps_start_timer
)/1000.0;
1192 float rate
= fps_counter
/secs
;
1194 if (secs
> 10000000) {
1195 // the timers are unsigned, so when the clock runs "backwards" it leads
1196 // to a very high difference value. In theory, this should never happen
1197 // with ticks, but it does on my machine (which may have a hw problem?).
1198 std::cerr
<< "Time glitch detected, need to restart FPS counters, sorry..." << std::endl
;
1200 fps_timer
= current_timer
;
1201 fps_start_timer
= current_timer
;
1202 fps_counter_total
= 0;
1207 // first FPS message?
1208 if (fps_timer
== fps_start_timer
) { // they're ints, so we can compare
1209 fps_rate_min
= rate
;
1210 fps_rate_max
= rate
;
1212 fps_rate_min
= std::min
<float>(fps_rate_min
, rate
);
1213 fps_rate_max
= std::max
<float>(fps_rate_max
, rate
);
1216 float avg
= fps_counter_total
/ secs_total
;
1218 //log_debug("Effective frame rate: %0.2f fps", (float)(fps_counter/secs));
1219 std::cerr
<< boost::format("Effective frame rate: %0.2f fps "
1220 "(min %0.2f, avg %0.2f, max %0.2f, "
1221 "%u frames in %0.1f secs total, "
1222 "dropped %u)") % rate
%
1223 fps_rate_min
% avg
% fps_rate_max
%
1224 fps_counter_total
% secs_total
%
1225 frames_dropped
<< std::endl
;
1228 fps_timer
= current_timer
;
1236 Gui::addFlashVars(Gui::VariableMap
& from
)
1238 for (VariableMap::iterator i
=from
.begin(), ie
=from
.end(); i
!=ie
; ++i
) {
1239 _flashVars
[i
->first
] = i
->second
;
1244 Gui::setMovieDefinition(movie_definition
* md
)
1251 Gui::setStage(movie_root
* stage
)
1259 Gui::yesno(const std::string
& question
)
1261 log_error(_("This gui didn't override 'yesno', assuming 'yes' answer to "
1262 "question: %s"), question
);
1267 Gui::setQuality(Quality q
)
1270 log_error(_("Gui::setQuality called before a movie_root was available"));
1273 _stage
->setQuality(q
);
1277 Gui::getQuality() const
1280 log_error(_("Gui::getQuality called before a movie_root was available"));
1282 return QUALITY_HIGH
;
1284 return _stage
->getQuality();
1291 // indent-tabs-mode: nil