openFrameworks
chapter 2
openFrameworks
MSAFluids-Kinect
MSAFluids-data visualisation
Choose C++
ofApp.h
#pragma once
#include "MSAFluid.h"
//#include "MSATimer.h"
#include "ParticleSystem.h"
#include "ofMain.h"
#include "ofxOpenCv.h"
#include "ofxXmlSettings.h"
#include "ofxUI.h"
#include "ofxGui.h"
#include "ofxOsc.h"
#define HOST "localhost"
#define PORT 12345
#define NUM_MSG_STRINGS 20
// comment this line out if you don't wanna use TUIO
// you will need ofxTUIO & ofxOsc
#define USE_TUIO
// comment this line out if you don't wanna use the GUI
// you will need ofxSimpleGuiToo, ofxMSAInteractiveObject & ofxXmlSettings
// if you don't use the GUI, you won't be able to see the fluid parameters
#define USE_GUI
#ifdef USE_TUIO
#include "ofxTuio.h"
#define tuioCursorSpeedMult 0.5 // the iphone screen is so small, easy to rack up huge velocities! need to scale down
#define tuioStationaryForce 0.001f // force exerted when cursor is stationary
#endif
#ifdef USE_GUI
#include "ofxSimpleGuiToo.h"
#endif
// uncomment this to read from two kinects simultaneously
//#define USE_TWO_KINECTS
class ofApp : public ofBaseApp {
public:
void setup();
void setupGui();
void update();
void drawGui(ofEventArgs & args);
void draw();
void exit();
void keyPressed(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 windowResized(int w, int h);
void fadeToColor(float r, float g, float b, float speed);
void addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce);
ofVboMesh mesh;
ofEasyCam cam;
//ofxAssimpModelLoader model;
ofLight light;
float colorMult;
float velocityMult;
int fluidCellsX;
bool resizeFluid;
bool drawFluid;
bool drawParticles;
msa::fluid::Solver fluidSolver;
msa::fluid::DrawerGl fluidDrawer;
ParticleSystem particleSystem;
ofVec2f pMouse;
//Each frame take the number of blobs and create cursors at their centroids
vector<ofVec2f> cursors ;
float cursorXSensitivity ;
float cursorYSensitivity ;
bool bRestrictCursors ;
float cursorBorderPadding ;
bool bFullscreen;
bool bShowControlPanel;
bool bEpsCapture;
bool bThreshWithOpenCV;
bool bKinectOpen ;
int nearThreshold;
int farThreshold;
float minBlobSize , maxBlobSize ;
int maxCursors ;
/////earh here
ofImage texture;
bool holdingbutton;
int oldalpha;
int newalpha;
ofImage offimage;
ofImage onimage;
GLUquadricObj *quadric;
/////
int mouseX =0;
#ifdef USE_TUIO
ofxTuioClient tuioClient;
#endif
ofxCvColorImage colorImg;
ofxOscReceiver receiver;
float oscX = 0.0;
float oscY = 0.0;
int fadeAmt = 0;
//this holds all of our points
vector<ofVec3f> points;
//this keeps track of the center of all the points
//ofxPanel gui;
ofBlendMode blendMode;
ofImage rainbow;
ofTrueTypeFont vagRounded;
string eventString;
string timeString;
};
ofApp.cpp
#include "ofApp.h"
char sz[] = "[Rd9?-2XaUP0QY[hO%9QTYQ`-W`QZhcccYQY[`b";
float tuioXScaler = 1;
float tuioYScaler = 1;
//--------------------------------------------------------------
void ofApp::setup() {
ofSetLogLevel(OF_LOG_VERBOSE);
// turn on smooth lighting //
ofSetSmoothLighting(true);
//need this for alpha to come through
ofEnableAlphaBlending();
//OSC
receiver.setup(PORT);
cout << "listening for osc messages on port " << PORT << "\n";
//ofSetFrameRate(60);
//Fluids
for(int i=0; i<strlen(sz); i++) sz[i] += 20;
// setup fluid stuff
fluidSolver.setup(100, 100);
fluidSolver.enableRGB(true).setFadeSpeed(0.002).setDeltaT(0.5).setVisc(0.00015).setColorDiffusion(0);
fluidDrawer.setup(&fluidSolver);
fluidCellsX = 150;
drawFluid = true;
drawParticles = true;
ofSetFrameRate(60);
ofBackground(0);
ofSetVerticalSync(false);
#ifdef USE_TUIO
tuioClient.start(3333);
#endif
windowResized(ofGetWidth(), ofGetHeight()); // force this at start (cos I don't think it is called)
pMouse = msa::getWindowCenter();
resizeFluid = true;
//ofEnableAlphaBlending();
ofSetBackgroundAuto(false);
///////------mesh here
/*
mesh.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);
mesh.enableColors();
ofVec3f v0(-100, -100, -100);
ofVec3f v1(100, -100, -100);
ofVec3f v2(100, 100, -100);
mesh.addVertex(v0);
mesh.addColor(ofFloatColor(0.0, 0.0, 0.0));
mesh.addVertex(v1);
mesh.addColor(ofFloatColor(1.0, 0.0, 0.0));
mesh.addVertex(v2);
mesh.addColor(ofFloatColor(1.0, 1.0, 0.0));
*/
///---sphere here
ofDisableArbTex();
//ofLoadImage(texture, "earthTex.jpg");
texture.load("earthTex.jpg");
//this makes sure that the back of the model doesn't show through the front
ofEnableDepthTest();
// sphere.setRadius( width );
//prepare quadric for sphere
quadric = gluNewQuadric();
gluQuadricTexture(quadric, GL_TRUE);
gluQuadricNormals(quadric, GLU_SMOOTH);
/////////////////////////
}
//---------------------------------------
void ofApp::fadeToColor(float r, float g, float b, float speed) {
glColor4f(r, g, b, speed);
ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight());
}
// add force and dye to fluid, and create particles
void ofApp::addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce) {
float speed = vel.x * vel.x + vel.y * vel.y * msa::getWindowAspectRatio() * msa::getWindowAspectRatio(); // balance the x and y components of speed with the screen aspect ratio
if(speed > 0) {
pos.x = ofClamp(pos.x, 0.0f, 1.0f);
pos.y = ofClamp(pos.y, 0.0f, 1.0f);
int index = fluidSolver.getIndexForPos(pos);
if(addColor) {
// Color drawColor(CM_HSV, (getElapsedFrames() % 360) / 360.0f, 1, 1);
ofColor drawColor;
drawColor.setHsb((ofGetFrameNum() % 255), 255, 255);
fluidSolver.addColorAtIndex(index, drawColor * colorMult);
if(drawParticles)
particleSystem.addParticles(pos * ofVec2f(ofGetWindowSize()), 10);
}
if(addForce)
fluidSolver.addForceAtIndex(index, vel * velocityMult);
}
}
//--------------------------------------------------------------
void ofApp::setupGui(){
float dim = 24.0;
gui.addSlider("fluidCellsX", fluidCellsX, 20, 400);
gui.addButton("resizeFluid", resizeFluid);
gui.addSlider("colorMult", colorMult, 0, 100);
gui.addSlider("velocityMult", velocityMult, 0, 100);
gui.addSlider("fs.viscocity", fluidSolver.viscocity, 0.0, 0.01);
gui.addSlider("fs.colorDiffusion", fluidSolver.colorDiffusion, 0.0, 0.0003);
gui.addSlider("fs.fadeSpeed", fluidSolver.fadeSpeed, 0.0, 0.1);
gui.addSlider("fs.solverIterations", fluidSolver.solverIterations, 1, 50);
gui.addSlider("fs.deltaT", fluidSolver.deltaT, 0.1, 5);
gui.addComboBox("fd.drawMode", (int&)fluidDrawer.drawMode, msa::fluid::getDrawModeTitles());
gui.addToggle("fs.doRGB", fluidSolver.doRGB);
gui.addToggle("fs.doVorticityConfinement", fluidSolver.doVorticityConfinement);
gui.addToggle("fs.wrapX", fluidSolver.wrap_x);
gui.addToggle("fs.wrapY", fluidSolver.wrap_y);
gui.addToggle("drawFluid", drawFluid);
gui.addToggle("drawParticles", drawParticles);
gui.addSlider("tuioXScaler", tuioXScaler, 0, 2);
gui.addSlider("tuioYScaler", tuioYScaler, 0, 2);
//--
gui.currentPage().setXMLName("ofxMSAFluidSettings.xml");
gui.loadFromXML();
gui.setDefaultKeys(true);
gui.setAutoSave(true);
gui.show();
ofSetBackgroundColor(0);
}
//--------------------------------------------------------------
void ofApp::update() {
//OSC receive from SuperCollider
while (receiver.hasWaitingMessages()) {
ofxOscMessage m;
receiver.getNextMessage(m);
cout << "got message from OSC\n";
if (m.getAddress() == "/data"){
cout << "message was data as expected\n";
ofVec2f eventPos = ofVec2f(m.getArgAsFloat(0), m.getArgAsFloat(1));
ofVec2f mouseNorm = ofVec2f(eventPos) / ofGetWindowSize();
ofVec2f mouseVel = ofVec2f(eventPos - pMouse) / ofGetWindowSize();
addToFluid(mouseNorm, mouseVel, true, true);
pMouse = eventPos;
} else if (m.getAddress() == "/vertex") {
cout << "message was vertex as expected\n";
}
}
//Reset the cursors
cursors.clear() ;
if(resizeFluid) {
fluidSolver.setSize(fluidCellsX, fluidCellsX / msa::getWindowAspectRatio());
fluidDrawer.setup(&fluidSolver);
resizeFluid = false;
}
fluidSolver.update();
}
//--------------------------------------------------------------
void ofApp::draw() {
ofEnableAlphaBlending() ;
ofPushMatrix() ;
////////////////////////////////////////////////
for(int i = 1; i < points.size(); i++){
//find this point and the next point
ofVec3f thisPoint = points[i-1];
ofVec3f nextPoint = points[i];
//get the direction from one to the next.
//the ribbon should fan out from this direction
ofVec3f direction = (nextPoint - thisPoint);
//get the distance from one point to the next
float distance = direction.length();
//get the normalized direction. normalized vectors always have a length of one
//and are really useful for representing directions as opposed to something with length
ofVec3f unitDirection = direction.getNormalized() + 0.1f ;
//find both directions to the left and to the right
ofVec3f toTheLeft = unitDirection.getRotated(-90, ofVec3f(0,0,1));
ofVec3f toTheRight = unitDirection.getRotated(90, ofVec3f(0,0,1));
//use the map function to determine the distance.
//the longer the distance, the narrower the line.
//this makes it look a bit like brush strokes
float thickness = ofMap(distance, 0, 60, 40, 10, true);
//calculate the points to the left and to the right
//by extending the current point in the direction of left/right by the length
ofVec3f leftPoint = thisPoint+toTheLeft*thickness;
ofVec3f rightPoint = thisPoint+toTheRight*thickness;
//add these points to the triangle strip
mesh.addVertex(ofVec3f(leftPoint.x, leftPoint.y, leftPoint.z));
mesh.addVertex(ofVec3f(rightPoint.x, rightPoint.y, rightPoint.z));
mesh.addColor ( ofColor::fromHsb( sin ( (float)i ) * 40.0f + 128.0f, 255.0f , 255.0f ) ) ;
mesh.addColor ( ofColor::fromHsb( sin ( (float)i ) * 40.0f + 128.0f, 255.0f , 255.0f ) ) ;
}
if(drawFluid) {
ofClear(0);
glColor3f(1, 1, 1);
fluidDrawer.draw(0, 0, ofGetWidth(), ofGetHeight());
} else {
// if(ofGetFrameNum()%5==0)
fadeToColor(0, 0, 0, 0.01);
}
if(drawParticles)
particleSystem.updateAndDraw(fluidSolver, ofGetWindowSize(), drawFluid);
//ofDrawBitmapString(sz, 50, 50);
//earth here
int alpha = 120; // amount of smoothing
ofEnableAlphaBlending();
ofSetColor(255, 255, 255, alpha);
ofTranslate(ofGetWidth()/2, ofGetHeight()/2, 0);
ofRotateY(ofGetFrameNum());
ofRotateX(-90); //north pole facing up
//bind and draw texture
texture.getTexture().bind();
gluSphere(quadric, 200, 100, 100);
texture.draw(0, 0);
ofDisableAlphaBlending();
ofPopMatrix();
}
//-------------------------------------------------------------
void ofApp::drawGui(ofEventArgs & args){
gui.draw();
}
//--------------------------------------------------------------
//--------------------------------------------------------------
void ofApp::exit() {
}
//--------------------------------------------------------------
void ofApp::keyPressed (int key) {
switch(key) {
case '1':
fluidDrawer.setDrawMode(msa::fluid::kDrawColor);
break;
case '2':
fluidDrawer.setDrawMode(msa::fluid::kDrawMotion);
break;
case '3':
fluidDrawer.setDrawMode(msa::fluid::kDrawSpeed);
break;
case '4':
fluidDrawer.setDrawMode(msa::fluid::kDrawVectors);
break;
case 'd':
drawFluid ^= true;
break;
case 'p':
drawParticles ^= true;
break;
case 'f':
ofToggleFullscreen();
break;
case 'r':
fluidSolver.reset();
break;
case 'k':
bKinectOpen ^=true;
break;
case 'w':{
// texture.draw(0,0);
ofEnableAlphaBlending();
texture.getTextureReference().bind();
gluSphere(quadric, 200, 100, 100);
texture.draw(0,0);
if (holdingbutton) {
newalpha = oldalpha-1;
if (newalpha <0 ) {newalpha = 0;}
ofSetColor(255,255,255,newalpha);
oldalpha = newalpha;
}
else { ofSetColor(255,255,255,255);}
texture.draw(0,0);
ofDisableAlphaBlending();
}
case 'e':{
// texture.draw(0,0);
ofEnableAlphaBlending();
texture.draw(0,0);
texture.getTextureReference().bind();
gluSphere(quadric, 200, 100, 100);
if (holdingbutton) {
newalpha = oldalpha+1;
if (newalpha > 255) {newalpha = 255;}
ofSetColor(255,255,255,newalpha);
oldalpha = newalpha;
}
else { ofSetColor(255,255,255,0);}
texture.draw(0,0);
ofDisableAlphaBlending();
}
case 'b': {
// Timer timer;
// const int ITERS = 3000;
// timer.start();
// for(int i = 0; i < ITERS; ++i) fluidSolver.update();
// timer.stop();
// cout << ITERS << " iterations took " << timer.getSeconds() << " seconds." << std::endl;
}
break;
case 'o':
bShowControlPanel = !bShowControlPanel;
if (bShowControlPanel){
gui.show();
ofShowCursor();
} else {
gui.hide();
ofShowCursor();
}
break;
case 5:
blendMode = OF_BLENDMODE_ALPHA;
eventString = "Alpha";
break;
case 6:
blendMode = OF_BLENDMODE_ADD;
eventString = "Add";
break;
case 7:
blendMode = OF_BLENDMODE_MULTIPLY;
eventString = "Multiply";
break;
case 8:
blendMode = OF_BLENDMODE_SUBTRACT;
eventString = "Subtract";
break;
case 9:
blendMode = OF_BLENDMODE_SCREEN;
eventString = "Screen";
break;
default:
break;
}
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button)
{}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button)
{}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h)
{}