📄 soperfgraph.cpp
字号:
/*****************************************************************************\ * * SoPerfGraph.cpp * * Performance graph node * * Authors: PCJohn (peciva AT fit.vutbr.cz) * Contributors: * * ---------------------------------------------------------------------------- * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. * You may use, modify or distribute it freely. * * This source code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * If you find the source code useful, authors will kindly welcome * if you give them credit and keep their names with their source code, * but do not feel forced to do so. *\*****************************************************************************/#include <Inventor/nodes/SoAnnotation.h>#include <Inventor/nodes/SoBaseColor.h>#include <Inventor/nodes/SoComplexity.h>#include <Inventor/nodes/SoCoordinate3.h>#include <Inventor/nodes/SoFont.h>#include <Inventor/nodes/SoIndexedTriangleStripSet.h>#include <Inventor/nodes/SoLightModel.h>#include <Inventor/nodes/SoMaterial.h>#include <Inventor/nodes/SoOrthographicCamera.h>#include <Inventor/nodes/SoText2.h>#include <Inventor/nodes/SoTexture2.h>#include <Inventor/nodes/SoTextureCoordinate2.h>#include <Inventor/nodes/SoTranslation.h>#include <Inventor/nodes/SoTransparencyType.h>#include <Inventor/actions/SoGLRenderAction.h>#include <Inventor/actions/SoGetBoundingBoxAction.h>#include <Inventor/actions/SoPickAction.h>#include <Inventor/sensors/SoNodeSensor.h>#include <Inventor/misc/SoChildList.h>#include <Inventor/SbTime.h>#include <Inventor/C/tidbits.h> // coin_next_power_of_two#include "SoPerfGraph.h"SO_NODE_SOURCE(SoPerfGraph);#define THIS this->pimpl#define TEXTURE_COMPONENTS 4#define NUM_VALUES_OVER 20#define AVG_UPDATE_TIME 0.35#define AVG_SUM_TIME 1.class SoPerfGraphP {public: float *values; double *timeStamps; int numValues; int startIndex; float maxValue; float renderedMax; int texRequestedWidth; int texRequestedHeight; float maxTexCoordX; float maxTexCoordY; int texIndex; SoChildList children; SoPerfGraph *parent; SoOrthographicCamera *camera; SoCoordinate3 *coordNode; SoIndexedTriangleStripSet *triStrip; SoTexture2 *textureNode; SoTextureCoordinate2 *texCoordNode; SoTranslation *textTranslationMaxNode; SoTranslation *textTranslationAvgNode; SoText2 *textNodeMax; SoText2 *textNodeAvg; double lastAvgUpdate; SbViewportRegion previousViewport; SoNodeSensor nodeSensor; struct objData { SbBool vpValid : 1; SbBool posValid : 1; SbBool sizeValid : 1; SbBool textureNeedsResize : 1; objData() : vpValid(FALSE), posValid(FALSE), sizeValid(FALSE), textureNeedsResize(TRUE) {} } objData; SoPerfGraphP(SoPerfGraph *aparent) : values(NULL), timeStamps(NULL), children(aparent), parent(aparent), lastAvgUpdate(0.) { maxTexCoordX = 1.f; // this value may be used BEFORE its proper initialization in updateSceneIfNecessary() nodeSensor.setFunction(fieldChangedCB); nodeSensor.setData(this); nodeSensor.setPriority(0); nodeSensor.attach(aparent); } ~SoPerfGraphP() { delete[] values; delete[] timeStamps; } static void fieldChangedCB(void *data, SoSensor *sensor); void updateSceneIfNecessary(const SbViewportRegion &vp, SbBool textureDataRequired); void updateTextureCoordinates(int texSizeY); void redrawTexture(); static float roundUp(float value);};static int32_t coordIndices[] = { 0,1,2,3,-1, };static SbVec2f texCoords[] = { SbVec2f(0.f,0.f), SbVec2f(0.f,1.f), SbVec2f(1.f,0.f), SbVec2f(1.f,1.f) };SoPerfGraph::SoPerfGraph(){ SO_NODE_CONSTRUCTOR(SoPerfGraph); SO_NODE_ADD_FIELD(vertAlignment, (BOTTOM)); SO_NODE_ADD_FIELD(horAlignment, (LEFT)); SO_NODE_ADD_FIELD(size, (0.35f,0.15f)); SO_NODE_ADD_FIELD(position, (0.03f,0.03f)); SO_NODE_ADD_FIELD(sizeInPixels, (0,0)); SO_NODE_ADD_FIELD(positionInPixels, (0,0)); SO_NODE_ADD_FIELD(vertScreenOrigin, (BOTTOM)); SO_NODE_ADD_FIELD(horScreenOrigin, (LEFT)); SO_NODE_ADD_FIELD(dataScale, (2.f,1.f)); SO_NODE_DEFINE_ENUM_VALUE(VertAlignment, BOTTOM); SO_NODE_DEFINE_ENUM_VALUE(VertAlignment, HALF); SO_NODE_DEFINE_ENUM_VALUE(VertAlignment, TOP); SO_NODE_SET_SF_ENUM_TYPE(vertAlignment, VertAlignment); SO_NODE_SET_SF_ENUM_TYPE(vertScreenOrigin, VertAlignment); SO_NODE_DEFINE_ENUM_VALUE(HorAlignment, LEFT); SO_NODE_DEFINE_ENUM_VALUE(HorAlignment, CENTER); SO_NODE_DEFINE_ENUM_VALUE(HorAlignment, RIGHT); SO_NODE_SET_SF_ENUM_TYPE(horAlignment, HorAlignment); SO_NODE_SET_SF_ENUM_TYPE(horScreenOrigin, HorAlignment); pimpl = new SoPerfGraphP(this); THIS->numValues = 128 + NUM_VALUES_OVER; THIS->values = new float[THIS->numValues]; THIS->timeStamps = new double[THIS->numValues]; memset(THIS->values, 0, THIS->numValues*sizeof(float)); memset(THIS->timeStamps, 0, THIS->numValues*sizeof(double)); THIS->maxValue = 0.f; THIS->renderedMax = 0.f; THIS->startIndex = 0; THIS->texIndex = 0; SoSeparator *root = new SoAnnotation; root->renderCaching = SoSeparator::OFF; THIS->camera = new SoOrthographicCamera; THIS->camera->height = 1.f; THIS->camera->viewportMapping = SoCamera::LEAVE_ALONE; root->addChild(THIS->camera); SoLightModel *lm = new SoLightModel; lm->model.setValue(SoLightModel::BASE_COLOR); root->addChild(lm); SoTransparencyType *tt = new SoTransparencyType; tt->value = SoTransparencyType::BLEND; root->addChild(tt); THIS->coordNode = new SoCoordinate3; THIS->coordNode->point.setNum(4); root->addChild(THIS->coordNode); THIS->texCoordNode = new SoTextureCoordinate2; THIS->texCoordNode->point.setValues(0, sizeof(texCoords)/sizeof(int32_t), texCoords); root->addChild(THIS->texCoordNode); SoComplexity *cplx = new SoComplexity; cplx->textureQuality = 0.1f; // this should disable texture filtering, // that we do not want to happen in our graph (causes distortion) cplx->type.setIgnored(TRUE); cplx->value.setIgnored(TRUE); root->addChild(cplx); THIS->textureNode = new SoTexture2; THIS->textureNode->model = SoTexture2::REPLACE; root->addChild(THIS->textureNode); THIS->triStrip = new SoIndexedTriangleStripSet; THIS->triStrip->coordIndex.setValues(0, sizeof(coordIndices)/sizeof(int32_t), coordIndices); root->addChild(THIS->triStrip); // set default font SoFont *font = new SoFont; root->addChild(font); root->addChild(new SoTexture2); THIS->textTranslationMaxNode = new SoTranslation; root->addChild(THIS->textTranslationMaxNode); THIS->textNodeMax = new SoText2; root->addChild(THIS->textNodeMax); THIS->textTranslationAvgNode = new SoTranslation; root->addChild(THIS->textTranslationAvgNode); THIS->textNodeAvg = new SoText2; THIS->textNodeAvg->justification.setValue(SoText2::RIGHT); THIS->textNodeAvg->string.setValue("12"); root->addChild(THIS->textNodeAvg); THIS->children.append(root);}SoPerfGraph::~SoPerfGraph(){ delete pimpl;}void SoPerfGraphP::fieldChangedCB(void *data, SoSensor *sensor){ SoPerfGraphP *p = (SoPerfGraphP*)data; if (((SoNodeSensor*)sensor)->getTriggerNode() != p->parent) return; SoField *f = ((SoNodeSensor*)sensor)->getTriggerField(); // Camera settings may need to be changed if (f == &p->parent->vertScreenOrigin || f == &p->parent->horScreenOrigin) p->objData.vpValid = FALSE; // Coordinates may need recalculation if (f == &p->parent->vertAlignment || f == &p->parent->horAlignment || f == &p->parent->position || f == &p->parent->positionInPixels) p->objData.posValid = FALSE; // Texture size and coordinates may need to be updated if (f == &p->parent->size || f == &p->parent->sizeInPixels || f == &p->parent->dataScale) p->objData.sizeValid = FALSE;}void SoPerfGraph::appendValue(float v){ // update maxValue float newMax = THIS->renderedMax; if (v > THIS->maxValue) { // incoming value is the greatest one THIS->maxValue = v; newMax = THIS->roundUp(THIS->maxValue); } else { // leaving value is the greatest one if (THIS->values[THIS->startIndex] == THIS->maxValue) { float max = v; THIS->values[THIS->startIndex] = v; // old value, that we certainly do not want to find int i,c = THIS->numValues; for (i=0; i<c; i++) if (THIS->values[i] > max) max = THIS->values[i]; THIS->maxValue = max; newMax = THIS->roundUp(THIS->maxValue); } } // update text if (newMax != THIS->renderedMax) { // postphone scaling down (avoids quick rescalling) if (newMax < THIS->renderedMax) newMax = THIS->roundUp(THIS->maxValue * 1.1f); // update text and texture if (newMax != THIS->renderedMax) { THIS->renderedMax = newMax; THIS->redrawTexture(); SbString s; s.sprintf("%.5g", newMax); THIS->textNodeMax->string.setValue(s); } } // update value array THIS->values[THIS->startIndex] = v; THIS->timeStamps[THIS->startIndex] = SbTime::getTimeOfDay().getValue(); // update avg value // The update is done four times per second from values up to one second old. if (THIS->lastAvgUpdate + AVG_UPDATE_TIME <= THIS->timeStamps[THIS->startIndex]) { THIS->lastAvgUpdate = THIS->timeStamps[THIS->startIndex]; double stop = THIS->timeStamps[THIS->startIndex] - AVG_SUM_TIME; float sum = THIS->values[THIS->startIndex]; int num = 1; int i = THIS->startIndex - 1; if (i<0) i += THIS->numValues; while (THIS->timeStamps[i] > stop && i != THIS->startIndex) { sum += THIS->values[THIS->startIndex]; num++; if (--i<0) i += THIS->numValues; } SbString s; s.sprintf("avg: %#.5g", sum/num); THIS->textNodeAvg->string.setValue(s); } // move to the next index THIS->startIndex++; if (THIS->startIndex == THIS->numValues) THIS->startIndex = 0; // update texture SbVec2s texSize; int components; unsigned char *img = THIS->textureNode->image.startEditing(texSize, components); if (img) { rasterizeColumn(img+THIS->texIndex*texSize[0]*TEXTURE_COMPONENTS, texSize[0], v); THIS->texIndex++; if (THIS->texIndex == texSize[1]) THIS->texIndex = 0; } THIS->textureNode->image.finishEditing(); // animate texture coordinates THIS->updateTextureCoordinates(texSize[1]);}void SoPerfGraphP::updateSceneIfNecessary(const SbViewportRegion &vp, SbBool textureDataRequired){ if (!(vp == previousViewport) || !objData.posValid || !objData.sizeValid) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -