#ifdef WIN32
#include <windows.h>
#endif

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

#include "imvideocapture.h"

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

#include <im.h>

#include "gl_printf.h"
#include "imageUtils.h"
#include "Filters.h"
#include "edge.h"
#include "Recognize.h"

// Includes Flávio
#include "edges.h"
#include "tsai.h"

// Include MD3
#include "Md3.h"

CModelMD3* LaraMd3Model = NULL;

#define TEX_WIDTH 512.0
#define TEX_HEIGHT 256.0

enum Filters
{
  MEAN_FILTER         = 1,
  GAUSSIAN_FILTER     = 2,
  MEDIAN_FILTER       = 4,
  CONSERVATIVE_FILTER = 8,
  DIFF                = 16,
  DIFF_NORMALIZED     = 32,
};

enum EdgeAlgo
{
  SOBEL               = 1,
  LOG                 = 2,
};

struct AppImageConfig
{
  GLuint gTexImage;
  GLuint gTexImageLumi;
  unsigned char* gData;
  int filter;
  int edgeDetectAlgorithm;
  int luminance;
  int gaussianSteps;
  int cosFourthCorrection;
  int logThreshold;
  int sobelThreshold;
};

imVideoCapture* myVideoCap = NULL;
int gHeight = 0, gWidth = 0;
unsigned char* gData = NULL;
int show4Images = 0;
Ihandle* gCanvas;

struct AppImageConfig Image1Config;
struct AppImageConfig Image2Config;
struct AppImageConfig Image3Config;
struct AppImageConfig Image4Config;

bool cameraCalibrated=false;
int numSeq = 1;
double H[9];
double H2[9];
double H3[9];

static double modelview[16];
static double projection[16];

static char* getFilterName(struct AppImageConfig image)
{
  if (image.filter == 0 && !image.luminance)
    return "Original";
  if (image.filter == 0 && image.luminance )
    return "Luminancia";
  if (image.filter == GAUSSIAN_FILTER)
    return "Gaussiano";
  if (image.filter == MEAN_FILTER)
    return "Media";
  if (image.filter == MEDIAN_FILTER)
    return "Mediana";
  if (image.filter == CONSERVATIVE_FILTER)
    return "Conservativo";
  if (image.filter == DIFF)
    return "Diff";
  if (image.filter == DIFF_NORMALIZED)
    return "Diff Normalized";
  return "";
}

static char* getEdgeAlgorithmName(struct AppImageConfig image)
{
  if (image.edgeDetectAlgorithm == SOBEL)
  {
    return "Sobel";
  }
  if (image.edgeDetectAlgorithm == LOG)
  {
    return "Log";
  }
  return "";
}

int saveImageBGR(int width, int height, unsigned char* data, char* filename)
{
  unsigned char* red = new unsigned char[width*height];
  unsigned char* green = new unsigned char[width*height];
  unsigned char* blue = new unsigned char[width*height];

  unpackBGR(width, height, data, red, green, blue);
  imSaveRGB(width, height, IM_BMP, red, green, blue, filename);

  delete red;
  delete green;
  delete blue;
  return 1;
}

static int _cancelBtn(Ihandle* self)
{
  Ihandle* text = IupGetHandle("textCaptureImages");
  if (text)
    IupSetAttribute(text, IUP_VALUE, "");
  return IUP_CLOSE;
}

static int _okBtn(Ihandle* self)
{
  return IUP_CLOSE;
}

int iupNumberScan(char* dialogTitle, char* labelMsg, int defaultValue = 20)
{
  int number = 0;
  Ihandle* label = IupLabel(labelMsg);
  char buffer[20];
  itoa(defaultValue, buffer, 10);
  Ihandle* text = IupText(buffer);
  IupSetHandle("textCaptureImages", text);
  int mask = iupmaskSet(text, "/d*", 0, 1);
  IupSetAttribute(text, IUP_SIZE,   "100x");
  IupSetAttribute(text, IUP_EXPAND, IUP_HORIZONTAL);
  IupSetAttribute(text, IUP_VALUE, buffer);
  
  Ihandle* okBtn = IupButton("Ok", "captureImagesOkBtn");
  IupSetAttribute(okBtn, IUP_SIZE, "40x");
  IupSetFunction("captureImagesOkBtn", (Icallback) _okBtn);

  Ihandle* cancelBtn = IupButton("Cancela", "captureImagesCancelBtn");
  IupSetAttribute(cancelBtn, IUP_SIZE, "40x");
  IupSetFunction("captureImagesCancelBtn", (Icallback) _cancelBtn);

  Ihandle* dlg = IupDialog(IupHbox(IupFrame(IupVbox(label, text, IupHbox(okBtn, cancelBtn, NULL),NULL)), NULL));
  IupSetAttribute(dlg, IUP_GAP, "3");
  IupSetAttribute(dlg, IUP_MARGIN, "3x3");
  IupSetAttribute(dlg, IUP_MAXBOX, IUP_NO);
  IupSetAttribute(dlg, IUP_TITLE, dialogTitle);
  IupPopup(dlg, IUP_CENTER, IUP_CENTER);

  number = IupGetInt(text, IUP_VALUE);
  IupDestroy(dlg);
  return number;
}

