#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup() {

    // Make background white
    ofBackground(255, 255, 255);

    // Create the world
    box2d.setup();
    world = box2d.getWorld();
    // Also sets the openFrameworks framerate
    box2d.setFrameRate(60.0f);
    // Restrict the worlds area
    box2d.setBounds(20.0f, 20.0f, ofGetWidth()-40, ofGetHeight()-40,false);

    // The happy face
    circle.createShape(world, 100.0f, 100.0f, 20.0f);

    // Register mouse grabbing
    box2d.registerGrabbing();

    // Video dimensions
    videoWidth = 720;
    videoHeight = 576;
    // Scale that operations are performed at (to imporve performance)
    opScale = 4;
    // Dimensions that operations are performed at
    opWidth = videoWidth / opScale;
    opHeight = videoHeight / opScale;

    // only need listener when using blobOn, blobOff, blobMoved...
    blobTracker.setListener(this);
    blobTracker.world = world;
    blobTracker.scale_factor = opScale;

    // Get video or camera feed
    #ifdef _USE_LIVE_VIDEO
        vidGrabber.initGrabber(videoWidth, videoHeight);
    #else
        vidPlayer.loadMovie("city02BIG.mov");
        vidPlayer.play();
        vidPlayer.setVolume(0);
    #endif

    // Allocate memory for current frame
    colorImg.allocate(videoWidth, videoHeight);
    // Temp area for scaling down prior to operations
    scaleImg.allocate(opWidth,opHeight);

    // Gaussian mixing parameters
    CvGaussBGStatModelParams* params = new CvGaussBGStatModelParams;
    params->win_size=500;//2; /* Learning rate; alpha = 1/CV_GBG_WINDOW_SIZE */
    params->n_gauss=5;//5;
    params->bg_threshold=0.7;//0.7;
    params->std_threshold=3.5;//3.5;
    params->minArea=15;//15;
    params->weight_init=0.05;//0.05;
    params->variance_init=30;//30;

    gauss_bgModel = cvCreateGaussianBGModel(scaleImg.getCvImage(), params);
    //gauss_bgModel = cvCreateGaussianBGModel(scaleImg.getCvImage()); // WORKS WELL TOO
    // Allocate memory for gaussian foreground frame
    gauss_foregroundImg.allocate(opWidth, opHeight);

    // Set blur and threshold
    blur = 2;
	threshold = 80;
}

//--------------------------------------------------------------
void testApp::update() {

    bool bNewFrame = false;

    // Check if there is a new frame
    #ifdef _USE_LIVE_VIDEO
        vidGrabber.grabFrame();
        bNewFrame = vidGrabber.isFrameNew();
    #else
        vidPlayer.idleMovie();
        bNewFrame = vidPlayer.isFrameNew();
    #endif

    // If there is a new frame then do...
	if (bNewFrame) {

        // Show FPS, threshold and blur values in window title bar
        char info[255];
        sprintf(info, "FPS: %.1f | Threshold: %d | Blur: %d", ofGetFrameRate(), threshold, blur);
        ofSetWindowTitle(info);

        // Set pixels for current frame
        #ifdef _USE_LIVE_VIDEO
            colorImg.setFromPixels(vidGrabber.getPixels(), videoWidth, videoHeight);
        #else
            colorImg.setFromPixels(vidPlayer.getPixels(), videoWidth, videoHeight);
        #endif

        // Scale down for operations
        scaleImg.scaleIntoMe(colorImg);

        // Update background model with new frame to learn background
        cvUpdateBGStatModel(scaleImg.getCvImage() ,gauss_bgModel);
        // Set foreground image
        gauss_foregroundImg = gauss_bgModel->foreground;
        // Blur foreground and apply threshold
        gauss_foregroundImg.blur( blur );
        gauss_foregroundImg.threshold( threshold );

        // Generate contours
		contourFinder.findContours(gauss_foregroundImg, 200, (opWidth*opHeight)/10, 10, false);

        // Keep history of blobs
		blobTracker.trackBlobs(contourFinder.blobs);
	}

    // Update physics
    box2d.update();
}

//--------------------------------------------------------------
void testApp::draw() {

    // Draw current frame
	colorImg.draw(0, 0, videoWidth, videoHeight);

    // Draw the very last historical blob contour and
    // fill it half transparent white
    ofSetLineWidth(3);
    ofSetColor(0xffffff);
    blobTracker.HistStartAlpha = 100;
    blobTracker.HistEndAlpha = 100;
    blobTracker.HistLineCol = 0xffffff;
    blobTracker.bHistFill = true;
    blobTracker.drawHistory(-20, 0, 0); // Minus only draws 1 blob history
    ofSetLineWidth(1);

    // Draw the other historical blobs outlines and slowly fade them in
    blobTracker.HistStartAlpha = -127;
    blobTracker.HistEndAlpha = 50;
    blobTracker.bHistFill = false;
    blobTracker.drawHistory(20, 0, 0); // Draws the whole blob history

    // Make contours a linestrip in physics world
    // so they can interact with the happy face
    blobTracker.createStrips(0, 0);

    // Draw the happy face with a random colour
    int arr = ofRandom(50,255);
    int gee = ofRandom(50,255);
    int bee = ofRandom(50,255);
    circle.setColour(arr, gee, bee, 127);
    circle.draw();
}

//--------------------------------------------------------------
void testApp::keyPressed(int key) {
}
void testApp::keyReleased(int key) {
}
void testApp::mouseMoved(int x, int y ) {
}
void testApp::mouseDragged(int x, int y, int button) {
}
void testApp::mousePressed(int x, int y, int button) {
}
void testApp::mouseReleased(int x, int y, int button) {
}
void testApp::windowResized(int w, int h) {
}
void testApp::blobOn(int x, int y, int id, int order) {
}
void testApp::blobMoved(int x, int y, int id, int order) {
}
void testApp::blobOff(int x, int y, int id, int order) {
}

//--------------------------------------------------------------
void happyFace::draw(){
    if (m_body) {
        b2CircleShape* c = (b2CircleShape*)m_body->GetFixtureList()->GetShape();
        b2Vec2 p = m_body->GetPosition();
        p *= OFX_BOX2D_SCALE;

        glPushMatrix();
        glTranslatef(p.x, p.y, 0.0f);

        if (a < 255) { ofEnableAlphaBlending(); }
        ofColor prevCol = ofGetStyle().color;
        ofSetColor(r, g, b, a);

        // Colour of happy face
        ofFill();
        ofCircle(0.0f, 0.0f, c->m_radius * OFX_BOX2D_SCALE);

        // Colour of happy faces outline
        ofSetLineWidth(3);
        ofSetColor(r, g, b);
        ofNoFill();
        ofCircle(0.0f, 0.0f, c->m_radius * OFX_BOX2D_SCALE);

        // White fill for eyes
        ofSetLineWidth(1);
        ofSetColor(0xffffff);
        ofFill();
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*-0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/3);
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/3);

        // Black surrounding for eyes
        ofSetColor(0x000000);
        ofNoFill();
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*-0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/3);
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/3);

        // Black pupils
        ofSetColor(0x000000);
        ofFill();
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*-0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/5);
        ofCircle((c->m_radius * OFX_BOX2D_SCALE)*0.4, (c->m_radius * OFX_BOX2D_SCALE)*-0.3, c->m_radius * OFX_BOX2D_SCALE/5);

        ofSetColor(prevCol.r, prevCol.g, prevCol.b, prevCol.a);
        if (a < 255) { ofDisableAlphaBlending(); }

        glPopMatrix();
    }
}
