From 212e00c3e93a40cf37dcd2d88c6468ae92033e7c Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 23 Dec 2003 23:12:40 +0000 Subject: [PATCH] new FrameRateMeter --- panda/src/framework/config_framework.cxx | 2 + panda/src/framework/config_framework.h | 2 + panda/src/framework/windowFramework.cxx | 8 + panda/src/framework/windowFramework.h | 3 + panda/src/grutil/Sources.pp | 5 +- panda/src/grutil/config_grutil.cxx | 30 +++- panda/src/grutil/config_grutil.h | 10 +- panda/src/grutil/frameRateMeter.I | 115 ++++++++++++++ panda/src/grutil/frameRateMeter.cxx | 183 +++++++++++++++++++++++ panda/src/grutil/frameRateMeter.h | 99 ++++++++++++ panda/src/grutil/grutil_composite1.cxx | 5 +- 11 files changed, 455 insertions(+), 7 deletions(-) create mode 100644 panda/src/grutil/frameRateMeter.I create mode 100644 panda/src/grutil/frameRateMeter.cxx create mode 100644 panda/src/grutil/frameRateMeter.h diff --git a/panda/src/framework/config_framework.cxx b/panda/src/framework/config_framework.cxx index 1ea1fc99b6..813f7ed1ee 100644 --- a/panda/src/framework/config_framework.cxx +++ b/panda/src/framework/config_framework.cxx @@ -35,6 +35,8 @@ const bool undecorated = config_framework.GetBool("undecorated", false); const bool cursor_hidden = config_framework.GetBool("cursor-hidden", false); const float aspect_ratio = config_framework.GetFloat("aspect-ratio", 0.0f); +const bool show_frame_rate_meter = config_framework.GetBool("show-frame-rate-meter", false); + // The default window background color. const float win_background_r = config_framework.GetFloat("win-background-r", 0.41); const float win_background_g = config_framework.GetFloat("win-background-g", 0.41); diff --git a/panda/src/framework/config_framework.h b/panda/src/framework/config_framework.h index e6ed332736..06f3287fa9 100644 --- a/panda/src/framework/config_framework.h +++ b/panda/src/framework/config_framework.h @@ -32,6 +32,8 @@ extern const bool undecorated; extern const bool cursor_hidden; extern const float aspect_ratio; +extern const bool show_frame_rate_meter; + extern const float win_background_r; extern const float win_background_g; extern const float win_background_b; diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 8f93f23332..b208935cdd 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -118,6 +118,12 @@ open_window(const WindowProperties &props, GraphicsEngine *engine, // Set up a 3-d camera for the window by default. make_camera(); + + if (show_frame_rate_meter) { + _frame_rate_meter = new FrameRateMeter("frame_rate_meter"); + _frame_rate_meter->setup_layer(_window); + } + return _window; } @@ -146,6 +152,8 @@ close_window() { _two_sided_enabled = false; _one_sided_reverse_enabled = false; _lighting_enabled = false; + + _frame_rate_meter == (FrameRateMeter *)NULL; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/framework/windowFramework.h b/panda/src/framework/windowFramework.h index 98fb7b479f..e1ccd01bfa 100644 --- a/panda/src/framework/windowFramework.h +++ b/panda/src/framework/windowFramework.h @@ -26,6 +26,7 @@ #include "animControlCollection.h" #include "trackball.h" #include "filename.h" +#include "frameRateMeter.h" #include "pointerTo.h" #include "pvector.h" #include "typedReferenceCount.h" @@ -136,6 +137,8 @@ private: bool _one_sided_reverse_enabled; bool _lighting_enabled; + PT(FrameRateMeter) _frame_rate_meter; + BackgroundType _background_type; public: diff --git a/panda/src/grutil/Sources.pp b/panda/src/grutil/Sources.pp index 9d91f10c4b..2df7284c32 100644 --- a/panda/src/grutil/Sources.pp +++ b/panda/src/grutil/Sources.pp @@ -4,22 +4,25 @@ #begin lib_target #define TARGET grutil #define LOCAL_LIBS \ - pgraph gobj linmath putil + display text pgraph gobj linmath putil #define COMBINED_SOURCES $[TARGET]_composite1.cxx #define SOURCES \ cardMaker.I cardMaker.h \ config_grutil.h \ + frameRateMeter.I frameRateMeter.h \ lineSegs.I lineSegs.h #define INCLUDED_SOURCES \ cardMaker.cxx \ config_grutil.cxx \ + frameRateMeter.cxx \ lineSegs.cxx #define INSTALL_HEADERS \ cardMaker.I cardMaker.h \ + frameRateMeter.I frameRateMeter.h \ lineSegs.I lineSegs.h #define IGATESCAN all diff --git a/panda/src/grutil/config_grutil.cxx b/panda/src/grutil/config_grutil.cxx index 9e417deb1b..02d96e38ba 100644 --- a/panda/src/grutil/config_grutil.cxx +++ b/panda/src/grutil/config_grutil.cxx @@ -17,12 +17,40 @@ //////////////////////////////////////////////////////////////////// #include "config_grutil.h" +#include "frameRateMeter.h" -#include +#include "dconfig.h" Configure(config_grutil); NotifyCategoryDef(grutil, ""); ConfigureFn(config_grutil) { + init_libgrutil(); +} + +const double frame_rate_meter_update_interval = config_grutil.GetDouble("frame-rate-meter-update-interval", 1.0); +const string frame_rate_meter_text_pattern = config_grutil.GetString("frame-rate-meter-text-pattern", "%0.1f fps"); +const int frame_rate_meter_layer_sort = config_grutil.GetInt("frame-rate-meter-layer-sort", 1000); +const float frame_rate_meter_scale = config_grutil.GetFloat("frame-rate-meter-scale", 0.05f); +const float frame_rate_meter_side_margins = config_grutil.GetFloat("frame-rate-meter-side-margins", 0.5f); + + +//////////////////////////////////////////////////////////////////// +// Function: init_libgrutil +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libgrutil() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + + FrameRateMeter::init_type(); } diff --git a/panda/src/grutil/config_grutil.h b/panda/src/grutil/config_grutil.h index 20b278f89e..470dd909e3 100644 --- a/panda/src/grutil/config_grutil.h +++ b/panda/src/grutil/config_grutil.h @@ -20,10 +20,18 @@ #define CONFIG_GRUTIL_H #include "pandabase.h" -#include +#include "notifyCategoryProxy.h" NotifyCategoryDecl(grutil, EXPCL_PANDA, EXPTP_PANDA); +extern const double frame_rate_meter_update_interval; +extern const string frame_rate_meter_text_pattern; +extern const int frame_rate_meter_layer_sort; +extern const float frame_rate_meter_scale; +extern const float frame_rate_meter_side_margins; + +extern EXPCL_PANDA void init_libgrutil(); + #endif diff --git a/panda/src/grutil/frameRateMeter.I b/panda/src/grutil/frameRateMeter.I new file mode 100644 index 0000000000..2670931b3c --- /dev/null +++ b/panda/src/grutil/frameRateMeter.I @@ -0,0 +1,115 @@ +// Filename: frameRateMeter.I +// Created by: drose (23Dec03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::setup_layer +// Access: Published +// Description: Sets up the frame rate meter to create a layer to +// render itself into the indicated window. +//////////////////////////////////////////////////////////////////// +INLINE void FrameRateMeter:: +setup_layer(GraphicsWindow *window) { + setup_layer(window->get_channel(0)); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::get_layer +// Access: Published +// Description: Returns the GraphicsLayer that the meter has created +// to render itself into the window or channel supplied +// to setup_layer(), or NULL if setup_layer() has not +// been called. +//////////////////////////////////////////////////////////////////// +INLINE GraphicsLayer *FrameRateMeter:: +get_layer() const { + return _layer; +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::set_update_interval +// Access: Published +// Description: Specifies the number of seconds that should elapse +// between updates to the frame rate indication. This +// should be reasonably slow (e.g. 0.2 to 1.0) so that +// the calculation of the frame rate text does not +// itself dominate the frame rate. +//////////////////////////////////////////////////////////////////// +INLINE void FrameRateMeter:: +set_update_interval(double update_interval) { + _update_interval = update_interval; +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::get_update_interval +// Access: Published +// Description: Returns the number of seconds that will elapse +// between updates to the frame rate indication. +//////////////////////////////////////////////////////////////////// +INLINE double FrameRateMeter:: +get_update_interval() const { + return _update_interval; +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::set_text_pattern +// Access: Published +// Description: Sets the sprintf() pattern that is used to format the +// text. The string "%f" or some variant will be +// replaced with the current frame rate in frames per +// second. +//////////////////////////////////////////////////////////////////// +INLINE void FrameRateMeter:: +set_text_pattern(const string &text_pattern) { + _text_pattern = text_pattern; + do_update(); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::get_text_pattern +// Access: Published +// Description: Returns the sprintf() pattern that is used to format the +// text. +//////////////////////////////////////////////////////////////////// +INLINE const string &FrameRateMeter:: +get_text_pattern() const { + return _text_pattern; +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::set_clock_object +// Access: Published +// Description: Sets the clock that is used to determine the frame +// rate. The default is the application's global clock +// (ClockObject::get_global_clock()). +//////////////////////////////////////////////////////////////////// +INLINE void FrameRateMeter:: +set_clock_object(ClockObject *clock_object) { + _clock_object = clock_object; +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::get_clock_object +// Access: Published +// Description: Returns the clock that is used to determine the frame +// rate. +//////////////////////////////////////////////////////////////////// +INLINE ClockObject *FrameRateMeter:: +get_clock_object() const { + return _clock_object; +} diff --git a/panda/src/grutil/frameRateMeter.cxx b/panda/src/grutil/frameRateMeter.cxx new file mode 100644 index 0000000000..35fdb5b21d --- /dev/null +++ b/panda/src/grutil/frameRateMeter.cxx @@ -0,0 +1,183 @@ +// Filename: frameRateMeter.cxx +// Created by: drose (23Dec03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "frameRateMeter.h" +#include "camera.h" +#include "displayRegion.h" +#include "orthographicLens.h" +#include "graphicsChannel.h" +#include "clockObject.h" +#include "config_grutil.h" +#include "depthTestAttrib.h" +#include "depthWriteAttrib.h" + +TypeHandle FrameRateMeter::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +FrameRateMeter:: +FrameRateMeter(const string &name) : TextNode(name) { + _update_interval = frame_rate_meter_update_interval; + _text_pattern = frame_rate_meter_text_pattern; + _clock_object = ClockObject::get_global_clock(); + + set_align(A_right); + set_transform(LMatrix4f::scale_mat(frame_rate_meter_scale) * + LMatrix4f::translate_mat(1.0f - frame_rate_meter_side_margins * frame_rate_meter_scale, 0.0f, 1.0f - frame_rate_meter_scale)); + set_card_color(0.0f, 0.0f, 0.0f, 0.4f); + set_card_as_margin(frame_rate_meter_side_margins, frame_rate_meter_side_margins, 0.1f, 0.0f); + + do_update(); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +FrameRateMeter:: +~FrameRateMeter() { + clear_layer(); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::setup_layer +// Access: Published +// Description: Sets up the frame rate meter to create a layer to +// render itself into the indicated channel. +//////////////////////////////////////////////////////////////////// +void FrameRateMeter:: +setup_layer(GraphicsChannel *channel) { + clear_layer(); + + _root = NodePath("frame_rate_root"); + _root.attach_new_node(this); + + CPT(RenderAttrib) dt = DepthTestAttrib::make(DepthTestAttrib::M_none); + CPT(RenderAttrib) dw = DepthWriteAttrib::make(DepthWriteAttrib::M_off); + _root.node()->set_attrib(dt, 1); + _root.node()->set_attrib(dw, 1); + _root.set_material_off(1); + _root.set_two_sided(1, 1); + + // Make a layer on the channel to hold our display region. + _layer = channel->make_layer(frame_rate_meter_layer_sort); + + // And create a display region that covers the entire window. + PT(DisplayRegion) dr = _layer->make_display_region(); + + // Finally, we need a camera to associate with the display region. + PT(Camera) camera = new Camera("frame_rate_camera"); + NodePath camera_np = _root.attach_new_node(camera); + + PT(Lens) lens = new OrthographicLens; + + static const float left = -1.0f; + static const float right = 1.0f; + static const float bottom = -1.0f; + static const float top = 1.0f; + lens->set_film_size(right - left, top - bottom); + lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5); + lens->set_near_far(-1000, 1000); + + camera->set_lens(lens); + camera->set_scene(_root); + dr->set_camera(camera_np); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::clear_layer +// Access: Published +// Description: Undoes the effect of a previous call to +// setup_layer(). +//////////////////////////////////////////////////////////////////// +void FrameRateMeter:: +clear_layer() { + if (_layer != (GraphicsLayer *)NULL) { + GraphicsChannel *channel = _layer->get_channel(); + if (channel != (GraphicsChannel *)NULL) { + channel->remove_layer(_layer); + } + _layer = (GraphicsLayer *)NULL; + } + + _root = NodePath(); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::cull_callback +// Access: Protected, Virtual +// Description: If has_cull_callback() returns true, this function +// will be called during the cull traversal to perform +// any additional operations that should be performed at +// cull time. This may include additional manipulation +// of render state or additional visible/invisible +// decisions, or any other arbitrary operation. +// +// By the time this function is called, the node has +// already passed the bounding-volume test for the +// viewing frustum, and the node's transform and state +// have already been applied to the indicated +// CullTraverserData object. +// +// The return value is true if this node should be +// visible, or false if it should be culled. +//////////////////////////////////////////////////////////////////// +bool FrameRateMeter:: +cull_callback(CullTraverser *trav, CullTraverserData &data) { + // Check to see if it's time to update. + double now = _clock_object->get_frame_time(); + double elapsed = now - _last_update; + if (elapsed < 0.0 || elapsed >= _update_interval) { + do_update(); + } + + return TextNode::cull_callback(trav, data); +} + +//////////////////////////////////////////////////////////////////// +// Function: FrameRateMeter::do_update +// Access: Private +// Description: Resets the text according to the current frame rate. +//////////////////////////////////////////////////////////////////// +void FrameRateMeter:: +do_update() { + _last_update = _clock_object->get_frame_time(); + + double frame_rate = _clock_object->get_average_frame_rate(); + + static const size_t buffer_size = 1024; + char buffer[buffer_size]; +#ifdef WIN32_VC + // Windows doesn't define snprintf(). Hope we don't overflow. + sprintf(buffer, _text_pattern.c_str(), frame_rate); +#else + snprintf(buffer, buffer_size, _text_pattern.c_str(), frame_rate); +#endif + nassertv(strlen(buffer) < buffer_size); + + if (get_text() == buffer) { + // Never mind; the frame rate hasn't changed. + return; + } + + set_text(buffer); +} diff --git a/panda/src/grutil/frameRateMeter.h b/panda/src/grutil/frameRateMeter.h new file mode 100644 index 0000000000..9252dea7d3 --- /dev/null +++ b/panda/src/grutil/frameRateMeter.h @@ -0,0 +1,99 @@ +// Filename: frameRateMeter.h +// Created by: drose (23Dec03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef FRAMERATEMETER_H +#define FRAMERATEMETER_H + +#include "pandabase.h" +#include "textNode.h" +#include "nodePath.h" +#include "graphicsWindow.h" +#include "graphicsLayer.h" +#include "pointerTo.h" + +class GraphicsChannel; +class ClockObject; + +//////////////////////////////////////////////////////////////////// +// Class : FrameRateMeter +// Description : This is a special TextNode that automatically updates +// itself with the current frame rate. It can be placed +// anywhere in the world where you'd like to see the +// frame rate. +// +// It also has a special mode in which it may be +// attached directly to a channel or window. If this is +// done, it creates a layer for itself and renders +// itself in the upper-right-hand corner. +//////////////////////////////////////////////////////////////////// +class EXPCL_FRAMEWORK FrameRateMeter : public TextNode { +PUBLISHED: + FrameRateMeter(const string &name); + virtual ~FrameRateMeter(); + + INLINE void setup_layer(GraphicsWindow *window); + void setup_layer(GraphicsChannel *channel); + void clear_layer(); + + INLINE GraphicsLayer *get_layer() const; + + INLINE void set_update_interval(double update_interval); + INLINE double get_update_interval() const; + + INLINE void set_text_pattern(const string &text_pattern); + INLINE const string &get_text_pattern() const; + + INLINE void set_clock_object(ClockObject *clock_object); + INLINE ClockObject *get_clock_object() const; + +protected: + virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + +private: + void do_update(); + +private: + PT(GraphicsLayer) _layer; + NodePath _root; + + double _update_interval; + double _last_update; + string _text_pattern; + ClockObject *_clock_object; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TextNode::init_type(); + register_type(_type_handle, "FrameRateMeter", + TextNode::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "frameRateMeter.I" + +#endif diff --git a/panda/src/grutil/grutil_composite1.cxx b/panda/src/grutil/grutil_composite1.cxx index 96deeee4ee..875cedf02b 100644 --- a/panda/src/grutil/grutil_composite1.cxx +++ b/panda/src/grutil/grutil_composite1.cxx @@ -1,7 +1,4 @@ - #include "cardMaker.cxx" #include "config_grutil.cxx" #include "lineSegs.cxx" - - - +#include "frameRateMeter.cxx"