int captureImages()
{
  int numberOfImages = 0;
  numberOfImages = iupNumberScan("Captura de Imagens", "Entre com o número de Quadros a ser capturado:");
  if (numberOfImages > 0)
  {
    if (numberOfImages > 100)
	{
	  int answer = IupAlarm("Aviso", "Foi Solicitado um número de imagens muito alto.\nDeseja realmente continuar?", "Sim", "Não", NULL);
	  if (answer == 2) return 1;
	}
	Ihandle* msg = IupLabel("Aguarde.\nSalvando Imagens");
	Ihandle* warning = IupDialog(IupHbox(IupFrame(msg), NULL));
    IupSetAttribute(warning, IUP_MARGIN, "3x3");
    IupSetAttribute(warning, IUP_MAXBOX, IUP_NO);
	IupShowXY(warning, IUP_CENTER, IUP_CENTER);
/*
    if (!myVideoCap || !imVideoCaptureLive(myVideoCap, IMVC_QUERY))
	{
	}

	int width, height;
    imVideoCaptureGetImageSize(myVideoCap, &width, &height);

    
    imVideoCaptureFrame(myVideoCap, gData, 1000);
*/
    char *filename = new char[15];
	for (int i = 0; i < numberOfImages; i++)
	{
      sprintf(filename, "frame%02d.bmp", numberOfImages+1);
      //imSaveRGB(gc.biGetColorFormat.bmiHeader.biWidth, gc.biGetColorFormat.bmiHeader.biHeight, IM_BMP, rData, gData, bData, filename);
	}
	IupHide(warning);
    delete filename;
	IupDestroy(warning);
  }
  return 1;
}

int myDisplay(Ihandle* self) 
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-1, 1, -1, 1, 0, 1);
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity();
  double hw=0.5;
  char* fiterDesc[200];

  // FPS counter
  static unsigned long lastCount=0, lastFrameCount=0;
  static int frames = 0;
  static LARGE_INTEGER counter, freq;

  QueryPerformanceCounter(&counter);
  QueryPerformanceFrequency(&freq);

  double elapsedSecs = (double)(counter.LowPart-lastCount)/freq.LowPart;
  lastCount = counter.LowPart;

  static int fps = -1;
  frames++;
  if (frames == 5)
  {
	frames = 0;

    double elapsedSecs = (double)(counter.LowPart-lastFrameCount)/freq.LowPart;
	lastFrameCount = counter.LowPart;

	fps = 5.0/elapsedSecs;
  }

  glDisable(GL_DEPTH_TEST);
  if (show4Images)
  {
    // Draw Top Left
    glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, Image1Config.gTexImage);
    glBegin(GL_QUADS);
    glColor3d(1.0, 1.0, 0.0);
    glTexCoord2d(0.0, 0.0); glVertex2d(-2*hw, 0.0);
    glTexCoord2d(0.0, gHeight/TEX_HEIGHT); glVertex2d(-2*hw, 1.0);
    glTexCoord2d(gWidth/TEX_WIDTH, gHeight/TEX_HEIGHT); glVertex2d(0, 1.0);
    glTexCoord2d(gWidth/TEX_WIDTH, 0.0); glVertex2d(0, 0.0);
    glEnd();

    // Draw Top Right
    glBindTexture(GL_TEXTURE_2D, Image2Config.gTexImage);
    glBegin(GL_QUADS);
    glColor3d(1.0, 1.0, 0.0);
    glTexCoord2d(0.0, 0.0); glVertex2d(0, 0.0);
    glTexCoord2d(0.0, gHeight/TEX_HEIGHT); glVertex2d(0, 1.0);
    glTexCoord2d(gWidth/TEX_WIDTH, gHeight/TEX_HEIGHT); glVertex2d(2*hw, 1.0);
    glTexCoord2d(gWidth/TEX_WIDTH, 0.0); glVertex2d(2*hw, 0.0);
    glEnd();

    // Draw Down Left
    glBindTexture(GL_TEXTURE_2D, Image3Config.gTexImage);
    glBegin(GL_QUADS);
    glColor3d(1.0, 1.0, 0.0);
    glTexCoord2d(0.0, 0.0); glVertex2d(-2*hw, -1.0);
    glTexCoord2d(0.0, gHeight/TEX_HEIGHT); glVertex2d(-2*hw, 0.0);
    glTexCoord2d(gWidth/TEX_WIDTH, gHeight/TEX_HEIGHT); glVertex2d(0, 0.0);
    glTexCoord2d(gWidth/TEX_WIDTH, 0.0); glVertex2d(0, -1.0);
    glEnd();

    // Draw Down Right
    glBindTexture(GL_TEXTURE_2D, Image4Config.gTexImage);
    glBegin(GL_QUADS);
    glColor3d(1.0, 1.0, 0.0);
    glTexCoord2d(0.0, 0.0); glVertex2d(0, -1.0);
    glTexCoord2d(0.0, gHeight/TEX_HEIGHT); glVertex2d(0, 0.0);
    glTexCoord2d(gWidth/TEX_WIDTH, gHeight/TEX_HEIGHT); glVertex2d(2*hw, 0.0);
    glTexCoord2d(gWidth/TEX_WIDTH, 0.0); glVertex2d(2*hw, -1.0);
    glEnd();

	char msg[200];
	strcpy(msg, getFilterName(Image1Config));
	strcat(msg, " ");
	strcat(msg, getEdgeAlgorithmName(Image1Config));
	gl_printf::printf(0,0, msg);

	strcpy(msg, getFilterName(Image2Config));
	strcat(msg, " ");
	strcat(msg, getEdgeAlgorithmName(Image2Config));
	gl_printf::printf(0.5,0, msg);

	strcpy(msg, getFilterName(Image3Config));
	strcat(msg, " ");
	strcat(msg, getEdgeAlgorithmName(Image3Config));
	gl_printf::printf(0,0.5, msg);

	strcpy(msg, getFilterName(Image4Config));
	strcat(msg, " ");
	strcat(msg, getEdgeAlgorithmName(Image4Config));
	gl_printf::printf(0.5,0.5, msg);

	// print Frames per Second
    gl_printf::printf(0.45, 0.45, " %d FPS", fps);
  }
  else
  {
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, Image1Config.gTexImage);
    glBegin(GL_QUADS);
    glColor3d(1.0, 1.0, 0.0);
    glTexCoord2d(0.0, 0.0); glVertex2d(-hw, -hw);
    glTexCoord2d(0.0, gHeight/TEX_HEIGHT); glVertex2d(-hw, hw);
    glTexCoord2d(gWidth/TEX_WIDTH, gHeight/TEX_HEIGHT); glVertex2d(hw, hw);
    glTexCoord2d(gWidth/TEX_WIDTH, 0.0); glVertex2d(hw, -hw);
    glEnd();   
	char msg[200];
	strcpy(msg, getFilterName(Image1Config));
	strcat(msg, " ");
	strcat(msg, getEdgeAlgorithmName(Image1Config));
	gl_printf::printf(0.25,0.25, msg);

	// print Frames per Second
    gl_printf::printf(0.25, 0.75, " %d FPS", fps);
  }

  // desenhando Linhas
  glDisable(GL_DEPTH_TEST);
  glDisable(GL_TEXTURE_2D);
  //glEnable(GL_COLOR_MATERIAL);
  glDisable(GL_LIGHTING);
  
