/* 
   Augmented Reality Program 
   Computer Vision Couse/PUC-Rio

   This is the interface module for the homework project.
   
   This modules uses the following tools: 
       IUP for user interface (see: http://www.tecgraf.puc-rio.br/iup/)
       IM for image I/O and capture (see: http://www.tecgraf.puc-rio.br/im/ ) 
       OpenGL for drawing   (see: http://www.tecgraf.puc-rio.br/cd/)

  Needs IUP: comctl32.lib iup.lib iupcontrols.lib iupgl.lib cd.lib cdiup.lib 
        IM: im.lib im_capture.lib im_process.lib im_avi.lib strmiids.lib vfw32.lib 
        OpenGL: opengl32.lib glu32.lib

  We are using a beta version of im_capture.lib giving in the same zip file

  The "strmiids.lib" may have to be updated to the version in:
         http://www.tecgraf.puc-rio.br/im/download/strmiids.zip

  User's Manual:
  You must first connect to a capture device, if the conection is successfull
  images will be captured from the device and shown on the sup canvas.
  You may change capture device settings and control if the capture is live or not.

  Images can also be played from a video file. This includes any format supported by IM.
  Frames will also be reproduced in idle function not considering the original frame rate.

  When you process the capture data, the result is always displayed in the inf canvas. 
  The objective is to preserve the original image to display 3D data on top of it.

  Version:
            2.0 - Code re-structure to separate the work of the class from the interface.
            1.3 - Can save frame sequence in TIFF, GIF and AVI. 
                  arProcess API changed to include gldata.
                  Dial replaced by another Valuator.
            1.2 - New video file input.
                  Changed some button image sizes to 23x23 in "iconlib.c".
                  Fixed image type initialization of the save inf video file.
                  New save sup video file.
            1.1 - Full iconlib.c 

  Authors:
            Antonio Scuri
            Marcelo Gattass
            Fabíola Maffra
         Mauricio Hofmam

  Tecgraf/PUC-Rio - 2005
*/

#ifdef WIN32            
#include <windows.h>    /* necessary because of the Microsoft OpenGL headers dependency */
#endif

#include <GL/gl.h>
#include <GL/glu.h>

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

#include <iup.h>
#include <iupcontrols.h>
#include <iupgl.h>

#include <im.h>
#include "im_capture.h"
#include <im_format_avi.h>
#include <im_image.h>
#include <im_util.h>

#define WIDTH 320
#define HEIGHT 240
int FORMAT=0;

/* implemented in "iconlib.c" to load standard icon images into IUP */
void IconLibOpen(void);

/* HERE ARE THE FUNCTIONS YOU HAVE TO IMPLEMENT IN THE ARProcess.c file ******************************************** */
void userOpen(int width, int height,char *model_file_name);
void userProcessLeft(int width, int height, unsigned char* inFrame, int* flags, float* values, unsigned char* outFrame, char *label ) ;
void userProcessRight(int width, int height, unsigned char* inFrame, int* flags, float* values, unsigned char* outFrame);
void userDrawUpperLeft(int width, int height);
void userDrawLowerLeft(int width, int height);
void userDrawRight(int width, int height);
void userClose( );
/**********************************************************************************************************************/



struct _itfData   /* interface variables */
{
   imFile* capFile;             /* file input */
   imVideoCapture* capVideo;    /* live capture input */

   int imgFileIndex;         /* -1 = paused */

   unsigned char* supFrame;       /* opengl display buffer (sup) */
   unsigned char* infFrame;
   int            frameWidth;
   int            frameHeight;
   int            saveVideo;
   int            saveProcessedVideo;
   imFile* videoFile;
   imFile* processedVideoFile;
   /* Global to help enable/disable items in the interface */
   Ihandle *supCanvas, *infCanvas,
            *configBut, *configMenu,
            *captureMenu, *saveBut, *saveProcessedBut;
   int     canvasWidth;
   int     canvasHeight;
}  itfDataLeft = {NULL,NULL,0,NULL,NULL,0,0,0,0, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 0,0},
   itfDataRight = {NULL,NULL,0,NULL,NULL,0,0,0,0, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 0,0};

struct _usrData{
   Ihandle *FPSLabel ;
   Ihandle *statusLabel ;
   Ihandle *userButton1, *userButton2, *userButton3, *userButton4, *userButton5 ;
   Ihandle *userButtonA, *userButtonB;
   int      usrFlags[7];
   float    usrValues[2];
   char     usrLabelString[128] ;
}usrData={NULL,NULL,NULL,NULL,NULL,NULL, NULL, NULL, NULL,{1,0,0,0,0,1,0},{1.0f,1.0f}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} };

struct _globalData{
   Ihandle *TypeOfCaptureBut, *showCounterBut, *captureBut, 
           *counterDialog,    *counterCanvas, *timer;
   int captureLive;         /*false or true*/
   int TypeOfCapture;      /*0:n frames or 1:one frame*/
   int showingCounter;   /*false or true*/
   unsigned char *character[10];
}globalData={NULL,NULL,NULL,NULL,NULL,NULL,1,0,0,NULL};

void itfResetImageData(struct _itfData *itfData);

