diff --git a/example_remote-server/Makefile b/example_remote-server/Makefile
new file mode 100644
index 0000000..8d8e4c0
--- /dev/null
+++ b/example_remote-server/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=$(realpath ../../..)
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/example_remote-server/addons.make b/example_remote-server/addons.make
new file mode 100644
index 0000000..8e7845c
--- /dev/null
+++ b/example_remote-server/addons.make
@@ -0,0 +1,6 @@
+ofxGui
+ofxJSON
+ofxNetwork
+ofxOpenCv
+ofxPiMapper
+ofxXmlSettings
diff --git a/example_remote-server/bin/data/ofxpimapper.xml b/example_remote-server/bin/data/ofxpimapper.xml
new file mode 100644
index 0000000..a11fe2e
--- /dev/null
+++ b/example_remote-server/bin/data/ofxpimapper.xml
@@ -0,0 +1,36 @@
+
+
+
+
+ 640.000000000
+ 50.000000000
+
+
+ 1230.000000000
+ 750.000000000
+
+
+ 50.000000000
+ 750.000000000
+
+
+
+
+ 0.500000000
+ 0.000000000
+
+
+ 1.000000000
+ 1.000000000
+
+
+ 0.000000000
+ 1.000000000
+
+
+
+ video
+ gene-nsynthesis-loop-b.mp4
+
+
+
diff --git a/example_remote-server/bin/data/sources/videos/gene-nsynthesis-loop-b.mp4 b/example_remote-server/bin/data/sources/videos/gene-nsynthesis-loop-b.mp4
new file mode 100644
index 0000000..eba3582
--- /dev/null
+++ b/example_remote-server/bin/data/sources/videos/gene-nsynthesis-loop-b.mp4
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2da7b85225116bee7e1ae5275f58cca7684c2a5d013b97bdd46955c2c418a812
+size 2045077
diff --git a/example_remote-server/config.make b/example_remote-server/config.make
new file mode 100644
index 0000000..df10f64
--- /dev/null
+++ b/example_remote-server/config.make
@@ -0,0 +1,142 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../..
+################################################################################
+# OF_ROOT = ../../..
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+# TODO: should this be a default setting?
+# PROJECT_LDFLAGS=-Wl,-rpath=./libs
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CFLAGS =
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/example_remote-server/src/TCPServer.cpp b/example_remote-server/src/TCPServer.cpp
new file mode 100644
index 0000000..e3c5127
--- /dev/null
+++ b/example_remote-server/src/TCPServer.cpp
@@ -0,0 +1,93 @@
+#include "TCPServer.h"
+
+shared_ptr TCPServer::_instance = 0;
+
+shared_ptr TCPServer::instance(){
+ if(_instance == 0){
+ _instance = shared_ptr(new TCPServer);
+ }
+ return _instance;
+}
+
+TCPServer::TCPServer(){
+ std::cout << "TCPServer initialized" << std::endl;
+}
+
+void TCPServer::setup(int port){
+ _tcpServer.setup(port);
+}
+
+void TCPServer::update(){
+ int numClients = _tcpServer.getLastID();
+ for(auto i = 0; i < numClients; ++i){
+ if(_tcpServer.isClientConnected(i)){
+
+ // Notify application when new client connects
+ if(!_tcpConnections[i]){
+ ofxJSONElement json;
+ json["ip"] = _tcpServer.getClientIP(i);
+ json["port"] = _tcpServer.getClientPort(i);
+ json["id"] = i;
+ json["event"] = "connected";
+
+ ofMessage message(json.getRawString());
+ ofSendMessage(message);
+
+ _tcpConnections[i] = true;
+ }
+
+ // Receive messages
+ string rx = _tcpServer.receive(i);
+ if(rx.length() > 0){
+ ofxJSONElement json;
+ bool ok = json.parse(rx);
+
+ if(!ok){
+ json["ip"] = _tcpServer.getClientIP(i);
+ json["port"] = _tcpServer.getClientPort(i);
+ json["id"] = i;
+ json["event"] = "received";
+ json["data"] = rx;
+ }
+
+ ofMessage message(json.getRawString());
+ ofSendMessage(message);
+ }
+ }else{
+
+ // Notify application when client disconnects
+ if(_tcpConnections[i]){
+ ofxJSONElement json;
+ json["ip"] = _tcpServer.getClientIP(i);
+ json["port"] = _tcpServer.getClientPort(i);
+ json["id"] = i;
+ json["event"] = "disconnected";
+
+ ofMessage message(json.getRawString());
+ ofSendMessage(message);
+
+ _tcpConnections[i] = false;
+ }
+ }
+ }
+}
+
+void TCPServer::draw(){
+ int numClients = _tcpServer.getLastID();
+ int clientsConnected = 0;
+ for(auto i = 0; i < numClients; ++i){
+ if(_tcpServer.isClientConnected(i)){
+ ofSetColor(0, 255, 0);
+ ofPushMatrix();
+ ofTranslate(10, 10);
+ ofDrawRectangle(clientsConnected * 20, 0, 10, 10);
+ ofPopMatrix();
+ clientsConnected++;
+ }
+ }
+}
+
+void TCPServer::send(int clientID, std::string message){
+ _tcpServer.send(clientID, message);
+}
+
diff --git a/example_remote-server/src/TCPServer.h b/example_remote-server/src/TCPServer.h
new file mode 100644
index 0000000..a6be1c2
--- /dev/null
+++ b/example_remote-server/src/TCPServer.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxNetwork.h"
+#include "ofxJSONElement.h"
+
+class TCPServer {
+public:
+ static shared_ptr instance();
+
+ void setup(int port);
+ void update();
+ void draw();
+
+ void send(int clientID, std::string message);
+
+private:
+ TCPServer();
+ static shared_ptr _instance;
+
+ ofxTCPServer _tcpServer;
+ std::map _tcpConnections;
+};
diff --git a/example_remote-server/src/main.cpp b/example_remote-server/src/main.cpp
new file mode 100644
index 0000000..c696d20
--- /dev/null
+++ b/example_remote-server/src/main.cpp
@@ -0,0 +1,7 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+int main(){
+ ofSetupOpenGL(1280, 800, OF_WINDOW);
+ ofRunApp(new ofApp());
+}
diff --git a/example_remote-server/src/ofApp.cpp b/example_remote-server/src/ofApp.cpp
new file mode 100644
index 0000000..7532328
--- /dev/null
+++ b/example_remote-server/src/ofApp.cpp
@@ -0,0 +1,84 @@
+#include "ofApp.h"
+
+void ofApp::setup(){
+ ofBackground(0);
+ mapper.setup();
+ TCPServer::instance()->setup(9999);
+
+#ifdef TARGET_RASPBERRY_PI
+ ofSetFullscreen(true);
+#endif
+}
+
+void ofApp::update(){
+ mapper.update();
+ TCPServer::instance()->update();
+}
+
+void ofApp::draw(){
+ mapper.draw();
+ TCPServer::instance()->draw();
+}
+
+// Here is where we process messages received from TCPServer instance
+void ofApp::gotMessage(ofMessage m){
+ std::cout << m.message << std::endl;
+
+ ofxJSONElement json;
+ bool ok = json.parse(m.message);
+ if(ok){
+ if(json["event"].asString() == "connected"){
+ // Save Mapper composition and get config as string
+ std::cout << "Sending mapper config" << std::endl;
+ mapper.saveProject();
+
+ ofFile file;
+ file.open(ofToDataPath("ofxpimapper.xml"), ofFile::ReadOnly, false);
+ ofBuffer buff = file.readToBuffer();
+ string text = buff.getText();
+
+ TCPServer::instance()->send(json["id"].asInt(), text);
+ }
+
+ if(json["event"].asString() == "keyPressed"){
+ mapper.keyPressed(json["key"].asInt());
+ }
+
+ if(json["event"].asString() == "keyReleased"){
+ mapper.keyReleased(json["key"].asInt());
+ }
+
+ if(json["event"].asString() == "mousePressed"){
+ mapper.mousePressed(json["x"].asInt(), json["y"].asInt(), json["button"].asInt());
+ }
+
+ if(json["event"].asString() == "mouseReleased"){
+ mapper.mouseReleased(json["x"].asInt(), json["y"].asInt(), json["button"].asInt());
+ }
+
+ if(json["event"].asString() == "mouseDragged"){
+ mapper.mouseDragged(json["x"].asInt(), json["y"].asInt(), json["button"].asInt());
+ }
+ }
+}
+
+void ofApp::keyPressed(int key){
+ mapper.keyPressed(key);
+}
+
+void ofApp::keyReleased(int key){
+ mapper.keyReleased(key);
+}
+
+void ofApp::mousePressed(int x, int y, int button){
+ mapper.mousePressed(x, y, button);
+}
+
+void ofApp::mouseReleased(int x, int y, int button){
+ mapper.mouseReleased(x, y, button);
+}
+
+void ofApp::mouseDragged(int x, int y, int button){
+ mapper.mouseDragged(x, y, button);
+}
+
diff --git a/example_remote-server/src/ofApp.h b/example_remote-server/src/ofApp.h
new file mode 100644
index 0000000..6c95a21
--- /dev/null
+++ b/example_remote-server/src/ofApp.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "ofMain.h"
+#include "TCPServer.h"
+#include "ofxPiMapper.h"
+#include "ofxJSONElement.h"
+
+class ofApp : public ofBaseApp{
+public:
+ void setup();
+ void update();
+ void draw();
+
+ void gotMessage(ofMessage m);
+
+ void keyPressed(int key);
+ void keyReleased(int key);
+ void mousePressed(int x, int y, int button);
+ void mouseReleased(int x, int y, int button);
+ void mouseDragged(int x, int y, int button);
+
+ ofxPiMapper mapper;
+};