/***************************************************************************
 *	Reveal.cpp
 *	Part of Revil
 *	2015-  Florent Berthaut
 *	hitmuri.net
 ****************************************************************************/
/*
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


#include "Reveal.hpp" 

#include <iostream>
#include <unistd.h>
#include <FL/filename.H>

#include <OpenNI.h>

#include "geoms/BoxGeometry.hpp"
#include "geoms/CamGeometry.hpp"
#include "geoms/QuadGeometry.hpp"
#include "geoms/SphereGeometry.hpp"
#include "geoms/TubeGeometry.hpp"
#include "geoms/ConeGeometry.hpp"
#include "geoms/FrameGeometry.hpp"

#include "modules/RevealedShapeModule.hpp"
#include "modules/RevealedPathModule.hpp"
#include "modules/RevealedTextModule.hpp"
#include "modules/RevealedCutModule.hpp"
#include "modules/RevealedArrowModule.hpp"
#include "modules/RevealedGridModule.hpp"
#include "modules/RevealedModelModule.hpp"
#include "modules/GroupModule.hpp"
#include "modules/SpaceModule.hpp"
#include "modules/PreviewModule.hpp"
#include "modules/ProjectorModule.hpp"
#include "modules/DepthCamModule.hpp"
#include "modules/DepthShapeModule.hpp"
#include "modules/DepthMeshModule.hpp"
#include "modules/DepthGroupModule.hpp"
#include "modules/RootSceneGroupModule.hpp"
#include "modules/SceneGroupModule.hpp"
#include "modules/OutputManagerModule.hpp"
#include "gui/MainWindow.hpp"
#include "gui/GuiListener.hpp"
#include "osc/OscManager.hpp"
#include "osc/OscListener.hpp"
#include "audio/AudioManager.hpp"


using namespace std;

Reveal* Reveal::getInstance() {
    static Reveal rev;
    return &rev;
}

Reveal::~Reveal(){}

Reveal::Reveal() : GroupModule() {
    m_type="Rivill";
    m_name="rivill";
    addAttribute(new Attribute("open", 
                Attribute::FILE_OPEN_ATTRIBUTE, 
                openCallback, this, Attribute::LOCAL, 
                false));
    addAttribute(new Attribute("save", 
                Attribute::FILE_SAVE_ATTRIBUTE, 
                saveCallback, this, Attribute::LOCAL, 
                false));
    addAttribute(new Attribute("quit", 
                Attribute::ACTION_ATTRIBUTE, 
                quitCallback, this, Attribute::LOCAL, 
                false));

    addAttribute(new Attribute("audio_output", 
                Attribute::BOOL_ATTRIBUTE, 
                audioOutputCallback,this,1,Attribute::GLOBAL));
    m_audioOut=false;

    /*
       addAttribute(new Attribute("ressources_folder", 
       Attribute::FOLDER_OPEN_ATTRIBUTE, 
       ressourcesCallback, this, Attribute::LOCAL, 
       false));
       addAttribute(new Attribute("ressource_upload", 
       Attribute::ACTION_STRING_ATTRIBUTE, 
       uploadCallback,this,2,Attribute::GLOBAL,false));
       */
    addAttribute(new Attribute("debug_osc_input", 
                Attribute::BOOL_ATTRIBUTE, 
                debugOscCallback,this,1,Attribute::GLOBAL));
    m_debugOSC=false;
}

void idleFunc(void* data) {
    Reveal::getInstance()->update();
    usleep(1000);
}

void Reveal::init() {
    m_openPlanned=0;

    //initialize osc input 
    OscManager::getInstance()->init();

    //initialize depth cameras
    openni::OpenNI::initialize();
    openni::OpenNI::setLogConsoleOutput(false);
    cout<<"Initialized OpenNI "<<openni::OpenNI::getExtendedError()<<endl;

    //initialize observers counter
    m_upObsIdCounter=0;

    //create all scene geometries 
    m_geomsMap[GEOM_BOX] = new BoxGeometry();
    m_geomsMap[GEOM_QUAD] = new QuadGeometry();
    m_geomsMap[GEOM_SPHERE] = new SphereGeometry();
    m_geomsMap[GEOM_TUBE] = new TubeGeometry();
    m_geomsMap[GEOM_CONE] = new ConeGeometry();
    m_geomsMap[GEOM_FRAME] = new FrameGeometry();
    map<GEOM_ID, Geometry*>::iterator itGeom = m_geomsMap.begin();
    for(; itGeom!=m_geomsMap.end(); ++itGeom) {
        itGeom->second->setGeomID(itGeom->first);
        m_geoms.push_back(itGeom->second);
    }

    m_contextHandlersCounter=0;

    m_maxNbRevealed=502;
    m_maxNbDepthCams=10;

    //add the outputs module
    m_output = new OutputManagerModule();
    addChild(m_output);

    //add spaces module 
    m_spaces = new SpacesModule();
    addChild(m_spaces);

    //create scene module
    m_scene = new RootSceneGroupModule();
    m_scene->addGroupAttributes();
    addChild(m_scene);

    //Initialize main window
    fl_register_images();
    MainWindow::getInstance()->init();
    Fl::add_idle(idleFunc, MainWindow::getInstance());

    //Initialize glfw for preview and projector windows
    glewExperimental = GL_TRUE;
    if(!glfwInit()) {
        exit(EXIT_FAILURE);
    }
    glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); //FIXME GLFW 3.3
    glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
    glfwWindowHint(GLFW_AUTO_ICONIFY, GL_FALSE);
#ifdef GL43
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#else 
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif
#ifdef OSX
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif

    //add preview module
    m_preview = new PreviewModule();
    m_spaces->addChild(m_preview);

    refreshModules();

    //Show main window
    MainWindow::getInstance()->show();

    //start timer
    gettimeofday(&m_prevTime, NULL);
}

GLFWwindow* Reveal::getPreviewWindow() {
    return m_preview->getWindow();
}

void Reveal::setAudioOutput(const bool& aud) {
    if(aud) {
        AudioManager::getInstance()->init();
    }
}

void Reveal::planOpen(std::string opSt) {
    //FIXME find better strategy for delaying text
    m_openPlanned=10;
    m_openPlannedName=opSt;
}

void Reveal::update() {
    //delete listeners, attributes and modules
    testDelete();

    //update osc manager
    OscManager::getInstance()->update();

    //FIXME distinguish between anim and update (cam)
    //update observers every 50ms 
    timeval curTime, timeDiff;
    gettimeofday(&curTime,NULL);
    timersub(&curTime, &m_prevTime, &timeDiff);
    int timeDiffMs = timeDiff.tv_sec*1000.0+timeDiff.tv_usec/1000.0;
    m_prevTime=curTime;
    vector<Module*>::iterator itUp = m_updateObservers.begin();
    for(; itUp!=m_updateObservers.end(); ++itUp) {
        (*itUp)->update(timeDiffMs);
    }

    //draw all spaces
    m_spaces->draw();

    //delayed open to fix text rendering issues ...
    if(m_openPlanned>0) {
        m_openPlanned--;
        if(m_openPlanned==0) {
            open(m_openPlannedName);
        }
    }

    glfwPollEvents();
}

int Reveal::run() {
    return Fl::run();
}

void Reveal::askQuit() {
    MainWindow::getInstance()->cbQuit();
}

void Reveal::quit() {
    glfwTerminate();
    exit(0);
}

