diff --git a/zonebb/addons.make b/zonebb/addons.make
new file mode 100644
index 0000000..4b55504
--- /dev/null
+++ b/zonebb/addons.make
@@ -0,0 +1,6 @@
+ofxAzureKinect
+ofxFluid
+ofxFX
+ofxGui
+ofxShader
+ofxV4L2
diff --git a/zonebb/bin/data/.gitkeep b/zonebb/bin/data/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/zonebb/bin/data/settings.xml b/zonebb/bin/data/settings.xml
new file mode 100644
index 0000000..0f0ee4b
--- /dev/null
+++ b/zonebb/bin/data/settings.xml
@@ -0,0 +1,9 @@
+
+
+ 61.2245, -28.5714
+ 1.7965
+ video3
+ 4
+ 1
+ 3
+
diff --git a/zonebb/config.make b/zonebb/config.make
new file mode 100644
index 0000000..836fce7
--- /dev/null
+++ b/zonebb/config.make
@@ -0,0 +1,141 @@
+################################################################################
+# 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.
+################################################################################
+# 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/zonebb/src/main.cpp b/zonebb/src/main.cpp
new file mode 100644
index 0000000..e57370b
--- /dev/null
+++ b/zonebb/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "ofApp.h"
+
+//========================================================================
+int main( ){
+ ofSetupOpenGL(1024,768,OF_WINDOW); // <-------- setup the GL context
+
+ // this kicks off the running of my app
+ // can be OF_WINDOW or OF_FULLSCREEN
+ // pass in width and height too:
+ ofRunApp(new ofApp());
+
+}
diff --git a/zonebb/src/ofApp.cpp b/zonebb/src/ofApp.cpp
new file mode 100644
index 0000000..35ace6c
--- /dev/null
+++ b/zonebb/src/ofApp.cpp
@@ -0,0 +1,345 @@
+#include "ofApp.h"
+
+void ofApp::setupGui()
+{
+ gui.setup("ZONE B", "settings.xml"); // most of the time you don't need a name
+ gui.add(registrationXY.setup("XY", {-208, -257}, {-400, -400}, {400, 400}));
+ gui.add(registrationScale.setup("scale", 2.0, 0.1, 3));
+ gui.add(v4l2Delay.setup("thermo delay", 0, 0, 59));
+ gui.add(captureDeviceName.setup("device", "video3"));
+ gui.loadFromFile("settings.xml");
+ gui.setPosition(10, 10);
+
+ debugGui.setup("DEBUG");
+ debugGui.add(calibMode.setup("calib", false));
+ debugGui.add(dummyMode.setup("dummy", true)); // should be false
+ debugGui.add(dummyXY.setup("XY", {0, 0}, {-500, -500}, {500, 500})); // should be false
+ debugGui.add(debugFps.setup("FPS", "0"));
+ debugGui.setPosition(230, 10);
+}
+
+void ofApp::setupKinect()
+{
+ ofLogNotice(__FUNCTION__) << "Found " << ofxAzureKinect::Device::getInstalledCount() << " installed devices.";
+
+ auto kinectSettings = ofxAzureKinect::DeviceSettings();
+ kinectSettings.updateIr = false;
+ kinectSettings.updateColor = true;
+ kinectSettings.colorResolution = K4A_COLOR_RESOLUTION_1080P;
+ kinectSettings.updateVbo = false;
+
+ auto deviceSettings = ofxAzureKinect::DeviceSettings();
+ deviceSettings.syncImages = false;
+ deviceSettings.depthMode = K4A_DEPTH_MODE_NFOV_UNBINNED;
+ deviceSettings.updateIr = false;
+ deviceSettings.updateColor = false;
+ //deviceSettings.colorResolution = K4A_COLOR_RESOLUTION_1080P;
+ deviceSettings.updateWorld = true;
+ deviceSettings.updateVbo = false;
+ auto bodyTrackingSettings = ofxAzureKinect::BodyTrackingSettings();
+ //bodyTrackingSettings.processingMode = K4ABT_TRACKER_PROCESSING_MODE_CPU;
+ bodyTrackingSettings.updateBodies = true;
+ if (kinectDevice.open())
+ {
+ kinectDevice.startCameras(kinectSettings, bodyTrackingSettings);
+ }
+}
+
+void ofApp::setupThermal()
+{
+ // this must be called before init (otherwise fprintf will tell you so)
+ // note that high framerates will only function properly if the usb has enough bandwidth
+ // for example, a ps3 eye cam at 60 fps will only function when it has full USB 2.0 bandwidth available
+ v4l2Cam.setDesiredFramerate(60);
+
+ // use this to set appropriate device and capture method
+ std::string dev = captureDeviceName;
+ v4l2Cam.initGrabber((std::string("/dev/") + dev).c_str(), IO_METHOD_MMAP, camWidth, camHeight);
+
+ // some initial settings
+ int set_gain = 2.0;
+ bool set_autogain = true;
+
+ // rudimentary settings implementation: each settings needs a seperate call to the settings method
+ v4l2Cam.settings(ofxV4L2_AUTOGAIN, set_autogain);
+ v4l2Cam.settings(ofxV4L2_GAIN, set_gain);
+
+ v4l2Buffer.resize(60);
+ for (int i = 0; i < v4l2Buffer.size(); i++)
+ {
+ v4l2Buffer.at(i).allocate(512, 512, GL_RGB);
+ }
+
+ v4l2Pixels.allocate(512, 512, OF_PIXELS_RGB);
+ for (int i = 0; i < 512; i++)
+ {
+ for (int j = 0; j < 512; j++)
+ {
+ v4l2Pixels.setColor(j, i, 0);
+ }
+ }
+
+ areThereTwoPeople = false;
+ areThereTwoPeopleTween = 0;
+}
+
+void ofApp::setupFluid()
+{
+ width = 1920;
+ height = 1200;
+
+ // Initial Allocation
+ //
+ fluid.allocate(width, height, 0.5);
+
+ // Seting the gravity set up & injecting the background image
+ //
+ fluid.dissipation = 0.9;
+ fluid.velocityDissipation = 0.995;
+
+ fluid.setGravity(ofVec2f(0.0, 0.0));
+ // fluid.setGravity(ofVec2f(0.0,0.0098));
+
+ // Set obstacle
+ //
+ // fluid.begin();
+ // ofSetColor(0, 0);
+ // ofSetColor(255);
+ // ofCircle(width * 0.5, height * 0.35, 40);
+ // fluid.end();
+ fluid.setUseObstacles(false);
+
+ // Adding constant forces
+ //
+ // fluid.addConstantForce(ofPoint(width * 0.5, height * 0.85), ofPoint(0, -2), ofFloatColor(0.5, 0.1, 0.0), 10.f);
+}
+
+void ofApp::setup()
+{
+ ofEnableAlphaBlending();
+ ofSetCircleResolution(100);
+
+ ofSetWindowShape(1920, 1080);
+
+ setupGui();
+ setupKinect();
+ setupThermal();
+ setupFluid();
+
+ fbos.insert({"main", ofFbo()});
+ fbos.at("main").allocate(ofGetWidth(), ofGetHeight(), GL_RGBA32F_ARB);
+}
+
+ofVec3f ofApp::getDepthAt(int x, int y)
+{
+ auto ray = kinectDevice.getDepthToWorldPix().getColor(x, y);
+ auto depthShort = kinectDevice.getDepthPix().getColor(x, y).r;
+ float depth = -depthShort;
+ if (depthShort == 0)
+ depth = -2000;
+ ofVec3f pos(ray.r * depth, ray.g * depth, depth);
+ return pos;
+}
+
+void ofApp::updateThermal()
+{
+ v4l2Cam.grabFrame();
+ if (v4l2Cam.isNewFrame())
+ {
+ auto &body = kinectDevice.getBodyIndexPix();
+ hotspots.clear();
+ for (int i = 0; i < kinectDevice.getNumBodies(); i++)
+ {
+ hotspots.push_back(std::vector());
+ }
+ for (int i = 0; i < 512; i++)
+ {
+ for (int j = 0; j < 512; j++)
+ {
+ int x = (j - 256) * registrationScale + 256 + registrationXY->x;
+ int y = (i - 256) * registrationScale + 256 + registrationXY->y;
+ if (ofInRange(x, 0, camWidth - 1) == false || ofInRange(y, 0, camHeight - 1) == false)
+ {
+ continue;
+ }
+ int count = x + y * camWidth;
+ int a = v4l2Cam.getPixels()[count];
+ v4l2Pixels.setColor(j, i, a);
+ if (i % 4 == 0 && j % 4 == 0)
+ {
+ auto c = body.getColor(j, i);
+ if (c.r < hotspots.size())
+ {
+ hotspots.at(c.r).push_back(ofVec3f(j, i, a));
+ }
+ }
+ }
+ }
+ v4l2BufferCount = (v4l2BufferCount + 1) % (v4l2Delay + 1);
+ v4l2Buffer.at(v4l2BufferCount).allocate(v4l2Pixels);
+
+ struct
+ {
+ bool operator()(ofVec3f a, ofVec3f b) const
+ {
+ return a.z > b.z;
+ }
+ } compareZThermal;
+ for (int i = 0; i < hotspots.size(); i++)
+ {
+ std::sort(hotspots.at(i).begin(), hotspots.at(i).end(), compareZThermal);
+ }
+
+ if (dummyMode == false)
+ {
+ if (hotspots.size() > 0 && hotspots.at(0).size() > 0)
+ {
+ hotspot0 = hotspots.at(0).at(0);
+ }
+ if (hotspots.size() > 1 && hotspots.at(1).size() > 0)
+ {
+ hotspot1 = hotspots.at(1).at(0);
+ areThereTwoPeople = true;
+ areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween + 0.02, 0, 1);
+ }
+ else
+ {
+ areThereTwoPeople = false;
+ areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween - 0.02, 0, 1);
+ }
+ }
+ else
+ {
+ if (hotspots.size() > 0 && hotspots.at(0).size() > 0)
+ {
+ hotspot0 = hotspots.at(0).at(0);
+ }
+ {
+ hotspot1 = ofVec3f(dummyXY->x + 500, dummyXY->y + 500, 0);
+ areThereTwoPeople = true;
+ areThereTwoPeopleTween = ofClamp(areThereTwoPeopleTween + 0.02, 0, 1);
+ }
+ }
+ }
+}
+
+void ofApp::updateFluid()
+{
+ fluid.addColor(v4l2Buffer.at(v4l2BufferCount), 0.1f);
+
+ ofPoint m = ofPoint(mouseX,mouseY);
+ ofPoint d = (m - oldM)*10.0;
+ oldM = m;
+ ofPoint c = ofPoint(640*0.5, 480*0.5) - m;
+ c.normalize();
+ fluid.addTemporalForce(m, d, ofFloatColor(0)*sin(ofGetElapsedTimef()),15.0f,20);
+
+ // Update
+ //
+ fluid.update();
+}
+
+void ofApp::update()
+{
+ if (dummyMode == false)
+ {
+ auto &bodySkeletons = kinectDevice.getBodySkeletons();
+ std::vector bodies;
+ if (bodySkeletons.size() >= 2)
+ {
+ for (auto &skeleton : bodySkeletons)
+ {
+ auto joint = skeleton.joints[26];
+ bodies.push_back(toGlm(joint.position));
+ }
+ uBetween = uBetween.getInterpolated(bodies.at(0).getInterpolated(bodies.at(1), 0.5f), 0.1f);
+ }
+ else
+ {
+ // uBetween = ofVec3f(10000000, 0, 0);
+ }
+ }
+ else
+ {
+ uBetween = ofVec3f(dummyXY->x, 0, dummyXY->y);
+ }
+
+ updateThermal();
+ updateFluid();
+
+ debugFps = ofToString(ofGetFrameRate(), 2);
+}
+
+void ofApp::drawMain()
+{
+ ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_LINEAR);
+
+ fluid.draw();
+}
+
+void ofApp::drawDebug()
+{
+ gui.draw();
+ debugGui.draw();
+}
+
+void ofApp::draw()
+{
+ drawMain();
+ drawDebug();
+}
+
+
+void ofApp::keyPressed(int key)
+{
+}
+
+
+void ofApp::keyReleased(int key)
+{
+}
+
+
+void ofApp::mouseMoved(int x, int y)
+{
+}
+
+
+void ofApp::mouseDragged(int x, int y, int button)
+{
+}
+
+
+void ofApp::mousePressed(int x, int y, int button)
+{
+}
+
+
+void ofApp::mouseReleased(int x, int y, int button)
+{
+}
+
+
+void ofApp::mouseEntered(int x, int y)
+{
+}
+
+
+void ofApp::mouseExited(int x, int y)
+{
+}
+
+
+void ofApp::windowResized(int w, int h)
+{
+}
+
+
+void ofApp::gotMessage(ofMessage msg)
+{
+}
+
+
+void ofApp::dragEvent(ofDragInfo dragInfo)
+{
+}
diff --git a/zonebb/src/ofApp.h b/zonebb/src/ofApp.h
new file mode 100644
index 0000000..af1282c
--- /dev/null
+++ b/zonebb/src/ofApp.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "ofMain.h"
+#include "ofxGui.h"
+#include "ofxAzureKinect.h"
+#include "ofxFluid.h"
+#include "ofxV4L2.h"
+
+class ofApp : public ofBaseApp
+{
+
+public:
+ void setupKinect();
+ void setupThermal();
+ void setupFluid();
+ void setupGui();
+ void setup();
+
+ ofVec3f getDepthAt(int x, int y);
+ void updateThermal();
+ void updateFluid();
+ void update();
+ void drawMain();
+ void drawDebug();
+ void draw();
+
+ void keyPressed(int key);
+ void keyReleased(int key);
+ void mouseMoved(int x, int y);
+ void mouseDragged(int x, int y, int button);
+ void mousePressed(int x, int y, int button);
+ void mouseReleased(int x, int y, int button);
+ void mouseEntered(int x, int y);
+ void mouseExited(int x, int y);
+ void windowResized(int w, int h);
+ void dragEvent(ofDragInfo dragInfo);
+ void gotMessage(ofMessage msg);
+
+ std::map fbos;
+ std::map gradients;
+ std::vector gradientNames{"warm1", "warm2", "cold1", "cold2"};
+
+ ofxAzureKinect::Device kinectDevice;
+
+ ofxFluid fluid;
+
+ ofVec2f oldM;
+ int width, height;
+ bool bPaint, bObstacle, bBounding, bClear;
+
+ const int camWidth = 640;
+ const int camHeight = 480;
+
+ ofxV4L2 v4l2Cam;
+ std::vector v4l2Buffer;
+ int v4l2BufferCount;
+ ofPixels v4l2Pixels;
+
+ std::vector> hotspots;
+ ofVec3f hotspot0, hotspot1;
+ ofVec3f uBetween;
+ bool areThereTwoPeople;
+ float areThereTwoPeopleTween;
+
+ ofxVec2Slider registrationXY;
+ ofxFloatSlider registrationScale;
+ ofxIntSlider v4l2Delay;
+ ofxInputField captureDeviceName;
+ ofxPanel gui;
+
+ ofxToggle calibMode;
+ ofxToggle dummyMode;
+ ofxVec2Slider dummyXY;
+ ofxLabel debugFps;
+ ofxPanel debugGui;
+};