// Filename: sceneGraphAnalyzerMeter.cxx // Created by: pratt (14Feb07) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #include "sceneGraphAnalyzerMeter.h" #include "camera.h" #include "displayRegion.h" #include "orthographicLens.h" #include "config_grutil.h" #include "depthTestAttrib.h" #include "depthWriteAttrib.h" #include "pStatTimer.h" #include // For sprintf/snprintf PStatCollector SceneGraphAnalyzerMeter::_show_analyzer_pcollector("*:Show scene graph analysis"); TypeHandle SceneGraphAnalyzerMeter::_type_handle; //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::Constructor // Access: Published // Description: //////////////////////////////////////////////////////////////////// SceneGraphAnalyzerMeter:: SceneGraphAnalyzerMeter(const string &name, PandaNode *node) : TextNode(name) { set_cull_callback(); Thread *current_thread = Thread::get_current_thread(); _update_interval = scene_graph_analyzer_meter_update_interval; _last_update = 0.0f; _node = node; _clock_object = ClockObject::get_global_clock(); set_align(A_left); set_transform(LMatrix4::scale_mat(scene_graph_analyzer_meter_scale) * LMatrix4::translate_mat(LVector3::rfu(-1.0f + scene_graph_analyzer_meter_side_margins * scene_graph_analyzer_meter_scale, 0.0f, 1.0f - scene_graph_analyzer_meter_scale))); set_card_color(0.0f, 0.0f, 0.0f, 0.4); set_card_as_margin(scene_graph_analyzer_meter_side_margins, scene_graph_analyzer_meter_side_margins, 0.1f, 0.0f); set_usage_hint(Geom::UH_client); do_update(current_thread); } //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::Destructor // Access: Published, Virtual // Description: //////////////////////////////////////////////////////////////////// SceneGraphAnalyzerMeter:: ~SceneGraphAnalyzerMeter() { clear_window(); } //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::setup_window // Access: Published // Description: Sets up the frame rate meter to create a // DisplayRegion to render itself into the indicated // window. //////////////////////////////////////////////////////////////////// void SceneGraphAnalyzerMeter:: setup_window(GraphicsOutput *window) { clear_window(); _window = window; _root = NodePath("scene_graph_analyzer_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); // Create a display region that covers the entire window. _display_region = _window->make_display_region(); _display_region->set_sort(scene_graph_analyzer_meter_layer_sort); // Finally, we need a camera to associate with the display region. PT(Camera) camera = new Camera("scene_graph_analyzer_camera"); NodePath camera_np = _root.attach_new_node(camera); PT(Lens) lens = new OrthographicLens; static const PN_stdfloat left = -1.0f; static const PN_stdfloat right = 1.0f; static const PN_stdfloat bottom = -1.0f; static const PN_stdfloat 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); _display_region->set_camera(camera_np); } //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::clear_window // Access: Published // Description: Undoes the effect of a previous call to // setup_window(). //////////////////////////////////////////////////////////////////// void SceneGraphAnalyzerMeter:: clear_window() { if (_window != (GraphicsOutput *)NULL) { _window->remove_display_region(_display_region); _window = (GraphicsOutput *)NULL; _display_region = (DisplayRegion *)NULL; } _root = NodePath(); } //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::cull_callback // Access: Protected, Virtual // Description: 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. // // Note that this function will *not* be called unless // set_cull_callback() is called in the constructor of // the derived class. It is necessary to call // set_cull_callback() to indicated that we require // cull_callback() to be called. // // 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 SceneGraphAnalyzerMeter:: cull_callback(CullTraverser *trav, CullTraverserData &data) { Thread *current_thread = trav->get_current_thread(); // Statistics PStatTimer timer(_show_analyzer_pcollector, current_thread); // Check to see if it's time to update. double now = _clock_object->get_frame_time(current_thread); double elapsed = now - _last_update; if (elapsed < 0.0 || elapsed >= _update_interval) { do_update(current_thread); } return TextNode::cull_callback(trav, data); } //////////////////////////////////////////////////////////////////// // Function: SceneGraphAnalyzerMeter::do_update // Access: Private // Description: Resets the text according to the current frame rate. //////////////////////////////////////////////////////////////////// void SceneGraphAnalyzerMeter:: do_update(Thread *current_thread) { _last_update = _clock_object->get_frame_time(current_thread); _scene_graph_analyzer.clear(); _scene_graph_analyzer.add_node( _node ); static const size_t buffer_size = 1024; char buffer[buffer_size]; const char *pattern = "Nodes: %d\n" "Instances: %d\n" "Transforms: %d\n" "Nodes with Attribs: %d\n" "GeomNodes: %d\n" "Geoms: %d\n" "GeomVertexDatas: %d\n" "Vertices: %d\n" "Normals: %d\n" "TexCoords: %d\n" "Tris: %d\n" "Lines: %d\n" "Points: %d\n" "Texture memory: %.1f KB\n"; #if defined(WIN32_VC) || defined(WIN64_VC) _snprintf(buffer, buffer_size, pattern, _scene_graph_analyzer.get_num_nodes(), _scene_graph_analyzer.get_num_instances(), _scene_graph_analyzer.get_num_transforms(), _scene_graph_analyzer.get_num_nodes_with_attribs(), _scene_graph_analyzer.get_num_geom_nodes(), _scene_graph_analyzer.get_num_geoms(), _scene_graph_analyzer.get_num_geom_vertex_datas(), _scene_graph_analyzer.get_num_vertices(), _scene_graph_analyzer.get_num_normals(), _scene_graph_analyzer.get_num_texcoords(), _scene_graph_analyzer.get_num_tris(), _scene_graph_analyzer.get_num_lines(), _scene_graph_analyzer.get_num_points(), _scene_graph_analyzer.get_texture_bytes()/1024.0); #else snprintf(buffer, buffer_size, pattern, _scene_graph_analyzer.get_num_nodes(), _scene_graph_analyzer.get_num_instances(), _scene_graph_analyzer.get_num_transforms(), _scene_graph_analyzer.get_num_nodes_with_attribs(), _scene_graph_analyzer.get_num_geom_nodes(), _scene_graph_analyzer.get_num_geoms(), _scene_graph_analyzer.get_num_geom_vertex_datas(), _scene_graph_analyzer.get_num_vertices(), _scene_graph_analyzer.get_num_normals(), _scene_graph_analyzer.get_num_texcoords(), _scene_graph_analyzer.get_num_tris(), _scene_graph_analyzer.get_num_lines(), _scene_graph_analyzer.get_num_points(), _scene_graph_analyzer.get_texture_bytes()/1024.0); #endif nassertv(strlen(buffer) < buffer_size); if (get_text() == buffer) { // Never mind; the data hasn't changed. return; } set_text(buffer); }