void Reveal::open(const std::string& fileName) {
    cout<<"Opening "<<fileName<<endl;
    bool open=true;
    xmlDocPtr doc = xmlReadFile(fileName.c_str(), NULL, 0);
    xmlNodePtr rootNode = xmlDocGetRootElement(doc);
    if(doc==NULL || rootNode==NULL) {
        DEBUG("Could not open file "<<fileName);
        open=false;
    }
    else if(xmlStrcmp(rootNode->name, (const xmlChar*)"Rivill")) {
        xmlFreeDoc(doc);
        DEBUG("Could not open file "<<fileName);
        open=false;
    }
    if(open) { //if the file is valid
        m_currentFile=fileName;
        //clear the scene and spaces
        m_scene->deleteChildren();
        m_spaces->removeChild(m_preview);
        m_spaces->deleteChildren();
        m_spaces->addChild(m_preview);
        m_revealedMap.clear();
        m_registeredOutputRevealed.clear();
        m_registeredOutputDepthCams.clear();
        m_upObsIdCounter=0;
        m_updateObservers.clear();
        //and load
        load(rootNode);
        m_attributesMap["save"]->initFile(m_currentFile);
        MainWindow::getInstance()->refreshModules();
        DEBUG("Opened file "<<fileName);
    }
}

void Reveal::save(const std::string& fileName) {
    cout<<"Saving to "<<fileName<<endl;
    m_currentFile=fileName;
    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
    xmlNodePtr rootNode = GroupModule::save(NULL);
    xmlDocSetRootElement(doc, rootNode);
    xmlSaveFormatFileEnc(fileName.c_str(), doc, "UTF-8", 1);
    xmlFreeDoc(doc);
    xmlCleanupParser();
}

void Reveal::setRessourcesFolder(const std::string& f) {

}

void Reveal::uploadRessource(const std::vector<std::string>& vf) {

}

void Reveal::load(xmlNodePtr node) {
    Module::load(node);
    xmlNodePtr modsNode;
    for(modsNode=node->children; modsNode; modsNode=modsNode->next){
        if(modsNode->type == XML_ELEMENT_NODE &&
                !xmlStrcmp(modsNode->name, (const xmlChar *) "Modules")) {
            xmlNodePtr modNode;
            for(modNode=modsNode->children; modNode; modNode=modNode->next){
                if(modNode->type == XML_ELEMENT_NODE) {
                    if(!xmlStrcmp(modNode->name,(const xmlChar *)"Scene")) {
                        m_scene->load(modNode);
                    }
                    else if(!xmlStrcmp(modNode->name,(const xmlChar*)"Spaces")){
                        m_spaces->load(modNode);
                    }
                }
            }
        }
    }
}

Module* Reveal::createModule(const std::string& typeStr) {
    Module* mod=NULL;
    if(typeStr.compare("Projector")==0) {
        mod=new ProjectorModule();
    }
    else if(typeStr.compare("Space")==0) {
        mod=new SpaceModule();
    }
    else if(typeStr.compare("DepthGroup")==0) {
        mod=new DepthGroupModule();
    }
    else if(typeStr.compare("DepthCam")==0) {
        mod=new DepthCamModule();
    }
    else if(typeStr.compare("DepthShape")==0) {
        mod=new DepthShapeModule();
    }
    else if(typeStr.compare("DepthMesh")==0) {
        mod=new DepthMeshModule();
    }
    else if(typeStr.compare("SceneGroup")==0) {
        mod=new SceneGroupModule();
    }
    else if(typeStr.compare("Shape")==0) {
        mod=new RevealedShapeModule();
    }
    else if(typeStr.compare("Model")==0) {
        mod=new RevealedModelModule();
    }
    else if(typeStr.compare("Path")==0) {
        mod=new RevealedPathModule();
    }
    else if(typeStr.compare("Text")==0) {
        mod=new RevealedTextModule();
    }
    else if(typeStr.compare("Cut")==0) {
        mod=new RevealedCutModule();
    }
    else if(typeStr.compare("Arrow")==0) {
        mod=new RevealedArrowModule();
    }
    else if(typeStr.compare("Grid")==0) {
        mod=new RevealedGridModule();
    }
    return mod;
}

Listener* Reveal::createListener(const std::string& typeStr) {
    Listener* lis=NULL;
    if(typeStr.compare("OscListener")==0) {
        lis=new OscListener();
    }
    return lis;
}