/*---------------------------------------------------------------------------*/
// itfButton1_cb
/*---------------------------------------------------------------------------*/
int itfButton1_cb(Ihandle *self, int v)
{
   usrData.usrFlags[0]=v;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfButton2_cb
/*---------------------------------------------------------------------------*/
int itfButton2_cb(Ihandle *self, int v)
{
   usrData.usrFlags[1]=v;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfButton3_cb
/*---------------------------------------------------------------------------*/
int itfButton3_cb(Ihandle *self, int v)
{
   usrData.usrFlags[2]=v;
   return IUP_DEFAULT;
}
/*---------------------------------------------------------------------------*/
// itfButton4_cb
/*---------------------------------------------------------------------------*/
int itfButton4_cb(Ihandle *self, int v)
{
   usrData.usrFlags[3]=v;
   return IUP_DEFAULT;
}
/*---------------------------------------------------------------------------*/
// itfButton5_cb
/*---------------------------------------------------------------------------*/
int itfButton5_cb(Ihandle *self, int v)
{
   usrData.usrFlags[4]=v;
   return IUP_DEFAULT;
}
/*---------------------------------------------------------------------------*/
// itfButtonA_cb
/*---------------------------------------------------------------------------*/
int itfButtonA_cb(Ihandle *self, int v)
{
   usrData.usrFlags[5]=v;
   return IUP_DEFAULT;
}
/*---------------------------------------------------------------------------*/
// itfButtonB_cb
/*---------------------------------------------------------------------------*/
int itfButtonB_cb(Ihandle *self, int v)
{
   usrData.usrFlags[6]=v;
   return IUP_DEFAULT;
}




/*---------------------------------------------------------------------------*/
// itfVal1_cb
/*---------------------------------------------------------------------------*/
int itfVal1_cb(Ihandle *self, double value)
{
   usrData.usrValues[0] = (float)value ;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfVal2_cb
/*---------------------------------------------------------------------------*/
int itfVal2_cb(Ihandle *self, double value)
{
   usrData.usrValues[1] = (float)value ;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfSaveFile
/*---------------------------------------------------------------------------*/
int itfSaveFile(struct _itfData *ptIftData, int processed)
{
   int fps=15;
   Ihandle *fileDlg; 
   Ihandle **button; 
   int *saveVideo;
   imFile **videoFile;

   int error;
   if(!processed){
      saveVideo=&ptIftData->saveVideo;
      videoFile=&ptIftData->videoFile;
      button=&ptIftData->saveBut;
   }
   else{
      saveVideo=&ptIftData->saveProcessedVideo;
      videoFile=&ptIftData->processedVideoFile;
      button=&ptIftData->saveProcessedBut;
   }
   if(!*saveVideo){
      fileDlg = IupFileDlg(); 
      IupSetAttributes(fileDlg, "DIALOGTYPE = SAVE, TITLE = \"File Save\"");
      IupSetAttributes(fileDlg, "FILTER = \"*.avi\", FILTERINFO = \"*.avi - Video Files\"");
      IupSetAttributes(fileDlg, "FILE = \"untitled01.avi\"");
      IupPopup(fileDlg, IUP_ANYWHERE, IUP_ANYWHERE); 
      switch(IupGetInt(fileDlg, IUP_STATUS)){
         case 1: 
            break; 
         case 0 : 
            break; 
         case -1 : 
            IupSetAttribute(*button,"VALUE","OFF");
            return IUP_DEFAULT;
         break; 
      }
      *videoFile=imFileNew(IupGetAttribute(fileDlg, IUP_VALUE), "AVI", &error);
      if (!*videoFile) 
         printf("Error creating file AVI. %d\n",error);
      else {
         *saveVideo=1;
         IupSetAttribute(*button,"VALUE","ON");
         imFileSetInfo(*videoFile, "CUSTOM");
         imFileWriteImageInfo(*videoFile, 320, 240, IM_RGB|IM_PACKED, IM_BYTE);
         imFileSetAttribute (*videoFile, "FPS", IM_INT, 1, &fps);
      }
   }
   else{
      *saveVideo=0;
      IupSetAttribute(*button,"VALUE","OFF");
      imFileClose(*videoFile);
      *videoFile=NULL;
   }
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfSaveFileLeft_cb
/*---------------------------------------------------------------------------*/
int itfSaveFileLeft_cb(Ihandle *self, double value)
{
   itfSaveFile(&itfDataLeft, 0);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfSaveFileRight_cb
/*---------------------------------------------------------------------------*/
int itfSaveFileRight_cb(Ihandle *self, double value)
{
   itfSaveFile(&itfDataRight, 0);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfSaveFileLeftProcessed_cb
/*---------------------------------------------------------------------------*/
int itfSaveFileLeftProcessed_cb(Ihandle *self, double value)
{
   itfSaveFile(&itfDataLeft, 1);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfSaveFileRightProcessed_cb
/*---------------------------------------------------------------------------*/
int itfSaveFileRightProcessed_cb(Ihandle *self, double value)
{
   itfSaveFile(&itfDataRight, 1);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfTypeOfCapture_cb
/*---------------------------------------------------------------------------*/
int itfTypeOfCapture_cb(Ihandle *self){
   if(globalData.TypeOfCapture == 0){
      globalData.TypeOfCapture=1;/* Toggles to ImCaptureOneFrame*/
      if (itfDataLeft.capVideo && !imVideoCaptureLive(itfDataLeft.capVideo, 1)== -1)
         IupMessage("Error!", "Failure while toggling mode.");
      if (itfDataRight.capVideo && !imVideoCaptureLive(itfDataRight.capVideo, 1)== -1)
         IupMessage("Error!", "Failure while toggling mode.");
      IupSetAttribute(globalData.TypeOfCaptureBut,"IMAGE","icon_lib_capture_one_frame");
      IupSetAttribute(globalData.timer, "RUN", "NO");
   }
   else{
      globalData.TypeOfCapture=0;/* Toggles to ImCaptureFrame*/
      if (itfDataLeft.capVideo){
         imVideoCaptureLive(itfDataLeft.capVideo, 1);
         itfResetImageData(&itfDataLeft);
      }
      if (itfDataRight.capVideo) {
         imVideoCaptureLive(itfDataRight.capVideo, 1);
         itfResetImageData(&itfDataRight);
      }
      IupSetAttribute(globalData.TypeOfCaptureBut,"IMAGE","icon_lib_capture_n_frames");
      if(globalData.captureLive==1)
         IupSetAttribute(globalData.timer, "RUN", "YES");
   }
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfRepaintUpperLeft_cb
/*---------------------------------------------------------------------------*/
int itfRepaintUpperLeft_cb(Ihandle* self)
{
   IupGLMakeCurrent(self);        /* activates this GL Canvas as the current drawing area. */
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  /* clears the back buffer */
   if (itfDataLeft.supFrame){
      /* Draws the captured image at (0,0) */
      glMatrixMode(GL_PROJECTION);

      glPushMatrix();
      glLoadIdentity();
      gluOrtho2D (0.f, itfDataLeft.frameWidth, 0.f, itfDataLeft.frameHeight);
      glRasterPos2f(0.f, 0.f);
      glDrawPixels(itfDataLeft.frameWidth, itfDataLeft.frameHeight, GL_RGB, GL_UNSIGNED_BYTE, itfDataLeft.supFrame);
      glPopMatrix();
      userDrawUpperLeft(itfDataLeft.frameWidth, itfDataLeft.frameHeight);
   }
   IupGLSwapBuffers(self);  /* swap data from back buffer to front buffer */
   
   return IUP_DEFAULT;
} 

/*---------------------------------------------------------------------------*/
// itfRepaintUpperRight_cb
/*---------------------------------------------------------------------------*/
int itfRepaintUpperRight_cb(Ihandle* self)
{
   IupGLMakeCurrent(self);        /* activates this GL Canvas as the current drawing area. */
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  /* clears the back buffer */
   if (itfDataRight.supFrame){
      /* Draws the captured image at (0,0) */
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      gluOrtho2D (0.f, itfDataRight.frameWidth, 0.f, itfDataRight.frameHeight);
      glRasterPos2f(0.f, 0.f);
      glDrawPixels(itfDataRight.frameWidth, itfDataRight.frameHeight, GL_RGB, GL_UNSIGNED_BYTE, itfDataRight.supFrame);
      userDrawRight(itfDataRight.frameWidth, itfDataRight.frameHeight);
   }
   IupGLSwapBuffers(self);  /* swap data from back buffer to front buffer */
   return IUP_DEFAULT;
} 

/*---------------------------------------------------------------------------*/
// itfRepaintLowerLeft_cb
/*---------------------------------------------------------------------------*/
int itfRepaintLowerLeft_cb(Ihandle* self)
{
   IupGLMakeCurrent(self);        /* activates this GL Canvas as the current drawing area. */
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  /* clears the back buffer */
   if (itfDataLeft.infFrame){
      /* Draws the captured image at (0,0) */
      glRasterPos2f(0.f, 0.f); 
      glDrawPixels(itfDataLeft.frameWidth, itfDataLeft.frameHeight, GL_RGB, GL_UNSIGNED_BYTE, itfDataLeft.infFrame);
      userDrawLowerLeft(itfDataLeft.frameWidth, itfDataLeft.frameHeight);
   }
   IupGLSwapBuffers(self);  /* swap data from back buffer to front buffer */
   return IUP_DEFAULT;
} 

/*---------------------------------------------------------------------------*/
// itfRepaintLoweRight_cb
/*---------------------------------------------------------------------------*/
int itfRepaintLoweRight_cb(Ihandle* self)
{
   IupGLMakeCurrent(self);        /* activates this GL Canvas as the current drawing area. */
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  /* clears the back buffer */
   if (itfDataRight.infFrame){
      /* Draws the captured image at (0,0) */
      glRasterPos2f(0.f, 0.f); 
      glDrawPixels(itfDataRight.frameWidth, itfDataRight.frameHeight, GL_RGB, GL_UNSIGNED_BYTE, itfDataRight.infFrame);
   }
   IupGLSwapBuffers(self);  /* swap data from back buffer to front buffer */
   return IUP_DEFAULT;
} 

/*---------------------------------------------------------------------------*/
// itfResize_cb
/*---------------------------------------------------------------------------*/
int itfResize_cb(Ihandle *self, int width, int height)
{
   /* focous OpenGL in this canvas */
   IupGLMakeCurrent(self);

   /* define coord range for the OpenGL primitives */
   glViewport(0,0,width,height);

   /* set identitity matrix as the instanciation transformation */
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   /* set orthographic projection */
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluOrtho2D (0.f, width, 0.f, height);  /* ortografica no plano xy de [0,w]x[0,h] */

   /* save new canvas size */
   itfDataLeft.canvasWidth=width;
   itfDataLeft.canvasHeight=height;
   itfDataRight.canvasWidth=width;
   itfDataRight.canvasHeight=height;

   /* return control to IUP event manager */
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfInitDraw
/*---------------------------------------------------------------------------*/
void itfInitDraw()
{
   GLfloat pos[4], amb[4], dif[4], esp[4];
   userOpen(WIDTH,HEIGHT,"input/modelo13.mdl");

   glEnable (GL_DEPTH_TEST);      //zbuffer habilitado
   glDepthFunc (GL_LESS);
   glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
   glEnable (GL_LIGHTING);
   glDisable (GL_NORMALIZE);
   glShadeModel(GL_FLAT);  
   glClearColor(0.0, 0.0, 0.0, 0.0);

   pos[0] = -10.0f;   pos[1] = -10.0f,   pos[2] = -10.0f;   pos[3] = 1.0f;
   amb[0] = 0.1f;   amb[1] = 0.1f,   amb[2] = 0.1f;   amb[3] = 1.0f;
   dif[0] = 1.0f;   dif[1] = 1.0f,   dif[2] = 1.0f;   dif[3] = 1.0f;
   esp[0] = 0.5f;   esp[1] = 0.5f,   esp[2] = 0.5f;   esp[3] = 1.0f;
   amb[0] = 0.0f;   amb[1] = 0.0f,   amb[2] = 0.0f;   amb[3] = 1.0f;
   glLightfv (GL_LIGHT0, GL_POSITION, pos);
   glLightfv (GL_LIGHT0, GL_AMBIENT, amb);      
   glLightfv (GL_LIGHT0, GL_DIFFUSE, dif);
   glLightfv (GL_LIGHT0, GL_SPECULAR, esp);
   glEnable (GL_LIGHT0);
}

/*---------------------------------------------------------------------------*/
// itfTimer_cb
/*---------------------------------------------------------------------------*/
int itfTimer_cb(Ihandle *self)
{
   static int counter=0;
   char textCounter[5];
   int div=1000,n,dif,digit;
   itoa(counter,textCounter,10);
   IupGLMakeCurrent(globalData.counterCanvas);
   glClear(GL_COLOR_BUFFER_BIT);
   dif=0;
   for(n=0;n<4;n++){
      glRasterPos2f((float)(172*n), 0.f);
      digit=(counter-dif)/div;
      glDrawPixels(172, 256, GL_RGB, GL_UNSIGNED_BYTE, globalData.character[digit]);
      dif+=div*digit;
      div/=10;
   }
   IupGLSwapBuffers(globalData.counterCanvas);  /* swap data from back buffer to front buffer */
   counter++;
   if(counter>9999)
      counter=0;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfIdle_cb
/*---------------------------------------------------------------------------*/
int itfIdle_cb(void){
   int process = 0;
   if(globalData.TypeOfCapture==1){
      itfTimer_cb(NULL);
   }
/*Takes care of the superior canvas*/
   if (itfDataLeft.capVideo && imVideoCaptureLive(itfDataLeft.capVideo, -1) && globalData.TypeOfCapture==0){
      imVideoCaptureFrame(itfDataLeft.capVideo, itfDataLeft.supFrame, IM_RGB|IM_PACKED, -1);
      process = 1;
   }
   if (itfDataLeft.capVideo && globalData.TypeOfCapture==1){
      imVideoCaptureOneFrame(itfDataLeft.capVideo, itfDataLeft.supFrame, IM_RGB|IM_PACKED);
      process = 1;
   }
   if (process){
      userProcessLeft(itfDataLeft.frameWidth,itfDataLeft.frameHeight,itfDataLeft.supFrame,usrData.usrFlags,usrData.usrValues,itfDataLeft.infFrame, &(usrData.usrLabelString) ) ;
      /* force a repaint */
      itfRepaintUpperLeft_cb(itfDataLeft.supCanvas);
      itfRepaintLowerLeft_cb(itfDataLeft.infCanvas);
   }
/*Takes care of the inferior canvas*/
   process=0;
   if (itfDataRight.capVideo && imVideoCaptureLive(itfDataRight.capVideo, -1) && globalData.TypeOfCapture==0){
      imVideoCaptureFrame(itfDataRight.capVideo, itfDataRight.supFrame, IM_RGB|IM_PACKED, -1);
      process = 1;
   }
   if (itfDataRight.capVideo && globalData.TypeOfCapture==1){
      imVideoCaptureOneFrame(itfDataRight.capVideo, itfDataRight.supFrame, IM_RGB|IM_PACKED);
      process = 1;
   }
   if (process){
      userProcessRight(itfDataRight.frameWidth,itfDataRight.frameHeight,itfDataRight.supFrame,usrData.usrFlags,usrData.usrValues,itfDataRight.infFrame);
      /* force a repaint */
      itfRepaintUpperRight_cb(itfDataRight.supCanvas);
      itfRepaintLoweRight_cb(itfDataRight.infCanvas);
   }
/*Saves video files*/
   if(itfDataLeft.saveVideo)
   {
      IupGLMakeCurrent( itfDataLeft.supCanvas );
      glReadPixels( 0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, itfDataLeft.supFrame) ;
      imFileWriteImageData(itfDataLeft.videoFile,itfDataLeft.supFrame);

   }
   if(itfDataRight.saveVideo)
      imFileWriteImageData(itfDataRight.videoFile,itfDataRight.supFrame);
   if(itfDataLeft.saveProcessedVideo)
      imFileWriteImageData(itfDataLeft.processedVideoFile,itfDataLeft.infFrame);
   if(itfDataRight.saveProcessedVideo)
      imFileWriteImageData(itfDataRight.processedVideoFile,itfDataRight.infFrame);
/*Takes care of the status bar*/
   if (itfDataLeft.capVideo || 
      itfDataRight.capVideo ){      
      /* estimate the number of frames per second */
      static int frame_count = 1;
      static int start_time = 0;
      int current_time = timeGetTime();
      if (current_time - start_time > CLOCKS_PER_SEC)
      {
         IupSetfAttribute( usrData.FPSLabel, "TITLE", "fps: %3.2f", 
            (double)(frame_count*CLOCKS_PER_SEC)/(double)(current_time-start_time) );

         IupSetAttribute( usrData.statusLabel, "TITLE", usrData.usrLabelString ) ;

         frame_count = 0;
         start_time = current_time;
      }
      frame_count++;
   }
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfUpdateInterface
/*---------------------------------------------------------------------------*/
void itfUpdateInterface(struct _itfData *itfData)
{
   if ((!itfData->capVideo || imVideoCaptureConnect(itfData->capVideo, -1) == -1) &&    !itfData->capFile){
      /* if no input, disable everything */
      IupSetAttribute(itfData->configBut,"ACTIVE","NO");
      IupSetAttribute(itfData->configMenu,"ACTIVE","NO");
      IupSetAttribute(itfData->captureMenu,"ACTIVE","NO");
      IupSetAttribute(itfData->saveBut,"ACTIVE","NO");
      IupSetAttribute(itfData->saveProcessedBut,"ACTIVE","NO");
      return;
   }
   /* if any input, enable almost everything */
   IupSetAttribute(itfData->captureMenu,"ACTIVE","YES");
   /* enable config only when capture device connected */
   if (itfData->capVideo && imVideoCaptureConnect(itfData->capVideo, -1) != -1){
      IupSetAttribute(itfData->configBut,"ACTIVE","YES");
      IupSetAttribute(itfData->configMenu,"ACTIVE","YES");
      IupSetAttribute(itfData->saveBut,"ACTIVE","YES");
      IupSetAttribute(itfData->saveProcessedBut,"ACTIVE","YES");
   }
   else{
      IupSetAttribute(itfData->configBut,"ACTIVE","NO");
      IupSetAttribute(itfData->configMenu,"ACTIVE","NO");
      IupSetAttribute(itfData->saveBut,"ACTIVE","NO");
      IupSetAttribute(itfData->saveProcessedBut,"ACTIVE","NO");
   }
   /* if live set the idle and update the start/stop toggle */
   if ((itfData->capVideo && imVideoCaptureLive(itfData->capVideo, -1)) ||
      (itfData->capFile && itfData->imgFileIndex != -1)){
      IupSetFunction(IUP_IDLE_ACTION, (Icallback)itfIdle_cb);
   }
   else{
   }
   if(!itfDataRight.capVideo && !itfDataLeft.capVideo)
      IupSetFunction(IUP_IDLE_ACTION, (Icallback)NULL);
   if(itfDataRight.capVideo || itfDataLeft.capVideo)
      IupSetAttribute(globalData.captureBut,"ACTIVE","YES");
   else
      IupSetAttribute(globalData.captureBut,"ACTIVE","NO");
}

/*---------------------------------------------------------------------------*/
// itfResetImageData
/*---------------------------------------------------------------------------*/
void itfResetImageData(struct _itfData *itfData)
{
   int width = 0, height = 0;
   /* retrieve the image size */
   if (itfData->capFile)
      imFileReadImageInfo(itfData->capFile, 0, &width, &height, NULL, NULL);
   else if (itfData->capVideo)
      imVideoCaptureGetImageSize(itfData->capVideo, &width, &height);
   if (width == 0 || height == 0)   {
      IupMessage("Error!", "Invalid image size.");
      return;
   }
   itfData->frameWidth=width;
   itfData->frameHeight=height;
   /* alocates the buffers */
   if (itfData->supFrame) 
      free(itfData->supFrame);
   itfData->supFrame = malloc(width*height*3);
   if(itfData->infFrame) 
      free(itfData->infFrame);
   itfData->infFrame = malloc(width*height*3);
}

/*---------------------------------------------------------------------------*/
// itfCapture_cb
/*---------------------------------------------------------------------------*/
int itfCapture_cb(Ihandle *self)
{
   if(globalData.captureLive){
      globalData.captureLive=0;
      IupSetAttribute(globalData.captureBut,"VALUE","OFF");
   }
   else{
      globalData.captureLive=1;
      IupSetAttribute(globalData.captureBut,"VALUE","ON");
   }
   if (itfDataRight.capVideo && imVideoCaptureConnect(itfDataRight.capVideo, -1) != -1){
      if (!imVideoCaptureLive(itfDataRight.capVideo, globalData.captureLive)) 
         IupMessage("Error!", "Could not change live state!");
   }
   itfUpdateInterface(&itfDataRight);
   if (itfDataLeft.capVideo && imVideoCaptureConnect(itfDataLeft.capVideo, -1) != -1){
      if (!imVideoCaptureLive(itfDataLeft.capVideo, globalData.captureLive)) 
         IupMessage("Error!", "Could not change live state!");
   }
   itfUpdateInterface(&itfDataLeft);
   if(!globalData.captureLive){
      IupSetAttribute(globalData.timer, "RUN", "NO");
      IupSetFunction(IUP_IDLE_ACTION, (Icallback)NULL);
   }
   else{
      if(globalData.TypeOfCapture==0)
         IupSetAttribute(globalData.timer, "RUN", "YES");
      IupSetFunction(IUP_IDLE_ACTION, (Icallback)itfIdle_cb);
   }
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfShowCounter_cb
/*---------------------------------------------------------------------------*/
int itfShowCounter_cb(Ihandle *self)
{
   if(!globalData.showingCounter){
      globalData.showingCounter=1;
      IupShowXY(globalData.counterDialog, IUP_LEFT, IUP_TOP);
   }
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfGetCapture
/*---------------------------------------------------------------------------*/
/* Returns a capture device */
int itfGetCapture(void)
{
   int i, ret;
   char* cap_list[50];
      int numCameras = imVideoCaptureDeviceCount();
   if (numCameras == 1) 
      return 0;
   for (i = 0; i < numCameras; i++)
      cap_list[i] = (char*)imVideoCaptureDeviceDesc(i);
   ret = IupListDialog(1,"Capture Device Selection",numCameras,cap_list,1,40,10,NULL);
   return ret;
}

/*---------------------------------------------------------------------------*/
// itfConnect_cb
/*---------------------------------------------------------------------------*/
int itfConnect_cb(struct _itfData *pt_itfData)/* Initializes the capture device */
{
   char desc[BUFSIZ];
   int i;
   int width=0, height=0, format=0;
   int captureNumber;
   /* creates an IM video capture manager */
   pt_itfData->capVideo = imVideoCaptureCreate();
   if (!pt_itfData->capVideo) {
      printf("No capture device found.\n"); return IUP_CLOSE;
   }
   /* conects the device */
   captureNumber=itfGetCapture();
   if(captureNumber==-1){
      pt_itfData->capVideo=NULL;
      return IUP_DEFAULT;
   }
   if (!imVideoCaptureConnect(pt_itfData->capVideo, captureNumber)) {
      imVideoCaptureDestroy(pt_itfData->capVideo);
      printf("Can not connect to capture device.\n");  return IUP_CLOSE;
   }
   if (!imVideoCaptureLive(pt_itfData->capVideo, 1)) {
      imVideoCaptureDisconnect(pt_itfData->capVideo);
      imVideoCaptureDestroy(pt_itfData->capVideo);
      printf("Can not activate capturing.\n");  return IUP_CLOSE;
   }
   /* selects maximum resolution format */
   format = imVideoCaptureFormatCount(pt_itfData->capVideo);
   for (i=0; i<format; i++) {
      imVideoCaptureGetFormat(pt_itfData->capVideo, i, &width, &height, desc);
      if (width == WIDTH && height == HEIGHT)
         FORMAT = i;
   }
   imVideoCaptureSetFormat(pt_itfData->capVideo, FORMAT);
   itfResetImageData(pt_itfData);
   itfUpdateInterface(pt_itfData);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfConnectLeft_cb
/*---------------------------------------------------------------------------*/
int itfConnectLeft_cb(Ihandle *self)/* Initializes the capture device */
{
   itfConnect_cb(&itfDataLeft);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfConnectRight_cb
/*---------------------------------------------------------------------------*/
int itfConnectRight_cb(Ihandle *self)/* Initializes the capture device */
{
   itfConnect_cb(&itfDataRight);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfConfigure_cb
/*---------------------------------------------------------------------------*/
int itfConfigure_cb(struct _itfData *pt_itfData)
{
   int dlg = 0, live;
   /* get a configuration dialog */
   int dlg_count = imVideoCaptureDialogCount(pt_itfData->capVideo);
   if (dlg_count > 1){
      int i, ret;
      char* dlg_list[50];

      for (i = 0; i < dlg_count; i++)
      dlg_list[i] = (char*)imVideoCaptureDialogDesc(pt_itfData->capVideo, i);

      ret = IupListDialog(1,"Configuration Dialog Selection",dlg_count,dlg_list,1,20,10,NULL);
      if (ret == -1)
      return IUP_DEFAULT;

      dlg = ret;
   }
   live = imVideoCaptureLive(pt_itfData->capVideo, -1);
   if (live)
      imVideoCaptureLive(pt_itfData->capVideo, 0);  /* deactivate the capture before calling the dialog */

   if (!imVideoCaptureShowDialog(pt_itfData->capVideo, dlg, IupGetAttribute((Ihandle*)IupGetGlobal("app_dialog"), "WID"))) {
      IupMessage("Error!", "Could not set configuration.");
      itfUpdateInterface(pt_itfData);
      return IUP_DEFAULT;
   }
   /* reset data because the dialogs can change the image size */
   itfResetImageData(pt_itfData);
   if (live)
      imVideoCaptureLive(pt_itfData->capVideo, 1);  /* restore the live state */
   itfUpdateInterface(pt_itfData);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfConfigureRight_cb
/*---------------------------------------------------------------------------*/
int itfConfigureRight_cb(Ihandle *self)
{
   itfConfigure_cb(&itfDataRight);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfConfigureLeft_cb
/*---------------------------------------------------------------------------*/
int itfConfigureLeft_cb(Ihandle *self)
{
   itfConfigure_cb(&itfDataLeft);
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfExit_cb
/*---------------------------------------------------------------------------*/
int itfExit_cb(Ihandle *self)
{
   /* destroy buffers, disconnect devices, close files */
   if (itfDataLeft.capFile) 
      imFileClose(itfDataLeft.capFile);
   if (itfDataLeft.capVideo)
      imVideoCaptureDestroy(itfDataLeft.capVideo);
   if (itfDataLeft.supFrame) 
      free(itfDataLeft.supFrame);
   if (itfDataLeft.infFrame) 
      free(itfDataLeft.infFrame);
   if (itfDataRight.capFile) 
      imFileClose(itfDataRight.capFile);
   if (itfDataRight.capVideo)
      imVideoCaptureDestroy(itfDataRight.capVideo);
   if (itfDataRight.supFrame) 
      free(itfDataRight.supFrame);
   if (itfDataRight.infFrame) 
      free(itfDataRight.infFrame);
   if(globalData.timer)
      IupDestroy(globalData.timer); 
   userClose( );
   return IUP_CLOSE;
}

/*---------------------------------------------------------------------------*/
// itfCounterClose_cb
/*---------------------------------------------------------------------------*/
int itfCounterClose_cb(Ihandle *self)
{
   globalData.showingCounter=0;
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfAbout_cb
/*---------------------------------------------------------------------------*/
int itfAbout_cb(Ihandle *self)
{
   IupMessagef("About", "3DPhoto 1.0\n"
                  "Tecgraf/PUC-Rio\n"
                  " ---------------- \n"
                  "IUP Version %s\n"
                  "IM Version %s\n"
                  " ---------------- \n"
                  "OpenGL:\n"
                  "  Vendor: %s\n"
                  "  Renderer: %s\n"
                  "  Version: %s\n"
                  , IUP_RELEASE_VERSION, IM_VERSION, 
                     glGetString(GL_VENDOR),glGetString(GL_RENDERER),glGetString(GL_VERSION));
   return IUP_DEFAULT;
}

/*---------------------------------------------------------------------------*/
// itfReadCharacters
/*---------------------------------------------------------------------------*/
void itfReadCharacters(){
   int width, height, color_mode, data_type;
   int error,n;
   char fileName[150];
   char atribute[100];
   imFile* ifile;
   Ihandle *fileDlg;
   void* data;
   for(n=0;n<10;n++){
      sprintf(fileName,"input/%d.jpg",n);
      ifile = imFileOpen(fileName, &error);
      if (!ifile) {
         sprintf(fileName,"../input/%d.jpg",n);
         ifile = imFileOpen(fileName, &error);
      }
      if (!ifile) {
         sprintf(fileName,"../../input/%d.jpg",n);
         ifile = imFileOpen(fileName, &error);
      }
      if (!ifile) {
         sprintf(fileName,"%d.jpg",n);
         fileDlg = IupFileDlg();
         sprintf(atribute,"DIALOGTYPE = OPEN, TITLE = \"Missing %d.jpg\"",n);
         IupSetAttributes(fileDlg, atribute);
         sprintf(atribute, "FILTER = \"%d.jpg\", FILTERINFO = \"*.jpg - JPEG image file\"",n);
         IupSetAttributes(fileDlg, atribute);
         sprintf(atribute,"FILE = \"%d.jpg\"",n);
         IupSetAttributes(fileDlg, atribute);
         IupPopup(fileDlg, IUP_ANYWHERE, IUP_ANYWHERE); 
         switch(IupGetInt(fileDlg, IUP_STATUS)){
            case 1: 
               return; 
            case 0 : 
               break; 
            case -1 : 
               return;
            break; 
         }
         ifile = imFileOpen(IupGetAttribute(fileDlg, IUP_VALUE),&error);
      }
      if (!ifile) {
         printf("Error opening image %s: %d\n",fileName,error);
         return;
      }
      error = imFileReadImageInfo(ifile, 0, &width, &height, &color_mode, &data_type);
      if (error != IM_ERR_NONE){                                 /* force the image to be converted to a bitmap */
         printf("Error loading image info: %d\n",error);
         return;
      }
      if(width!=172 || height!=256){
         printf("Error loading image: incorrect size\n");
         return;
      }
      data = malloc(imImageDataSize(width, height, color_mode, data_type));
      error = imFileReadImageData(ifile, data, 0, IM_RGB | IM_PACKED );
      if (error != IM_ERR_NONE){
         printf("Error loading image data: %d\n",error);
         return;
      }
      globalData.character[n]=data;
      imFileClose(ifile);
   }
/*If everthing worked fine*/
   IupSetAttribute(globalData.showCounterBut,"ACTIVE","YES");
}

/*---------------------------------------------------------------------------*/
// itfCreateMainMenu
/*---------------------------------------------------------------------------*/
void itfCreateMainMenu( ) 
{
   Ihandle* file_menu = IupMenu(
      IupItem( "Exit", "itfExit_cb"),
      NULL
   );

   Ihandle* captureMenu = IupMenu(
      IupItem( "Connect Input Device...", "itfConnect_cb"),
      itfDataLeft.configMenu = IupItem( "Configure Device...", "itfConfigure_cb"),
      IupSeparator(),
      itfDataLeft.captureMenu = IupItem( "Start/Stop", "itfCapture_cb"),
      NULL
   );

   Ihandle* process_menu = IupMenu(
      IupItem( "F1", "user1_left_cb"),   /* EDIT_HERE */
      IupItem( "F2", "user_val2_left_cb"),
      IupItem( "Fr3", "user3_left_cb"),
      NULL
   );

   Ihandle* help_menu = IupMenu(
      IupItem( "About...", "itfAbout_cb"),
      NULL
   );

   Ihandle* menu = IupMenu(
      IupSubmenu("File", file_menu),
      IupSubmenu("Capture", captureMenu),
      IupSubmenu("Process", process_menu),
      IupSubmenu("Help", help_menu),
      NULL
   );

   IupSetAttribute(itfDataLeft.configMenu,"ACTIVE","NO");
   IupSetAttribute(itfDataLeft.captureMenu,"ACTIVE","NO");

   /* this will be used by the dialog */
   IupSetHandle("app_menu", menu);

   /* associate callbacks with names */
   IupSetFunction("itfExit_cb", (Icallback)itfExit_cb);
   IupSetFunction("itfAbout_cb", (Icallback)itfAbout_cb);
}


/*---------------------------------------------------------------------------*/
// itfSaveButton
/*---------------------------------------------------------------------------*/
Ihandle* itfSaveButton(char *bar)
{
   Ihandle *save;
   char name[50];
   sprintf(name,"itfSaveFile%s_cb",bar);
   save = IupToggle("",name);
   IupSetAttribute(save,"TIP","Save video to file.");
   IupSetAttribute(save,"IMAGE","icon_lib_save");
   IupSetAttribute(save,"IMINACTIVE","icon_lib_save_inactive");
   IupSetAttribute(save,"ACTIVE","YES");
   return save;
}

/*---------------------------------------------------------------------------*/
// itfCaptureToolbar
/*---------------------------------------------------------------------------*/
Ihandle* itfCaptureToolbar(char *bar, struct _itfData *pt_itfData)
{
   Ihandle *toolbar, *connect, *configure, *save;
   char name[50];
   sprintf(name,"itfConnect%s_cb",bar);
   connect = IupButton("",name);
   IupSetAttribute(connect,"TIP","Connects to a capture device.");
   IupSetAttribute(connect,"IMAGE","icon_lib_connect");

   sprintf(name,"itfConfigure%s_cb",bar);
   configure = IupButton("",name);
   IupSetAttribute(configure,"TIP","Configure the capture device.");
   IupSetAttribute(configure,"IMAGE","icon_lib_configure");
   IupSetAttribute(configure,"IMINACTIVE","icon_lib_configure_inactive");
   IupSetAttribute(configure,"ACTIVE","NO");
   pt_itfData->configBut = configure;

   save=itfSaveButton(bar);
   pt_itfData->saveBut=save;

   toolbar = IupHbox(
      connect, 
      configure,
      save,
      NULL);

   IupSetAttribute(toolbar, "ALIGNMENT", "ACENTER");
   IupSetAttribute(toolbar, "MARGIN", "2x2");
   return toolbar;
}

/*---------------------------------------------------------------------------*/
// itfCommonToolbar
/*---------------------------------------------------------------------------*/
Ihandle* itfCommonToolbar(){
   Ihandle *TypeOfCapture, *capture, *toolbar, *showCounter;

   capture = IupToggle("","itfCapture_cb");
   IupSetAttribute(capture,"TIP","Stop/Play capture devices.");
   IupSetAttribute(capture,"IMAGE","icon_lib_capture");
   IupSetAttribute(capture,"IMINACTIVE","icon_lib_capture_inactive");
   IupSetAttribute(capture,"ACTIVE","NO");
   IupSetAttribute(capture,"VALUE","ON");
   IupSetFunction("itfCapture_cb", (Icallback)itfCapture_cb);
   IupSetAttribute(globalData.captureBut,"ACTIVE","NO");
   globalData.captureBut = capture;

   TypeOfCapture = IupToggle("","itfTypeOfCapture_cb");
   IupSetAttribute(TypeOfCapture,"TIP","Toggles one/multiple captures.");
   IupSetAttribute(TypeOfCapture,"IMAGE","icon_lib_capture_n_frames");
   IupSetFunction("itfTypeOfCapture_cb", (Icallback)itfTypeOfCapture_cb);
   globalData.TypeOfCaptureBut=TypeOfCapture;

   showCounter = IupButton("","itfShowCounter_cb");
   IupSetAttribute(showCounter,"TIP","Shows the counter dialog.");
   IupSetAttribute(showCounter,"IMAGE","icon_lib_shwoCounter");
   IupSetAttribute(showCounter,"ACTIVE","NO");
   IupSetFunction("itfShowCounter_cb", (Icallback)itfShowCounter_cb);
   globalData.showCounterBut=showCounter;

   toolbar = IupHbox(
      TypeOfCapture,
      capture,
      showCounter,
      NULL);
   return toolbar;
}

/*---------------------------------------------------------------------------*/
// userToolbar
/*---------------------------------------------------------------------------*/
Ihandle* itfParametersToolbar() 
{
   Ihandle *toolbar, *val1, *val2, *saveLeft, *saveRight;
   Ihandle *radio_paramSup ;
   Ihandle *radio_paramInf  ;

   val1 = IupVal("HORIZONTAL");
   IupSetAttribute(val1, "MOUSEMOVE_CB", "itfVal1_cb");
   val2 = IupVal("HORIZONTAL");
   IupSetAttribute(val2, "MOUSEMOVE_CB", "itfVal2_cb");
   saveLeft=itfSaveButton("LeftProcessed");
   saveRight=itfSaveButton("RightProcessed");
   itfDataLeft.saveProcessedBut=saveLeft;
   itfDataRight.saveProcessedBut=saveRight;

   usrData.userButton1=IupToggle("", "itfButton1_cb"),  /* EDIT_HERE */
   IupSetAttribute(usrData.userButton1,"IMAGE","icon_lib_user1");
   usrData.userButton2=IupToggle("", "itfButton2_cb"),
   IupSetAttribute(usrData.userButton2,"IMAGE","icon_lib_user2");
   usrData.userButton3=IupToggle("", "itfButton3_cb"),
   IupSetAttribute(usrData.userButton3,"IMAGE","icon_lib_user3");
   usrData.userButton4=IupToggle("", "itfButton4_cb"),
   IupSetAttribute(usrData.userButton4,"IMAGE","icon_lib_user4");
   usrData.userButton5=IupToggle("", "itfButton5_cb"),
   IupSetAttribute(usrData.userButton5,"IMAGE","icon_lib_user5");

   radio_paramSup = IupRadio( IupHbox(usrData.userButton1, usrData.userButton2, usrData.userButton3, usrData.userButton4, usrData.userButton5,NULL  ) ) ;

   usrData.userButtonA=IupToggle("", "itfButtonA_cb"),  /* EDIT_HERE */
   IupSetAttribute(usrData.userButtonA,"IMAGE","icon_lib_userA");
   usrData.userButtonB=IupToggle("", "itfButtonB_cb"),
   IupSetAttribute(usrData.userButtonB,"IMAGE","icon_lib_userB");

   radio_paramInf = IupRadio( IupHbox(usrData.userButtonA, usrData.userButtonB, NULL  ) ) ;

   toolbar = IupHbox(
      saveLeft,
      IupFill(),
      radio_paramSup,
      IupFill(),
      radio_paramInf,
      IupFill(),
      val1,
      val2,
      IupFill(),
      saveRight,
      NULL);
   IupSetAttribute(toolbar, "ALIGNMENT", "ACENTER");
   IupSetAttribute(toolbar, "MARGIN", "2x2");
   return toolbar;
}

/*---------------------------------------------------------------------------*/
// itfCreateDialogCounter
/*---------------------------------------------------------------------------*/
void itfCreateDialogCounter(Ihandle * parentDialog)
{
   Ihandle *dialog, *canvas;
   canvas = IupLabel("counterLabel");

   canvas = IupGLCanvas("app_counter_repaint_cb");
   IupSetAttribute(canvas, "BORDER", "NO");
   IupSetAttribute(canvas, "EXPAND", "YES");
   IupSetAttribute(canvas, "RASTERSIZE", "688x256");
   IupSetAttribute(canvas, "BUFFER", "DOUBLE");   /* use double buffer */
   IupSetAttribute(canvas, IUP_DEPTH_SIZE, "16");   /* use double buffer */
   IupSetAttribute(canvas, "RESIZE_CB", "itfResize_cb");   /* configure the resize callback */
   globalData.counterCanvas = canvas;

   dialog = IupDialog(canvas);
   IupSetAttribute(dialog, "CLOSE_CB", "itfCounterClose_cb");
   IupSetAttribute(dialog, "TITLE", "Counter");
   IupSetAttribute(dialog, "SHRINK", "NO");
   IupSetFunction("itfCounterClose_cb", (Icallback)itfCounterClose_cb);
   IupSetGlobal(IUP_PARENTDIALOG, "app_dialog");
   globalData.counterDialog=dialog;
}

/*----------------------*/
/* itfCreateMainDialog  */
/*----------------------*/
void itfCreateMainDialog()
{
   Ihandle *dialog, *statusbar, *controlToolbar, *toolbarLeft, *toolbarRight, 
      *toolbarCommon, *userToolbar, *box, *canvas, *supCanvas, *infCanvas,
      *statuslabel, *fpslabel, *supLeftCanvas, *infLeftCanvas, *supRightCanvas, *infRightCanvas;

   itfDataLeft.capVideo = imVideoCaptureCreate();
   if (!itfDataLeft.capVideo)
      IupMessage("Error!", "No Capture Device available!");

   /* initialize interface */
   toolbarLeft = itfCaptureToolbar("Left",&itfDataLeft);
   toolbarRight = itfCaptureToolbar("Right",&itfDataRight);
   toolbarCommon = itfCommonToolbar();
   
   controlToolbar = IupHbox(
      toolbarLeft,
      IupFill(),
      toolbarCommon,
      IupFill(),
      toolbarRight, 
      NULL);
   userToolbar=itfParametersToolbar();
   IupSetFunction("itfConnectLeft_cb", (Icallback)itfConnectLeft_cb);
   IupSetFunction("itfConfigureLeft_cb", (Icallback)itfConfigureLeft_cb);

   IupSetFunction("itfConnectRight_cb", (Icallback)itfConnectRight_cb);
   IupSetFunction("itfConfigureRight_cb", (Icallback)itfConfigureRight_cb);

   IupSetFunction("itfVal2_cb", (Icallback)itfVal2_cb);
   IupSetFunction("itfVal1_cb", (Icallback)itfVal1_cb);

   IupSetFunction("itfButton1_cb", (Icallback)itfButton1_cb); 
   IupSetFunction("itfButton2_cb", (Icallback)itfButton2_cb);
   IupSetFunction("itfButton3_cb", (Icallback)itfButton3_cb);
   IupSetFunction("itfButton4_cb", (Icallback)itfButton4_cb);
   IupSetFunction("itfButton5_cb", (Icallback)itfButton5_cb);
   IupSetFunction("itfButtonA_cb", (Icallback)itfButtonA_cb);
   IupSetFunction("itfButtonB_cb", (Icallback)itfButtonB_cb);



   /* sup canvas for the captured image and the final results (3D data) */
   /* inf canvas for intermediate results */
   supLeftCanvas = IupGLCanvas("itfRepaintUpperLeft_cb");
   IupSetAttribute(supLeftCanvas, "BORDER", "NO");
   IupSetAttribute(supLeftCanvas, "EXPAND", "YES");
   IupSetAttribute(supLeftCanvas, "RASTERSIZE", "320x240");
   IupSetAttribute(supLeftCanvas, "BUFFER", "DOUBLE");   /* use double buffer */
   IupSetAttribute(supLeftCanvas, IUP_DEPTH_SIZE, "16"); 
   IupSetAttribute(supLeftCanvas, "RESIZE_CB", "itfResize_cb");   /* configure the resize callback */
   itfDataLeft.supCanvas = supLeftCanvas;

   infLeftCanvas = IupGLCanvas("itfRepaintLowerLeft_cb");
   IupSetAttribute(infLeftCanvas, "BORDER", "NO");
   IupSetAttribute(infLeftCanvas, "EXPAND", "YES");
   IupSetAttribute(infLeftCanvas, "RASTERSIZE", "320x240");
   IupSetAttribute(infLeftCanvas, "BUFFER", "DOUBLE");  /* use double buffer */
   IupSetAttribute(infLeftCanvas, "RESIZE_CB", "itfResize_cb");  /* configure the resize callback */
   itfDataLeft.infCanvas = infLeftCanvas;

   supRightCanvas = IupGLCanvas("itfRepaintUpperRight_cb");
   IupSetAttribute(supRightCanvas, "BORDER", "NO");
   IupSetAttribute(supRightCanvas, "EXPAND", "YES");
   IupSetAttribute(supRightCanvas, "RASTERSIZE", "320x240");
   IupSetAttribute(supRightCanvas, "BUFFER", "DOUBLE");   /* use double buffer */
   IupSetAttribute(supRightCanvas, "RESIZE_CB", "itfResize_cb");   /* configure the resize callback */
   itfDataRight.supCanvas = supRightCanvas;

   infRightCanvas = IupGLCanvas("itfRepaintLoweRight_cb");
   IupSetAttribute(infRightCanvas, "BORDER", "NO");
   IupSetAttribute(infRightCanvas, "EXPAND", "YES");
   IupSetAttribute(infRightCanvas, "RASTERSIZE", "320x240");
   IupSetAttribute(infRightCanvas, "BUFFER", "DOUBLE");  /* use double buffer */
   IupSetAttribute(infRightCanvas, "RESIZE_CB", "itfResize_cb");  /* configure the resize callback */
   itfDataRight.infCanvas = infRightCanvas;

   IupSetFunction("itfResize_cb", (Icallback)itfResize_cb);
   IupSetFunction("itfRepaintUpperLeft_cb", (Icallback)itfRepaintUpperLeft_cb);
   IupSetFunction("itfRepaintLowerLeft_cb", (Icallback)itfRepaintLowerLeft_cb);
   IupSetFunction("itfRepaintUpperRight_cb", (Icallback)itfRepaintUpperRight_cb);
   IupSetFunction("itfRepaintLoweRight_cb", (Icallback)itfRepaintLoweRight_cb);

   IupSetFunction("itfSaveFileLeft_cb", (Icallback)itfSaveFileLeft_cb);
   IupSetFunction("itfSaveFileRight_cb", (Icallback)itfSaveFileRight_cb);
   IupSetFunction("itfSaveFileLeftProcessed_cb", (Icallback)itfSaveFileLeftProcessed_cb);
   IupSetFunction("itfSaveFileRightProcessed_cb", (Icallback)itfSaveFileRightProcessed_cb);

   /* the status bar is just a label to put some usefull information in run time */
   fpslabel = IupLabel("fps:  ");
   IupSetAttribute(fpslabel, "EXPAND", "HORIZONTAL");
   IupSetAttribute(fpslabel, "FONT", "COURIER_NORMAL_10");

   statuslabel = IupLabel("                                           ");
   IupSetAttribute(statuslabel, "EXPAND", "HORIZONTAL");
   IupSetAttribute(statuslabel, "FONT", "COURIER_NORMAL_10");

   statusbar = IupSetAttributes(IupHbox(
               IupFrame(IupVbox(fpslabel,IupFill(),statuslabel, NULL)), 
               NULL), "MARGIN=5x5");

   usrData.statusLabel = statuslabel;
   usrData.FPSLabel = fpslabel ;

   /* this is the most external box that puts together
      the toolbar, the two canvas and the status bar */
   supCanvas = IupHbox(supLeftCanvas, supRightCanvas, NULL);
   IupSetAttribute(supCanvas, "GAP", "5");
   infCanvas = IupHbox(infLeftCanvas, infRightCanvas, NULL);
   IupSetAttribute(infCanvas, "GAP", "5");
   canvas=IupVbox(
         supCanvas,
         userToolbar,
         infCanvas,
         NULL);
   box = IupVbox(
         controlToolbar,
         canvas,
         statusbar, 
         NULL);

   /* create the dialog and set its attributes */
   itfCreateMainMenu(itfDataLeft);
   dialog = IupDialog(box);
   IupSetAttribute(dialog, "MENU", "app_menu");     /* configure the menu */
   IupSetAttribute(dialog, "CLOSE_CB", "itfExit_cb");
   IupSetAttribute(dialog, "TITLE", "3DPhoto");
   IupSetAttribute(dialog, "SHRINK", "NO");
   IupSetHandle("app_dialog", dialog);
   IupSetGlobal(IUP_PARENTDIALOG, "app_dialog");     /* to be used by the idle callback */

   itfCreateDialogCounter(dialog);


   IupShowXY(dialog, IUP_CENTER, IUP_CENTER);
}

/*---------------------------------------------------------------------------*/
// counterThread
/*---------------------------------------------------------------------------*/
DWORD WINAPI counterThread( LPVOID lpParam ) 
{ 
   globalData.timer=IupTimer();
   IupSetFunction("timer", (Icallback) itfTimer_cb);
   IupSetAttribute(globalData.timer, "TIME", "20");
   IupSetAttribute(globalData.timer, "RUN", "YES");
   IupSetAttribute(globalData.timer, "ACTION_CB", "timer");
   IupMainLoop();
   IupControlsClose();
   IupClose();
   return 0;
} 
 
/*---------------------------------------------------------------------------*/
// main
/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[]) 
{
   DWORD dwThreadId, dwThrdParam = 1; 
   HANDLE hThread; 
   /* IUP initialization */
   IupOpen();
   IupControlsOpen();
   IupGLCanvasOpen();
   IconLibOpen();

   imFormatRegisterAVI () ;

   /* Create and show the main dialog */
   itfCreateMainDialog();

   itfInitDraw();

   itfReadCharacters();
   /* Creates counter thread */
   hThread = CreateThread( 
      NULL,                        // default security attributes 
      0,                           // use default stack size  
      counterThread,               // thread function 
      &dwThrdParam,                // argument to thread function 
      0,                           // use default creation flags 
      &dwThreadId);                // returns the thread identifier 
   if (hThread == NULL) {
      printf( "CreateThread failed." ); 
   }

   /* IUP event loop */
   IupMainLoop();

   /* IUP closing */
   IupControlsClose();
   IupClose();

   return 0;
}