//*/
  //desenhaLinhas();
//*/
  // Desenhando Linhas do reconhecidas do Modelo
  if (getNumberRecognizedLines() > 4)
  {
    desenhaLinhasReconhecidas();
    desenhaPontos();
  }
  
  float light_pos[4] = {0, 0, 20, 1};
  glViewport(0, 240, 320, 240);
  if (cameraCalibrated)
    CalibrateCamera(modelview, projection);
//  glEnable(GL_LIGHTING | GL_LIGHT0);
//  glDisable(GL_COLOR_MATERIAL);
//  glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadMatrixd(projection);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadMatrixd(modelview);
  
  desenhaModelo();
#ifdef MODELO_1
  glTranslatef(7.0f, 9.0f, 1.5f);
#else
  glTranslatef(5.0f, 5.0f, 1.5f);
#endif

  if (LaraMd3Model)
  {
    glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);  
	
	glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
	glColor3f(1.0f, 1.0f, 1.0f);
//    glDisable(GL_COLOR_MATERIAL);

	glScalef(0.1f, 0.1f, 0.1f);
	glRotatef(90, 1.0f, 0.0f, 0.0f);
    LaraMd3Model->DrawModel();
  }
  else
  {
    GLUquadricObj* esfera = gluNewQuadric();
    gluQuadricNormals(esfera, GLU_SMOOTH);
    gluSphere(esfera, 3, 32, 32);
    gluDeleteQuadric(esfera);
  }

  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  glViewport(0, 0, 640, 480);
  glDisable(GL_LIGHTING);

  IupGLSwapBuffers(self);
  return IUP_DEFAULT;
}

void updateImage(struct AppImageConfig imageConfig)
{
  unsigned char* filtersAcumm = new unsigned char[3*gWidth*gHeight];
  if (imageConfig.cosFourthCorrection)
  {
    cosCorrection(gWidth, gHeight, gData, filtersAcumm);
  }
  else
    memcpy(filtersAcumm, gData, 3*gWidth*gHeight);
  

  if (imageConfig.filter == 0 && !imageConfig.luminance)
  {
	memcpy(imageConfig.gData, filtersAcumm, 3*gWidth*gHeight);
  }
  if (imageConfig.luminance)
  {
	if (imageConfig.filter == 0)
	  transformToLuminance(gWidth, gHeight, IMG_BGR, filtersAcumm, imageConfig.gData);
	else
	{
      transformToLuminance(gWidth, gHeight, IMG_BGR, gData, filtersAcumm);
	}
  }

  if (imageConfig.filter == MEAN_FILTER)
  {
    meanFilter(gWidth, gHeight, 1, filtersAcumm, imageConfig.gData);
  }
  if (imageConfig.filter == GAUSSIAN_FILTER)
  {
//  gaussianFilter(gWidth, gHeight, imageConfig.gaussianSteps, gData, imageConfig.gData);
	  fastGaussianFilter(gWidth, gHeight, 3, 0/*imageConfig.luminance*/, imageConfig.gaussianSteps, filtersAcumm, imageConfig.gData);
  }
  if (imageConfig.filter == MEDIAN_FILTER)
  {
    medianFilter(gWidth, gHeight, 1, filtersAcumm, imageConfig.gData);
  }
  if (imageConfig.filter == CONSERVATIVE_FILTER)
  {
    conservativeFilter(gWidth, gHeight, 1, filtersAcumm, imageConfig.gData);
  }
  if (imageConfig.filter == DIFF)
  {
    diffFilter(gWidth, gHeight, Image2Config.gData, Image3Config.gData, imageConfig.gData);
  }
  if (imageConfig.filter == DIFF_NORMALIZED)
  {
    diffFilterNormalized(gWidth, gHeight, Image2Config.gData, Image3Config.gData, imageConfig.gData);
  }
  if (imageConfig.edgeDetectAlgorithm == SOBEL)
  {
    memcpy(filtersAcumm, imageConfig.gData, 3*gWidth*gHeight);
	sobelFilter(gWidth, gHeight, 3,imageConfig.luminance, imageConfig.sobelThreshold, filtersAcumm, imageConfig.gData);
  }
  if (imageConfig.edgeDetectAlgorithm == LOG)
  {
    memcpy(filtersAcumm, imageConfig.gData, 3*gWidth*gHeight);
	logFilter(gWidth, gHeight, 3,imageConfig.luminance, imageConfig.logThreshold, filtersAcumm, imageConfig.gData);
  }

  glBindTexture(GL_TEXTURE_2D, imageConfig.gTexImage);
  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gWidth, gHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, imageConfig.gData);

  delete filtersAcumm;
}