int Reveal::getVisibilityMask(const std::string& visibleFrom) {
    int res=0;
    map<string, int>::iterator itVis = m_visibleFromMap.find(visibleFrom);
    if(itVis!=m_visibleFromMap.end()) {
        res=itVis->second;
    }
    return res;
}

void Reveal::addUpdateObserver(Module* upObs) {
    m_updateObservers.push_back(upObs);
    upObs->setUpID(m_upObsIdCounter);
    m_upObsIdCounter++;
}

void Reveal::removeUpdateObserver(Module* upObs) {
    vector<Module*>::iterator itObs = m_updateObservers.begin();
    for(; itObs!=m_updateObservers.end(); ) {
        if((*itObs)->getUpID()==upObs->getUpID()) {
            itObs = m_updateObservers.erase(itObs);
        }
        else {
            itObs++;
        }
    }
}

void Reveal::addModuleListObserver(ModuleListObserver* obs) {
    unsigned int obsID=0;
    while(m_moduleListObservers.find(obsID)!=m_moduleListObservers.end()) {
        obsID++;
    }
    m_moduleListObservers[obsID]=obs;
    obs->setModuleListObsID(obsID);
}

void Reveal::removeModuleListObserver(ModuleListObserver* obs) {
    m_moduleListObservers.erase(obs->getModuleListObsID());
}

void Reveal::addContextHandler(ContextHandler* cont) {
    m_contextHandlers[m_contextHandlersCounter]=cont;
    cont->setContextHandlerID(m_contextHandlersCounter);
    m_contextHandlersCounter++;
}

void Reveal::removeContextHandler(ContextHandler* cont) {
    m_contextHandlers.erase(cont->getContextHandlerID());
}

void Reveal::registerGeom(Geometry* geom) {
    GEOM_ID newID = GEOM_MODEL;
    while(m_geomsMap.find(newID)!=m_geomsMap.end()) {
        newID = GEOM_ID(int(newID)+1);
    }
    geom->setGeomID(newID);
    m_geomsMap[newID]=geom;
    m_geoms.push_back(geom);
}

void Reveal::unregisterGeom(Geometry* geom) {
    m_geomsMap.erase(geom->getGeomID());
    vector<Geometry*>::iterator itGeom = m_geoms.begin();
    for(; itGeom!=m_geoms.end(); ) {
        if((*itGeom)->getGeomID()==geom->getGeomID()) {
            itGeom = m_geoms.erase(itGeom);
        }
        else {
            ++itGeom;
        }
    }
}

void Reveal::registerRevealed(RevealedModule* rev) {
    m_revealedVec.push_back(rev);
    updateRevealed();
}

void Reveal::unregisterRevealed(RevealedModule* rev) {
    vector<RevealedModule*>::iterator itRev=m_revealedVec.begin();
    for(; itRev!=m_revealedVec.end();) {
        if((*itRev)->getRevID()==rev->getRevID()) {
            itRev=m_revealedVec.erase(itRev);
        }
        else {
            ++itRev;
        }
    }
    updateRevealed();
    unregisterOutputRevealed(rev);
}

void Reveal::updateRevealed() {
    m_revealedMap.clear();
    vector<RevealedModule*>::iterator itRev=m_revealedVec.begin();
    unsigned int id=1;
    for(; itRev!=m_revealedVec.end(); ++itRev, ++id) {
        (*itRev)->setRevID(id);
        m_revealedMap[id]=*itRev;
    }
}

