Panda3D
|
00001 // Filename: frameRateMeter.cxx 00002 // Created by: drose (23Dec03) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "frameRateMeter.h" 00016 #include "camera.h" 00017 #include "displayRegion.h" 00018 #include "orthographicLens.h" 00019 #include "clockObject.h" 00020 #include "config_grutil.h" 00021 #include "depthTestAttrib.h" 00022 #include "depthWriteAttrib.h" 00023 #include "pStatTimer.h" 00024 #include <stdio.h> // For sprintf/snprintf 00025 00026 PStatCollector FrameRateMeter::_show_fps_pcollector("*:Show fps"); 00027 00028 TypeHandle FrameRateMeter::_type_handle; 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: FrameRateMeter::Constructor 00032 // Access: Published 00033 // Description: 00034 //////////////////////////////////////////////////////////////////// 00035 FrameRateMeter:: 00036 FrameRateMeter(const string &name) : TextNode(name) { 00037 set_cull_callback(); 00038 00039 Thread *current_thread = Thread::get_current_thread(); 00040 00041 _update_interval = frame_rate_meter_update_interval; 00042 _last_update = 0.0f; 00043 _text_pattern = frame_rate_meter_text_pattern; 00044 _clock_object = ClockObject::get_global_clock(); 00045 00046 // The top of the visible frame is 80% of the line height, based on 00047 // the calculation within TextAssembler. 00048 PN_stdfloat height = 1.0f; 00049 TextFont *font = get_font(); 00050 if (font != NULL){ 00051 height = font->get_line_height() * 0.8; 00052 } 00053 00054 set_align(A_right); 00055 set_transform(LMatrix4::scale_mat(frame_rate_meter_scale) * 00056 LMatrix4::translate_mat(LVector3::rfu(1.0f - frame_rate_meter_side_margins * frame_rate_meter_scale, 0.0f, 1.0f - frame_rate_meter_scale * height))); 00057 set_card_color(0.0f, 0.0f, 0.0f, 0.4); 00058 set_card_as_margin(frame_rate_meter_side_margins, frame_rate_meter_side_margins, 0.1f, 0.0f); 00059 // set_usage_hint(Geom::UH_client); 00060 00061 do_update(current_thread); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: FrameRateMeter::Destructor 00066 // Access: Published, Virtual 00067 // Description: 00068 //////////////////////////////////////////////////////////////////// 00069 FrameRateMeter:: 00070 ~FrameRateMeter() { 00071 clear_window(); 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: FrameRateMeter::setup_window 00076 // Access: Published 00077 // Description: Sets up the frame rate meter to create a 00078 // DisplayRegion to render itself into the indicated 00079 // window. 00080 //////////////////////////////////////////////////////////////////// 00081 void FrameRateMeter:: 00082 setup_window(GraphicsOutput *window) { 00083 clear_window(); 00084 00085 _window = window; 00086 00087 _root = NodePath("frame_rate_root"); 00088 _root.attach_new_node(this); 00089 00090 CPT(RenderAttrib) dt = DepthTestAttrib::make(DepthTestAttrib::M_none); 00091 CPT(RenderAttrib) dw = DepthWriteAttrib::make(DepthWriteAttrib::M_off); 00092 _root.node()->set_attrib(dt, 1); 00093 _root.node()->set_attrib(dw, 1); 00094 _root.set_material_off(1); 00095 _root.set_two_sided(1, 1); 00096 00097 // Create a display region that covers the entire window. 00098 _display_region = _window->make_mono_display_region(); 00099 _display_region->set_sort(frame_rate_meter_layer_sort); 00100 00101 // Finally, we need a camera to associate with the display region. 00102 PT(Camera) camera = new Camera("frame_rate_camera"); 00103 NodePath camera_np = _root.attach_new_node(camera); 00104 00105 PT(Lens) lens = new OrthographicLens; 00106 00107 static const PN_stdfloat left = -1.0f; 00108 static const PN_stdfloat right = 1.0f; 00109 static const PN_stdfloat bottom = -1.0f; 00110 static const PN_stdfloat top = 1.0f; 00111 lens->set_film_size(right - left, top - bottom); 00112 lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5); 00113 lens->set_near_far(-1000, 1000); 00114 00115 camera->set_lens(lens); 00116 camera->set_scene(_root); 00117 _display_region->set_camera(camera_np); 00118 } 00119 00120 //////////////////////////////////////////////////////////////////// 00121 // Function: FrameRateMeter::clear_window 00122 // Access: Published 00123 // Description: Undoes the effect of a previous call to 00124 // setup_window(). 00125 //////////////////////////////////////////////////////////////////// 00126 void FrameRateMeter:: 00127 clear_window() { 00128 if (_window != (GraphicsOutput *)NULL) { 00129 _window->remove_display_region(_display_region); 00130 _window = (GraphicsOutput *)NULL; 00131 _display_region = (DisplayRegion *)NULL; 00132 } 00133 _root = NodePath(); 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: FrameRateMeter::cull_callback 00138 // Access: Protected, Virtual 00139 // Description: This function will be called during the cull 00140 // traversal to perform any additional operations that 00141 // should be performed at cull time. This may include 00142 // additional manipulation of render state or additional 00143 // visible/invisible decisions, or any other arbitrary 00144 // operation. 00145 // 00146 // Note that this function will *not* be called unless 00147 // set_cull_callback() is called in the constructor of 00148 // the derived class. It is necessary to call 00149 // set_cull_callback() to indicated that we require 00150 // cull_callback() to be called. 00151 // 00152 // By the time this function is called, the node has 00153 // already passed the bounding-volume test for the 00154 // viewing frustum, and the node's transform and state 00155 // have already been applied to the indicated 00156 // CullTraverserData object. 00157 // 00158 // The return value is true if this node should be 00159 // visible, or false if it should be culled. 00160 //////////////////////////////////////////////////////////////////// 00161 bool FrameRateMeter:: 00162 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00163 Thread *current_thread = trav->get_current_thread(); 00164 00165 // Statistics 00166 PStatTimer timer(_show_fps_pcollector, current_thread); 00167 00168 // Check to see if it's time to update. 00169 double now = _clock_object->get_frame_time(current_thread); 00170 double elapsed = now - _last_update; 00171 if (elapsed < 0.0 || elapsed >= _update_interval) { 00172 do_update(current_thread); 00173 } 00174 00175 return TextNode::cull_callback(trav, data); 00176 } 00177 00178 //////////////////////////////////////////////////////////////////// 00179 // Function: FrameRateMeter::do_update 00180 // Access: Private 00181 // Description: Resets the text according to the current frame rate. 00182 //////////////////////////////////////////////////////////////////// 00183 void FrameRateMeter:: 00184 do_update(Thread *current_thread) { 00185 _last_update = _clock_object->get_frame_time(current_thread); 00186 00187 double frame_rate = _clock_object->get_average_frame_rate(current_thread); 00188 double deviation = _clock_object->calc_frame_rate_deviation(current_thread); 00189 00190 static const size_t buffer_size = 1024; 00191 char buffer[buffer_size]; 00192 #if defined(WIN32_VC) || defined(WIN64_VC) 00193 // Windows doesn't define snprintf(). Hope we don't overflow. 00194 sprintf(buffer, _text_pattern.c_str(), frame_rate, deviation); 00195 #else 00196 snprintf(buffer, buffer_size, _text_pattern.c_str(), frame_rate, deviation); 00197 #endif 00198 nassertv(strlen(buffer) < buffer_size); 00199 00200 if (get_text() == buffer) { 00201 // Never mind; the frame rate hasn't changed. 00202 return; 00203 } 00204 00205 set_text(buffer); 00206 }