Panda3D
 All Classes Functions Variables Enumerations
frameRateMeter.cxx
1 // Filename: frameRateMeter.cxx
2 // Created by: drose (23Dec03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "frameRateMeter.h"
16 #include "camera.h"
17 #include "displayRegion.h"
18 #include "orthographicLens.h"
19 #include "clockObject.h"
20 #include "config_grutil.h"
21 #include "depthTestAttrib.h"
22 #include "depthWriteAttrib.h"
23 #include "pStatTimer.h"
24 #include "omniBoundingVolume.h"
25 #include <stdio.h> // For sprintf/snprintf
26 
27 PStatCollector FrameRateMeter::_show_fps_pcollector("*:Show fps");
28 
29 TypeHandle FrameRateMeter::_type_handle;
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: FrameRateMeter::Constructor
33 // Access: Published
34 // Description:
35 ////////////////////////////////////////////////////////////////////
36 FrameRateMeter::
37 FrameRateMeter(const string &name) :
38  TextNode(name),
39  _last_aspect_ratio(-1) {
40 
41  set_cull_callback();
42 
43  // Don't do frustum culling, as the text will always be in view.
44  set_bounds(new OmniBoundingVolume());
45  set_final(true);
46 
47  Thread *current_thread = Thread::get_current_thread();
48 
49  _show_milliseconds = frame_rate_meter_milliseconds;
50  if (_show_milliseconds) {
51  _text_pattern = frame_rate_meter_ms_text_pattern;
52  } else {
53  _text_pattern = frame_rate_meter_text_pattern;
54  }
55 
56  _update_interval = frame_rate_meter_update_interval;
57  _last_update = 0.0f;
58  _clock_object = ClockObject::get_global_clock();
59 
60  // The top of the visible frame is 80% of the line height, based on
61  // the calculation within TextAssembler.
62  PN_stdfloat height = 1.0f;
63  TextFont *font = get_font();
64  if (font != NULL){
65  height = font->get_line_height() * 0.8;
66  }
67 
68  set_align(A_right);
69  set_transform(LMatrix4::scale_mat(frame_rate_meter_scale) *
70  LMatrix4::translate_mat(LVector3::rfu(-frame_rate_meter_side_margins * frame_rate_meter_scale, 0.0f, -frame_rate_meter_scale * height)));
71  set_card_color(0.0f, 0.0f, 0.0f, 0.4);
72  set_card_as_margin(frame_rate_meter_side_margins, frame_rate_meter_side_margins, 0.1f, 0.0f);
73  // set_usage_hint(Geom::UH_client);
74 
75  do_update(current_thread);
76 }
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: FrameRateMeter::Destructor
80 // Access: Published, Virtual
81 // Description:
82 ////////////////////////////////////////////////////////////////////
83 FrameRateMeter::
84 ~FrameRateMeter() {
85  clear_window();
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: FrameRateMeter::setup_window
90 // Access: Published
91 // Description: Sets up the frame rate meter to create a
92 // DisplayRegion to render itself into the indicated
93 // window.
94 ////////////////////////////////////////////////////////////////////
97  clear_window();
98 
99  _window = window;
100 
101  _root = NodePath("frame_rate_root");
102  _root.attach_new_node(this);
103 
104  CPT(RenderAttrib) dt = DepthTestAttrib::make(DepthTestAttrib::M_none);
105  CPT(RenderAttrib) dw = DepthWriteAttrib::make(DepthWriteAttrib::M_off);
106  _root.node()->set_attrib(dt, 1);
107  _root.node()->set_attrib(dw, 1);
108  _root.set_material_off(1);
109  _root.set_two_sided(1, 1);
110 
111  // If we don't set this explicitly, Panda will cause it to be rendered
112  // in a back-to-front cull bin, which will cause the bounding volume
113  // to be computed unnecessarily. Saves a little bit of overhead.
114  _root.set_bin("unsorted", 0);
115 
116  // Create a display region that covers the entire window.
117  _display_region = _window->make_mono_display_region();
118  _display_region->set_sort(frame_rate_meter_layer_sort);
119 
120  // Finally, we need a camera to associate with the display region.
121  PT(Camera) camera = new Camera("frame_rate_camera");
122  NodePath camera_np = _root.attach_new_node(camera);
123 
124  PT(Lens) lens = new OrthographicLens;
125 
126  // We choose these values such that we can place the text against (0, 0).
127  static const PN_stdfloat left = -2.0f;
128  static const PN_stdfloat right = 0.0f;
129  static const PN_stdfloat bottom = -2.0f;
130  static const PN_stdfloat top = 0.0f;
131  lens->set_film_size(right - left, top - bottom);
132  lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5);
133  lens->set_near_far(-1000, 1000);
134 
135  camera->set_lens(lens);
136  camera->set_scene(_root);
137  _display_region->set_camera(camera_np);
138 }
139 
140 ////////////////////////////////////////////////////////////////////
141 // Function: FrameRateMeter::clear_window
142 // Access: Published
143 // Description: Undoes the effect of a previous call to
144 // setup_window().
145 ////////////////////////////////////////////////////////////////////
146 void FrameRateMeter::
148  if (_window != (GraphicsOutput *)NULL) {
149  _window->remove_display_region(_display_region);
150  _window = (GraphicsOutput *)NULL;
151  _display_region = (DisplayRegion *)NULL;
152  }
153  _root = NodePath();
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: FrameRateMeter::cull_callback
158 // Access: Protected, Virtual
159 // Description: This function will be called during the cull
160 // traversal to perform any additional operations that
161 // should be performed at cull time. This may include
162 // additional manipulation of render state or additional
163 // visible/invisible decisions, or any other arbitrary
164 // operation.
165 //
166 // Note that this function will *not* be called unless
167 // set_cull_callback() is called in the constructor of
168 // the derived class. It is necessary to call
169 // set_cull_callback() to indicated that we require
170 // cull_callback() to be called.
171 //
172 // By the time this function is called, the node has
173 // already passed the bounding-volume test for the
174 // viewing frustum, and the node's transform and state
175 // have already been applied to the indicated
176 // CullTraverserData object.
177 //
178 // The return value is true if this node should be
179 // visible, or false if it should be culled.
180 ////////////////////////////////////////////////////////////////////
181 bool FrameRateMeter::
182 cull_callback(CullTraverser *trav, CullTraverserData &data) {
183  // This triggers when you try to parent a frame rate meter into
184  // the scene graph yourself. Instead, use setup_window().
185  nassertr(_display_region != NULL, false);
186 
187  Thread *current_thread = trav->get_current_thread();
188 
189  // Statistics
190  PStatTimer timer(_show_fps_pcollector, current_thread);
191 
192  // This is probably a good time to check if the aspect ratio on
193  // the window has changed.
194  int width = _display_region->get_pixel_width();
195  int height = _display_region->get_pixel_height();
196  PN_stdfloat aspect_ratio = 1;
197  if (width != 0 && height != 0) {
198  aspect_ratio = (PN_stdfloat)height / (PN_stdfloat)width;
199  }
200 
201  // Scale the transform by the calculated aspect ratio.
202  if (aspect_ratio != _last_aspect_ratio) {
203  _aspect_ratio_transform = TransformState::make_scale(LVecBase3(aspect_ratio, 1, 1));
204  _last_aspect_ratio = aspect_ratio;
205  }
206  data._net_transform = data._net_transform->compose(_aspect_ratio_transform);
207 
208  // Check to see if it's time to update.
209  double now = _clock_object->get_frame_time(current_thread);
210  double elapsed = now - _last_update;
211  if (elapsed < 0.0 || elapsed >= _update_interval) {
212  do_update(current_thread);
213  }
214 
215  return TextNode::cull_callback(trav, data);
216 }
217 
218 ////////////////////////////////////////////////////////////////////
219 // Function: FrameRateMeter::do_update
220 // Access: Private
221 // Description: Resets the text according to the current frame rate.
222 ////////////////////////////////////////////////////////////////////
223 void FrameRateMeter::
224 do_update(Thread *current_thread) {
225  _last_update = _clock_object->get_frame_time(current_thread);
226 
227  double value = _clock_object->get_average_frame_rate(current_thread);
228  double deviation = _clock_object->calc_frame_rate_deviation(current_thread);
229 
230  if (_show_milliseconds) {
231  value = 1000.0 / value;
232  deviation = 1000.0 / deviation;
233  }
234 
235  static const size_t buffer_size = 1024;
236  char buffer[buffer_size];
237 #if defined(WIN32_VC) || defined(WIN64_VC)
238  // Windows doesn't define snprintf(). Hope we don't overflow.
239  sprintf(buffer, _text_pattern.c_str(), value, deviation);
240 #else
241  snprintf(buffer, buffer_size, _text_pattern.c_str(), value, deviation);
242 #endif
243  nassertv(strlen(buffer) < buffer_size);
244 
245  if (get_text() == buffer) {
246  // Never mind; the frame rate hasn't changed.
247  return;
248  }
249 
250  set_text(buffer);
251 }
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
double get_average_frame_rate(Thread *current_thread=Thread::get_current_thread()) const
Returns the average frame rate in number of frames per second over the last get_average_frame_rate_in...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
static LMatrix4f scale_mat(const LVecBase3f &scale)
Returns a matrix that applies the indicated scale in each of the three axes.
Definition: lmatrix.h:2456
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
static LMatrix4f translate_mat(const LVecBase3f &trans)
Returns a matrix that applies the indicated translation.
Definition: lmatrix.h:2397
void set_text(const string &text)
Changes the text that is displayed under the TextNode.
Definition: textNode.I:1171
void clear_window()
Undoes the effect of a previous call to setup_window().
void set_film_size(PN_stdfloat width)
Sets the horizontal size of the film without changing its shape.
Definition: lens.I:226
string get_text() const
Returns the current text, as encoded via the current encoding system.
Definition: textEncoder.I:167
This collects together the pieces of data that are accumulated for each node while walking the scene ...
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
double calc_frame_rate_deviation(Thread *current_thread=Thread::get_current_thread()) const
Returns the standard deviation of the frame times of the frames rendered over the past get_average_fr...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
static LVector3f rfu(float right, float fwd, float up, CoordinateSystem cs=CS_default)
Returns a vector that is described by its right, forward, and up components, in whatever way the coor...
Definition: lvector3.h:631
An encapsulation of a font; i.e.
Definition: textFont.h:36
void setup_window(GraphicsOutput *window)
Sets up the frame rate meter to create a DisplayRegion to render itself into the indicated window...
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
Definition: textNode.cxx:685
A lightweight class that represents a single element that may be timed and/or counted via stats...
void set_bin(const string &bin_name, int draw_order, int priority=0)
Assigns the geometry at this level and below to the named rendering bin.
Definition: nodePath.cxx:3263
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.I:48
This is a base class for the various different classes that represent the result of a frame of render...
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:1107
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
Definition: cullTraverser.I:33
An orthographic lens.
A thread; that is, a lightweight process.
Definition: thread.h:51
void set_material_off(int priority=0)
Sets the geometry at this level and below to render using no material.
Definition: nodePath.cxx:4760
The primary interface to this module.
Definition: textNode.h:52
This is a special kind of GeometricBoundingVolume that fills all of space.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:61
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:37
void set_two_sided(bool two_sided, int priority=0)
Specifically sets or disables two-sided rendering mode on this particular node.
Definition: nodePath.cxx:5135
PN_stdfloat get_line_height() const
Returns the number of units high each line of text is.
Definition: textFont.I:45
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:723