fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Statistics / Foregrounds / OSGPerfMonitorForeground.cpp
blob04579d801bfeb8bc65a7cbb2c6fa879121fc6666
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #include <cstdlib>
44 #include <cstdio>
45 #include <sstream>
47 #include <boost/format.hpp>
48 #include <boost/assign/list_of.hpp>
50 #include "OSGConfig.h"
51 #include "OSGViewport.h"
53 #include "OSGPerfMonitorForeground.h"
54 #include "OSGPerfMonitor.h"
56 #include "OSGDefaultFont.h"
57 #include "OSGTextTXFFace.h"
58 #include "OSGTextLayoutParam.h"
59 #include "OSGTextLayoutResult.h"
60 #include "OSGTextTXFGlyph.h"
63 OSG_BEGIN_NAMESPACE
65 // Documentation for this class is emitted in the
66 // OSGPerfMonitorForegroundBase.cpp file.
67 // To modify it, please change the .fcd file (OSGPerfMonitorForeground.fcd) and
68 // regenerate the base file.
70 /***************************************************************************\
71 * Class variables *
72 \***************************************************************************/
74 /***************************************************************************\
75 * Class methods *
76 \***************************************************************************/
78 void PerfMonitorForeground::initMethod(InitPhase ePhase)
80 Inherited::initMethod(ePhase);
83 if(ePhase == TypeObject::SystemPost)
90 /***************************************************************************\
91 * Instance methods *
92 \***************************************************************************/
94 /*-------------------------------------------------------------------------*\
95 - private -
96 \*-------------------------------------------------------------------------*/
98 /*----------------------- constructors & destructors ----------------------*/
100 PerfMonitorForeground::PerfMonitorForeground(void) :
101 Inherited(), _face(0), _texchunk(NULL), _texenvchunk(NULL), mode_names()
103 _texenvchunk = TextureEnvChunk::create();
104 _texenvchunk->setEnvMode(GL_MODULATE);
107 PerfMonitorForeground::PerfMonitorForeground(const PerfMonitorForeground &source) :
108 Inherited (source),
109 _face (source._face),
110 _texchunk (source._texchunk),
111 _texenvchunk(source._texenvchunk),
112 mode_names (source.mode_names)
116 PerfMonitorForeground::~PerfMonitorForeground(void)
120 /*----------------------------- class specific ----------------------------*/
122 void PerfMonitorForeground::cycleMode(int increment)
124 int next_mode(getMode());
125 next_mode += increment;
126 if (next_mode >= PerfMonitorForeground::MODE_END)
128 next_mode = 0;
130 if (next_mode < 0)
132 next_mode = PerfMonitorForeground::MODE_END - 1;
135 setMode(static_cast<UInt32>(next_mode));
139 void PerfMonitorForeground::changed(ConstFieldMaskArg whichField,
140 UInt32 origin,
141 BitVector details)
143 Inherited::changed(whichField, origin, details);
146 void PerfMonitorForeground::dump( UInt32 ,
147 const BitVector ) const
149 SLOG << "Dump PerfMonitorForeground NI" << std::endl;
152 /*! Initialize the text used. We may use the default compiled into the library.
154 void PerfMonitorForeground::initText(const std::string &family, Real32 size)
156 // Cleanup
157 if (_face != 0)
158 OSG::subRef(_face);
160 // Create the font
161 if (!family.empty())
163 TextTXFParam param;
164 param.size = static_cast<UInt32>(size);
165 _face = TextTXFFace::create(family, TextFace::STYLE_PLAIN, param);
166 if (_face != 0)
168 _texchunk = TextureObjChunk::create();
169 ImageUnrecPtr texture = _face->getTexture();
170 _texchunk->setImage(texture);
171 _texchunk->setWrapS(GL_CLAMP);
172 _texchunk->setWrapT(GL_CLAMP);
173 _texchunk->setMinFilter(GL_NEAREST);
174 _texchunk->setMagFilter(GL_NEAREST);
178 // We failed to create the font - fallback to the default font
179 if (_face == 0)
181 _face = DefaultFont::the()->getFace();
182 _texchunk = DefaultFont::the()->getTexture();
185 // Increment reference counters
186 OSG::addRef(_face);
188 #if 0
189 // Init the text for the chart
190 mode_names = boost::assign::map_list_of
191 (PerfMonitorForeground::Text, "Text")
192 (PerfMonitorForeground::PercentLines, "PercentLines")
193 (PerfMonitorForeground::PercentTotalLines, "PercentTotalLines")
194 (PerfMonitorForeground::MaxLines, "MaxLines")
195 (PerfMonitorForeground::ThreadTiming, "ThreadTiming");
196 #endif
199 /** Draw the foreground on the viewport. */
200 void PerfMonitorForeground::draw(DrawEnv *pEnv)
202 // -- Check all early exit and lazy initialization code -- //
203 // If we aren't active, then exit immediately
204 if (!getActive())
205 { return; }
207 return;
211 // Find the dimensions of the viewport and any other params needed for rendering
212 Real32 vpWidth = Real32(pPort->getPixelWidth());
213 Real32 vpHeight = Real32(pPort->getPixelHeight());
215 // If we have an empty or NULL vp, then don't do anything
216 if(vpWidth < 1 || vpHeight < 1)
217 return;
218 Real32 vpAspectRatio = vpWidth/vpHeight;
220 // Lazy init of the font face
221 if(NULL == _face)
223 initText(getFamily(), 10); //getSize());
226 // --- BUILD UP TEXT AND DATA TO DRAW --- //
227 PerfMonitorBase::sample_pair_vector_t samples = PerfMonitor::the()->getFlatSampleTree();
228 unsigned num_samples(samples.size());
229 PerfMonitorForeground::Mode render_mode = PerfMonitorForeground::Mode(getMode());
231 std::vector<std::string> output_lines; // This will be the list of lines of text
233 // Put some basic stats at the top of the output
234 boost::format stats_formatter("FPS: %s");
235 std::string stats_line = boost::str(stats_formatter % PerfMonitor::the()->getFrameRate(10));
236 output_lines.push_back(stats_line);
238 // compute the max length of the prefix strings (" sample_name")
239 unsigned indent_size(2);
240 unsigned max_len (0);
241 for (unsigned i=0; i<num_samples;++i)
243 const unsigned cur_len((samples[i].mDepth*indent_size) + samples[i].mSample->mName.size());
244 if(cur_len > max_len)
245 { max_len = cur_len; }
248 // Now create the lines of text
249 OSG_ASSERT(mode_names.count(render_mode) == 1);
250 std::string mode_name = mode_names[render_mode];
251 std::string header_string = boost::str(
252 boost::format("%s%s %=10s %=10s %=7s") % mode_name
253 % std::string(max_len-mode_name.size(), ' ')
254 % "Avg" % "Max" % "%");
255 boost::format formatter("%s [%8.5f] [%8.5f] [%5.3f]"); // Formatter for each line
257 output_lines.push_back(header_string);
258 for (unsigned i=0; i<num_samples; ++i)
260 unsigned sample_depth = samples[i].mDepth;
261 NestedSampleInfoPtr sample = samples[i].mSample;
263 // Create a correctly spaced "prefix" string with indent, name, and filler
264 std::string indent_str(sample_depth*2, ' ');
265 std::string name_string(indent_str + sample->mName);
266 std::string filler_string(max_len - name_string.size(), ' ');
267 name_string += filler_string;
268 std::string str_out = boost::str(formatter % name_string
269 % sample->mAverage
270 % sample->mMax
271 % sample->mPercentage);
272 output_lines.push_back(str_out);
275 // --- Create chart data to render -- //
276 // - We allocate all buffers but only fill them if we are in that mode.
277 // Chart data vectors that is used when rendering normalized data (percentages, etc)
278 // Note: all buffers *must* have max_samples entries to be valid
279 std::vector< std::vector<float> > normalized_chart_data;
280 unsigned max_samples = PerfMonitorBase::max_samples;
282 if (PerfMonitorForeground::PercentLines == render_mode)
284 for(unsigned i=0;i<num_samples;++i)
286 std::vector<float> percent_samples = samples[i].mSample->getPercentageSamples();
287 percent_samples.resize(max_samples, 0.0f);
288 normalized_chart_data.push_back(percent_samples);
291 // Create new data that has percentage of each sample out of total time.
292 else if (PerfMonitorForeground::PercentTotalLines == render_mode)
294 std::vector<float> total_values = samples[0].mSample->getSamples();
295 total_values.resize(max_samples, 0.0f);
297 for(unsigned i=0;i<num_samples;++i)
299 std::vector<float> values = samples[i].mSample->getSamples();
300 values.resize(max_samples, 0.0f);
301 for (unsigned j=0;j<max_samples;j++)
303 float total_value(total_values[j]);
304 if (total_value == 0.0)
305 { values[j] = 0.0; }
306 else
307 { values[j] = values[j] / total_value; }
309 normalized_chart_data.push_back(values);
312 // List of samples normalized by the max value in each set
313 else if (PerfMonitorForeground::MaxLines == render_mode)
315 for (unsigned i=0;i<num_samples;++i)
317 std::vector<float> values = samples[i].mSample->getSamples();
318 float max_value=0.0f;
319 // find max value
320 for (unsigned j=0;j<values.size();j++)
321 { max_value = OSG::osgMax(values[j], max_value); }
322 // normalize the values based on max value
323 if (max_value != 0.0f)
325 for(unsigned j=0;j<values.size();j++)
326 { values[j] = values[j]/max_value; }
328 values.resize(max_samples, 0.0f);
329 normalized_chart_data.push_back(values);
333 // --- LAYOUT THE TEXT and DATA --- //
334 // Now layout the text to draw it on the screen
335 TextLayoutParam layoutParam;
336 layoutParam.spacing = 1.1;
337 layoutParam.majorAlignment = TextLayoutParam::ALIGN_BEGIN;
338 layoutParam.minorAlignment = TextLayoutParam::ALIGN_BEGIN;
340 TextLayoutResult layoutResult;
341 _face->layout(output_lines, layoutParam, layoutResult);
343 unsigned num_lines(output_lines.size());
344 Real32 est_height(float(num_lines)*1.1f);
346 // layoutResult.textBounds is almost the number of lines and characters in size
347 // - It takes into account spacing and stuff like that
348 Real32 scale = 1.0f / _face->getScale(); // Scale to get to pixels or num pixels in size ??
349 Real32 size = _face->getParam().size; // Size of the face in pixels?
350 Real32 textBlockWidth = layoutResult.textBounds.x() * scale; // Num base font pixels in size ??
351 Real32 textBlockHeight = layoutResult.textBounds.y() * scale; // Num base font pixels in size ??
352 Real32 chartBlockWidth(0.0), chartBlockHeight(0.0);
353 if (PerfMonitorForeground::Text != render_mode)
355 chartBlockWidth = textBlockWidth * 2.0; // Hack for now, should be based on window size
356 chartBlockHeight = textBlockHeight;
358 // Panel is larger then just text, we add on size/2 spacing and two margins
359 Real32 panelWidth = textBlockWidth + chartBlockWidth + size + (getTextMargin().x() * 2.0f);
360 Real32 panelHeight = textBlockHeight + + size + (getTextMargin().y() * 2.0f);
362 // Scale the size of the virtual surfaced based on what can fit
363 float surf_mult(1.0);
364 if (panelHeight > vpHeight)
365 { surf_mult = (panelHeight/vpHeight); }
367 Real32 surfaceWidth = vpWidth * surf_mult;
368 Real32 surfaceHeight = vpHeight * surf_mult;
370 // ---- SETUP THE VIRTUAL VIEWPORT ---- //
371 // Now setup the GL state for "drawing" the text
372 // Note on ortho: We want to map one unit to one pixel on the
373 // screen. Some sources in the internet say that we should
374 // add an offset of -0.375 to prevent rounding errors. Don't
375 // know if that is true, but it seems to work.
376 glPushAttrib(GL_LIGHTING_BIT | GL_POLYGON_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
378 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
379 glDisable(GL_DEPTH_TEST);
380 glDisable(GL_COLOR_MATERIAL);
381 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
382 glEnable(GL_BLEND);
384 glMatrixMode(GL_MODELVIEW);
385 glPushMatrix();
386 glLoadIdentity();
388 glMatrixMode(GL_PROJECTION);
389 glPushMatrix();
390 glLoadIdentity();
392 //glOrtho(0 - 0.375, (panelHeight*vpAspectRatio) - 0.375, 0 - 0.375, panelHeight - 0.375, 0, 1);
393 glOrtho(0 - 0.375, surfaceWidth - 0.375, 0 - 0.375, surfaceHeight - 0.375, 0, 1);
395 // --- DRAW EVERYTHING --- //
396 // Let's do some simple form of layout management
397 // - just determining the place to put the "text box"
398 Real32 startX(0), startY(surfaceHeight);
399 glTranslatef(startX, startY, 0.0);
401 // draw background
402 glColor4fv((GLfloat*)getBgColor().getValuesRGBA());
403 glBegin(GL_QUADS);
404 glVertex2f(0, -panelHeight); // LL
405 glVertex2f(panelWidth, -panelHeight); // LR
406 glVertex2f(panelWidth, 0); // UR
407 glVertex2f(0, 0); // UL
408 glEnd();
410 // draw border
411 if(getBorderColor().alpha() >= 0.0f)
413 glColor4fv((GLfloat*)getBorderColor().getValuesRGBA());
414 glBegin(GL_LINE_LOOP);
415 Real32 left(getBorderOffset().x()), bottom(-panelHeight+1+getBorderOffset().y()),
416 right(panelWidth -1 -getBorderOffset().x()), top(-1 - getBorderOffset().y());
417 glVertex2f(left, bottom); // LL
418 glVertex2f(right, bottom); // LR
419 glVertex2f(right, top); // UR
420 glVertex2f(left, top); // UL
421 glEnd();
424 // Create some colors for the chart bars (alternative color for better visibility)
425 std::vector<OSG::Color4f> chart_colors;
426 OSG::Color4f bg_color = getBgColor();
427 OSG::Color4f chart_color1 = OSG::Color4f(1.0,1.0,1.0,0.0);
428 OSG::Color4f chart_color2 = (bg_color * 0.2f);
429 chart_color2[3] = 0.4;
430 chart_colors.push_back(chart_color1);
431 chart_colors.push_back(chart_color2);
432 unsigned next_base_color_idx(0);
434 // Now render chart if needed
435 if ( (PerfMonitorForeground::PercentLines == render_mode) ||
436 (PerfMonitorForeground::PercentTotalLines == render_mode) ||
437 (PerfMonitorForeground::MaxLines == render_mode) )
439 glPushMatrix();
440 // Go to upper left of chart area
441 glTranslatef(( 0.5 * size) + getTextMargin().x() + textBlockWidth,
442 (-0.5 * size) - getTextMargin().y(), 0.0);
443 float left (0.0);
444 float right(chartBlockWidth);
445 float sample_height(1.1f * size); // XXX: ???
446 float value_width(chartBlockWidth/float(max_samples)); // Amount to move right for each chart value
448 // Skip the first line since it is the header and skip another to get to bottom of sample line
449 unsigned num_header_lines(2);
450 for (unsigned i=0;i<num_header_lines;i++)
451 { glTranslatef(0.0, -sample_height, 0.0); }
452 glTranslatef(0.0, -sample_height, 0.0);
454 // Alternate colors for the base color
455 for(unsigned i=0; i<num_samples;++i)
457 // Draw border box
458 glColor4fv(chart_colors[next_base_color_idx].getValuesRGBA());
459 next_base_color_idx += 1;
460 if (next_base_color_idx >= chart_colors.size())
461 { next_base_color_idx = 0; }
463 glBegin(GL_QUADS);
464 glVertex2f(-textBlockWidth, 0.0); // LL
465 glVertex2f(right, 0.0); // LR
466 glVertex2f(right, sample_height); // UR
467 glVertex2f(-textBlockWidth, sample_height); // UL
468 glEnd();
470 // Draw the data
471 OSG::Color3f base_color(1.0, 1.0, 0.0);
472 OSG::Color3f high_color(1.0, 0.4, 0.0);
473 OSG::Color3f cur_color;
474 std::vector<float>& norm_data(normalized_chart_data[i]);
475 OSG_ASSERT(norm_data.size() == max_samples);
477 glBegin(GL_LINE_STRIP);
478 for (unsigned x=0;x<max_samples;++x)
480 float cur_val(norm_data[x]);
481 cur_color = (base_color*(1.0-cur_val)) + (high_color*cur_val);
482 glColor3fv(cur_color.getValuesRGB());
483 glVertex2f(float(x)*value_width, norm_data[x]*size);
485 glEnd();
487 // Go to next line
488 glTranslatef(0.0, -sample_height, 0.0);
491 glPopMatrix();
494 // Now render the text
495 // - first offset by the margins into the text area
496 glPushMatrix();
497 glTranslatef(( 0.5 * size) + getTextMargin().x(),
498 (-0.5 * size) - getTextMargin().y(), 0.0);
500 _texchunk ->activate(pEnv); // Active the texture for the text
501 _texenvchunk->activate(pEnv);
503 // draw text
504 glColor4fv((GLfloat *) getColor().getValuesRGBA());
505 glPushMatrix();
506 glScalef(scale, scale, 1);
507 _face->drawCharacters(layoutResult);
508 glPopMatrix();
510 _texchunk ->deactivate(pEnv);
511 _texenvchunk->deactivate(pEnv);
512 glPopMatrix();
514 // Go back to the initial state
515 glMatrixMode(GL_PROJECTION);
516 glPopMatrix();
518 glMatrixMode(GL_MODELVIEW);
519 glPopMatrix();
521 glPopAttrib();
526 OSG_END_NAMESPACE