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?-2XaUP0QY[hO%9QTYQ`-W`QZhcccYQY[`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)
{}