void Reveal::refreshModules() {
    //recreate map of modules and attributes
    m_modulesMap.clear();
    m_fullAttributesMap.clear();
    GroupModule::listModulesAndAttributes("", m_modulesMap, 
            m_fullAttributesMap);

    //inform observers of the new module list
    map<unsigned int, ModuleListObserver*>::iterator itObs 
        = m_moduleListObservers.begin(); 
    for(; itObs!=m_moduleListObservers.end(); ++itObs) {
        itObs->second->updateModulesList(m_modulesMap);
    }

    //refresh space/projectors list
    m_visibleFromVec.clear();
    m_visibleFromMap.clear();
    m_visibleFromVec.push_back("none");
    m_visibleFromMap[m_visibleFromVec.back()]=VISIBLE_FROM_NONE;
    m_visibleFromVec.push_back("all");
    m_visibleFromMap[m_visibleFromVec.back()]=VISIBLE_FROM_ALL;
    m_spaces->getVisibleFromList(m_visibleFromVec, m_visibleFromMap);

    map<unsigned int, RevealedModule*>::iterator itMod
        = m_revealedMap.begin(); 
    for(; itMod!=m_revealedMap.end(); ++itMod) {
        itMod->second->setVisibleFromList(m_visibleFromVec);
    }

    //refresh display
    MainWindow::getInstance()->refreshModules();

    /*
    //TEMP list all attributes of all modules 
    map<string, Attribute*>::iterator itAtt = m_attributesMap.begin();
    for(;itAtt!=m_attributesMap.end(); ++itAtt) {
    cout<<itAtt->first<<endl;
    }
    */
}

Attribute* Reveal::findAttribute(const std::string& fullName) {
    map<string,Attribute*>::iterator itAtt = m_fullAttributesMap.find(fullName);
    if(itAtt!=m_fullAttributesMap.end()) {
        return itAtt->second;
    }
    return NULL;
}

Module* Reveal::findModule(const std::string& fullName) {
    map<string, Module*>::iterator itMod = m_modulesMap.find(fullName);
    if(itMod!=m_modulesMap.end()) {
        return itMod->second;
    }
    return NULL;
}

void Reveal::registerOutputRevealed(RevealedModule* rev) {
    bool found=false;
    vector<RevealedModule*>::iterator itSh=m_registeredOutputRevealed.begin();
    for(; itSh!=m_registeredOutputRevealed.end(); ++itSh) {
        if((*itSh)->getRevID()==rev->getRevID()) {
            found=true;
        }
    }
    if(!found) {
        m_registeredOutputRevealed.push_back(rev);
    }
    updateOutputRevealed();
}

void Reveal::unregisterOutputRevealed(RevealedModule* rev) {

    //remove it from list
    vector<RevealedModule*>::iterator itSh=m_registeredOutputRevealed.begin();
    for(; itSh!=m_registeredOutputRevealed.end(); ) {
        if((*itSh)->getRevID()==rev->getRevID()) {
            itSh=m_registeredOutputRevealed.erase(itSh);
        }
        else {
            ++itSh;
        }
    }

    //reset offsets 
    updateOutputRevealed();
}

void Reveal::updateOutputRevealed() {
    vector<RevealedModule*>::iterator itSh=m_registeredOutputRevealed.begin();
    unsigned int offset=0;
    for(; itSh!=m_registeredOutputRevealed.end(); ++itSh) {
        (*itSh)->updateRevOffset(offset);
    }
}

void Reveal::registerOutputDepthCam(DepthCamModule* cam) {
    bool found=false;
    vector<DepthCamModule*>::iterator itCa=m_registeredOutputDepthCams.begin();
    for(; itCa!=m_registeredOutputDepthCams.end(); ++itCa) {
        if((*itCa)->getDepthID()==cam->getDepthID()) {
            found=true;
        }
    }
    if(!found) {
        m_registeredOutputDepthCams.push_back(cam);
    }
}

void Reveal::unregisterOutputDepthCam(DepthCamModule* cam) {
    vector<DepthCamModule*>::iterator itCa=m_registeredOutputDepthCams.begin();
    for(; itCa!=m_registeredOutputDepthCams.end(); ) {
        if((*itCa)->getDepthID()==cam->getDepthID()) {
            itCa=m_registeredOutputDepthCams.erase(itCa);
        }
        else {
            ++itCa;
        }
    }
}

