PieSliceOverlay
A plugin overlay element for creating pie slices.
Welcome to the new Ogre Wiki!
If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
If you haven't done so already, be sure to visit the Wiki Portal to read about how the wiki works. Especially the Ogre Wiki Overview page.
Note: This code is hack of OgreBorderPanelOverlayElement and the OgreTextAreaOverlayElement. As such it may contain unnecessary code from these or may lack code which ogre needs. Use with caution!
Also uses a lot of trigonometry functions so probably not the fastest method.
Table of contents
PieSliceOverlayElement
PieSliceOverlayElement.h
#ifndef _PieSliceOverlayElement_H__ #define _PieSliceOverlayElement_H__ #include "OgreOverlayElement.h" #include "OgreOverlayElementFactory.h" #include "OgreFont.h" namespace Ogre { class _OgreExport PieSliceOverlayElement : public OverlayElement { public: /** Constructor. */ PieSliceOverlayElement(const String& name); virtual ~PieSliceOverlayElement(); virtual void initialise(void); void setStartAngle( Real angle ); Real getStartAngle() const; void setEndAngle( Real angle ); Real getEndAngle() const; /** See OverlayElement. */ virtual const String& getTypeName(void) const; /** See Renderable. */ void getRenderOperation(RenderOperation& op); /** Overridden from OverlayElement */ void setMaterialName(const String& matName); /** Overridden from OverlayElement */ void setMetricsMode(GuiMetricsMode gmm); /** Overridden from OverlayElement */ void _update(void); //----------------------------------------------------------------------------------------- /** Command object for setting the Start Angle. @see ParamCommand */ class CmdStartAngle : public ParamCommand { public: String doGet( const void* target ) const; void doSet( void* target, const String& val ); }; //----------------------------------------------------------------------------------------- /** Command object for setting the End Angle. @see ParamCommand */ class CmdEndAngle : public ParamCommand { public: String doGet( const void* target ) const; void doSet( void* target, const String& val ); }; protected: /// Flag indicating if this panel should be visual or just group things bool mTransparent; /// Render operation RenderOperation mRenderOp; /// Method for setting up base parameters for this class void addBaseParameters(void); static String msTypeName; static CmdStartAngle msCmdStartAngle; static CmdEndAngle msCmdEndAngle; /// Pie Slice angles Real mStartAngle; Real mEndAngle; /// Inherited function virtual void updatePositionGeometry(); /// Inherited function virtual void updateTextureGeometry(); }; /** Factory for creating PieSliceOverlayElement instances. */ class _OgreExport PieSliceOverlayElementFactory: public OverlayElementFactory { public: /** See OverlayElementFactory */ OverlayElement* createOverlayElement(const String& instanceName) { return new PieSliceOverlayElement(instanceName); } /** See OverlayElementFactory */ const String& getTypeName(void) const { static String name = "PieSlice"; return name; } }; } #endif
PieSliceOverlayElement.cpp
#include "OgreStableHeaders.h" #include "PieSliceOverlayElement.h" #include "OgreRoot.h" #include "OgreLogManager.h" #include "OgreOverlayManager.h" #include "OgreHardwareBufferManager.h" #include "OgreHardwareVertexBuffer.h" #include "OgreException.h" #include "OgreStringConverter.h" #include "OgreRenderSystem.h" #include "OgreMath.h" namespace Ogre { //--------------------------------------------------------------------- String PieSliceOverlayElement::msTypeName = "PieSlice"; PieSliceOverlayElement::CmdStartAngle PieSliceOverlayElement::msCmdStartAngle; PieSliceOverlayElement::CmdEndAngle PieSliceOverlayElement::msCmdEndAngle; //--------------------------------------------------------------------- #define POS_TEX_BINDING 0 //--------------------------------------------------------------------- PieSliceOverlayElement::PieSliceOverlayElement(const String& name) : OverlayElement(name) { mTransparent = false; mStartAngle = 0.0f; mEndAngle = Math::TWO_PI; if (createParamDictionary("PieSliceOverlayElement")) { addBaseParameters(); } } void PieSliceOverlayElement::initialise(void) { if (!mInitialised) { // Set up the render op // Combine positions and texture coords since they tend to change together // since character sizes are different mRenderOp.vertexData = new VertexData(); mRenderOp.vertexData->vertexCount = 5; // 8 cells, can't necessarily share vertices cos // texcoords may differ mRenderOp.vertexData->vertexStart = 0; size_t offset = 0; // Positions VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); // Texcoords decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); offset += VertexElement::getTypeSize(VET_FLOAT2); // Vertex buffer position and tex HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton(). createVertexBuffer( decl->getVertexSize(POS_TEX_BINDING), mRenderOp.vertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding; bind->setBinding(POS_TEX_BINDING, vbuf); mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; mRenderOp.useIndexes = true; // Index data mRenderOp.indexData = new IndexData(); mRenderOp.indexData->indexCount = 4 * 3; mRenderOp.indexData->indexStart = 0; mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton(). createIndexBuffer( HardwareIndexBuffer::IT_16BIT, mRenderOp.indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); ushort* pIdx = static_cast<ushort*>( mRenderOp.indexData->indexBuffer->lock( 0, mRenderOp.indexData->indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD) ); /* 0-----1 |\ /| | \ / | | 2 | | / \ | |/ \| 4-----3 */ *pIdx++ = 0; *pIdx++ = 2; *pIdx++ = 1; *pIdx++ = 2; *pIdx++ = 3; *pIdx++ = 1; *pIdx++ = 3; *pIdx++ = 2; *pIdx++ = 4; *pIdx++ = 4; *pIdx++ = 2; *pIdx++ = 0; mRenderOp.indexData->indexBuffer->unlock(); mInitialised = true; } } void PieSliceOverlayElement::updatePositionGeometry() { /* +-----+ +-----+ |\ 0 /| |\B B/| | \ / | |D\A/D| |3 : 1| | C:C | | / \ | |D/ \D| |/ 2 \| |/D D\| +-----+ +-----+ */ int startSeg, endSeg; Radian startAngle, endAngle,tempAngle; Radian aA,aB,aC,aD; Real sideC; Real left, right, top, bottom, centerX, centerY; left = _getDerivedLeft() * 2 - 1; right = left + (mWidth * 2); top = -((_getDerivedTop() * 2) - 1); bottom = top - (mHeight * 2); centerX = left + (right - left)/2; centerY = top + (bottom - top)/2; aB = Math::ATan((top - bottom)/(right - left)); aA = Radian(Math::PI) - aB -aB; aD = Radian(Math::HALF_PI) - aB; aC = Radian(Math::PI) - aA; sideC = Math::Sqrt(Math::Sqr(bottom - top) + Math::Sqr(right - left))/2.0f; startAngle = Radian(mStartAngle) + (aA/2.0); if (startAngle >= Radian(Math::TWO_PI)) startAngle -= Radian(Math::TWO_PI); endAngle = Radian(mEndAngle) + (aA/2.0); if (endAngle >= Radian(Math::TWO_PI)) endAngle -= Radian(Math::TWO_PI); if (startAngle < aA) startSeg = 0; else { if (startAngle < aA+aC) startSeg = 1; else { if (startAngle < aA+aC+aA) startSeg = 2; else { startSeg = 3; } } } if (endAngle < aA) endSeg = 0; else { if (endAngle < aA+aC) endSeg = 1; else { if (endAngle < aA+aC+aA) endSeg = 2; else { endSeg = 3; } } } // Set up the render op // Combine positions and texture coords since they tend to change together // since character sizes are different mRenderOp.vertexData = new VertexData(); if (startAngle>=endAngle) { if (startSeg == endSeg) mRenderOp.vertexData->vertexCount = 7; else { mRenderOp.vertexData->vertexCount = 3; int currentSeg = startSeg; while (currentSeg != endSeg) { mRenderOp.vertexData->vertexCount++; currentSeg++; currentSeg = currentSeg%4; } } } else { if (startSeg == endSeg) mRenderOp.vertexData->vertexCount = 3; else { mRenderOp.vertexData->vertexCount = 3; int currentSeg = startSeg; while (currentSeg != endSeg) { mRenderOp.vertexData->vertexCount++; currentSeg++; currentSeg = currentSeg%4; } } } mRenderOp.vertexData->vertexStart = 0; size_t offset = 0; // Positions VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration; decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); // Texcoords decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0); offset += VertexElement::getTypeSize(VET_FLOAT2); // Vertex buffer position and tex HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton(). createVertexBuffer( decl->getVertexSize(POS_TEX_BINDING), mRenderOp.vertexData->vertexCount, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding; bind->setBinding(POS_TEX_BINDING, vbuf); float* pPos = static_cast<float*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) ); // Use the furthest away depth value, since materials should have depth-check off // This initialised the depth buffer for any 3D objects in front Real zValue = Root::getSingleton().getRenderSystem()->getMaximumDepthInputValue(); *pPos++ = centerX; *pPos++ = centerY; *pPos++ = zValue; *pPos++ = 0.5; *pPos++ = 0.5; // calc start values here Real startX,startY,startU,startV,sideA; Radian angle; switch(startSeg) { case 0 : { angle = startAngle; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aB); startX = sideA+left; startY = top; startU = sideA/(right - left); startV = 0.0; break; } case 1 : { angle = startAngle-aA; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aD); startX = right; startY = top-sideA; startU = 1.0; startV = sideA/(top-bottom); break; } case 2 : { angle = startAngle-aA-aC; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aB); startX = right-sideA; startY = bottom; startU = 1.0-(sideA/(right - left)); startV = 1.0; break; } case 3 : { angle = startAngle-aA-aC-aA; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aD); startX = left; startY = bottom+sideA; startU = 0.0; startV = 1.0-(sideA/(top-bottom)); break; } } *pPos++ = startX; *pPos++ = startY; *pPos++ = zValue; *pPos++ = startU; *pPos++ = startV; int currentSeg = startSeg; int segCount = 1; bool largeSlice = false; if(startAngle >= endAngle) largeSlice = true; while (currentSeg != endSeg || largeSlice) { largeSlice = false; switch (currentSeg) { case 0 : { *pPos++ = right; *pPos++ = top; *pPos++ = zValue; *pPos++ = 1.0; *pPos++ = 0.0; break; } case 1 : { *pPos++ = right; *pPos++ = bottom; *pPos++ = zValue; *pPos++ = 1.0; *pPos++ = 1.0; break; } case 2 : { *pPos++ = left; *pPos++ = bottom; *pPos++ = zValue; *pPos++ = 0.0; *pPos++ = 1.0; break; } case 3 : { *pPos++ = left; *pPos++ = top; *pPos++ = zValue; *pPos++ = 0.0; *pPos++ = 0.0; break; } } currentSeg++; currentSeg = currentSeg % 4; segCount++; } // calc start values here Real endX,endY,endU,endV; switch(endSeg) { case 0 : { angle = endAngle; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aB); endX = sideA+left; endY = top; endU = sideA/(right - left); endV = 0.0; break; } case 1 : { angle = endAngle-aA; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aD); endX = right; endY = top-sideA; endU = 1.0; endV = sideA/(top-bottom); break; } case 2 : { angle = endAngle-aA-aC; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aB); endX = right-sideA; endY = bottom; endU = 1.0-(sideA/(right - left)); endV = 1.0; break; } case 3 : { angle = endAngle-aA-aC-aA; sideA = (Math::Sin(angle)*sideC)/Math::Sin(Radian(Math::PI)-angle-aD); endX = left; endY = bottom+sideA; endU = 0.0; endV = 1.0-(sideA/(top-bottom)); break; } } *pPos++ = endX; *pPos++ = endY; *pPos++ = zValue; *pPos++ = endU; *pPos++ = endV; vbuf->unlock(); mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; mRenderOp.useIndexes = true; // Index data mRenderOp.indexData = new IndexData(); mRenderOp.indexData->indexCount = (segCount+1)*3; mRenderOp.indexData->indexStart = 0; mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton(). createIndexBuffer( HardwareIndexBuffer::IT_16BIT, mRenderOp.indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY); ushort* pIdx = static_cast<ushort*>( mRenderOp.indexData->indexBuffer->lock( 0, mRenderOp.indexData->indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD) ); /* 5-6-1-2 |\ /| | \ / | | 0 | | / \ | |/ \| 4-----3 */ if (segCount>0) { *pIdx++ = 0; *pIdx++ = 2; *pIdx++ = 1; } if (segCount>1) { *pIdx++ = 0; *pIdx++ = 3; *pIdx++ = 2; } if (segCount>2) { *pIdx++ = 0; *pIdx++ = 4; *pIdx++ = 3; } if (segCount>3) { *pIdx++ = 0; *pIdx++ = 5; *pIdx++ = 4; } if (segCount>4) { *pIdx++ = 0; *pIdx++ = 6; *pIdx++ = 5; } mRenderOp.indexData->indexBuffer->unlock(); } void PieSliceOverlayElement::updateTextureGeometry() { // Nothing to do, we combine positions and textures } void PieSliceOverlayElement::setStartAngle( Real angle ) { mStartAngle = angle; mGeomPositionsOutOfDate = true; } Real PieSliceOverlayElement::getStartAngle() const { return mStartAngle; } void PieSliceOverlayElement::setEndAngle( Real angle ) { mEndAngle = angle; mGeomPositionsOutOfDate = true; } Real PieSliceOverlayElement::getEndAngle() const { return mEndAngle; } //--------------------------------------------------------------------- PieSliceOverlayElement::~PieSliceOverlayElement() { delete mRenderOp.vertexData; } //--------------------------------------------------------------------- const String& PieSliceOverlayElement::getTypeName(void) const { return msTypeName; } //--------------------------------------------------------------------- void PieSliceOverlayElement::getRenderOperation(RenderOperation& op) { op = mRenderOp; } //--------------------------------------------------------------------- void PieSliceOverlayElement::setMaterialName(const String& matName) { OverlayElement::setMaterialName(matName); } //--------------------------------------------------------------------- void PieSliceOverlayElement::addBaseParameters(void) { OverlayElement::addBaseParameters(); ParamDictionary* dict = getParamDictionary(); dict->addParameter(ParameterDef("start_angle", "Sets the start angle." , PT_REAL), &msCmdStartAngle); dict->addParameter(ParameterDef("end_angle", "Sets the end angle." , PT_REAL), &msCmdEndAngle); } //----------------------------------------------------------------------- void PieSliceOverlayElement::setMetricsMode(GuiMetricsMode gmm) { Real vpWidth, vpHeight; vpWidth = (Real) (OverlayManager::getSingleton().getViewportWidth()); vpHeight = (Real) (OverlayManager::getSingleton().getViewportHeight()); OverlayElement::setMetricsMode(gmm); } //----------------------------------------------------------------------- void PieSliceOverlayElement::_update(void) { Real vpWidth, vpHeight; vpWidth = (Real) (OverlayManager::getSingleton().getViewportWidth()); vpHeight = (Real) (OverlayManager::getSingleton().getViewportHeight()); if (mMetricsMode != GMM_RELATIVE && (OverlayManager::getSingleton().hasViewportChanged() || mGeomPositionsOutOfDate)) { // Recalc character size mGeomPositionsOutOfDate = true; } OverlayElement::_update(); } //--------------------------------------------------------------------------------------------- // StartAngle command object // String PieSliceOverlayElement::CmdStartAngle::doGet( const void* target ) const { return StringConverter::toString( static_cast< const PieSliceOverlayElement* >( target )->getStartAngle() ); } void PieSliceOverlayElement::CmdStartAngle::doSet( void* target, const String& val ) { static_cast< PieSliceOverlayElement* >( target )->setStartAngle( StringConverter::parseReal( val ) ); } //--------------------------------------------------------------------------------------------- // EndAngle command object // String PieSliceOverlayElement::CmdEndAngle::doGet( const void* target ) const { return StringConverter::toString( static_cast< const PieSliceOverlayElement* >( target )->getEndAngle() ); } void PieSliceOverlayElement::CmdEndAngle::doSet( void* target, const String& val ) { static_cast< PieSliceOverlayElement* >( target )->setEndAngle( StringConverter::parseReal( val ) ); } }
Usage
Create factory.
bool MyApplication::setup( void ) { mRoot = new Root(); mPieSliceFactory = new PieSliceOverlayElementFactory(); OverlayManager::getSingleton().addOverlayElementFactory(mPieSliceFactory); . . .
Then create a normal overlay element, passing parameter for angles. NOTE: Angles need to be in radian.
Overlay* PieSliceOverlay = OverlayManager::getSingleton().create("PieSliceOverlay"); PSpecialOverlay->setZOrder(2); NewPanel = static_cast<OverlayContainer*>(OverlayManager::getSingleton().createOverlayElement ("PieSlice", "Minority")); NewPanel->setMaterialName("PieChart/Blue"); NewPanel->setPosition(0.1f,0.1f); NewPanel->setWidth(0.8f); NewPanel->setHeight(0.8f); NewPanel->setParameter("start_angle", StringConverter::toString(Math::fDeg2Rad * 0.0f)); NewPanel->setParameter("end_angle", StringConverter::toString(Math::fDeg2Rad * 60.0f)); PSpecialOverlay->add2D(NewPanel); NewPanel = static_cast<OverlayContainer*>(OverlayManager::getSingleton().createOverlayElement ("PieSlice", "Magority")); NewPanel->setMaterialName("PieChart/Red"); NewPanel->setPosition(0.1f,0.1f); NewPanel->setWidth(0.8f); NewPanel->setHeight(0.8f); NewPanel->setParameter("start_angle", StringConverter::toString(Math::fDeg2Rad * 60.0f)); NewPanel->setParameter("end_angle", StringConverter::toString(Math::fDeg2Rad * 360.0f)); PSpecialOverlay->add2D(NewPanel); PSpecialOverlay->show();
Contributors to this page: jacmoe
and
Spacegaier
.
Page last modified on Saturday 26 of December, 2009 00:54:21 UTC by jacmoe
.
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.
Sidebar
Search box
Online users
107
online users

