Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

moved to github

  • Loading branch information...
commit d8a7ed86ad4c18afcb26e5487c01524374d24757 0 parents
@emarschner authored
Showing with 23,397 additions and 0 deletions.
  1. +56 −0 Color.cpp
  2. +178 −0 Engine.cpp
  3. +118 −0 MyAudio.cpp
  4. +692 −0 Network.cpp
  5. +1 −0  Point.cpp
  6. +275 −0 Shape.cpp
  7. +1,416 −0 Widget.cpp
  8. +24 −0 include/Color.h
  9. +22 −0 include/Common.h
  10. +55 −0 include/Engine.h
  11. +40 −0 include/MyAudio.h
  12. +119 −0 include/Network.h
  13. +51 −0 include/Point.h
  14. +117 −0 include/Shape.h
  15. +395 −0 include/Widget.h
  16. +81 −0 ip/IpEndpointName.cpp
  17. +84 −0 ip/IpEndpointName.h
  18. +49 −0 ip/NetworkingUtils.h
  19. +43 −0 ip/PacketListener.h
  20. +40 −0 ip/TimerListener.h
  21. +158 −0 ip/UdpSocket.h
  22. +57 −0 ip/posix/NetworkingUtils.cpp
  23. +546 −0 ip/posix/UdpSocket.cpp
  24. +88 −0 ip/win32/NetworkingUtils.cpp
  25. +521 −0 ip/win32/UdpSocket.cpp
  26. +496 −0 main.cpp
  27. +68 −0 makefile
  28. +73 −0 osc/MessageMappingOscPacketListener.h
  29. +54 −0 osc/OscException.h
  30. +69 −0 osc/OscHostEndianness.h
  31. +639 −0 osc/OscOutboundPacketStream.cpp
  32. +142 −0 osc/OscOutboundPacketStream.h
  33. +72 −0 osc/OscPacketListener.h
  34. +241 −0 osc/OscPrintReceivedElements.cpp
  35. +49 −0 osc/OscPrintReceivedElements.h
  36. +722 −0 osc/OscReceivedElements.cpp
  37. +486 −0 osc/OscReceivedElements.h
  38. +40 −0 osc/OscTypes.cpp
  39. +178 −0 osc/OscTypes.h
  40. +178 −0 stk/ADSR.h
  41. +146 −0 stk/Asymp.h
  42. +153 −0 stk/BandedWG.h
  43. +127 −0 stk/BeeThree.h
  44. +186 −0 stk/BiQuad.h
  45. +151 −0 stk/Blit.h
  46. +148 −0 stk/BlitSaw.h
  47. +170 −0 stk/BlitSquare.h
  48. +144 −0 stk/BlowBotl.h
  49. +185 −0 stk/BlowHole.h
  50. +150 −0 stk/BowTable.h
  51. +157 −0 stk/Bowed.h
  52. +147 −0 stk/Brass.h
  53. +172 −0 stk/Chorus.h
  54. +152 −0 stk/Clarinet.h
  55. +138 −0 stk/Cubic.h
  56. +188 −0 stk/Delay.h
  57. +207 −0 stk/DelayA.h
  58. +203 −0 stk/DelayL.h
  59. +130 −0 stk/Drummer.h
  60. +120 −0 stk/Echo.h
  61. +79 −0 stk/Effect.h
  62. +130 −0 stk/Envelope.h
  63. +122 −0 stk/FM.h
  64. +135 −0 stk/FMVoices.h
  65. +164 −0 stk/FileLoop.h
  66. +141 −0 stk/FileRead.h
  67. +116 −0 stk/FileWrite.h
  68. +196 −0 stk/FileWvIn.h
  69. +102 −0 stk/FileWvOut.h
  70. +124 −0 stk/Filter.h
  71. +155 −0 stk/Fir.h
  72. +166 −0 stk/Flute.h
  73. +190 −0 stk/FormSwep.h
  74. +41 −0 stk/Function.h
  75. +50 −0 stk/Generator.h
  76. +209 −0 stk/Granulate.h
  77. +126 −0 stk/HevyMetl.h
  78. +202 −0 stk/Iir.h
  79. +157 −0 stk/InetWvIn.h
  80. +98 −0 stk/InetWvOut.h
  81. +102 −0 stk/Instrmnt.h
  82. +166 −0 stk/JCRev.h
  83. +112 −0 stk/JetTable.h
  84. +143 −0 stk/Mandolin.h
  85. +144 −0 stk/Mesh2D.h
  86. +166 −0 stk/Messager.h
  87. +135 −0 stk/MidiFileIn.h
  88. +154 −0 stk/Modal.h
  89. +65 −0 stk/ModalBar.h
  90. +108 −0 stk/Modulate.h
  91. +125 −0 stk/Moog.h
  92. +74 −0 stk/Mutex.h
  93. +160 −0 stk/NRev.h
  94. +83 −0 stk/Noise.h
  95. +134 −0 stk/OnePole.h
  96. +134 −0 stk/OneZero.h
  97. +140 −0 stk/PRCRev.h
  98. +127 −0 stk/PercFlut.h
  99. +55 −0 stk/Phonemes.h
  100. +107 −0 stk/PitShift.h
  101. +117 −0 stk/Plucked.h
  102. +113 −0 stk/PoleZero.h
  103. +143 −0 stk/ReedTable.h
  104. +127 −0 stk/Resonate.h
  105. +128 −0 stk/Rhodey.h
  106. +980 −0 stk/RtAudio.h
  107. +60 −0 stk/RtError.h
  108. +306 −0 stk/RtMidi.h
  109. +125 −0 stk/RtWvIn.h
  110. +96 −0 stk/RtWvOut.h
  111. +129 −0 stk/SKINI.msg
  112. +135 −0 stk/SKINI.tbl
  113. +78 −0 stk/Sampler.h
  114. +166 −0 stk/Saxofony.h
  115. +168 −0 stk/Shakers.h
  116. +129 −0 stk/Simple.h
  117. +159 −0 stk/SineWave.h
  118. +136 −0 stk/SingWave.h
  119. +129 −0 stk/Sitar.h
  120. +122 −0 stk/Skini.h
  121. +89 −0 stk/Socket.h
  122. +79 −0 stk/Sphere.h
  123. +154 −0 stk/StifKarp.h
  124. +545 −0 stk/Stk.h
  125. +216 −0 stk/TapDelay.h
  126. +65 −0 stk/TcpClient.h
  127. +65 −0 stk/TcpServer.h
  128. +98 −0 stk/Thread.h
  129. +125 −0 stk/TubeBell.h
  130. +158 −0 stk/Twang.h
  131. +153 −0 stk/TwoPole.h
  132. +149 −0 stk/TwoZero.h
  133. +76 −0 stk/UdpSocket.h
  134. +68 −0 stk/Vector3D.h
  135. +161 −0 stk/VoicForm.h
  136. +219 −0 stk/Voicer.h
  137. +128 −0 stk/Whistle.h
  138. +128 −0 stk/Wurley.h
  139. +46 −0 stk/WvIn.h
  140. +85 −0 stk/WvOut.h
