mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
345 lines
12 KiB
C++
345 lines
12 KiB
C++
// Filename: pStatPianoRoll.cxx
|
|
// Created by: drose (18Jul00)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pStatPianoRoll.h"
|
|
|
|
#include "pStatFrameData.h"
|
|
#include "pStatCollectorDef.h"
|
|
#include "string_utils.h"
|
|
#include "config_pstats.h"
|
|
|
|
#include <algorithm>
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::BarBuilder::Constructor
|
|
// Access: Public
|
|
// Description: This class is used internally to build up the set of
|
|
// color bars defined by a frame's worth of data.
|
|
////////////////////////////////////////////////////////////////////
|
|
PStatPianoRoll::BarBuilder::
|
|
BarBuilder() {
|
|
_is_new = true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::BarBuilder::clear
|
|
// Access: Public
|
|
// Description: Resets the data in the BarBuilder for a new frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::BarBuilder::
|
|
clear() {
|
|
_is_new = false;
|
|
_color_bars.clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::BarBuilder::add_data_point
|
|
// Access: Public
|
|
// Description: Adds a new data point. The first data point for a
|
|
// given collector turns in on (starts the bar), the
|
|
// second data point turns it off (ends the bar).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::BarBuilder::
|
|
add_data_point(float time) {
|
|
if (_color_bars.empty() || _color_bars.back()._end >= 0.0) {
|
|
// This is an odd-numbered data point: start the bar.
|
|
ColorBar bar;
|
|
bar._start = time;
|
|
bar._end = -1.0;
|
|
_color_bars.push_back(bar);
|
|
|
|
} else {
|
|
// This is an even-numbered data point: end the bar.
|
|
_color_bars.back()._end = time;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::BarBuilder::finish
|
|
// Access: Public
|
|
// Description: Makes sure that each start-bar data point was matched
|
|
// by a corresponding end-bar data point.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::BarBuilder::
|
|
finish(float time) {
|
|
if (!_color_bars.empty() && _color_bars.back()._end < 0.0) {
|
|
nout << "Warning: collector was left on at the end of the frame.\n";
|
|
_color_bars.back()._end = time;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PStatPianoRoll::
|
|
PStatPianoRoll(PStatMonitor *monitor, int thread_index, int xsize, int ysize) :
|
|
PStatGraph(monitor, xsize, ysize),
|
|
_thread_index(thread_index)
|
|
{
|
|
_time_width = 1.0 / pstats_target_frame_rate;
|
|
_start_time = 0.0;
|
|
|
|
_current_frame = -1;
|
|
_guide_bar_units = GBU_ms | GBU_hz | GBU_show_units;
|
|
normal_guide_bars();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
PStatPianoRoll::
|
|
~PStatPianoRoll() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::update
|
|
// Access: Public
|
|
// Description: Updates the chart with the latest data.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
update() {
|
|
const PStatClientData *client_data = _monitor->get_client_data();
|
|
|
|
// Don't bother to update the thread data until we know at least
|
|
// something about the collectors and threads.
|
|
if (client_data->get_num_collectors() != 0 &&
|
|
client_data->get_num_threads() != 0) {
|
|
const PStatThreadData *thread_data =
|
|
client_data->get_thread_data(_thread_index);
|
|
if (!thread_data->is_empty()) {
|
|
int frame_number = thread_data->get_latest_frame_number();
|
|
if (frame_number != _current_frame) {
|
|
compute_page(thread_data->get_frame(frame_number));
|
|
_current_frame = frame_number;
|
|
force_redraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
idle();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::changed_size
|
|
// Access: Protected
|
|
// Description: To be called by the user class when the widget size
|
|
// has changed. This updates the chart's internal data
|
|
// and causes it to issue redraw commands to reflect the
|
|
// new size.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
changed_size(int xsize, int ysize) {
|
|
if (xsize != _xsize || ysize != _ysize) {
|
|
_xsize = xsize;
|
|
_ysize = ysize;
|
|
|
|
normal_guide_bars();
|
|
force_redraw();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::force_redraw
|
|
// Access: Protected
|
|
// Description: To be called by the user class when the whole thing
|
|
// needs to be redrawn for some reason.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
force_redraw() {
|
|
if (!_labels.empty()) {
|
|
begin_draw();
|
|
for (int i = 0; i < (int)_labels.size(); i++) {
|
|
int collector_index = _labels[i];
|
|
const ColorBars &bars = _page_data[collector_index]._color_bars;
|
|
|
|
begin_row(i);
|
|
ColorBars::const_iterator bi;
|
|
for (bi = bars.begin(); bi != bars.end(); ++bi) {
|
|
const ColorBar &bar = (*bi);
|
|
draw_bar(i, timestamp_to_pixel(bar._start), timestamp_to_pixel(bar._end));
|
|
}
|
|
end_row(i);
|
|
}
|
|
end_draw();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::normal_guide_bars
|
|
// Access: Protected, Virtual
|
|
// Description: Calls update_guide_bars with parameters suitable to
|
|
// this kind of graph.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
normal_guide_bars() {
|
|
// We want vaguely 100 pixels between guide bars.
|
|
update_guide_bars(get_xsize() / 100, _time_width);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::begin_draw
|
|
// Access: Protected, Virtual
|
|
// Description: Should be overridden by the user class. This hook
|
|
// will be called before drawing any bars in the chart.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
begin_draw() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::begin_row
|
|
// Access: Protected, Virtual
|
|
// Description: Should be overridden by the user class. This hook
|
|
// will be called before drawing any one row of bars.
|
|
// These bars correspond to the collector whose index is
|
|
// get_row_collector(row), and in the color
|
|
// get_row_color(row).
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
begin_row(int) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::draw_bar
|
|
// Access: Protected, Virtual
|
|
// Description: Draws a single bar in the chart for the indicated
|
|
// row, in the color get_row_color(row), for the
|
|
// indicated horizontal pixel range.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
draw_bar(int, int, int) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::end_row
|
|
// Access: Protected, Virtual
|
|
// Description: Should be overridden by the user class. This hook
|
|
// will be called after drawing a series of color bars
|
|
// for a single row.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
end_row(int) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::end_draw
|
|
// Access: Protected, Virtual
|
|
// Description: Should be overridden by the user class. This hook
|
|
// will be called after drawing a series of color bars
|
|
// in the chart.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
end_draw() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::idle
|
|
// Access: Protected, Virtual
|
|
// Description: Should be overridden by the user class to perform any
|
|
// other updates might be necessary after the bars have
|
|
// been redrawn.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
idle() {
|
|
}
|
|
|
|
|
|
// STL function object for sorting labels in order by the collector's
|
|
// sort index, used in compute_page(), below.
|
|
class SortCollectorLabels1 {
|
|
public:
|
|
SortCollectorLabels1(const PStatClientData *client_data) :
|
|
_client_data(client_data) {
|
|
}
|
|
bool operator () (int a, int b) const {
|
|
return
|
|
_client_data->get_collector_def(a)._sort >
|
|
_client_data->get_collector_def(b)._sort;
|
|
}
|
|
const PStatClientData *_client_data;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: PStatPianoRoll::compute_page
|
|
// Access: Private
|
|
// Description: Examines the given frame data and rebuilds the
|
|
// _page_data to match it.
|
|
////////////////////////////////////////////////////////////////////
|
|
void PStatPianoRoll::
|
|
compute_page(const PStatFrameData &frame_data) {
|
|
_start_time = frame_data.get_start();
|
|
|
|
// Clear out the page data and copy it to previous, so we can fill
|
|
// it up again and then check to see if we changed the set of bars
|
|
// this frame.
|
|
PageData previous;
|
|
_page_data.swap(previous);
|
|
|
|
int num_events = frame_data.get_num_events();
|
|
for (int i = 0; i < num_events; i++) {
|
|
int collector_index = frame_data.get_time_collector(i);
|
|
float time = frame_data.get_time(i);
|
|
_page_data[collector_index].add_data_point(time);
|
|
}
|
|
|
|
// Now check to see if the set of bars has changed.
|
|
bool changed_bars = (_page_data.size() != previous.size());
|
|
|
|
if (!changed_bars) {
|
|
PageData::const_iterator ai, bi;
|
|
ai = _page_data.begin();
|
|
bi = previous.begin();
|
|
while (ai != _page_data.end() && !changed_bars) {
|
|
changed_bars = ((*ai).first == (*bi).first);
|
|
++ai;
|
|
++bi;
|
|
}
|
|
}
|
|
|
|
if (changed_bars) {
|
|
// If we added or removed some new bars this time, we'll have to
|
|
// update our list.
|
|
const PStatClientData *client_data = _monitor->get_client_data();
|
|
|
|
_labels.clear();
|
|
PageData::const_iterator pi;
|
|
for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
|
|
int collector_index = (*pi).first;
|
|
if (client_data->has_collector(collector_index)) {
|
|
_labels.push_back(collector_index);
|
|
}
|
|
}
|
|
|
|
SortCollectorLabels1 sort_labels(client_data);
|
|
sort(_labels.begin(), _labels.end(), sort_labels);
|
|
|
|
_labels_changed = true;
|
|
}
|
|
|
|
// Finally, make sure all of the bars are closed.
|
|
float time = frame_data.get_end();
|
|
PageData::iterator pi;
|
|
for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
|
|
(*pi).second.finish(time);
|
|
}
|
|
}
|