summaryrefslogtreecommitdiff
path: root/src/player/CircleNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/player/CircleNode.cpp')
-rw-r--r--src/player/CircleNode.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/player/CircleNode.cpp b/src/player/CircleNode.cpp
new file mode 100644
index 0000000..8d00a8e
--- /dev/null
+++ b/src/player/CircleNode.cpp
@@ -0,0 +1,291 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+#include "CircleNode.h"
+
+#include "TypeDefinition.h"
+
+#include "../base/Exception.h"
+#include "../base/MathHelper.h"
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+namespace avg {
+
+void CircleNode::registerType()
+{
+ TypeDefinition def = TypeDefinition("circle", "filledvectornode",
+ ExportedObject::buildObject<CircleNode>)
+ .addArg(Arg<glm::vec2>("pos", glm::vec2(0,0), false, offsetof(CircleNode, m_Pos)))
+ .addArg(Arg<float>("r", 1, false, offsetof(CircleNode, m_Radius)))
+ .addArg(Arg<float>("texcoord1", 0, false, offsetof(CircleNode, m_TC1)))
+ .addArg(Arg<float>("texcoord2", 1, false, offsetof(CircleNode, m_TC2)))
+ ;
+ TypeRegistry::get()->registerType(def);
+}
+
+CircleNode::CircleNode(const ArgList& args)
+ : FilledVectorNode(args)
+{
+ args.setMembers(this);
+}
+
+CircleNode::~CircleNode()
+{
+}
+
+const glm::vec2& CircleNode::getPos() const
+{
+ return m_Pos;
+}
+
+void CircleNode::setPos(const glm::vec2& pt)
+{
+ m_Pos = pt;
+ setDrawNeeded();
+}
+
+float CircleNode::getR() const
+{
+ return m_Radius;
+}
+
+void CircleNode::setR(float r)
+{
+ if (int(r) <= 0) {
+ throw Exception(AVG_ERR_OUT_OF_RANGE, "Circle radius must be a positive number.");
+ }
+ m_Radius = r;
+ setDrawNeeded();
+}
+
+float CircleNode::getTexCoord1() const
+{
+ return m_TC1;
+}
+
+void CircleNode::setTexCoord1(float tc)
+{
+ m_TC1 = tc;
+ setDrawNeeded();
+}
+
+float CircleNode::getTexCoord2() const
+{
+ return m_TC2;
+}
+
+void CircleNode::setTexCoord2(float tc)
+{
+ m_TC2 = tc;
+ setDrawNeeded();
+}
+
+void CircleNode::getElementsByPos(const glm::vec2& pos, vector<NodePtr>& pElements)
+{
+ if (glm::length(pos-m_Pos) <= m_Radius && reactsToMouseEvents()) {
+ pElements.push_back(getSharedThis());
+ }
+}
+
+void CircleNode::calcVertexes(const VertexDataPtr& pVertexData, Pixel32 color)
+{
+ // TODO: This gets called whenever the circle position changes and is quite
+ // expensive. Should be optimized away.
+ glm::vec2 firstPt1 = getCirclePt(0, m_Radius+getStrokeWidth()/2)+m_Pos;
+ glm::vec2 firstPt2 = getCirclePt(0, m_Radius-getStrokeWidth()/2)+m_Pos;
+ int curVertex = 0;
+ pVertexData->appendPos(firstPt1, glm::vec2(m_TC1, 0), color);
+ pVertexData->appendPos(firstPt2, glm::vec2(m_TC1, 1), color);
+ vector<glm::vec2> innerCircle;
+ getEigthCirclePoints(innerCircle, m_Radius-getStrokeWidth()/2);
+ vector<glm::vec2> outerCircle;
+ getEigthCirclePoints(outerCircle, m_Radius+getStrokeWidth()/2);
+
+ typedef vector<glm::vec2>::iterator Vec2It;
+ typedef vector<glm::vec2>::reverse_iterator Vec2RIt;
+ int i = 0;
+ for (Vec2It iit = innerCircle.begin()+1, oit = outerCircle.begin()+1;
+ iit != innerCircle.end(); ++iit, ++oit)
+ {
+ appendCirclePoint(pVertexData, *iit, *oit, color, i, curVertex);
+ }
+ for (Vec2RIt iit = innerCircle.rbegin()+1, oit = outerCircle.rbegin()+1;
+ iit != innerCircle.rend(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(-iit->y, -iit->x);
+ glm::vec2 oPt = glm::vec2(-oit->y, -oit->x);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2It iit = innerCircle.begin()+1, oit = outerCircle.begin()+1;
+ iit != innerCircle.end(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(-iit->y, iit->x);
+ glm::vec2 oPt = glm::vec2(-oit->y, oit->x);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2RIt iit = innerCircle.rbegin()+1, oit = outerCircle.rbegin()+1;
+ iit !=innerCircle.rend(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(iit->x, -iit->y);
+ glm::vec2 oPt = glm::vec2(oit->x, -oit->y);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2It iit = innerCircle.begin()+1, oit = outerCircle.begin()+1;
+ iit != innerCircle.end(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(-iit->x, -iit->y);
+ glm::vec2 oPt = glm::vec2(-oit->x, -oit->y);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2RIt iit = innerCircle.rbegin()+1, oit = outerCircle.rbegin()+1;
+ iit != innerCircle.rend(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(iit->y, iit->x);
+ glm::vec2 oPt = glm::vec2(oit->y, oit->x);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2It iit = innerCircle.begin()+1, oit = outerCircle.begin()+1;
+ iit != innerCircle.end(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(iit->y, -iit->x);
+ glm::vec2 oPt = glm::vec2(oit->y, -oit->x);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+ for (Vec2RIt iit = innerCircle.rbegin()+1, oit = outerCircle.rbegin()+1;
+ iit != innerCircle.rend(); ++iit, ++oit)
+ {
+ glm::vec2 iPt = glm::vec2(-iit->x, iit->y);
+ glm::vec2 oPt = glm::vec2(-oit->x, oit->y);
+ appendCirclePoint(pVertexData, iPt, oPt, color, i, curVertex);
+ }
+}
+
+void CircleNode::calcFillVertexes(const VertexDataPtr& pVertexData, Pixel32 color)
+{
+ glm::vec2 minPt = m_Pos-glm::vec2(m_Radius, m_Radius);
+ glm::vec2 maxPt = m_Pos+glm::vec2(m_Radius, m_Radius);
+ glm::vec2 centerTexCoord = calcFillTexCoord(m_Pos, minPt, maxPt);
+ pVertexData->appendPos(m_Pos, centerTexCoord, color);
+ int curVertex = 1;
+ glm::vec2 firstPt = getCirclePt(0, m_Radius)+m_Pos;
+ glm::vec2 firstTexCoord = calcFillTexCoord(firstPt, minPt, maxPt);
+ pVertexData->appendPos(firstPt, firstTexCoord, color);
+ vector<glm::vec2> circlePoints;
+ getEigthCirclePoints(circlePoints, m_Radius);
+
+ for (vector<glm::vec2>::iterator it = circlePoints.begin()+1;
+ it != circlePoints.end(); ++it)
+ {
+ glm::vec2 curPt = *it+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::reverse_iterator it = circlePoints.rbegin()+1;
+ it != circlePoints.rend(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(-it->y, -it->x)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::iterator it = circlePoints.begin()+1;
+ it != circlePoints.end(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(-it->y, it->x)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::reverse_iterator it = circlePoints.rbegin()+1;
+ it != circlePoints.rend(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(it->x, -it->y)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::iterator it = circlePoints.begin()+1;
+ it != circlePoints.end(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(-it->x, -it->y)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::reverse_iterator it = circlePoints.rbegin()+1;
+ it != circlePoints.rend(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(it->y, it->x)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::iterator it = circlePoints.begin()+1;
+ it != circlePoints.end(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(it->y, -it->x)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+ for (vector<glm::vec2>::reverse_iterator it = circlePoints.rbegin()+1;
+ it != circlePoints.rend(); ++it)
+ {
+ glm::vec2 curPt = glm::vec2(-it->x, it->y)+m_Pos;
+ appendFillCirclePoint(pVertexData, curPt, minPt, maxPt, color, curVertex);
+ }
+}
+
+void CircleNode::appendCirclePoint(const VertexDataPtr& pVertexData,
+ const glm::vec2& iPt, const glm::vec2& oPt, Pixel32 color, int& i,
+ int& curVertex)
+{
+ i++;
+ float ratio = (float(i)/getNumCircumferencePoints());
+ float curTC = (1-ratio)*m_TC1+ratio*m_TC2;
+ pVertexData->appendPos(oPt+m_Pos, glm::vec2(curTC, 0), color);
+ pVertexData->appendPos(iPt+m_Pos, glm::vec2(curTC, 1), color);
+ pVertexData->appendQuadIndexes(curVertex+1, curVertex, curVertex+3, curVertex+2);
+ curVertex += 2;
+}
+
+void CircleNode::appendFillCirclePoint(const VertexDataPtr& pVertexData,
+ const glm::vec2& curPt, const glm::vec2& minPt, const glm::vec2& maxPt,
+ Pixel32 color, int& curVertex)
+{
+ glm::vec2 curTexCoord = calcFillTexCoord(curPt, minPt, maxPt);
+ pVertexData->appendPos(curPt, curTexCoord, color);
+ pVertexData->appendTriIndexes(0, curVertex, curVertex+1);
+ curVertex++;
+}
+
+int CircleNode::getNumCircumferencePoints()
+{
+ return int(ceil((m_Radius*3)/8)*8);
+}
+
+void CircleNode::getEigthCirclePoints(vector<glm::vec2>& pts, float radius)
+{
+ int numPts = getNumCircumferencePoints();
+ for (int i = 0; i <= numPts/8; ++i) {
+ float ratio = (float(i)/numPts);
+ float angle = ratio*2*PI;
+ pts.push_back(getCirclePt(angle, radius));
+ }
+}
+
+glm::vec2 CircleNode::getCirclePt(float angle, float radius)
+{
+ return glm::vec2(sin(angle)*radius, -cos(angle)*radius);
+}
+
+}