56 Color.cpp
@@ -0,0 +1,56 @@
+#include <stdlib.h>
+#include <time.h>
+
+#include "Color.h"
+
+Color Color::operator+(Color color)
+{
+ Color c;
+ c.r = color.r + this->r;
+ c.g = color.g + this->g;
+ c.b = color.b + this->b;
+ c.a = color.a + this->a;
+
+ return c;
+}
+
+Color Color::operator-(Color color)
+{
+ Color c;
+ c.r = this->r - color.r;
+ c.g = this->g - color.g;
+ c.b = this->b - color.b;
+ c.a = this->a - color.a;
+
+ return c;
+}
+
+Color Color::operator*(float num)
+{
+ Color c;
+ c.r = this->r * num;
+ c.g = this->g * num;
+ c.b = this->b * num;
+ c.a = this->a * num;
+
+ return c;
+}
+
+Color Color::operator/(float num)
+{
+ Color c;
+ c.r = this->r / num;
+ c.g = this->g / num;
+ c.b = this->b / num;
+ c.a = this->a / num;
+
+ return c;
+}
+
+Color Color::generateRandomColor()
+{
+ Color c((float)(rand() % 100) / 100,
+ (float)(rand() % 100) / 100,
+ (float)(rand() % 100) / 100);
+ return c;
+}
178 Engine.cpp
@@ -0,0 +1,178 @@
+#include <iostream>
+#include <stdlib.h>
+
+#ifdef __MACOSX_CORE__
+#include <GLUT/glut.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#endif
+
+#include "Engine.h"
+#include "Network.h"
+
+Engine::Engine() :
+ m_selectedWidget(NULL),
+ m_newRoundPad(NULL),
+ m_mouseCursor(new Spiral(Point2D(0, 0), 360, 5, 0, 5)),
+ m_cursorText(new Text(Point2D(-100, 100), "")),
+ m_textMode(TEXT_REPLACE),
+ m_xLine(Point2D(0, 0), Point2D(0, 0)),
+ m_yLine(Point2D(0, 0), Point2D(0, 0))
+{
+ m_mouseCursor->setColor(Color(51 / (float)255, 153 / (float)255, 1, 1));
+ m_mouseCursor->setFilled(true);
+ m_cursorText->setColor(Color(51 / (float)255, 153 / (float)255, 1, 1));
+ m_xLine.setColor(Color(0.95, 0.95, 0.95, 0.5));
+ m_xLine.setLineWidth(0.1);
+ m_yLine.setColor(Color(0.95, 0.95, 0.95, 0.5));
+ m_yLine.setLineWidth(0.1);
+ m_parent = this;
+}
+
+Engine::~Engine()
+{
+ delete m_mouseCursor;
+ delete m_cursorText;
+}
+
+bool Engine::handleDraw(float x, float y)
+{
+ m_maxRadius = FLT_MAX;
+ for (std::vector<Widget*>::iterator cit = m_children.begin(); cit != m_children.end(); cit++) {
+ RoundPad* pad = dynamic_cast<RoundPad*>(*cit);
+ if (pad)
+ m_maxRadius = std::min(m_maxRadius,
+ Point2D::distance(m_mouseDownPos,
+ pad->getCenter()) - pad->getRadius());
+ }
+
+ if (m_newRoundPad)
+ m_newRoundPad->setRadius(std::min(m_maxRadius,
+ Point2D::distance(m_newRoundPad->getCenter(),
+ Point2D(x, y))));
+ else
+ m_newRoundPad = new RoundPad(m_mouseDownPos, std::min(m_maxRadius,
+ Point2D::distance(m_mouseDownPos,
+ Point2D(x, y))));
+ return true;
+}
+
+bool Engine::handleDrawEnd(float x, float y)
+{
+ if (m_newRoundPad) {
+ Widget::getAll()->insert(WidgetData(m_newRoundPad->getUuid(), m_newRoundPad));
+ this->addChild(m_newRoundPad);
+ s_network->sendObjectMessage(m_newRoundPad);
+ m_newRoundPad = NULL;
+ }
+ return true;
+}
+
+bool Engine::onKeyDown(unsigned char key, float x, float y)
+{
+ switch(key) {
+ case 127:
+ if (m_textMode == TEXT_REPLACE && m_selectedWidget &&
+ (m_selectedWidget = m_selectedWidget->getParent()->removeChild(m_selectedWidget))) {
+ for (int i = 0; i < 5; i++)
+ s_network->sendObjectMessage(m_selectedWidget, true);
+ delete m_selectedWidget;
+ m_selectedWidget = NULL;
+ } else if (m_textMode == TEXT_APPEND) {
+ std::string text;
+ if (m_selectedWidget && dynamic_cast<RoundPad*>(m_selectedWidget)) {
+ RoundPad* pad = (RoundPad*)m_selectedWidget;
+ text = pad->getCommentText()->getText();
+ pad->setCommentText(text.substr(0, text.length() - 1));
+ s_network->sendRoundPadTextMessage(pad);
+ } else {
+ text = m_cursorText->getText();
+ m_cursorText->setText(text.substr(0, text.length() - 1));
+ s_network->sendPeerTextMessage(m_cursorText->getText());
+ }
+ }
+ break;
+ case 27:
+ exit(1);
+ break;
+ default:
+ std::string character(1, key);
+ if (m_selectedWidget && dynamic_cast<RoundPad*>(m_selectedWidget)) {
+ RoundPad* pad = (RoundPad*)m_selectedWidget;
+ if (m_textMode == TEXT_REPLACE) {
+ pad->setCommentText(character);
+ m_textMode = TEXT_APPEND;
+ } else
+ pad->appendCommentText(character);
+ s_network->sendRoundPadTextMessage(pad);
+ } else {
+ if (m_textMode == TEXT_REPLACE) {
+ m_cursorText->setText(character);
+ m_textMode = TEXT_APPEND;
+ } else
+ m_cursorText->setText(m_cursorText->getText() + character);
+ s_network->sendPeerTextMessage(m_cursorText->getText());
+ }
+ }
+
+ glutPostRedisplay( );
+ return true;
+}
+
+void Engine::draw()
+{
+ // clear the color and depth buffers
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // Draw the elements
+ for (int i = 0; i < m_children.size(); i ++)
+ m_children[i]->draw();
+
+ // Draw in-progress new round pad, if any
+ if (m_newRoundPad)
+ m_newRoundPad->draw();
+
+ Network::PeerMap* peers = s_network->getPeers();
+ for (Network::PeerMap::iterator pit = peers->begin(); pit != peers->end(); pit++)
+ pit->second->draw();
+
+ m_xLine.draw();
+ m_yLine.draw();
+ m_mouseCursor->draw();
+ m_cursorText->draw();
+}
+
+void Engine::setMouseCursorPosition(float x, float y)
+{
+ m_mouseCursor->setCenter(Point2D(x, y));
+ m_cursorText->setPos(Point2D(x + 10, y + 5));
+
+ for (std::vector<Widget *>::iterator cit = m_children.begin(); cit != m_children.end(); cit++)
+ if ((*cit)->hitTest(x, y)) {
+ m_xLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+ m_yLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+ return;
+ }
+
+ m_xLine.setPoints(Point2D(0, y), Point2D(m_width, y));
+ m_yLine.setPoints(Point2D(x, 0), Point2D(x, m_height));
+ return;
+}
+
+void Engine::setSize(int w, int h)
+{
+ m_width = w;
+ m_height = h;
+}
+
+void Engine::setCursorText(std::string text)
+{
+ m_cursorText->setText(text);
+}
118 MyAudio.cpp
@@ -0,0 +1,118 @@
+//
+// MyAudio.cpp
+// stkExample
+//
+// Created by Jorge Herrera on 2011-10-26.
+//
+// ------------------
+// Class to abstract audio stream
+// IMPORTANT: it will quit the app if it can't setup or start!!!
+
+
+#include "MyAudio.h"
+#include <iostream>
+#include <cstdlib>
+
+// constructor
+MyAudio::MyAudio( unsigned int nChann, float sr, unsigned int buffSize, RtAudioFormat format )
+{
+ m_audio = NULL;
+ m_numChannels = nChann;
+ m_sampleRate = sr;
+ m_bufferSize = buffSize;
+ m_format = format;
+}
+
+// destructor
+MyAudio::~MyAudio()
+{
+ if( m_audio )
+ {
+ stop();
+ delete m_audio;
+ }
+}
+
+// RtAudio configuration
+void MyAudio::setup( RtAudioCallback callback, void * userData )
+{
+ if( !callback )
+ {
+ std::cerr << "No callback provided!" << std::endl;
+ exit(1);
+ }
+
+ try
+ {
+ m_audio = new RtAudio();
+ }
+ catch( RtError & err ) {
+ err.printMessage();
+ exit(1);
+ }
+
+ if( m_audio->getDeviceCount() < 1 )
+ {
+ // nopes
+ std::cout << "no audio devices found!" << std::endl;
+ exit(1);
+ }
+
+ // let RtAudio print messages to stderr.
+ m_audio->showWarnings( true );
+
+ // set input and output parameters
+ RtAudio::StreamParameters iParams, oParams;
+ iParams.deviceId = m_audio->getDefaultInputDevice();
+ iParams.nChannels = m_numChannels;
+ iParams.firstChannel = 0;
+ oParams.deviceId = m_audio->getDefaultOutputDevice();
+ oParams.nChannels = m_numChannels;
+ oParams.firstChannel = 0;
+
+ // set the callback and start stream
+ try
+ {
+ m_audio->openStream( &oParams,
+ &iParams,
+ m_format,
+ m_sampleRate,
+ &m_bufferSize,
+ callback,
+ userData);
+
+ std::cerr << "Buffer size defined by RtAudio: " << m_bufferSize << std::endl;
+ }
+ catch( RtError & err )
+ {
+ err.printMessage();
+ exit(1);
+ }
+
+}
+
+// start audio stream
+void MyAudio::start()
+{
+ try
+ {
+ m_audio->startStream();
+ // test RtAudio functionality for reporting latency.
+ std::cout << "stream latency: " << m_audio->getStreamLatency() << " frames" << std::endl;
+ }
+ catch( RtError & err )
+ {
+ err.printMessage();
+ exit(1);
+ }
+}
+
+// stop audio stream
+void MyAudio::stop()
+{
+ if( m_audio )
+ {
+ if ( m_audio->isStreamRunning() ) m_audio->stopStream();
+ if ( m_audio->isStreamOpen() ) m_audio->closeStream();
+ }
+}
692 Network.cpp
@@ -0,0 +1,692 @@
+#include "include/Network.h"
+
+// ===================
+// Peer implementation
+// ===================
+
+Peer::Peer(const IpEndpointName& endpoint) :
+ m_location(endpoint),
+ m_socket(new UdpTransmitSocket(m_location)),
+ m_mousePosition(Point2D(-100, -100)),
+ m_mousePositionText(new Text(Point2D(-100, -100), "")),
+ m_mouseDown(false),
+ m_circle(new Spiral(m_mousePosition, 360, 5, 0, 5))
+{
+ m_circle->setColor(Color(1, 0, 1));
+ m_mousePositionText->setColor(Color(1, 0, 1));
+}
+
+Peer::Peer(const char* host, const int port) :
+ m_location(IpEndpointName(host, port)),
+ m_socket(new UdpTransmitSocket(m_location)),
+ m_mousePosition(Point2D(-100, -100)),
+ m_mousePositionText(new Text(Point2D(-100, -100), "")),
+ m_mouseDown(false),
+ m_circle(new Spiral(m_mousePosition, 360, 5, 0, 5))
+{
+ m_circle->setColor(Color(1, 0, 1));
+ m_mousePositionText->setColor(Color(1, 0, 1));
+}
+
+Peer::~Peer()
+{
+ delete m_socket;
+ delete m_circle;
+ delete m_mousePositionText;
+}
+
+void Peer::sendMessage(const osc::OutboundPacketStream& msg)
+{
+ m_socket->Send(msg.Data(), msg.Size());
+}
+
+const IpEndpointName& Peer::getLocation()
+{
+ return m_location;
+}
+
+void Peer::setMousePosition(float x, float y)
+{
+ m_mousePosition.x = x;
+ m_mousePosition.y = y;
+}
+
+const Point2D& Peer::getMousePosition()
+{
+ return m_mousePosition;
+}
+
+void Peer::setDisplayName(std::string displayName)
+{
+ m_mousePositionText->setText(displayName);
+}
+
+void Peer::setMouseDown(bool down)
+{
+ m_mouseDown = down;
+}
+
+const bool Peer::getMouseDown()
+{
+ return m_mouseDown;
+}
+
+void Peer::draw()
+{
+ m_circle->setCenter(m_mousePosition);
+ m_circle->setFilled(false);
+ m_circle->draw();
+ if (m_mouseDown) {
+ m_circle->setFilled(true);
+ m_circle->draw();
+ }
+ if (m_mousePositionText)
+ {
+ m_mousePositionText->setPos(Point2D(m_mousePosition.x + 10, m_mousePosition.y + 5));
+ m_mousePositionText->draw();
+ }
+}
+
+// ======================
+// Network implementation
+// ======================
+
+Network::Network() : m_engine(NULL)
+{
+ m_handlers.insert(HandlerData("/network/peer/up", &Network::handlePeerUpMessage));
+ m_handlers.insert(HandlerData("/network/peer/down", &Network::handlePeerDownMessage));
+ m_handlers.insert(HandlerData("/network/peer/text", &Network::handlePeerTextMessage));
+
+ m_handlers.insert(HandlerData("/mouse/position", &Network::handleMousePositionMessage));
+
+ m_handlers.insert(HandlerData("/object/plucker", &Network::handlePluckerMessage));
+ m_handlers.insert(HandlerData("/object/pad", &Network::handleObjectPadMessage));
+ m_handlers.insert(HandlerData("/object/pad/text", &Network::handleObjectPadTextMessage));
+ m_handlers.insert(HandlerData("/object/track/spiral", &Network::handleObjectSpiralMessage));
+ m_handlers.insert(HandlerData("/object/track/line", &Network::handleObjectLineMessage));
+ m_handlers.insert(HandlerData("/object/track/string", &Network::handleObjectStringMessage));
+ m_handlers.insert(HandlerData("/object/delete", &Network::handleObjectDeleteMessage));
+ m_handlers.insert(HandlerData("/object/query", &Network::handleObjectQueryMessage));
+}
+
+Network::~Network()
+{
+ sendPeerDownMessage();
+}
+
+int Network::getPort()
+{
+ return m_port;
+}
+
+void Network::rescueOrphans()
+{
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit, oit;
+ for (oit = m_orphans.begin(); oit != m_orphans.end(); oit++) {
+ if ((wit = widgets->find(oit->first)) != widgets->end()) { // parent found?!!
+ // De-orphan it
+ wit->second->addChild(oit->second);
+ if (dynamic_cast<SpiralTrack*>(oit->second))
+ ((SpiralTrack*)oit->second)->setCenter(((RoundPad*)wit->second)->getCenter());
+ else if (dynamic_cast<String*>(oit->second))
+ ((String*)oit->second)->setPadRadius(((RoundPad*)wit->second)->getRadius());
+ wit = widgets->insert(WidgetData(oit->second->getUuid(), oit->second)).first;
+ m_orphans.erase(oit);
+
+ // Tell the world about the now ex-orphan
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+ wit->second->toOutboundPacketStream(ps);
+ broadcast(ps);
+ }
+ }
+}
+
+Network::PeerMap* Network::getPeers()
+{
+ return &m_peers;
+}
+
+void Network::setEngine(Engine* engine)
+{
+ m_engine = engine;
+}
+
+void Network::listen(int port)
+{
+ m_port = port;
+ if (!m_thread.start(listen, this)) {
+ std::cerr << "Error when creating listener thread!" << std::endl;
+ exit(1);
+ }
+
+ usleep(1000000); // listener thread grace period
+ sendPeerUpMessage();
+}
+
+void* Network::listen(void* network)
+{
+ int port = ((Network*)network)->getPort();
+ std::cerr << "Starting to listen on port: " << port << std::endl;
+ UdpListeningReceiveSocket s(IpEndpointName(IpEndpointName::ANY_ADDRESS, port), (Network*)network);
+ s.Run();
+ std::cerr << "Exiting listening thread!" << std::endl;
+}
+
+void Network::broadcast(const osc::OutboundPacketStream& stream)
+{
+ for (PeerMap::iterator pit = m_peers.begin(); pit != m_peers.end(); pit++)
+ pit->second->sendMessage(stream);
+}
+
+void Network::addPeer(Peer& peer)
+{
+ if (m_peers.find(peer.getLocation()) == m_peers.end())
+ m_peers.insert(PeerData(peer.getLocation(), &peer));
+}
+
+void Network::ProcessMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ try {
+ std::string address = m.AddressPattern();
+ if (address != "/mouse/position") // too noisy!
+ std::cerr << "Port " << m_port << " >>> Received '" << address << "' message with arguments: ";
+ (this->*(m_handlers[address]))(m, remoteEndpoint);
+ } catch(osc::Exception& e) {
+ std::cerr << "error while parsing message: "
+ << m.AddressPattern() << ": " << e.what() << std::endl;
+ }
+
+ rescueOrphans();
+}
+
+void Network::sendPeerUpMessage()
+{
+ sendPeerMessage("up");
+}
+
+void Network::sendPeerDownMessage()
+{
+ sendPeerMessage("down");
+}
+
+void Network::sendPeerMessage(const std::string type)
+{
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+ ps << osc::BeginMessage(("/network/peer/" + type).c_str()) << (osc::int64)0 << (osc::int32)m_port << osc::EndMessage;
+ broadcast(ps);
+}
+
+void Network::sendPeerTextMessage(const std::string msg)
+{
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+ ps << osc::BeginMessage("/network/peer/text")
+ << (osc::int64)0
+ << (osc::int32)m_port
+ << osc::Symbol(msg.c_str())
+ << osc::EndMessage;
+ broadcast(ps);
+}
+
+void Network::sendMousePosition(const float x, const float y, const bool down)
+{
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+ ps << osc::BeginMessage("/mouse/position") << m_port << x << y << down << osc::EndMessage;
+ //std::cerr << m_port << ", " << x << ", " << y << std::endl;
+ broadcast(ps);
+}
+
+void Network::handlePeerUpMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::int32 port;
+ osc::int64 address;
+ m.ArgumentStream() >> address >> port >> osc::EndMessage;
+ if ((long)address == 0)
+ address = remoteEndpoint.address;
+ char ipStr[INET_ADDRSTRLEN];
+ uint32_t endian = htonl(address);
+ std::cerr << inet_ntop(AF_INET, &(endian), ipStr, INET_ADDRSTRLEN) << ", " << (int)port << std::endl;
+
+ // Check for known peer, add & broadcast if unknown
+ IpEndpointName peerEndpoint((unsigned long)address, (int)port);
+ PeerMap::iterator peer = m_peers.find(peerEndpoint);
+ if (peer == m_peers.end()) {
+ PeerData peerData(peerEndpoint, new Peer(peerEndpoint));
+
+ // Tell the world
+ for (PeerMap::iterator pit = m_peers.begin(); pit != m_peers.end(); pit++) {
+ std::cerr << "sending " << (int)port << " to " << pit->first.port << std::endl;
+ ps.Clear();
+ ps << osc::BeginMessage("/network/peer/up") << address << port << osc::EndMessage;
+ pit->second->sendMessage(ps);
+
+ ps.Clear();
+ ps << osc::BeginMessage("/network/peer/up")
+ << (osc::int64)(pit->first.address)
+ << (osc::int32)(pit->first.port)
+ << osc::EndMessage;
+ peerData.second->sendMessage(ps);
+ }
+
+ peer = m_peers.insert(peerData).first;
+ sendPeerUpMessage();
+
+ // Tell our new friend everything we know
+ /*
+ * This doesn't work terribly well, so it's disabled for now
+ *
+ WidgetMap* widgets = Widget::getAll();
+ for (WidgetMap::iterator wit = widgets->begin(); wit != widgets->end(); wit++) {
+ wit->second->toOutboundPacketStream(ps);
+ peer->second->sendMessage(ps);
+ }
+ */
+ }
+}
+
+void Network::handlePeerDownMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::int32 port;
+ osc::int64 address;
+ m.ArgumentStream() >> address >> port >> osc::EndMessage;
+ if (address == 0)
+ address = remoteEndpoint.address;
+ char ipStr[INET_ADDRSTRLEN];
+ uint32_t endian = htonl(address);
+ std::cerr << inet_ntop(AF_INET, &(endian), ipStr, INET_ADDRSTRLEN) << ", " << (int)port << std::endl;
+
+ // Check for known peer, add & broadcast if unknown
+ IpEndpointName peerEndpoint((unsigned long)address, (int)port);
+ PeerMap::iterator peer = m_peers.find(peerEndpoint);
+ if (peer != m_peers.end()) {
+ m_peers.erase(peer);
+
+ // Tell the world
+ ps << osc::BeginMessage("/network/peer/down") << address << port << osc::EndMessage;
+ broadcast(ps);
+ }
+}
+
+void Network::handlePeerTextMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol text;
+ osc::int64 address;
+ osc::int32 port;
+ m.ArgumentStream() >> address >> port >> text >> osc::EndMessage;
+
+ if (address == 0)
+ address = remoteEndpoint.address;
+
+ char ipStr[INET_ADDRSTRLEN];
+ uint32_t endian = htonl(address);
+ std::cerr << inet_ntop(AF_INET, &(endian), ipStr, INET_ADDRSTRLEN) << ": " << text << std::endl;
+
+ // Check for known peer, add & broadcast if unknown
+ IpEndpointName peerEndpoint((unsigned long)address, (int)port);
+ PeerMap::iterator peer = m_peers.find(peerEndpoint);
+ if (peer != m_peers.end())
+ peer->second->setDisplayName(std::string(text));
+}
+
+void Network::sendObjectMessage(const Widget* object, bool remove)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ if (remove) {
+ std::cerr << object->getUuid() << std::endl;
+ ps << osc::BeginMessage("/object/delete")
+ << osc::Symbol(object->getUuid())
+ << osc::EndMessage;
+ } else
+ object->toOutboundPacketStream(ps);
+
+ broadcast(ps);
+}
+
+void Network::sendRoundPadTextMessage(const RoundPad* pad)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ ps << osc::BeginMessage("/object/pad/text")
+ << osc::Symbol(pad->getUuid())
+ << osc::Symbol(pad->getCommentText()->getText().c_str())
+ << osc::EndMessage;
+
+ broadcast(ps);
+}
+
+void Network::sendPlucker(const Track* track)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ ps << osc::BeginMessage("/object/plucker")
+ << osc::Symbol(track->getUuid())
+ << osc::EndMessage;
+
+ broadcast(ps);
+}
+
+void Network::handleObjectPadMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ float x, y, radius;
+ osc::Symbol uuid;
+ m.ArgumentStream() >> uuid >> x >> y >> radius >> osc::EndMessage;
+ std::cerr << uuid << ", " << x << ", " << y << ", " << radius << std::endl;
+
+ // Check for known pad, add & broadcast if unknown
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ if (wit == widgets->end()) {
+ RoundPad* newPad = new RoundPad(Point2D(x, y), radius);
+ newPad->setUuid(uuid);
+ widgets->insert(WidgetData(std::string(uuid), newPad));
+ m_engine->addChild(newPad);
+
+ // Tell the world
+ newPad->toOutboundPacketStream(ps);
+ broadcast(ps);
+ }
+}
+
+void Network::handleObjectPadTextMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol uuid, text;
+ m.ArgumentStream() >> uuid >> text >> osc::EndMessage;
+ std::cerr << uuid << ", " << text << std::endl;
+
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ if (wit != widgets->end() && dynamic_cast<RoundPad*>(wit->second))
+ ((RoundPad*)wit->second)->setCommentText(std::string(text));
+}
+
+void Network::handlePluckerMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol uuid;
+ m.ArgumentStream() >> uuid >> osc::EndMessage;
+ std::cerr << uuid << std::endl;
+
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ if (wit != widgets->end() && dynamic_cast<Track*>(wit->second))
+ ((Track*)wit->second)->addPlucker();
+}
+
+void Network::handleObjectSpiralMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol uuid, padUuid;
+ float startAngle, startRadius, endAngle, endRadius;
+ m.ArgumentStream() >> uuid >> padUuid >> startAngle >> startRadius
+ >> endAngle >> endRadius >> osc::EndMessage;
+ std::cerr << uuid << ", " << padUuid << ", "
+ << startAngle << ", " << startRadius << ", "
+ << endAngle << ", " << endRadius << std::endl;
+
+ // Check for known arc, add & broadcast if unknown
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ if (wit == widgets->end()) {
+ wit = m_orphans.find(std::string(uuid));
+ if (wit == m_orphans.end()) {
+ SpiralTrack* newSpiral = NULL;
+
+ // Search for pad
+ wit = widgets->find(std::string(padUuid));
+ if (wit != widgets->end()) {
+ Point2D center = ((RoundPad*)wit->second)->getCenter();
+ Point2D startPoint = Spiral::getPointFromRadius(center, startRadius, startAngle);
+ Point2D endPoint = Spiral::getPointFromRadius(center, endRadius, endAngle);
+ Joint *endJoint = NULL, *startJoint = NULL;
+ std::vector<Widget*>* children = wit->second->getChildren();
+
+ for (int i = children->size() - 1; i >= 0; i --) {
+ Track *track = dynamic_cast<Track *>(children->at(i));
+ if (track) {
+ Joint *joint = track->getJoint1();
+ if (!startJoint && joint && joint->hitTest(startPoint.x, startPoint.y))
+ startJoint = joint;
+ else if (!endJoint && joint && joint->hitTest(endPoint.x, endPoint.y))
+ endJoint = joint;
+
+ joint = track->getJoint2();
+ if (!startJoint && joint && joint->hitTest(startPoint.x, startPoint.y))
+ startJoint = joint;
+ else if (!endJoint && joint && joint->hitTest(endPoint.x, endPoint.y))
+ endJoint = joint;
+ }
+ }
+
+ newSpiral = new SpiralTrack(center, startAngle, startRadius,
+ endAngle, endRadius, startJoint, endJoint);
+ newSpiral->setUuid(uuid);
+ newSpiral->getSpiral()->setLineWidth(3);
+ newSpiral->getJoint1()->setParentRoundPad(((RoundPad*)wit->second));
+ newSpiral->getJoint2()->setParentRoundPad(((RoundPad*)wit->second));
+
+ wit->second->addChild(newSpiral);
+ widgets->insert(WidgetData(std::string(uuid), newSpiral));
+
+ // Tell the world
+ newSpiral->toOutboundPacketStream(ps);
+ broadcast(ps);
+ } else {// orphan if we don't know about its pad yet
+ newSpiral = new SpiralTrack(Point2D(0, 0), startAngle, startRadius,
+ endAngle, endRadius, NULL, NULL);
+ newSpiral->setUuid(uuid);
+ m_orphans.insert(WidgetData(std::string(padUuid), newSpiral));
+ }
+ }
+ }
+}
+
+void Network::handleObjectLineMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol uuid, padUuid;
+ float startX, startY, endX, endY;
+ m.ArgumentStream() >> uuid >> padUuid >> startX >> startY
+ >> endX >> endY >> osc::EndMessage;
+ std::cerr << uuid << ", " << padUuid << ", "
+ << startX << ", " << startY << ", "
+ << endX << ", " << endY << std::endl;
+
+ // Check for known arc, add & broadcast if unknown
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ if (wit == widgets->end()) {
+ wit = m_orphans.find(std::string(uuid));
+ if (wit == m_orphans.end()) {
+ LineTrack* newLine = NULL;
+
+ // Search for pad
+ wit = widgets->find(std::string(padUuid));
+ if (wit != widgets->end()) {
+ Joint *endJoint = NULL, *startJoint = NULL;
+ for (WidgetMap::iterator ptr = widgets->begin(); ptr != widgets->end(); ptr++) {
+ Track *track = dynamic_cast<Track *>(ptr->second);
+ if (track) {
+ Joint *joint = track->getJoint1();
+ if (!startJoint && joint && joint->hitTest(startX, startY))
+ startJoint = joint;
+ else if (!endJoint && joint && joint->hitTest(endX, endY))
+ endJoint = joint;
+
+ joint = track->getJoint2();
+ if (!startJoint && joint && joint->hitTest(startX, startY))
+ startJoint = joint;
+ else if (!endJoint && joint && joint->hitTest(endX, endY))
+ endJoint = joint;
+ }
+ }
+
+ LineTrack* newLine = new LineTrack(Point2D(startX, startY), Point2D(endX, endY), startJoint, endJoint);
+ newLine->setUuid(uuid);
+ newLine->getLine()->setLineWidth(3);
+
+ wit->second->addChild(newLine);
+ widgets->insert(WidgetData(std::string(uuid), newLine));
+
+ // Tell the world
+ newLine->toOutboundPacketStream(ps);
+ broadcast(ps);
+ } else {// orphan if we don't know about its pad yet
+ newLine = new LineTrack(Point2D(startX, startY), Point2D(endX, endY), NULL, NULL);
+ newLine->setUuid(uuid);
+ m_orphans.insert(WidgetData(std::string(padUuid), newLine));
+ }
+ }
+ }
+}
+
+void Network::handleObjectStringMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Utility data structures
+ char buffer[1024];
+ osc::OutboundPacketStream ps(buffer, 1024);
+
+ // Parse OSC message
+ osc::Symbol uuid, padUuid;
+ float startX, startY, endX, endY;
+ m.ArgumentStream() >> uuid >> padUuid >> startX >> startY
+ >> endX >> endY >> osc::EndMessage;
+ std::cerr << uuid << ", " << padUuid << ", "
+ << startX << ", " << startY << ", "
+ << endX << ", " << endY << std::endl;
+
+ // Check for known arc, add & broadcast if unknown
+ bool unlocked = false;
+ SoundSource::lockGlobals();
+
+ SoundSourceMap* soundSources = SoundSource::getAllForEngine();
+ WidgetMap* widgets = Widget::getAll();
+ if (soundSources->find(std::string(uuid)) == soundSources->end()) {
+ WidgetMap::iterator wit = m_orphans.find(std::string(uuid));
+ if (wit == m_orphans.end()) {
+ // Search for pad
+ wit = widgets->find(std::string(padUuid));
+ if (wit != widgets->end()) {
+ String* newString = new String(Point2D(startX, startY), Point2D(endX, endY), 1);
+ newString->setUuid(uuid);
+ // Add string to soundsource
+ soundSources->insert(SoundSourceData(newString->getUuid(), newString));
+
+ wit->second->addChild(newString);
+ newString->setPadRadius(((RoundPad*)wit->second)->getRadius());
+
+ // Tell the world
+ newString->toOutboundPacketStream(ps);
+ broadcast(ps);
+ } else {// orphan if we don't know about its pad yet
+ String* newString = new String(Point2D(startX, startY), Point2D(endX, endY), 1);
+ newString->setUuid(uuid);
+ m_orphans.insert(WidgetData(std::string(padUuid), newString));
+ }
+
+ SoundSource::unlockGlobals();
+ unlocked = true;
+ }
+ }
+
+ if (!unlocked)
+ SoundSource::unlockGlobals();
+}
+
+void Network::handleMousePositionMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Parse OSC message
+ osc::int32 port;
+ float x, y;
+ bool down;
+ m.ArgumentStream() >> port >> x >> y >> down >> osc::EndMessage;
+
+ PeerMap::iterator pit = m_peers.find(IpEndpointName(remoteEndpoint.address, (int)port));
+ if (pit != m_peers.end()) {
+ pit->second->setMousePosition(x, y);
+ pit->second->setMouseDown(down);
+ }
+}
+
+void Network::handleObjectDeleteMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // Parse OSC message
+ osc::Symbol uuid;
+ m.ArgumentStream() >> uuid >> osc::EndMessage;
+
+ std::cerr << uuid << std::endl;
+
+ WidgetMap* widgets = Widget::getAll();
+ WidgetMap::iterator wit = widgets->find(std::string(uuid));
+ Widget* widget;
+ if (wit != widgets->end() &&
+ (widget = wit->second->getParent()->removeChild(wit->second))) {
+ sendObjectMessage(widget, true);
+ delete widget;
+ }
+}
+
+void Network::handleObjectQueryMessage(const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint)
+{
+ // TODO: well, maybe...
+}
1  Point.cpp
@@ -0,0 +1 @@
+#include "include/Point.h"
275 Shape.cpp
@@ -0,0 +1,275 @@
+#include <math.h>
+
+#ifdef __MACOSX_CORE__
+#include <GLUT/glut.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#endif
+
+#include <iostream>
+#include <time.h>
+#include <stdlib.h>
+
+#include "Shape.h"
+
+// ==================
+// Arc implementation
+// ==================
+
+Spiral::Spiral(Point2D center, float startAngle, float startRadius,
+ float endAngle, float endRadius) :
+ m_center(center),
+ m_startRadius(startRadius),
+ m_endRadius(endRadius),
+ m_startAngle(startAngle),
+ m_endAngle(endAngle),
+ m_filled(false)
+{
+ m_fDotted = false;
+ m_fDirected = false;
+ m_lineWidth = 1;
+ m_color = Color(0, 0, 0);
+}
+
+void Spiral::setFilled(bool filled)
+{
+ m_filled = filled;
+}
+
+void Spiral::setColor(const Color& color)
+{
+ m_color = color;
+}
+
+void Spiral::draw()
+{
+ float end = m_endAngle;
+ if (m_endAngle > m_startAngle)
+ end -= 360;
+
+ glColor4f(m_color.r, m_color.g, m_color.b, m_color.a);
+
+ /*
+ if (m_fDotted) {
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(1, 0xFF00);
+ }
+ */
+
+ float angle, x, y, interpRadius;
+ float maxRadius = std::max(m_startRadius, m_endRadius);
+ float radiusDiff = m_startRadius - m_endRadius;
+ float newAngleDiff, baseAngleDiff = m_startAngle - end;
+
+ if (!m_filled) {
+ glLineWidth(m_lineWidth);
+ glBegin(GL_LINE_STRIP);
+ } else
+ glBegin(GL_POLYGON);
+ {
+ // Draw counter-clockwise
+ x = m_center.x + m_endRadius * cos((double) m_endAngle * MY_PI / 180);
+ y = m_center.y - m_endRadius * sin((double) m_endAngle * MY_PI / 180);
+ glVertex2f(x, y);
+
+ for (angle = end + 180 / maxRadius; angle < m_startAngle; angle += 180 / maxRadius) {
+ newAngleDiff = Spiral::clampAngle(angle) - m_endAngle;
+ if (Spiral::clampAngle(angle) < m_endAngle)
+ newAngleDiff += 360;
+ interpRadius = m_endRadius + radiusDiff * newAngleDiff / baseAngleDiff;
+ x = m_center.x + interpRadius * cos((double) angle * MY_PI / 180);
+ y = m_center.y - interpRadius * sin((double) angle * MY_PI / 180);
+ glVertex2f(x, y);
+ }
+
+ x = m_center.x + m_startRadius * cos((double) m_startAngle * MY_PI / 180);
+ y = m_center.y - m_startRadius * sin((double) m_startAngle * MY_PI / 180);
+ glVertex2f(x, y);
+ }
+ glEnd();
+
+ /*
+ if (m_fDotted)
+ glDisable(GL_LINE_STIPPLE);
+ */
+}
+
+// Utility function that returns the angle of a point around the center.
+// Positive x-axis is 0 degree
+float Spiral::getAngle(Point2D center, Point2D p)
+{
+ // Flip the y because the direction of y is reversed
+ float dx = p.x - center.x,
+ dy = center.y - p.y;
+ float adx = abs(dx),
+ ady = abs(dy);
+ float baseAngle = 0.0f;
+
+ // The same point
+ if (adx == 0 && ady == 0)
+ return 0;
+
+ // Perpendicular
+ if (adx == 0) {
+ if (dy > 0)
+ return 90;
+ else
+ return 270;
+ } else if (ady == 0) {
+ if (dx > 0)
+ return 0;
+ else
+ return 180;
+ }
+
+ baseAngle = atan(ady / adx) * 180 / MY_PI;
+
+ if (dx < 0)
+ baseAngle = 180 - baseAngle;
+
+ if (dy < 0)
+ baseAngle = 360 - baseAngle;
+
+ return baseAngle;
+}
+
+Point2D Spiral::getPointFromRadius(Point2D center, float radius, float angle)
+{
+ float x = center.x + radius * cos((double) angle * MY_PI / 180),
+ y = center.y - radius * sin((double) angle * MY_PI / 180);
+ return Point2D(x, y);
+}
+
+float Spiral::clampAngle(float angle) {
+ for (; angle < 0; angle += 360);
+ for (; angle > 360; angle -= 360);
+ return angle;
+}
+
+// ===================
+// Line implementation
+// ===================
+
+Line::Line(Point2D p1, Point2D p2) : m_p1(p1), m_p2(p2)
+{
+ m_fDotted = false;
+ m_fDirected = false;
+ m_lineWidth = 1;
+ m_color = Color(0, 0, 0);
+}
+
+void Line::draw()
+{
+ glColor3f(m_color.r, m_color.g, m_color.b);
+
+ if (m_fDotted) {
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(1, 0xFF00);
+ }
+
+ glLineWidth(m_lineWidth);
+ glBegin(GL_LINES);
+ {
+ glVertex2f(m_p1.x, m_p1.y);
+ glVertex2f(m_p2.x, m_p2.y);
+ }
+ glEnd();
+
+ if (m_fDotted)
+ glDisable(GL_LINE_STIPPLE);
+
+ // Draw the indicator at the start and end part of the line
+ if (m_fDirected) {
+ glBegin(GL_POINTS);
+ {
+ glPointSize(10);
+ glVertex2f(m_p1.x, m_p1.y);
+ glPointSize(5);
+ glVertex2f(m_p2.x, m_p2.y);
+ }
+ glEnd();
+ }
+}
+
+float Line::getDistance(Point2D pos)
+{
+ // pos - start
+ Point2D a;
+ a.x = pos.x - m_p1.x;
+ a.y = pos.y - m_p1.y;
+
+ // end - start
+ Point2D b;
+ b.x = -(m_p2.y - m_p1.y);
+ b.y = m_p2.x - m_p1.x;
+
+ // length of end - start
+ float amp = sqrt(b.x * b.x + b.y * b.y);
+
+ // distance from line to point
+ // a dot b / amp
+ return (a.x * b.x + a.y * b.y) / amp;
+}
+
+float Line::getParallelPosition(Point2D pos)
+{
+ // pos - start
+ Point2D a;
+ a.x = pos.x - m_p1.x;
+ a.y = pos.y - m_p1.y;
+
+ // end - start
+ Point2D b;
+ b.x = m_p2.x - m_p1.x;
+ b.y = m_p2.y - m_p1.y;
+
+ // length of end - start
+ float amp = sqrt(b.x * b.x + b.y * b.y);
+
+ // position between start & end, from 0 -to-> 1
+ // a dot b / length^2
+ // < 0 or > 1 if beyond endpoints
+ return (a.x * b.x + a.y * b.y) / (amp * amp);
+}
+
+
+Text::Text(Point2D pos, std::string str) : m_pos(pos), m_str(str)
+{
+ m_color = Color(0, 0, 0);
+}
+
+void Text::draw()
+{
+ glColor3f(m_color.r, m_color.g, m_color.b);
+ glRasterPos2i(m_pos.x, m_pos.y);
+ int lines = 0;
+ for(const char *p = m_str.c_str(); *p; p++) {
+ while (*p == '\n') {
+ lines++;
+ p++;
+ glRasterPos2i(m_pos.x, m_pos.y + (lines * 18));
+ }
+ glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *p);
+ }
+}
+
+int Text::getWidth()
+{
+ int maxLineWidth = 0, width = 0;
+ for(const char *p = m_str.c_str(); *p; p++) {
+ if (*p == '\n') {
+ maxLineWidth = std::max(width, maxLineWidth);
+ width = 0;
+ }
+ width += glutBitmapWidth(GLUT_BITMAP_9_BY_15, *p);
+ }
+ maxLineWidth = std::max(width, maxLineWidth);
+ return maxLineWidth;
+}
1,416 Widget.cpp
@@ -0,0 +1,1416 @@
+#include <math.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string.h>
+#include <sstream>
+#include <time.h>
+#include <algorithm>
+
+#ifdef __MACOSX_CORE__
+#include <GLUT/glut.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#endif
+
+#include "Widget.h"
+#include "Engine.h"
+#include "Network.h"
+
+// Widget globals
+WidgetMap g_widgets;
+WidgetMap* Widget::getAll() { return &g_widgets; }
+
+SoundSourceMap g_soundSources1, g_soundSources2;
+void SoundSource::initializeGlobals() {
+ s_forAudio = &g_soundSources1;
+ s_forEngine = &g_soundSources2;
+}
+void SoundSource::lockGlobals() { s_swapMutex.lock(); }
+void SoundSource::unlockGlobals() { s_swapMutex.unlock(); }
+void SoundSource::swapGlobals() {
+ SoundSourceMap* tmp = s_forAudio;
+
+ s_swapMutex.lock();
+ {
+ s_forAudio = s_forEngine;
+ s_forEngine = tmp;
+ }
+ s_swapMutex.unlock();
+
+ s_forEngine->clear();
+ s_forEngine->insert(s_forAudio->begin(), s_forAudio->end());
+}
+SoundSourceMap* SoundSource::getAllForAudio() { return s_forAudio; }
+SoundSourceMap* SoundSource::getAllForEngine() { return s_forEngine; }
+SoundSourceMap* SoundSource::s_forAudio, *SoundSource::s_forEngine;
+stk::Mutex SoundSource::s_swapMutex;
+
+// Widget statics
+Network* Widget::s_network;
+
+// ==========================
+// Base Widget implementation
+// ==========================
+
+Widget::Widget() :
+ m_fLeftButtonDown(false),
+ m_fRightButtonDown(false),
+ m_mouseDownOn(NULL),
+ m_parent(NULL),
+ m_engine(NULL),
+ m_uuid("")
+{
+ uuid_t uuid;
+ uuid_generate(uuid);
+ char s[37];
+ uuid_unparse(uuid, s);
+ setUuid(s);
+}
+
+Widget::~Widget() {
+ for (std::vector<Widget*>::iterator cit = m_children.begin();
+ cit != m_children.end();
+ cit++)
+ delete *cit;
+ m_children.clear();
+
+ g_widgets.erase(m_uuid);
+}
+
+void Widget::setUuid(const char* uuid)
+{
+ m_uuid = std::string(uuid);
+}
+
+const char* Widget::getUuid() const
+{
+ return m_uuid.c_str();
+}
+
+void Widget::addChild(Widget* child)
+{
+ child->setParent(this);
+ m_children.push_back(child);
+}
+
+Widget* Widget::removeChild(Widget* child)
+{
+ for (std::vector<Widget*>::iterator wit = m_children.begin(); wit != m_children.end(); wit++)
+ if (*wit == child) {
+ m_children.erase(wit);
+ return child;
+ }
+ return NULL;
+}
+
+bool Widget::onMouseDown(int button, float x, float y)
+{
+ if (button == GLUT_LEFT_BUTTON) {
+ m_mouseDownPos = Point2D(x, y);
+ m_fLeftButtonDown = true;
+
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y)) {
+ m_mouseDownOn = m_children[i];
+ m_mouseDownOn->onMouseDown(button, x, y);
+ break;
+ }
+ } else if (button == GLUT_RIGHT_BUTTON) {
+ m_mouseDownPos = Point2D(x, y);
+ m_fRightButtonDown = true;
+
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y)) {
+ m_mouseDownOn = m_children[i];
+ m_mouseDownOn->onMouseDown(button, x, y);
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool Widget::onMouseUp(int button, float x, float y)
+{
+ if ((m_fLeftButtonDown && button == GLUT_LEFT_BUTTON) ||
+ (m_fRightButtonDown && button == GLUT_RIGHT_BUTTON)) {
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y) && m_children[i] == m_mouseDownOn) {
+ m_children[i]->handleSelect(x, y, m_fRightButtonDown);
+ break;
+ }
+ this->handleDrawEnd(x, y);
+ if (m_mouseDownOn) {
+ m_mouseDownOn->onMouseUp(button, x, y);
+ m_mouseDownOn = NULL;
+ }
+ m_fLeftButtonDown = false;
+ m_fRightButtonDown = false;
+ }
+
+ return true;
+}
+
+bool Widget::onMouseMove(float x, float y)
+{
+ if (m_mouseDownOn) {
+ m_mouseDownOn->onMouseMove(x, y);
+ } else if (m_fLeftButtonDown) {
+ this->handleDraw(x, y);
+ } else {
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y)) {
+ m_children[i]->onMouseOver(x, y);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Widget::onMouseOver(float x, float y)
+{
+ this->handleHover(x, y);
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y)) {
+ m_children[i]->onMouseOver(x, y);
+ return true;
+ }
+
+ return false;
+}
+
+void Widget::drawChildren()
+{
+ for (int i = 0; i < m_children.size(); i++)
+ m_children[i]->draw();
+}
+
+void Widget::setParent(Widget *parent)
+{
+ m_parent = parent;
+}
+
+void Widget::setNetwork(Network *network)
+{
+ s_network = network;
+}
+
+void Widget::toOutboundPacketStream(osc::OutboundPacketStream& ps) const
+{
+}
+
+Widget* Widget::getEngine()
+{
+ if (!m_engine) {
+ Widget* ancestor = m_parent;
+ while (ancestor && ancestor != ancestor->getParent())
+ ancestor = ancestor->getParent();
+ m_engine = ancestor;
+ }
+
+ return m_engine;
+}
+
+// =======================
+// RoundPad implementation
+// =======================
+
+RoundPad::RoundPad(Point2D center, float radius) :
+ m_center(center),
+ m_newTrack(NULL),
+ m_newSpiralTrack(NULL),
+ m_newString(NULL),
+ m_hoverLine(Point2D(0, 0), Point2D(0, 0)),
+ m_dragLine(Point2D(0, 0), Point2D(0, 0)),
+ m_commentText(new Text(Point2D(-100, -100), ""))
+{
+ this->setRadius(radius);
+ m_hoverLine.setColor(Color(0, 0, 0));
+ m_dragLine.setColor(Color(0, 0, 0));
+}
+
+RoundPad::~RoundPad()
+{
+ // Free the circles
+ for (int i = 0; i < m_circles.size(); i ++)
+ if (m_circles[i]) {
+ delete m_circles[i];
+ m_circles[i] = NULL;
+ }
+ // Special check for line track whose parent is not this round pad but has the end joint on it
+ std::vector<LineTrack *> lineTracks;
+ WidgetMap *widgets = Widget::getAll();
+ for (WidgetMap::iterator it = widgets->begin(); it != widgets->end(); it ++)
+ {
+ LineTrack *lineTrack = dynamic_cast<LineTrack *>(it->second);
+ if (lineTrack && lineTrack->getParent() != this &&
+ (lineTrack->getJoint1()->getParentRoundPad() == this ||
+ lineTrack->getJoint2()->getParentRoundPad() == this))
+ {
+ lineTracks.push_back(lineTrack);
+ }
+ }
+ for (int i = 0; i < lineTracks.size(); i ++)
+ {
+ lineTracks[i]->getParent()->removeChild(lineTracks[i]);
+ lineTracks[i] = NULL;
+ }
+
+}
+
+void RoundPad::setRadius(float radius) {
+ m_radius = radius;
+
+ // Delete old circles
+ for (std::vector<Spiral*>::iterator cit = m_circles.begin();
+ cit != m_circles.end();
+ cit++)
+ delete *cit;
+ m_circles.clear();
+
+ // Generate circles for rendering
+ Spiral* circle;
+ for (int i = 30; i <= m_radius; i += 20) {
+ circle = new Spiral(m_center, 360, i, 0, i);
+ circle->setColor(Color(0, 0, 0, 0.1));
+ circle->setLineWidth(1);
+ m_circles.push_back(circle);
+ }
+
+ circle = new Spiral(m_center, 360, m_radius, 0, m_radius);
+ m_circles.push_back(circle);
+
+ circle = new Spiral(m_center, 360, m_radius, 0, m_radius);
+ circle->setFilled(true);
+ circle->setColor(Color(0.75, 0.75, 0.75, 0.1));
+ m_circles.push_back(circle);
+
+ circle = new Spiral(m_center, 360, 10, 0, 10);
+ circle->setFilled(true);
+ m_circles.push_back(circle);
+
+ m_commentText->setPos(Point2D(m_center.x - m_commentText->getWidth() / 2,
+ m_center.y + m_radius + 20));
+}
+
+void RoundPad::draw()
+{
+ if (m_newSpiralTrack)
+ m_newSpiralTrack->draw();
+ if (m_newString)
+ m_newString->draw();
+
+ for (int i = 0; i < m_circles.size(); i++)
+ m_circles[i]->draw();
+
+ drawChildren();
+
+ m_hoverLine.draw();
+ m_dragLine.draw();
+
+ m_commentText->draw();
+}
+
+Widget *RoundPad::hitTest(float x, float y)
+{
+ Point2D p(x, y);
+ float dist = Point2D::distance(m_center, p);
+
+ if (dist < m_radius)
+ return this;
+
+ m_hoverLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+ return NULL;
+}
+
+void RoundPad::toOutboundPacketStream(osc::OutboundPacketStream& ps) const
+{
+ ps.Clear();
+ ps << osc::BeginMessage("/object/pad")
+ << osc::Symbol(m_uuid.c_str()) << m_center.x << m_center.y << m_radius
+ << osc::EndMessage;
+}
+
+bool RoundPad::handleDraw(float x, float y)
+{
+ // Draw guide-lines
+ float angle = Spiral::getAngle(m_center, Point2D(x, y));
+ m_dragLine.setPoints(Spiral::getPointFromRadius(m_center, -m_radius, angle),
+ Spiral::getPointFromRadius(m_center, m_radius, angle));
+
+ Point2D pos(x, y);
+ float startAngle = Spiral::getAngle(m_center, m_mouseDownPos);
+ m_hoverLine.setPoints(Spiral::getPointFromRadius(m_center, -m_radius, startAngle),
+ Spiral::getPointFromRadius(m_center, m_radius, startAngle));
+
+ // Decide between drawing a string or a track
+ Line radialLine(Spiral::getPointFromRadius(m_center, 0, startAngle),
+ Spiral::getPointFromRadius(m_center, m_radius, startAngle));
+ if (radialLine.getParallelPosition(pos) >= 0 && fabs(radialLine.getDistance(pos)) < 10) {
+ Point2D endPoint =
+ Spiral::getPointFromRadius(m_center,
+ std::min(m_radius, Point2D::distance(m_center, pos)),
+ startAngle);
+ if (m_newString)
+ m_newString->initialize(m_mouseDownPos, endPoint, m_radius);
+ else {
+ m_newString = new String(m_mouseDownPos, endPoint, m_radius);
+ SoundSource::getAllForEngine()->insert(SoundSourceData(m_newString->getUuid(), m_newString));
+ }
+
+ if (m_newSpiralTrack) {
+ delete m_newSpiralTrack;
+ m_newSpiralTrack = NULL;
+ }
+ } else {
+ // Find whether the position corresponds to other end point
+ float endAngle = Spiral::getAngle(m_center, pos);
+ float startRadius = Point2D::distance(m_center, m_mouseDownPos);
+ float endRadius = std::min(m_radius, Point2D::distance(m_center, pos));
+ Joint *endJoint = NULL;
+
+ for (int i = m_children.size() - 1; i >= 0; i --) {
+ Track *track = dynamic_cast<Track *>(m_children[i]);
+ if (track) {
+ Joint *joint = track->getJoint1();
+ if (joint && joint->hitTest(x, y)) {
+ endJoint = joint;
+ break;
+ }
+
+ joint = track->getJoint2();
+ if (joint && joint->hitTest(x, y)) {
+ endJoint = joint;
+ break;
+ }
+ }
+ }
+
+ if (m_newSpiralTrack)
+ m_newSpiralTrack->initialize(m_center, startAngle, startRadius, endAngle, endRadius, NULL, endJoint);
+ else {
+ m_newSpiralTrack = new SpiralTrack(m_center, startAngle, startRadius,
+ endAngle, endRadius, NULL, endJoint);
+ m_newSpiralTrack->getSpiral()->setLineWidth(1);
+ m_newSpiralTrack->setEnabled(false);
+ }
+ m_newSpiralTrack->getJoint1()->setParentRoundPad(this);
+ m_newSpiralTrack->getJoint2()->setParentRoundPad(this);
+
+ if (m_newString) {
+ delete m_newString;
+ m_newString = NULL;
+ }
+ }
+ return true;
+}
+
+bool RoundPad::handleDrawEnd(float x, float y)
+{
+ m_hoverLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+ m_dragLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+
+ if (m_newSpiralTrack) {
+ m_newSpiralTrack->getSpiral()->setLineWidth(3);
+ m_newSpiralTrack->setEnabled(true);
+ g_widgets.insert(WidgetData(m_newSpiralTrack->getUuid(), m_newSpiralTrack));
+ addChild(m_newSpiralTrack);
+ s_network->sendObjectMessage(m_newSpiralTrack);
+ m_newSpiralTrack = NULL;
+ }
+ if (m_newString) {
+ g_widgets.insert(WidgetData(m_newString->getUuid(), m_newString));
+ addChild(m_newString);
+ s_network->sendObjectMessage(m_newString);
+ m_newString = NULL;
+ }
+ return true;
+}
+
+bool RoundPad::handleHover(float x, float y)
+{
+ Color color = Color(0, 0, 0, 1);
+ if (Point2D::distance(m_center, Point2D(x, y)) <= 10) {
+ m_hoverLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+ bool childHovered = false;
+ for (int i = m_children.size() - 1; i >= 0; i--)
+ if (m_children[i]->hitTest(x, y)) {
+ childHovered = true;
+ break;
+ }
+ if (!childHovered) {
+ ((Engine*)getEngine())->setSelectedWidget(this);
+ color = Color(1, .5, 0, 1);
+ }
+ } else {
+ float angle = Spiral::getAngle(m_center, Point2D(x, y));
+ m_hoverLine.setPoints(Spiral::getPointFromRadius(m_center, -m_radius, angle),
+ Spiral::getPointFromRadius(m_center, m_radius, angle));
+ }
+ (*(m_circles.end() - 1))->setColor(color);
+}
+
+void RoundPad::setCommentText(std::string comment)
+{
+ m_commentText->setText(comment);
+ m_commentText->setPos(Point2D(m_center.x - m_commentText->getWidth() / 2,
+ m_center.y + m_radius + 30));
+}
+
+void RoundPad::appendCommentText(std::string comment)
+{
+ m_commentText->setText(m_commentText->getText() + comment);
+ m_commentText->setPos(Point2D(m_center.x - m_commentText->getWidth() / 2,
+ m_center.y + m_radius + 30));
+}
+
+// ====================
+// Joint implementation
+// ====================
+
+Joint::Joint(Point2D center, float radius) :
+ m_center(center),
+ m_radius(radius),
+ m_newSpiralTrack(NULL),
+ m_newLineTrack(NULL),
+ m_drawing(false),
+ m_dragLine(Point2D(0, 0), Point2D(0, 0)),
+ m_parentRoundPad(NULL)
+{
+ m_circle = new Spiral(center, 360, radius, 0, radius);
+ m_circle->setLineWidth(3);
+ m_circle->setFilled(true);
+ m_dragLine.setColor(Color(0, 0, 0));
+}
+
+Joint::~Joint()
+{
+ delete m_circle;
+}
+
+void Joint::draw()
+{
+ // Prevent recursive draw
+ if (m_drawing)
+ return;
+
+ m_drawing = true;
+ m_circle->draw();
+ m_dragLine.draw();
+
+ if (m_newSpiralTrack)
+ m_newSpiralTrack->draw();
+ if (m_newLineTrack)
+ m_newLineTrack->draw();
+
+ m_drawing = false;
+}
+
+void Joint::addTrack(Track *track)
+{
+ if (track)
+ if (std::find(m_tracks.begin(), m_tracks.end(), track) == m_tracks.end())
+ m_tracks.push_back(track);
+}
+
+Widget *Joint::hitTest(float x, float y)
+{
+ if (Point2D::distance(m_center, Point2D(x, y)) <= m_radius)
+ return this;
+ return NULL;
+}
+
+void Joint::setCenter(Point2D center)
+{
+ //std::cerr << "Joint::setCenter" << std::endl;
+ //std::cerr << m_center.x << " " << m_center.y << std::endl;
+ m_center = center;
+ m_circle->setCenter(m_center);
+}
+
+void Joint::setColor(Color color)
+{
+ m_circle->setColor(color);
+}
+
+bool Joint::handleDraw(float x, float y)
+{
+ Point2D center;
+ float radius;
+ RoundPad *pad;
+
+ // This shouldn't happen actually
+ if (m_tracks.size() <= 0)
+ return false;
+
+ pad = getParentRoundPad();
+ // Can't find any parent round pad so the operation fails
+ if (!pad)
+ return false;
+
+ center = pad->getCenter();
+ radius = pad->getRadius();
+
+ // Find whether the position corresponds to other end point
+ Joint *endJoint = NULL;
+ WidgetMap widgets = *Widget::getAll();
+ for (WidgetMap::iterator ptr = widgets.begin(); ptr != widgets.end(); ptr ++) {
+ Track *track = dynamic_cast<Track *>(ptr->second);
+ if (track) {
+ Joint *joint = track->getJoint1();
+ if (joint && joint != this && joint->hitTest(x, y)) {
+ endJoint = joint;
+ break;
+ }
+ joint = track->getJoint2();
+ if (joint && joint != this && joint->hitTest(x, y)) {
+ endJoint = joint;
+ break;
+ }
+ }
+ }
+
+ float angle = Spiral::getAngle(center, Point2D(x, y));
+ m_dragLine.setPoints(Spiral::getPointFromRadius(center, -radius, angle),
+ Spiral::getPointFromRadius(center, radius, angle));
+ Point2D pos(x, y);
+ float startAngle = Spiral::getAngle(center, m_mouseDownPos),
+ endAngle = Spiral::getAngle(center, pos);
+
+ if (endJoint && pad != endJoint->getParentRoundPad()) {
+ //std::cerr << "Joint::handleDraw: Connecting two joints in differnet pads" << std::endl;
+ Point2D endPoint =
+ Spiral::getPointFromRadius(center,
+ std::min(radius, Point2D::distance(center, pos)),
+ startAngle);
+ if (m_newLineTrack)
+ m_newLineTrack->initialize(m_mouseDownPos, endPoint, this, endJoint);
+ else {
+ m_newLineTrack = new LineTrack(m_mouseDownPos, endPoint, this, endJoint);
+ m_newLineTrack->getLine()->setLineWidth(1);
+ m_newLineTrack->setEnabled(false);
+ }
+
+ if (m_newSpiralTrack) {
+ delete m_newSpiralTrack;
+ m_newSpiralTrack = NULL;
+ }
+ } else {
+ float startRadius = Point2D::distance(center, m_mouseDownPos);
+ float endRadius = std::min(radius, Point2D::distance(center, pos));
+ if (m_newSpiralTrack)
+ m_newSpiralTrack->initialize(center, startAngle, startRadius, endAngle, endRadius, this, endJoint);
+ else
+ {
+ m_newSpiralTrack = new SpiralTrack(center, startAngle, startRadius,
+ endAngle, endRadius, this, endJoint);
+ m_newSpiralTrack->getSpiral()->setLineWidth(1);
+ m_newSpiralTrack->setEnabled(false);
+ }
+ m_newSpiralTrack->getJoint2()->setParentRoundPad(pad);
+ if (m_newLineTrack) {
+ delete m_newLineTrack;
+ m_newLineTrack = NULL;
+ }
+ }
+ return true;
+}
+
+bool Joint::handleDrawEnd(float x, float y)
+{
+ RoundPad *pad = getParentRoundPad();
+
+ if (!pad)
+ return false;
+
+ m_dragLine.setPoints(Point2D(0, 0), Point2D(0, 0));
+
+ if (m_newSpiralTrack) {
+ m_newSpiralTrack->getSpiral()->setLineWidth(3);
+ m_newSpiralTrack->setEnabled(true);
+ g_widgets.insert(WidgetData(m_newSpiralTrack->getUuid(), m_newSpiralTrack));
+ pad->addChild(m_newSpiralTrack);
+ s_network->sendObjectMessage(m_newSpiralTrack);
+ m_newSpiralTrack = NULL;
+ }
+ if (m_newLineTrack) {
+ m_newLineTrack->getLine()->setLineWidth(3);
+ m_newLineTrack->setEnabled(true);
+ g_widgets.insert(WidgetData(m_newLineTrack->getUuid(), m_newLineTrack));
+ pad->addChild(m_newLineTrack);
+ s_network->sendObjectMessage(m_newLineTrack);
+ m_newLineTrack = NULL;
+ }
+
+ return true;
+}
+
+bool Joint::handleSelect(float x, float y, bool send)
+{
+ for (int i = 0; i < m_tracks.size(); i ++) {
+ Track* track = m_tracks[i];
+
+ // If it's the start point
+ if (track->getJoint1() == this) {
+ track->addPlucker();
+ if (send)
+ s_network->sendPlucker(track);
+ }
+ }
+ return true;
+}
+
+std::string Joint::toString()
+{
+ std::ostringstream os;
+ os << "Joint Center: " << m_center.x << " " << m_center.y
+ << " Tracks: " << m_tracks.size();
+ return os.str();
+}
+
+// =========================
+// Base Track implementation
+// =========================
+
+Track::Track() :
+ m_joint1(NULL),
+ m_joint2(NULL),
+ m_fEnabled(true),
+ m_fActive(true),
+ m_fDirected(true),
+ m_fImmediate(false)
+{
+}
+
+// Small hack to prevent a joint to be deleted in Widget::~Widget()
+Track::~Track() {
+ //std::cerr << "Track::~Track" << std::endl;
+
+ for (std::vector<Widget*>::iterator cit = m_children.begin();
+ cit != m_children.end();
+ cit++)
+ {
+ Joint *joint = dynamic_cast<Joint *>(*cit);
+ if (joint)
+ {
+ std::vector<Track *> *tracks = joint->getTracks();
+ std::vector<Track *>::iterator ptr = std::find(tracks->begin(), tracks->end(), this);
+ if (ptr != tracks->end())
+ tracks->erase(ptr);
+ //std::cerr << tracks->size() << std::endl;
+ if (tracks->size() == 0)
+ delete *cit;
+ }
+ else
+ delete *cit;
+ }
+ m_children.clear();
+
+}
+
+void Track::detachJoint(Joint *joint)
+{
+ std::vector<Widget *>::iterator ptr;
+ std::vector<Track *>::iterator trackPtr;
+ if (joint)
+ {
+ ptr = std::find(m_children.begin(), m_children.end(), joint);
+ if (ptr != m_children.end())
+ m_children.erase(ptr);
+ std::vector<Track *> tracks = *joint->getTracks();
+ // remove the track from the joint
+ trackPtr = std::find(tracks.begin(), tracks.end(), this);
+ if (trackPtr != tracks.end())
+ tracks.erase(trackPtr);
+ if (tracks.size() == 0)
+ delete joint;
+ joint = NULL;
+ }
+}
+
+void Track::setupJoints(Joint *joint1, Joint *joint2)
+{
+ this->detachJoint(m_joint1);
+ this->detachJoint(m_joint2);
+ m_joint1 = NULL;
+ m_joint2 = NULL;
+
+ if (joint1)
+ m_joint1 = joint1;
+ else {
+ // Set to origin first
+ m_joint1 = new Joint(Point2D(0, 0), 7);
+ m_joint1->setColor(Color(0.2, 0.6, 0.3));
+ }
+
+ if (joint2)
+ m_joint2 = joint2;
+ else {
+ m_joint2 = new Joint(Point2D(0, 0), 7);
+ m_joint2->setColor(Color(0.6, 0.2, 0.3));
+ }
+
+ m_joint1->addTrack(this);
+ m_joint2->addTrack(this);
+ m_children.insert(m_children.begin(), m_joint2);
+ m_children.insert(m_children.begin(), m_joint1);
+}
+
+void Track::addPlucker()
+{
+ Plucker *plucker = new Plucker(this, getJoint1(), getJoint2());
+ this->addChild(plucker);
+}
+
+void Track::drawChildren()
+{
+ for (int i = 0; i < m_children.size(); i++) {
+ Plucker* plucker = dynamic_cast<Plucker*>(m_children[i]);
+ if (plucker) {
+ plucker->tick();
+
+ if (plucker->isAtEnd()) {
+ std::vector<Plucker *> pluckers = plucker->split();
+ delete plucker;
+ m_children.erase(m_children.begin() + i);
+ i--;
+
+ for (int j = 0; j < pluckers.size(); j++)
+ pluckers[j]->draw();
+ } else
+ plucker->draw();
+ } else
+ m_children[i]->draw();
+ }
+}
+
+// =======================
+// SpiralTrack implementation
+// =======================
+
+SpiralTrack::SpiralTrack(Point2D center, float startAngle, float startRadius,
+ float endAngle, float endRadius,
+ Joint *joint1, Joint *joint2) :
+ Track(),
+ m_center(center),
+ m_startRadius(startRadius),
+ m_endRadius(endRadius),
+ m_startAngle(startAngle),
+ m_endAngle(endAngle),
+ m_spiral(NULL)
+{
+ m_fActive = true;
+
+ initialize(center, startAngle, startRadius, endAngle, endRadius, joint1, joint2);
+}
+
+std::string SpiralTrack::toString()
+{
+ std::ostringstream os;
+ os << "center: " << m_center.x << ", " << m_center.y << "; "
+ << "start: " << m_startRadius << ", " << m_startAngle << "; "
+ << "end: " << m_endRadius << ", " << m_endAngle << "; "
+ << "joint1: " << m_joint1->toString() << "; "
+ << "joint2: " << m_joint2->toString();
+ return os.str();
+}
+
+SpiralTrack::~SpiralTrack()
+{
+ delete m_spiral;
+}
+
+void SpiralTrack::initialize(Point2D center, float startAngle, float startRadius,
+ float endAngle, float endRadius, Joint *joint1, Joint *joint2) {
+ setupJoints(joint1, joint2);
+
+ // Adjust the settings based on the joints
+ if (m_joint1->getTracks()->size() > 1)
+ {
+ startAngle = Spiral::getAngle(center, m_joint1->getCenter()),
+ startRadius = Point2D::distance(center, m_joint1->getCenter());
+ }
+
+ if (m_joint2->getTracks()->size() > 1)
+ {
+ endAngle = Spiral::getAngle(center, m_joint2->getCenter()),
+ endRadius = Point2D::distance(center, m_joint2->getCenter());
+ }
+
+ // Restrict the angle to be between 0 and 360
+ m_startAngle = Spiral::clampAngle(startAngle);
+ m_endAngle = Spiral::clampAngle(endAngle);
+
+ m_startRadius = startRadius;
+ m_endRadius = endRadius;
+
+ if (m_spiral) {
+ m_spiral->setRadii(m_startRadius, m_endRadius);
+ m_spiral->setCenter(center);
+ m_spiral->setAngles(m_startAngle, m_endAngle);
+ } else
+ m_spiral = new Spiral(center, m_startAngle, m_startRadius, m_endAngle, m_endRadius);
+
+ if (!joint1)
+ m_joint1->setCenter(getEndPoint1());
+
+ if (!joint2)
+ m_joint2->setCenter(getEndPoint2());
+
+}
+
+void SpiralTrack::draw()
+{
+ m_spiral->setDotted(!m_fActive);
+ m_spiral->setDirected(m_fDirected);
+
+ m_spiral->draw();
+ drawChildren();
+
+}
+
+Point2D SpiralTrack::getEndPoint1()
+{
+ float x = m_center.x + m_startRadius * cos((double) m_startAngle * MY_PI / 180),
+ y = m_center.y - m_startRadius * sin((double) m_startAngle * MY_PI / 180);
+ return Point2D(x, y);
+}
+
+Point2D SpiralTrack::getEndPoint2()
+{
+ float x = m_center.x + m_endRadius * cos((double) m_endAngle * MY_PI / 180),
+ y = m_center.y - m_endRadius * sin((double) m_endAngle * MY_PI / 180);
+ return Point2D(x, y);
+}
+
+Widget *SpiralTrack::hitTest(float x, float y)
+{
+ if (m_joint1->hitTest(x, y) || m_joint2->hitTest(x, y))
+ return this;
+
+ Widget* hit = NULL;
+ Color color(0, 0, 0, 1);
+
+ Point2D p(x, y);
+ float angle = Spiral::getAngle(m_center, p);
+ if (angle > m_endAngle && m_endAngle > m_startAngle || angle < m_startAngle) {
+ float baseAngleDiff = m_startAngle - m_endAngle;
+ float angleDiff = m_startAngle - angle;
+ if (m_endAngle > m_startAngle) {
+ baseAngleDiff += 360;
+ if (angle > m_startAngle)
+ angleDiff += 360;
+ }
+ float radius = m_endRadius + (m_startRadius - m_endRadius) * (1 - angleDiff / baseAngleDiff);
+ float dist = Point2D::distance(m_center, p);
+ if (fabs(radius - dist) < 5) {
+ color = Color(1, .5, 0, 1);
+ hit = this;
+ }
+ }
+
+ m_spiral->setColor(color);
+ return hit;
+}
+
+void SpiralTrack::toOutboundPacketStream(osc::OutboundPacketStream& ps) const
+{
+ ps.Clear();
+ ps << osc::BeginMessage("/object/track/spiral")
+ << osc::Symbol(m_uuid.c_str()) << osc::Symbol(m_parent->getUuid())
+ << m_startAngle << m_startRadius << m_endAngle << m_endRadius
+ << osc::EndMessage;
+}
+
+Point2D SpiralTrack::getNextPos(bool fReverse, float distance, Point2D pos)
+{
+ float oradius = m_startRadius,
+ dradius = m_endRadius,
+ oangle = m_startAngle,
+ dangle = m_endAngle,
+ cangle = Spiral::getAngle(m_center, pos);
+ /*
+ if (fabs(cangle - oangle) < 1)
+ cangle = oangle;
+
+ if (fabs(cangle - dangle) < 1)
+ cangle = dangle;
+ */
+ //std::cerr << pos.x << ", " << pos.y << std::endl;
+ // adjust the value of the angle for more convenient computation
+ for (; cangle > oangle; cangle -= 360);
+ for (; dangle > cangle; dangle -= 360);
+
+ float oangleR = oangle * MY_PI / 180,
+ dangleR = dangle * MY_PI / 180,
+ cangleR = cangle * MY_PI / 180;
+
+ float angleDiff = oangle - dangle,
+ angleDiffR = angleDiff * MY_PI / 180;
+
+ if (angleDiff == 0)
+ return pos;
+
+ float radiusDiff = dradius - oradius,
+ rate = radiusDiff / angleDiff,
+ rateR = radiusDiff / angleDiffR;
+
+ float newAngleR;
+ //std::cerr << rateR << std::endl;
+ if (fabs(radiusDiff) < 0.0001)
+ {
+ newAngleR = cangleR - distance / oradius;
+ // std::cerr << distance / oradius << std::endl;
+ }
+ else
+ {
+ float a = rateR / 2,
+ b = -oradius - rateR * oangleR,
+ c = oradius * cangleR + rateR * oangleR * cangleR - rateR * cangleR * cangleR / 2 - distance;
+ // new angle
+ float sol1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a),
+ sol2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
+
+ newAngleR = (sol1 <= cangleR && sol1 >= dangleR) ? sol1 :
+ (sol2 <= cangleR && sol2 >= dangleR) ? sol2 : dangleR;
+ }
+ float newRadius = oradius + (oangleR - newAngleR) * rateR;
+ Point2D result = Point2D(m_center.x + newRadius * cos(newAngleR), m_center.y - newRadius * sin(newAngleR));
+ /*
+ std::cerr << "SpiralTrack::getNextPos: from " << pos.x << ", " << po