int myIdle(void)
{
  if (!myVideoCap || !imVideoCaptureLive(myVideoCap, IMVC_QUERY))
    return IUP_DEFAULT;

  imVideoCaptureGetImageSize(myVideoCap, &gWidth, &gHeight);

  if(!gData)
  {
    gData = new unsigned char[gHeight*gWidth*3];  // This is valid only because capture images are DWORD aligned already
	memset(gData,0,gHeight*gWidth*3);
  }

  if(!Image1Config.gData)
  {
    Image1Config.gData= new unsigned char[gHeight*gWidth*3];  // This is valid only because capture images are DWORD aligned already
	memset(Image1Config.gData,0,gHeight*gWidth*3);
  }
  if(!Image2Config.gData)
  {
    Image2Config.gData = new unsigned char[gHeight*gWidth*3];  // This is valid only because capture images are DWORD aligned already
	memset(Image2Config.gData,0,gHeight*gWidth*3);
  }
  if(!Image3Config.gData)
  {
    Image3Config.gData = new unsigned char[gHeight*gWidth*3];  // This is valid only because capture images are DWORD aligned already
	memset(Image3Config.gData,0,gHeight*gWidth*3);
  }
  if(!Image4Config.gData)
  {
    Image4Config.gData = new unsigned char[gHeight*gWidth*3];  // This is valid only because capture images are DWORD aligned already
	memset(Image4Config.gData,0,gHeight*gWidth*3);
  }

  imVideoCaptureFrame(myVideoCap, gData, 1000);

  if (show4Images)
  {
	updateImage(Image1Config);
	updateImage(Image2Config);
	updateImage(Image3Config);
	updateImage(Image4Config);
/*
#if 0 //#ifdef MODELO_1
	//recognize(gData, 320);
	if (!cameraCalibrated)
	  cameraCalibrated = recognizeInterpret(gData, 320, H);
	else
	  cameraCalibrated = recognize(gData, 320, H);
	
#else
//	recognize(Image4Config.gData, Image4Config.logThreshold);
	if (!cameraCalibrated)
	  cameraCalibrated = recognizeInterpret(Image4Config.gData, Image4Config.logThreshold, H);
	else
	  cameraCalibrated = recognize(Image4Config.gData, Image4Config.logThreshold, H);
#endif
*/

#if 0 //#ifdef MODELO_1
	//recognize(gData, 320);
	if (!cameraCalibrated)
	{
	  numSeq = 1;
	  cameraCalibrated = recognizeInterpret(gData, 320, H);
	}
	else
	{
	  if (numSeq == 1)
	  {
	    cameraCalibrated = recognize(gData, 320, H);
		if (cameraCalibrated)
		  numSeq = 2;
	  }
	  else if (numSeq == 2)
	  {
        memcpy(H2, H, 9*sizeof(double));
	    cameraCalibrated = recognize(gData, 320, H2);
		if (cameraCalibrated)
		  numSeq = 3;
	  }
	  else
	  {
	    cameraCalibrated = recognize(gData, 320, 0.5, 0.5, H, H2, H3);
		if (cameraCalibrated)
		{
          memcpy(H, H2, 9*sizeof(double));
          memcpy(H2, H3, 9*sizeof(double));
		}
 
	  }
	}
	
#else
//	recognize(Image4Config.gData, Image4Config.logThreshold);
	if (!cameraCalibrated)
	{
	  numSeq = 1;
	  cameraCalibrated = recognizeInterpret(Image4Config.gData, Image4Config.logThreshold, H);
	}
	else
	{
	  if (numSeq == 1)
	  {
	    cameraCalibrated = recognize(Image4Config.gData, Image4Config.logThreshold, H);
		if (cameraCalibrated)
		  numSeq = 2;
	  }
	  else if (numSeq == 2)
	  {
        memcpy(H2, H, 9*sizeof(double));
	    cameraCalibrated = recognize(Image4Config.gData, Image4Config.logThreshold, H2);
		if (cameraCalibrated)
		  numSeq = 3;
	  }
	  else
	  {
	    cameraCalibrated = recognize(Image4Config.gData, Image4Config.logThreshold, 0.3f, 0.3f, H, H2, H3);
		if (cameraCalibrated)
		{
          memcpy(H, H2, 9*sizeof(double));
          memcpy(H2, H3, 9*sizeof(double));
		}
 
	  }
	}
#endif

  }
  else
  {
	updateImage(Image1Config);
  }

  myDisplay(gCanvas);

  return IUP_DEFAULT;
}

int myKey(Ihandle* self, int key, int press)
{
  if (!press)
    return IUP_DEFAULT;

  switch (key) 
  {
  case 27: 
    imVideoCaptureDisconnect(myVideoCap);
    imVideoCaptureDestroy(myVideoCap);
    delete Image1Config.gData;
    delete Image2Config.gData;
	delete Image3Config.gData;
	delete Image4Config.gData;
	delete LaraMd3Model;

	glDeleteTextures(1, &Image1Config.gTexImage);
	glDeleteTextures(1, &Image1Config.gTexImageLumi);

	glDeleteTextures(1, &Image2Config.gTexImage);
	glDeleteTextures(1, &Image2Config.gTexImageLumi);

	glDeleteTextures(1, &Image3Config.gTexImage);
	glDeleteTextures(1, &Image3Config.gTexImageLumi);

	glDeleteTextures(1, &Image4Config.gTexImage);
	glDeleteTextures(1, &Image4Config.gTexImageLumi);
    //   CoUninitialize();
    return IUP_CLOSE;
  case ' ':
    if (imVideoCaptureLive(myVideoCap, IMVC_QUERY))
      imVideoCaptureLive(myVideoCap, 0);
    else
      imVideoCaptureLive(myVideoCap, 1);
    break;
  case 's':
//    imVideoCaptureShowDialog(myVideoCap, 1, (void*)IupGetAttribute(IupGetDialog(self), IUP_WID));
    imVideoCaptureShowDialog(myVideoCap, NULL, NULL);
    break;
  case 'c':
    captureImages();
	break;
  case 'm':
    // Image1
    char filename[100] = "Image1-";
    strcat(filename, getFilterName(Image1Config));
    strcat(filename, ".bmp");
	if (Image1Config.filter == 0 && !Image1Config.luminance)
   	  saveImageBGR(gWidth, gHeight, gData, filename);
	else
	  saveImageBGR(gWidth, gHeight, Image1Config.gData, filename);

	if (show4Images)
	{
	  // Image2
	  strcpy(filename,"Image2-");
	  strcat(filename, getFilterName(Image2Config));
	  strcat(filename, ".bmp");
	  if (Image2Config.filter == 0 && !Image2Config.luminance)
		saveImageBGR(gWidth, gHeight, gData, filename);
	  else
		saveImageBGR(gWidth, gHeight, Image2Config.gData, filename);

	  // Image3
	  strcpy(filename,"Image3-");
	  strcat(filename, getFilterName(Image3Config));
	  strcat(filename, ".bmp");
	  if (Image3Config.filter == 0 && !Image3Config.luminance)
		saveImageBGR(gWidth, gHeight, gData, filename);
	  else
		saveImageBGR(gWidth, gHeight, Image3Config.gData, filename);

	  // Image3
	  strcpy(filename,"Image4-");
	  strcat(filename, getFilterName(Image4Config));
	  strcat(filename, ".bmp");
	  if (Image4Config.filter == 0 && !Image4Config.luminance)
		saveImageBGR(gWidth, gHeight, gData, filename);
	  else
		saveImageBGR(gWidth, gHeight, Image4Config.gData, filename);
	}
    break;
  }
  return IUP_DEFAULT;
}