void Reveal::deleteListener(Listener* lis) {
    m_listenersDeleteVec.push_back(lis);
}

void Reveal::deleteModule(Module* mod) {
    m_modulesDeleteVec.push_back(mod);
    refreshModules();
}

void Reveal::testDelete() {
    bool erasedListeners=false;
    vector<Listener*>::iterator itLis = m_listenersDeleteVec.begin();
    for(; itLis!=m_listenersDeleteVec.end(); ++itLis) {
        delete (*itLis);
        erasedListeners=true;
    }
    m_listenersDeleteVec.clear();


    if(m_modulesDeleteVec.size()>0) {
        MainWindow::getInstance()->refreshModules(true, erasedListeners);
    }
    vector<Module*>::iterator itMod = m_modulesDeleteVec.begin();
    for(; itMod!=m_modulesDeleteVec.end(); ++itMod) {
        delete (*itMod);
    }
    m_modulesDeleteVec.clear();
}

GLuint Reveal::createProgram(const char* vertSource, const char* fragSource) {
    GLint compile_ok = GL_FALSE, link_ok = GL_FALSE;
    GLuint vertexShader, fragmentShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertSource, NULL);
    glCompileShader(vertexShader);
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &compile_ok);
    if(!compile_ok) {
        cout << "Error in vertex shader" << endl;
        GLint maxLength = 0;
        glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> errorLog(maxLength);
        glGetShaderInfoLog(vertexShader,maxLength,&maxLength, &errorLog[0]);
        vector<GLchar>::iterator itC=errorLog.begin();
        for(; itC!=errorLog.end(); ++itC) {
            cout<<*itC;
        }
        cout<<endl;
    } 
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragSource, NULL);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &compile_ok);
    if(!compile_ok) {
        cout << "Error in fragment shader" << endl;
        GLint maxLength = 0;
        glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> errorLog(maxLength);
        glGetShaderInfoLog(fragmentShader,maxLength,&maxLength, &errorLog[0]);
        vector<GLchar>::iterator itC=errorLog.begin();
        for(; itC!=errorLog.end(); ++itC) {
            cout<<*itC;
        }
        cout<<endl;
    }
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
    if(!link_ok) {
        cout<<"Error linking glsl program "<<program<<" "<<endl;
        GLint maxLength = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> errorLog(maxLength);
        glGetProgramInfoLog(program,maxLength,&maxLength, &errorLog[0]);
        vector<GLchar>::iterator itC=errorLog.begin();
        for(; itC!=errorLog.end(); ++itC) {
            cout<<*itC;
        }
        cout<<endl;
    }
    return program;
}

void Reveal::measureStart() {
    gettimeofday(&m_measureTime, NULL);
    m_measuring=true;
}

void Reveal::measureStore(const int& nbPixels) {
    if(m_measuring) {
        timeval curTime, timeDiff;
        gettimeofday(&curTime, NULL);
        timersub(&curTime, &m_measureTime, &timeDiff);
        int timeDiffMs=int(timeDiff.tv_sec)*1000000 
            + int(timeDiff.tv_usec);
        if(m_measurePixelNb.find(nbPixels)==m_measurePixelNb.end()) {
            m_measurePixelTimes[nbPixels]=0;
            m_measurePixelNb[nbPixels]=0;
        }
        m_measurePixelNb[nbPixels]++;
        m_measurePixelTimes[nbPixels]+=timeDiffMs;
        cout<<nbPixels<<" "
            <<float(m_measurePixelTimes[nbPixels])
            / float(m_measurePixelNb[nbPixels])<<endl;

        m_measuring=false;
    }
}

//MAIN 
int main( int argc, char **argv ) {
    Reveal::getInstance()->init();
    if(argc>1) {
        char* abs = new char[200];
        fl_filename_absolute(abs, 200, argv[1]);
        Reveal::getInstance()->planOpen(string(abs));	 
    }
    return Reveal::getInstance()->run();
}