beginnings of win-stats

This commit is contained in:
David Rose 2003-12-25 16:15:14 +00:00
parent e1be4d99df
commit 0e366091e5
14 changed files with 1392 additions and 0 deletions

View File

@ -260,6 +260,7 @@ end_draw() {
////////////////////////////////////////////////////////////////////
void PStatPianoRoll::
idle() {
update();
}

View File

@ -50,6 +50,7 @@ PStatStripChart(PStatMonitor *monitor, PStatView &view,
_start_time = 0.0;
_level_index = 0;
_title_unknown = true;
const PStatClientData *client_data = _monitor->get_client_data();
if (client_data->has_collector(_collector_index)) {
@ -236,6 +237,59 @@ get_collector_under_pixel(int xpoint, int ypoint) {
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: PStatStripChart::get_title_text
// Access: Private
// Description: Returns the text suitable for the title label on the
// top line.
////////////////////////////////////////////////////////////////////
string PStatStripChart::
get_title_text() {
string text;
_title_unknown = false;
bool _show_level = false;
int _thread_index = 0;
const PStatClientData *client_data = _monitor->get_client_data();
if (client_data->has_collector(_collector_index)) {
const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
if (_show_level) {
if (def._level_units.empty()) {
text = def._name;
} else {
text = def._name + " (" + def._level_units + ")";
}
} else {
text = def._name + " time";
}
} else {
_title_unknown = true;
}
if (_thread_index != 0) {
if (client_data->has_thread(_thread_index)) {
text += "(" + client_data->get_thread_name(_thread_index) + " thread)";
} else {
_title_unknown = true;
}
}
return text;
}
////////////////////////////////////////////////////////////////////
// Function: PStatStripChart::is_title_unknown
// Access: Public
// Description: Returns true if get_title_text() has never yet
// returned an answer, false if it has.
////////////////////////////////////////////////////////////////////
bool PStatStripChart::
is_title_unknown() const {
return _title_unknown;
}
////////////////////////////////////////////////////////////////////
// Function: PStatStripChart::get_frame_data
// Access: Protected

View File

@ -72,6 +72,9 @@ public:
INLINE int height_to_pixel(float value) const;
INLINE float pixel_to_height(int y) const;
string get_title_text();
bool is_title_unknown() const;
protected:
class ColorData {
public:
@ -117,6 +120,7 @@ private:
float _time_width;
float _start_time;
float _value_height;
bool _title_unknown;
};
#include "pStatStripChart.I"

View File

@ -0,0 +1,23 @@
#define BUILD_DIRECTORY $[and $[WINDOWS_PLATFORM],$[HAVE_NET]]
#define USE_PACKAGES net
#begin bin_target
#define TARGET pstats
#define LOCAL_LIBS \
progbase pstatserver
#define OTHER_LIBS \
pstatclient:c linmath:c putil:c net:c express:c pandaexpress:m panda:m \
dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m \
pystub
#define SOURCES \
winStats.cxx \
winStatsGraph.cxx winStatsGraph.h \
winStatsServer.cxx winStatsServer.h \
winStatsMonitor.cxx winStatsMonitor.h \
winStatsStripChart.cxx winStatsStripChart.h
#define WIN_SYS_LIBS Imm32.lib winmm.lib kernel32.lib oldnames.lib user32.lib gdi32.lib
#end bin_target

View File

@ -0,0 +1,126 @@
// Filename: winStats.cxx
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "pandatoolbase.h"
#include "winStatsServer.h"
#include "config_pstats.h"
#include <windows.h>
static const char *toplevel_class_name = "pstats";
static WinStatsServer *server = NULL;
////////////////////////////////////////////////////////////////////
// Function: toplevel_window_proc
// Description:
////////////////////////////////////////////////////////////////////
static LONG WINAPI
toplevel_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_TIMER:
server->poll();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
////////////////////////////////////////////////////////////////////
// Function: create_toplevel_window
// Description: Creates the initial, toplevel window for the
// application.
////////////////////////////////////////////////////////////////////
static HWND
create_toplevel_window(HINSTANCE application) {
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = (WNDPROC)toplevel_window_proc;
wc.hInstance = application;
wc.lpszClassName = toplevel_class_name;
if (!RegisterClass(&wc)) {
nout << "Could not register window class!\n";
exit(1);
}
DWORD window_style = WS_POPUP | WS_SYSMENU | WS_ICONIC;
HWND toplevel_window =
CreateWindow(toplevel_class_name, "PStats", window_style,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, application, 0);
if (!toplevel_window) {
nout << "Could not create toplevel window!\n";
exit(1);
}
return toplevel_window;
}
// WinMain() is the correct way to start a Windows-only application,
// but it is sometimes more convenient during development to use
// main() instead, which doesn't squelch the stderr output.
#ifdef USE_WINMAIN
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
#else
int main(int argc, char *argv[])
#endif
{
HINSTANCE application = GetModuleHandle(NULL);
HWND toplevel_window = create_toplevel_window(application);
ShowWindow(toplevel_window, SW_SHOWMINIMIZED);
// Create the server object.
server = new WinStatsServer;
if (!server->listen()) {
nout << "Unable to open port.\n";
exit(1);
}
// Set up a timer to poll the pstats every so often.
SetTimer(toplevel_window, 1, 200, NULL);
// Now get lost in the Windows message loop.
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
while (retval != 0) {
if (retval == -1) {
nout << "Error processing message queue.\n";
exit(1);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
retval = GetMessage(&msg, NULL, 0, 0);
}
return (0);
}

View File

@ -0,0 +1,25 @@
// Filename: winStats.h
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINSTATS_H
#define WINSTATS_H
#include "pStatServer.h"
#endif

View File

@ -0,0 +1,209 @@
// Filename: winStatsGraph.cxx
// Created by: drose (03Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "winStatsGraph.h"
#include "winStatsMonitor.h"
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsGraph::
WinStatsGraph(WinStatsMonitor *monitor) :
_monitor(monitor)
{
_window = 0;
_bitmap = 0;
_bitmap_dc = 0;
_bitmap_xsize = 0;
_bitmap_ysize = 0;
_left_margin = 64;
_right_margin = 32;
_top_margin = 16;
_bottom_margin = 8;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
WinStatsGraph::
~WinStatsGraph() {
_monitor = (WinStatsMonitor *)NULL;
release_bitmap();
Brushes::iterator bi;
for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) {
HBRUSH brush = (*bi).second;
DeleteObject(brush);
}
if (_window) {
DestroyWindow(_window);
_window = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::new_collector
// Access: Public, Virtual
// Description: Called whenever a new Collector definition is
// received from the client.
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
new_collector(int new_collector) {
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::new_data
// Access: Public, Virtual
// Description: Called whenever new data arrives.
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
new_data(int thread_index, int frame_number) {
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::close
// Access: Protected
// Description: Should be called when the user closes the associated
// window. This tells the monitor to remove the graph.
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
close() {
WinStatsMonitor *monitor = _monitor;
_monitor = (WinStatsMonitor *)NULL;
if (monitor != (WinStatsMonitor *)NULL) {
monitor->remove_graph(this);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::setup_bitmap
// Access: Protected
// Description: Sets up a backing-store bitmap of the indicated size.
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
setup_bitmap(int xsize, int ysize) {
release_bitmap();
_bitmap_xsize = max(xsize, 0);
_bitmap_ysize = max(ysize, 0);
_frame_rect.left = _left_margin;
_frame_rect.top = _top_margin;
_frame_rect.right = _left_margin + _bitmap_xsize;
_frame_rect.bottom = _bottom_margin + _bitmap_ysize;
HDC hdc = GetDC(_window);
_bitmap_dc = CreateCompatibleDC(hdc);
_bitmap = CreateCompatibleBitmap(hdc, _bitmap_xsize, _bitmap_ysize);
SelectObject(_bitmap_dc, _bitmap);
ReleaseDC(_window, hdc);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::release_bitmap
// Access: Protected
// Description: Frees the backing-store bitmap created by
// setup_bitmap().
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
release_bitmap() {
if (_bitmap) {
DeleteObject(_bitmap);
_bitmap = 0;
}
if (_bitmap_dc) {
DeleteDC(_bitmap_dc);
_bitmap_dc = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::get_collector_brush
// Access: Protected
// Description: Returns a brush suitable for drawing in the indicated
// collector's color.
////////////////////////////////////////////////////////////////////
HBRUSH WinStatsGraph::
get_collector_brush(int collector_index) {
Brushes::iterator bi;
bi = _brushes.find(collector_index);
if (bi != _brushes.end()) {
return (*bi).second;
}
// Ask the monitor what color this guy should be.
RGBColorf rgb = _monitor->get_collector_color(collector_index);
int r = (int)(rgb[0] * 255.0f);
int g = (int)(rgb[1] * 255.0f);
int b = (int)(rgb[2] * 255.0f);
HBRUSH brush = CreateSolidBrush(RGB(r, g, b));
_brushes[collector_index] = brush;
return brush;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsGraph::draw_graph
// Access: Protected
// Description: Draws the graph into the window by blitting the
// backing-store bitmap in, along with a suitable frame.
////////////////////////////////////////////////////////////////////
void WinStatsGraph::
draw_graph(HDC hdc) {
if (_bitmap_xsize == 0 || _bitmap_ysize == 0) {
// Never mind: nothing to draw.
return;
}
// First, draw a frame around the graph.
// Windows doesn't seem to have an API to ask how big the outer
// frame will be before we draw it, only a way to draw the outer
// frame and return the size of the inner frame afterwards.
// So we have to make our best guess about the correct size of the
// outer frame before we draw it, then examine the size of the
// resulting inner frame. If it didn't come out to the correct size
// (that is, exactly large enough to frame our graph), we expand the
// outer frame by the difference, and redraw it.
RECT rect = _frame_rect;
DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
if (rect.left != _left_margin ||
rect.top != _top_margin ||
rect.right != _left_margin + _bitmap_xsize ||
rect.bottom != _top_margin + _bitmap_ysize) {
_frame_rect.left = _left_margin - (rect.left - _frame_rect.left);
_frame_rect.top = _top_margin - (rect.top - _frame_rect.top);
_frame_rect.right = _left_margin + _bitmap_xsize + (_frame_rect.right - rect.right);
_frame_rect.bottom = _top_margin + _bitmap_ysize + (_frame_rect.bottom - rect.bottom);
DrawEdge(hdc, &_frame_rect, EDGE_SUNKEN, BF_RECT);
}
// Now fill in the graph.
BitBlt(hdc, _left_margin, _top_margin,
_bitmap_xsize, _bitmap_ysize,
_bitmap_dc, 0, 0,
SRCCOPY);
}

View File

@ -0,0 +1,71 @@
// Filename: winStatsGraph.h
// Created by: drose (03Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINSTATSGRAPH_H
#define WINSTATSGRAPH_H
#include "pandatoolbase.h"
#include "pmap.h"
#include <windows.h>
class WinStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : WinStatsGraph
// Description : This is just an abstract base class to provide a
// common pointer type for the various kinds of graphs
// that may be created for a WinStatsMonitor.
////////////////////////////////////////////////////////////////////
class WinStatsGraph {
public:
WinStatsGraph(WinStatsMonitor *monitor);
virtual ~WinStatsGraph();
virtual void new_collector(int collector_index);
virtual void new_data(int thread_index, int frame_number);
protected:
void close();
void setup_bitmap(int xsize, int ysize);
void release_bitmap();
HBRUSH get_collector_brush(int collector_index);
void draw_graph(HDC hdc);
protected:
// Table of brushes for our various collectors.
typedef pmap<int, HBRUSH> Brushes;
Brushes _brushes;
WinStatsMonitor *_monitor;
HWND _window;
HBITMAP _bitmap;
HDC _bitmap_dc;
int _bitmap_xsize, _bitmap_ysize;
int _left_margin, _right_margin;
int _top_margin, _bottom_margin;
RECT _frame_rect;
};
#endif

View File

@ -0,0 +1,333 @@
// Filename: winStatsMonitor.cxx
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "winStatsMonitor.h"
#include "winStatsStripChart.h"
#include "pStatCollectorDef.h"
bool WinStatsMonitor::_window_class_registered = false;
const char * const WinStatsMonitor::_window_class_name = "monitor";
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsMonitor::
WinStatsMonitor() {
_window = 0;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
WinStatsMonitor::
~WinStatsMonitor() {
cerr << "WinStatsMonitor destructor\n";
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
delete (*gi);
}
_graphs.clear();
if (_window) {
DestroyWindow(_window);
_window = 0;
}
// For now, exit when the first monitor closes.
exit(0);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::get_monitor_name
// Access: Public, Virtual
// Description: Should be redefined to return a descriptive name for
// the type of PStatsMonitor this is.
////////////////////////////////////////////////////////////////////
string WinStatsMonitor::
get_monitor_name() {
return "WinStats";
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::initialized
// Access: Public, Virtual
// Description: Called after the monitor has been fully set up. At
// this time, it will have a valid _client_data pointer,
// and things like is_alive() and close() will be
// meaningful. However, we may not yet know who we're
// connected to (is_client_known() may return false),
// and we may not know anything about the threads or
// collectors we're about to get data on.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
initialized() {
cerr << "Monitor initialized (refcount = " << get_ref_count() << ")\n";
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::got_hello
// Access: Public, Virtual
// Description: Called when the "hello" message has been received
// from the client. At this time, the client's hostname
// and program name will be known.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
got_hello() {
create_window();
add_graph(new WinStatsStripChart(this, get_view(0), 0));
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::got_bad_version
// Access: Public, Virtual
// Description: Like got_hello(), this is called when the "hello"
// message has been received from the client. At this
// time, the client's hostname and program name will be
// known. However, the client appears to be an
// incompatible version and the connection will be
// terminated; the monitor should issue a message to
// that effect.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
got_bad_version(int client_major, int client_minor,
int server_major, int server_minor) {
cerr << "Got bad version " << client_major << "." << client_minor
<< " from " << get_client_progname() << " on "
<< get_client_hostname() << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::new_collector
// Access: Public, Virtual
// Description: Called whenever a new Collector definition is
// received from the client. Generally, the client will
// send all of its collectors over shortly after
// connecting, but there's no guarantee that they will
// all be received before the first frames are received.
// The monitor should be prepared to accept new Collector
// definitions midstream.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
new_collector(int collector_index) {
cerr << "Got new collector " << get_collector_name(collector_index)
<< "\n";
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
WinStatsGraph *graph = (*gi);
graph->new_collector(collector_index);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::new_data
// Access: Public, Virtual
// Description: Called as each frame's data is made available. There
// is no gurantee the frames will arrive in order, or
// that all of them will arrive at all. The monitor
// should be prepared to accept frames received
// out-of-order or missing.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
new_data(int thread_index, int frame_number) {
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
WinStatsGraph *graph = (*gi);
graph->new_data(thread_index, frame_number);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::lost_connection
// Access: Public, Virtual
// Description: Called whenever the connection to the client has been
// lost. This is a permanent state change. The monitor
// should update its display to represent this, and may
// choose to close down automatically.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
lost_connection() {
cerr << "Lost connection to " << get_client_hostname()
<< " (refcount = " << get_ref_count() << ")\n";
if (_window) {
DestroyWindow(_window);
_window = 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::idle
// Access: Public, Virtual
// Description: If has_idle() returns true, this will be called
// periodically to allow the monitor to update its
// display or whatever it needs to do.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
idle() {
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::has_idle
// Access: Public, Virtual
// Description: Should be redefined to return true if you want to
// redefine idle() and expect it to be called.
////////////////////////////////////////////////////////////////////
bool WinStatsMonitor::
has_idle() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::get_window
// Access: Public
// Description: Returns the window handle to the monitor's window.
////////////////////////////////////////////////////////////////////
HWND WinStatsMonitor::
get_window() const {
return _window;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::add_graph
// Access: Private
// Description: Adds the newly-created graph to the list of managed
// graphs.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
add_graph(WinStatsGraph *graph) {
_graphs.insert(graph);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::remove_graph
// Access: Private
// Description: Deletes the indicated graph.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
remove_graph(WinStatsGraph *graph) {
Graphs::iterator gi = _graphs.find(graph);
if (gi != _graphs.end()) {
_graphs.erase(gi);
delete graph;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::create_window
// Access: Private
// Description: Creates the window for this monitor.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
create_window() {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
_window_title = get_client_progname() + " on " + get_client_hostname();
DWORD window_style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
_window =
CreateWindow(_window_class_name, _window_title.c_str(), window_style,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, application, 0);
if (!_window) {
nout << "Could not create monitor window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
ShowWindow(_window, SW_SHOWNORMAL);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::register_window_class
// Access: Private, Static
// Description: Registers the window class for the monitor window, if
// it has not already been registered.
////////////////////////////////////////////////////////////////////
void WinStatsMonitor::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)static_window_proc;
wc.hInstance = application;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wc.lpszMenuName = NULL;
wc.lpszClassName = _window_class_name;
// Reserve space to associate the this pointer with the window.
wc.cbWndExtra = sizeof(WinStatsMonitor *);
if (!RegisterClass(&wc)) {
nout << "Could not register monitor window class!\n";
exit(1);
}
_window_class_registered = true;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::static_window_proc
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
LONG WINAPI WinStatsMonitor::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
WinStatsMonitor *self = (WinStatsMonitor *)GetWindowLongPtr(hwnd, 0);
if (self != (WinStatsMonitor *)NULL && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsMonitor::window_proc
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
LONG WinStatsMonitor::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_DESTROY:
close();
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@ -0,0 +1,77 @@
// Filename: winStatsMonitor.h
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINSTATSMONITOR_H
#define WINSTATSMONITOR_H
#include "pandatoolbase.h"
#include "winStatsGraph.h"
#include "pStatMonitor.h"
#include "pointerTo.h"
#include "pset.h"
#include <windows.h>
////////////////////////////////////////////////////////////////////
// Class : WinStatsMonitor
// Description : This class represents a connection to a PStatsClient
// and manages the data exchange with the client.
////////////////////////////////////////////////////////////////////
class WinStatsMonitor : public PStatMonitor {
public:
WinStatsMonitor();
virtual ~WinStatsMonitor();
virtual string get_monitor_name();
virtual void initialized();
virtual void got_hello();
virtual void got_bad_version(int client_major, int client_minor,
int server_major, int server_minor);
virtual void new_collector(int collector_index);
virtual void new_data(int thread_index, int frame_number);
virtual void lost_connection();
virtual void idle();
virtual bool has_idle();
HWND get_window() const;
private:
void add_graph(WinStatsGraph *graph);
void remove_graph(WinStatsGraph *graph);
void create_window();
static void register_window_class(HINSTANCE application);
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
typedef pset<WinStatsGraph *> Graphs;
Graphs _graphs;
HWND _window;
string _window_title;
static bool _window_class_registered;
static const char * const _window_class_name;
friend class WinStatsGraph;
};
#endif

View File

@ -0,0 +1,30 @@
// Filename: winStatsServer.cxx
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "winStatsServer.h"
#include "winStatsMonitor.h"
////////////////////////////////////////////////////////////////////
// Function: WinStatsServer::make_monitor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
PStatMonitor *WinStatsServer::
make_monitor() {
return new WinStatsMonitor;
}

View File

@ -0,0 +1,36 @@
// Filename: winStatsServer.h
// Created by: drose (02Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINSTATSSERVER_H
#define WINSTATSSERVER_H
#include "pandatoolbase.h"
#include "pStatServer.h"
////////////////////////////////////////////////////////////////////
// Class : WinStatsServer
// Description : The class that owns the main loop, waiting for client
// connections.
////////////////////////////////////////////////////////////////////
class WinStatsServer : public PStatServer {
public:
virtual PStatMonitor *make_monitor();
};
#endif

View File

@ -0,0 +1,336 @@
// Filename: winStatsStripChart.cxx
// Created by: drose (03Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 "winStatsStripChart.h"
#include "winStatsMonitor.h"
static const int default_strip_chart_width = 400;
static const int default_strip_chart_height = 100;
bool WinStatsStripChart::_window_class_registered = false;
const char * const WinStatsStripChart::_window_class_name = "strip";
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WinStatsStripChart::
WinStatsStripChart(WinStatsMonitor *monitor, PStatView &view,
int collector_index) :
PStatStripChart(monitor, view, collector_index,
default_strip_chart_width,
default_strip_chart_height),
WinStatsGraph(monitor)
{
cerr << "Constructing strip chart " << (void *)this << "\n";
_brush_origin = 0;
setup_bitmap(get_xsize(), get_ysize());
clear_region();
create_window();
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
WinStatsStripChart::
~WinStatsStripChart() {
cerr << "Destructing strip chart " << (void *)this << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::new_collector
// Access: Public, Virtual
// Description: Called whenever a new Collector definition is
// received from the client.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
new_collector(int collector_index) {
if (is_title_unknown()) {
string window_title = get_title_text();
if (!is_title_unknown()) {
SetWindowText(_window, window_title.c_str());
}
}
WinStatsGraph::new_collector(collector_index);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::idle
// Access: Public, Virtual
// Description: Called as each frame's data is made available. There
// is no gurantee the frames will arrive in order, or
// that all of them will arrive at all. The monitor
// should be prepared to accept frames received
// out-of-order or missing.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
new_data(int thread_index, int frame_number) {
update();
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::clear_region
// Access: Protected, Virtual
// Description: Erases the chart area.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
clear_region() {
RECT rect = { 0, 0, get_xsize(), get_ysize() };
FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::copy_region
// Access: Protected, Virtual
// Description: Should be overridden by the user class to copy a
// region of the chart from one part of the chart to
// another. This is used to implement scrolling.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
copy_region(int start_x, int end_x, int dest_x) {
BitBlt(_bitmap_dc, dest_x, 0,
end_x - start_x, get_ysize(),
_bitmap_dc, start_x, 0,
SRCCOPY);
// Also shift the brush origin over, so we still get proper
// dithering.
_brush_origin += (dest_x - start_x);
SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL);
RECT rect = {
_left_margin + dest_x, _top_margin,
_left_margin + end_x - start_x, _top_margin + get_ysize()
};
InvalidateRect(_window, &rect, FALSE);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::draw_slice
// Access: Protected, Virtual
// Description: Draws a single vertical slice of the strip chart, at
// the given pixel position, and corresponding to the
// indicated level data.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
draw_slice(int x, int frame_number) {
const FrameData &frame = get_frame_data(frame_number);
// Start by clearing the band first.
RECT rect = { x, 0, x + 1, get_ysize() };
FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
float overall_time = 0.0;
int y = get_ysize();
FrameData::const_iterator fi;
for (fi = frame.begin(); fi != frame.end(); ++fi) {
const ColorData &cd = (*fi);
overall_time += cd._net_value;
HBRUSH brush = get_collector_brush(cd._collector_index);
if (overall_time > get_vertical_scale()) {
// Off the top. Go ahead and clamp it by hand, in case it's so
// far off the top we'd overflow the 16-bit pixel value.
rect.top = 0;
rect.bottom = y;
FillRect(_bitmap_dc, &rect, brush);
// And we can consider ourselves done now.
return;
}
int top_y = height_to_pixel(overall_time);
rect.top = top_y;
rect.bottom = y;
FillRect(_bitmap_dc, &rect, brush);
y = top_y;
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::draw_empty
// Access: Protected, Virtual
// Description: Draws a single vertical slice of background color.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
draw_empty(int x) {
RECT rect = { x, 0, x + 1, get_ysize() };
FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::draw_cursor
// Access: Protected, Virtual
// Description: Draws a single vertical slice of foreground color.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
draw_cursor(int x) {
RECT rect = { x, 0, x + 1, get_ysize() };
FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::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 strip chart; it gives the pixel range that
// was just redrawn.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
end_draw(int from_x, int to_x) {
RECT rect = { from_x, 0, to_x + 1, get_ysize() };
InvalidateRect(_window, &rect, FALSE);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::create_window
// Access: Private
// Description: Creates the window for this strip chart.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
create_window() {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
string window_title = get_title_text();
DWORD window_style = WS_CHILD | WS_OVERLAPPEDWINDOW;
RECT win_rect = {
0, 0,
_left_margin + get_xsize() + _right_margin,
_top_margin + get_ysize() + _bottom_margin
};
// compute window size based on desired client area size
AdjustWindowRect(&win_rect, window_style, FALSE);
_window =
CreateWindow(_window_class_name, window_title.c_str(), window_style,
CW_USEDEFAULT, 0,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
WinStatsGraph::_monitor->get_window(), NULL, application, 0);
if (!_window) {
nout << "Could not create StripChart window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
ShowWindow(_window, SW_SHOWNORMAL);
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::register_window_class
// Access: Private, Static
// Description: Registers the window class for the stripChart window, if
// it has not already been registered.
////////////////////////////////////////////////////////////////////
void WinStatsStripChart::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)static_window_proc;
wc.hInstance = application;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wc.lpszMenuName = NULL;
wc.lpszClassName = _window_class_name;
// Reserve space to associate the this pointer with the window.
wc.cbWndExtra = sizeof(WinStatsStripChart *);
if (!RegisterClass(&wc)) {
nout << "Could not register StripChart window class!\n";
exit(1);
}
_window_class_registered = true;
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::static_window_proc
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
LONG WINAPI WinStatsStripChart::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
WinStatsStripChart *self = (WinStatsStripChart *)GetWindowLongPtr(hwnd, 0);
if (self != (WinStatsStripChart *)NULL && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
////////////////////////////////////////////////////////////////////
// Function: WinStatsStripChart::window_proc
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
LONG WinStatsStripChart::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_DESTROY:
close();
break;
case WM_DISPLAYCHANGE:
setup_bitmap(get_xsize(), get_ysize());
force_redraw();
break;
case WM_SIZE:
changed_size(LOWORD(lparam) - (_left_margin + _right_margin),
HIWORD(lparam) - (_top_margin + _bottom_margin));
setup_bitmap(get_xsize(), get_ysize());
force_redraw();
InvalidateRect(hwnd, NULL, FALSE);
break;
case WM_PAINT:
{
// Repaint the graph by copying the backing pixmap in.
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
draw_graph(hdc);
EndPaint(hwnd, &ps);
return 0;
}
default:
break;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}

View File

@ -0,0 +1,67 @@
// Filename: winStatsStripChart.h
// Created by: drose (03Dec03)
//
////////////////////////////////////////////////////////////////////
//
// 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 WINSTATSSTRIPCHART_H
#define WINSTATSSTRIPCHART_H
#include "pandatoolbase.h"
#include "winStatsGraph.h"
#include "pStatStripChart.h"
#include "pointerTo.h"
#include <windows.h>
class WinStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : WinStatsStripChart
// Description :
////////////////////////////////////////////////////////////////////
class WinStatsStripChart : public PStatStripChart, public WinStatsGraph {
public:
WinStatsStripChart(WinStatsMonitor *monitor,
PStatView &view, int collector_index);
virtual ~WinStatsStripChart();
virtual void new_collector(int collector_index);
virtual void new_data(int thread_index, int frame_number);
protected:
virtual void clear_region();
virtual void copy_region(int start_x, int end_x, int dest_x);
virtual void draw_slice(int x, int frame_number);
virtual void draw_empty(int x);
virtual void draw_cursor(int x);
virtual void end_draw(int from_x, int to_x);
private:
void create_window();
static void register_window_class(HINSTANCE application);
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
int _brush_origin;
static bool _window_class_registered;
static const char * const _window_class_name;
};
#endif