void myGlInit()
{
  glClearColor(0.0, 0.0, 0.0, 1.0);
  glShadeModel (GL_SMOOTH);
  glFrontFace(GL_CCW);
  glEnable(GL_DEPTH_TEST);

  // Image 1
  glGenTextures(1, &Image1Config.gTexImage);
  glBindTexture(GL_TEXTURE_2D, Image1Config.gTexImage);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_WIDTH, TEX_HEIGHT, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  glGenTextures(1, &Image1Config.gTexImageLumi);
  glBindTexture(GL_TEXTURE_2D, Image1Config.gTexImageLumi);
  glTexImage2D(GL_TEXTURE_2D, 0, 1, TEX_WIDTH, TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  //Image 2
  glGenTextures(1, &Image2Config.gTexImage);
  glBindTexture(GL_TEXTURE_2D, Image2Config.gTexImage);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_WIDTH, TEX_HEIGHT, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  glGenTextures(1, &Image2Config.gTexImageLumi);
  glBindTexture(GL_TEXTURE_2D, Image2Config.gTexImageLumi);
  glTexImage2D(GL_TEXTURE_2D, 0, 1, TEX_WIDTH, TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  // Image 3
  glGenTextures(1, &Image3Config.gTexImage);
  glBindTexture(GL_TEXTURE_2D, Image3Config.gTexImage);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_WIDTH, TEX_HEIGHT, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  glGenTextures(1, &Image3Config.gTexImageLumi);
  glBindTexture(GL_TEXTURE_2D, Image3Config.gTexImageLumi);
  glTexImage2D(GL_TEXTURE_2D, 0, 1, TEX_WIDTH, TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  // Image 4
  glGenTextures(1, &Image4Config.gTexImage);
  glBindTexture(GL_TEXTURE_2D, Image4Config.gTexImage);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_WIDTH, TEX_HEIGHT, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  glGenTextures(1, &Image4Config.gTexImageLumi);
  glBindTexture(GL_TEXTURE_2D, Image4Config.gTexImageLumi);
  glTexImage2D(GL_TEXTURE_2D, 0, 1, TEX_WIDTH, TEX_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

  gl_printf::open();
  gl_printf::set_viewport(640, 480);
}

static int _image1NoFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->filter = 0;
    config->luminance = 0;
  }
  return IUP_DEFAULT;
}
static int _image1LuminanceCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
	config->luminance = 1;
  return IUP_DEFAULT;
}
static int _image1NothingFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->filter = 0;
  }
  return IUP_DEFAULT;
}
static int _image1MeanFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
    config->filter = MEAN_FILTER;
  return IUP_DEFAULT;
}
static int _image1GaussianFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->filter = GAUSSIAN_FILTER;
    int steps = iupNumberScan("Configuração do Filtro Gaussiano", "Entre com o número de passadas:", config->gaussianSteps);
    if (steps > 0)
	  config->gaussianSteps = steps;
  }
  return IUP_DEFAULT;
}
static int _image1MedianFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
    config->filter = MEDIAN_FILTER;
  return IUP_DEFAULT;
}
static int _image1ConservativeFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
    config->filter = CONSERVATIVE_FILTER;
  return IUP_DEFAULT;
}
static int _image1DiffFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
    config->filter = DIFF;
  return IUP_DEFAULT;
}
static int _image1DiffNormFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
    config->filter = DIFF_NORMALIZED;
  return IUP_DEFAULT;
}

static int _image1NothingEdgeCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->edgeDetectAlgorithm = 0;
  }
  return IUP_DEFAULT;
}

static int _image1SobelFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->edgeDetectAlgorithm = SOBEL;
    int threshold = iupNumberScan("Configuração do Sobel", "Entre com o Threshold:", config->sobelThreshold);
    if (threshold > 0)
	  config->sobelThreshold = threshold;
  }
  return IUP_DEFAULT;
}
static int _image1LogFilterCB(Ihandle* self)
{
  AppImageConfig* config = (AppImageConfig*) IupGetAttribute(self, "imageConfig");
  if (config)
  {
    config->edgeDetectAlgorithm = LOG;
    int threshold = iupNumberScan("Configuração do Log", "Entre com o Threshold:", config->logThreshold);
    if (threshold > 0)
	  config->logThreshold = threshold;
  }
  return IUP_DEFAULT;
}

Ihandle* Imagem1Submenu()
{
  Ihandle* NoFilterItem = IupItem("Original", "image1NoFilter");
  IupSetFunction("image1NoFilter", (Icallback)_image1NoFilterCB);
  IupSetAttribute(NoFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* LuminanceItem = IupItem("Luminacia", "image1Luminance");
  IupSetFunction("image1Luminance", (Icallback)_image1LuminanceCB);
  IupSetAttribute(LuminanceItem, "imageConfig", (char*) &Image1Config);

  Ihandle* NothingFilterItem = IupItem("Nothing", "image1NothingFilter");
  IupSetFunction("image1NothingFilter", (Icallback)_image1NothingFilterCB);
  IupSetAttribute(NothingFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* MeanFilterItem = IupItem("Filtro da Média", "image1MeanFilter");
  IupSetFunction("image1MeanFilter", (Icallback)_image1MeanFilterCB);
  IupSetAttribute(MeanFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* GaussianFilterItem = IupItem("Filtro Gaussiano", "image1GaussianFilter");
  IupSetFunction("image1GaussianFilter", (Icallback)_image1GaussianFilterCB);
  IupSetAttribute(GaussianFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* MedianFilterItem = IupItem("Filtro da Mediana", "image1MedianFilter");
  IupSetFunction("image1MedianFilter", (Icallback)_image1MedianFilterCB);
  IupSetAttribute(MedianFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* ConservativeFilterItem = IupItem("Filtro Conservativo", "image1ConservativeFilter");
  IupSetFunction("image1ConservativeFilter", (Icallback)_image1ConservativeFilterCB);
  IupSetAttribute(ConservativeFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* NothingEdgeItem = IupItem("Nothing", "image1EdgeFilter");
  IupSetFunction("image1EdgeFilter", (Icallback)_image1NothingEdgeCB);
  IupSetAttribute(NothingEdgeItem, "imageConfig", (char*) &Image1Config);

  Ihandle* SobelFilterItem = IupItem("Sobel", "image1SobelFilter");
  IupSetFunction("image1SobelFilter", (Icallback)_image1SobelFilterCB);
  IupSetAttribute(SobelFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* LogFilterItem = IupItem("Log", "image1LogFilter");
  IupSetFunction("image1LogFilter", (Icallback)_image1LogFilterCB);
  IupSetAttribute(LogFilterItem, "imageConfig", (char*) &Image1Config);

  Ihandle* imagem1menu = IupMenu(NoFilterItem,
	                             LuminanceItem,
								 IupSeparator(),
								 NothingFilterItem,
								 MeanFilterItem,
								 GaussianFilterItem,
								 MedianFilterItem,
								 ConservativeFilterItem,
								 IupSeparator(),
								 NothingEdgeItem,
								 SobelFilterItem,
								 LogFilterItem,
								 NULL);

  return IupSubmenu("Imagem1", imagem1menu);
}

Ihandle* Imagem2Submenu()
{
  Ihandle* NoFilterItem = IupItem("Original", "image2NoFilter");
  IupSetFunction("image2NoFilter", (Icallback)_image1NoFilterCB);
  IupSetAttribute(NoFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* LuminanceItem = IupItem("Luminacia", "image2Luminance");
  IupSetFunction("image2Luminance", (Icallback)_image1LuminanceCB);
  IupSetAttribute(LuminanceItem, "imageConfig", (char*) &Image2Config);

  Ihandle* NothingFilterItem = IupItem("Nothing", "image2NothingFilter");
  IupSetFunction("image2NothingFilter", (Icallback)_image1NothingFilterCB);
  IupSetAttribute(NothingFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* MeanFilterItem = IupItem("Filtro da Média", "image2MeanFilter");
  IupSetFunction("image2MeanFilter", (Icallback)_image1MeanFilterCB);
  IupSetAttribute(MeanFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* GaussianFilterItem = IupItem("Filtro Gaussiano", "image2GaussianFilter");
  IupSetFunction("image2GaussianFilter", (Icallback)_image1GaussianFilterCB);
  IupSetAttribute(GaussianFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* MedianFilterItem = IupItem("Filtro da Mediana", "image2MedianFilter");
  IupSetFunction("image2MedianFilter", (Icallback)_image1MedianFilterCB);
  IupSetAttribute(MedianFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* ConservativeFilterItem = IupItem("Filtro Conservativo", "image2ConservativeFilter");
  IupSetFunction("image2ConservativeFilter", (Icallback)_image1ConservativeFilterCB);
  IupSetAttribute(ConservativeFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* NothingEdgeItem = IupItem("Nothing", "image2EdgeFilter");
  IupSetFunction("image2EdgeFilter", (Icallback)_image1NothingEdgeCB);
  IupSetAttribute(NothingEdgeItem, "imageConfig", (char*) &Image2Config);

  Ihandle* SobelFilterItem = IupItem("Sobel", "image2SobelFilter");
  IupSetFunction("image2SobelFilter", (Icallback)_image1SobelFilterCB);
  IupSetAttribute(SobelFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* LogFilterItem = IupItem("Log", "image2LogFilter");
  IupSetFunction("image2LogFilter", (Icallback)_image1LogFilterCB);
  IupSetAttribute(LogFilterItem, "imageConfig", (char*) &Image2Config);

  Ihandle* imagem2menu = IupMenu(NoFilterItem,
	                             LuminanceItem,
								 IupSeparator(),
								 NothingFilterItem,
								 MeanFilterItem,
								 GaussianFilterItem,
								 MedianFilterItem,
								 ConservativeFilterItem,
								 IupSeparator(),
								 NothingEdgeItem,
								 SobelFilterItem,
								 LogFilterItem,
								 NULL);

  return IupSubmenu("Imagem2", imagem2menu);
}

Ihandle* Imagem3Submenu()
{
  Ihandle* NoFilterItem = IupItem("Original", "image3NoFilter");
  IupSetFunction("image3NoFilter", (Icallback)_image1NoFilterCB);
  IupSetAttribute(NoFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* LuminanceItem = IupItem("Luminacia", "image3Luminance");
  IupSetFunction("image3Luminance", (Icallback)_image1LuminanceCB);
  IupSetAttribute(LuminanceItem, "imageConfig", (char*) &Image3Config);

  Ihandle* NothingFilterItem = IupItem("Nothing", "image3NothingFilter");
  IupSetFunction("image3NothingFilter", (Icallback)_image1NothingFilterCB);
  IupSetAttribute(NothingFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* MeanFilterItem = IupItem("Filtro da Média", "image3MeanFilter");
  IupSetFunction("image3MeanFilter", (Icallback)_image1MeanFilterCB);
  IupSetAttribute(MeanFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* GaussianFilterItem = IupItem("Filtro Gaussiano", "image3GaussianFilter");
  IupSetFunction("image3GaussianFilter", (Icallback)_image1GaussianFilterCB);
  IupSetAttribute(GaussianFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* MedianFilterItem = IupItem("Filtro da Mediana", "image3MedianFilter");
  IupSetFunction("image3MedianFilter", (Icallback)_image1MedianFilterCB);
  IupSetAttribute(MedianFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* ConservativeFilterItem = IupItem("Filtro Conservativo", "image3ConservativeFilter");
  IupSetFunction("image3ConservativeFilter", (Icallback)_image1ConservativeFilterCB);
  IupSetAttribute(ConservativeFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* NothingEdgeItem = IupItem("Nothing", "image3EdgeFilter");
  IupSetFunction("image3EdgeFilter", (Icallback)_image1NothingEdgeCB);
  IupSetAttribute(NothingEdgeItem, "imageConfig", (char*) &Image3Config);

  Ihandle* SobelFilterItem = IupItem("Sobel", "image3SobelFilter");
  IupSetFunction("image3SobelFilter", (Icallback)_image1SobelFilterCB);
  IupSetAttribute(SobelFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* LogFilterItem = IupItem("Log", "image3LogFilter");
  IupSetFunction("image3LogFilter", (Icallback)_image1LogFilterCB);
  IupSetAttribute(LogFilterItem, "imageConfig", (char*) &Image3Config);

  Ihandle* imagem3menu = IupMenu(NoFilterItem,
	                             LuminanceItem,
								 IupSeparator(),
								 NothingFilterItem,
								 MeanFilterItem,
								 GaussianFilterItem,
								 MedianFilterItem,
								 ConservativeFilterItem,
								 IupSeparator(),
								 NothingEdgeItem,
								 SobelFilterItem,
								 LogFilterItem,
								 NULL);

  return IupSubmenu("Imagem3", imagem3menu);
}

Ihandle* Imagem4Submenu()
{
  Ihandle* NoFilterItem = IupItem("Original", "image4NoFilter");
  IupSetFunction("image4NoFilter", (Icallback)_image1NoFilterCB);
  IupSetAttribute(NoFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* LuminanceItem = IupItem("Luminacia", "image4Luminance");
  IupSetFunction("image4Luminance", (Icallback)_image1LuminanceCB);
  IupSetAttribute(LuminanceItem, "imageConfig", (char*) &Image4Config);

  Ihandle* NothingFilterItem = IupItem("Nothing", "image4NothingFilter");
  IupSetFunction("image4NothingFilter", (Icallback)_image1NothingFilterCB);
  IupSetAttribute(NothingFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* MeanFilterItem = IupItem("Filtro da Média", "image4MeanFilter");
  IupSetFunction("image4MeanFilter", (Icallback)_image1MeanFilterCB);
  IupSetAttribute(MeanFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* GaussianFilterItem = IupItem("Filtro Gaussiano", "image4GaussianFilter");
  IupSetFunction("image4GaussianFilter", (Icallback)_image1GaussianFilterCB);
  IupSetAttribute(GaussianFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* MedianFilterItem = IupItem("Filtro da Mediana", "image4MedianFilter");
  IupSetFunction("image4MedianFilter", (Icallback)_image1MedianFilterCB);
  IupSetAttribute(MedianFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* ConservativeFilterItem = IupItem("Filtro Conservativo", "image4ConservativeFilter");
  IupSetFunction("image4ConservativeFilter", (Icallback)_image1ConservativeFilterCB);
  IupSetAttribute(ConservativeFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* DiffFilterItem = IupItem("Diferença Entre Imagens 2 e 3", "image4DiffFilter");
  IupSetFunction("image4DiffFilter", (Icallback)_image1DiffFilterCB);
  IupSetAttribute(DiffFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* DiffNormFilterItem = IupItem("Diferença Normalizada Entre Imagens 2 e 3", "image4DiffNormFilter");
  IupSetFunction("image4DiffNormFilter", (Icallback)_image1DiffNormFilterCB);
  IupSetAttribute(DiffNormFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* NothingEdgeItem = IupItem("Nothing", "image4EdgeFilter");
  IupSetFunction("image4EdgeFilter", (Icallback)_image1NothingEdgeCB);
  IupSetAttribute(NothingEdgeItem, "imageConfig", (char*) &Image4Config);

  Ihandle* SobelFilterItem = IupItem("Sobel", "image4SobelFilter");
  IupSetFunction("image4SobelFilter", (Icallback)_image1SobelFilterCB);
  IupSetAttribute(SobelFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* LogFilterItem = IupItem("Log", "image4LogFilter");
  IupSetFunction("image4LogFilter", (Icallback)_image1LogFilterCB);
  IupSetAttribute(LogFilterItem, "imageConfig", (char*) &Image4Config);

  Ihandle* imagem4menu = IupMenu(NoFilterItem,
	                             LuminanceItem,
								 IupSeparator(),
								 NothingFilterItem,
								 MeanFilterItem,
								 GaussianFilterItem,
								 MedianFilterItem,
								 ConservativeFilterItem,
								 DiffFilterItem,
								 DiffNormFilterItem,
								 IupSeparator(),
								 NothingEdgeItem,
								 SobelFilterItem,
								 LogFilterItem,
								 NULL);

  return IupSubmenu("Imagem4", imagem4menu);
}

static int _exitCb(Ihandle* self)
{
  return myKey(self, 27, 1);
}

static int _show4imagesCB(Ihandle* self)
{
  show4Images = !show4Images;
  if (show4Images)
    IupSetAttribute(self, IUP_VALUE, IUP_ON);
  else
    IupSetAttribute(self, IUP_VALUE, IUP_OFF);
  return IUP_DEFAULT;
}

Ihandle* buildMenu()
{
  // File Menu
  Ihandle* exit_item = IupItem("Sair", "exit");
  IupSetFunction("exit", (Icallback) _exitCb);

  Ihandle* file_menu = IupMenu(exit_item, NULL);
  Ihandle* file_sub_menu = IupSubmenu("Arquivo", file_menu);

  // Options Menu
  Ihandle* fourImages_item = IupItem("Mostrar 4 Imagens", "show4images");
  IupSetFunction("show4images", (Icallback) _show4imagesCB);
  _show4imagesCB(fourImages_item);

  Ihandle* options_menu = IupMenu(fourImages_item,
	                              Imagem1Submenu(),
								  Imagem2Submenu(),
								  Imagem3Submenu(),
								  Imagem4Submenu(), 
								  NULL);
  Ihandle* options_sub_menu = IupSubmenu("Opções", options_menu);

  // Menu
  Ihandle* menu = IupMenu(file_sub_menu, options_sub_menu, NULL);

  return menu;
}

void initConfig()
{
  Image1Config.gData = NULL;
  Image2Config.gData = NULL;
  Image3Config.gData = NULL;
  Image4Config.gData = NULL;
  Image1Config.filter = 0;
  Image2Config.filter = 0;
  Image3Config.filter = MEAN_FILTER;
  Image4Config.filter = GAUSSIAN_FILTER;
  Image4Config.edgeDetectAlgorithm = LOG;
//  Image4Config.filter = DIFF;
//  Image4Config.filter = DIFF_NORMALIZED;
  Image1Config.luminance = 0;
  Image2Config.luminance = 1;
  Image3Config.luminance = 1;
  Image4Config.luminance = 1;
  Image1Config.gaussianSteps = 1;
  Image2Config.gaussianSteps = 1;
  Image3Config.gaussianSteps = 1;
  Image4Config.gaussianSteps = 1;
  Image1Config.cosFourthCorrection = 0;
  Image2Config.cosFourthCorrection = 0;
  Image3Config.cosFourthCorrection = 0;
  Image4Config.cosFourthCorrection = 0;
  Image1Config.sobelThreshold = 100;
  Image2Config.sobelThreshold = 100;
  Image3Config.sobelThreshold = 100;
  Image4Config.sobelThreshold = 100;
  Image1Config.logThreshold = 10;
  Image2Config.logThreshold = 10;
  Image3Config.logThreshold = 10;
  Image4Config.logThreshold = 20;
}

int main(int argc, char* argv[])
{
  IupOpen();
  iupmaskInit();
  IupGLCanvasOpen();
  initConfig();
  
  // Carrega Modelo de Detecção
  #ifdef MODELO_1  
  CarregaMeuModelo("mymodel.mdl");
  #else
  CarregaMeuModelo("mymodel2.mdl");
  #endif

  gCanvas = IupGLCanvas("myDisplay");
  IupSetAttribute(gCanvas, "RASTERSIZE", "640x480");
  IupSetAttribute(gCanvas, "BUFFER", "DOUBLE");
  IupSetAttribute(gCanvas, "KEYPRESS_CB", "myKey");

  Ihandle* menu = buildMenu();
  IupSetHandle("main_menu", menu);

  Ihandle* iup_dialog = IupDialog(gCanvas);
  IupSetAttribute(iup_dialog, "TITLE", "VideoCapture");
  IupSetAttribute(iup_dialog, IUP_MENU, "main_menu");

  IupMap(iup_dialog);
  IupSetAttribute(gCanvas, "RASTERSIZE", NULL);

  IupSetFunction("myDisplay", (Icallback)myDisplay);
  IupSetFunction("myKey", (Icallback)myKey);
  IupSetFunction(IUP_IDLE_ACTION, (Icallback)myIdle);

  IupGLMakeCurrent(gCanvas);

  // Carrega Modelo MD3
  LaraMd3Model = new CModelMD3();
  if (LaraMd3Model)
  {
	// Load the 3 body part meshes and their skin, textures and animation config files
	LaraMd3Model->LoadModel("LaraModel", "lara");
	// Load the gun and attach it to our character
	LaraMd3Model->LoadWeapon("LaraModel", "Railgun");

	// Set the standing animation for the torso
	LaraMd3Model->SetTorsoAnimation("TORSO_STAND");

	// Set the walking animation for the legs
//	LaraMd3Model->SetLegsAnimation("LEGS_WALK");
	LaraMd3Model->SetLegsAnimation("LEGS_IDLE");
  }
  myGlInit();

  myVideoCap = imVideoCaptureCreate();
  if (!myVideoCap)
  {
    IupMessage("Error!", "No Capture Device!\n");
    IupClose();
    return 0;
  }

  imVideoCaptureConnect(myVideoCap, 0);
  imVideoCaptureLive(myVideoCap, 1);

  imVideoCaptureShowDialog(myVideoCap, NULL, NULL);

  IupShow(iup_dialog);

  IupMainLoop();
  gl_printf::close();
  IupClose();

  return 1;
}
