// Please see the README file or the LEGAL NOTES-section in the manual before modifying, compiling or using 'xmrm'
//   Idea: Manfred Kopp
//   Programming: Gerhard Waldhör, Andreas Artmann

#include <tiffio.h>
#include <forms.h>
#include <stdlib.h>

#ifndef MIPS
  #include <sys/time.h>
#else
  #include <sys/types.h>
  #include <sys/system.h>
#endif

#include "const.h"
#include "morphvec.h"
#include "wavemorph.h"
#include "wave_rts.h"
#include "io.h"
#include "xmrm.h"
#include "init.h"
#include "areas.h"

#define REPLACE_ALL 3

#define SIMPLE_MORPH 1
#define AREA_MORPH 2
#define WARP 3
#define ANIMATE_DETAIL 4

#define FSEL_IMGS 0
#define FSEL_VECS 1
#define FSEL_PROJ 1
#define FSEL_ANIM 2

#define INTERVAL 1500

#define EMPTY "0"

struct project
{
  char filename_source[BUFSIZ];
  char filename_destination[BUFSIZ];
  char filename_vector[BUFSIZ];
  char filename_area_map[BUFSIZ];

  int morph_mode;
  int advanced;
  int border_vecs;
  int use_wavelets;

  int selected_wavelets[MAX_LEVELS];
  double wavelets[MAX_LEVELS];

  int akima_nr;
  double akima_points[AKIMA_MAX][2];

  double weight_a;
  double weight_b;
  double weight_p;

  int save_start;
  int save_step;
};

extern MyImageClass *MyImage, *cinema[MAX_PIC];
extern int max_x, max_y;
extern WindowClass *m_win,*s_win,*d_win;

extern Display *disp;
extern MorphVecClass *s_vec, *d_vec;//, *i_vec;
extern PictureClass *s_pic, *d_pic, *result_pic;
extern AreaClass *area;

extern FL_OBJECT *obj_s, *obj_d, *obj_vs, *obj_vd, *obj_m, *obj_a;
extern FD_MRM *fd_MRM;
extern FD_MORPH *fd_MORPH;  
extern FD_AREAS *fd_AREAS;  
extern FD_RESULT *fd_RESULT;
extern FD_CREDITS *fd_CREDITS;
extern FD_WAIT *fd_WAIT;
extern FD_SLID_CONTR *fd_SLID_CONTR;
extern FD_VEC_MENU *fd_VEC_MENU;

/* Class ControlClass: */
extern ControlClass control;

/* Constructor: */
ControlClass::ControlClass()
{
  int i;
 
  strcpy(filename_source, EMPTY);
  strcpy(filename_destination, EMPTY);
  strcpy(filename_vector, EMPTY);
  strcpy(filename_project, EMPTY);
  strcpy(filename_area_map, EMPTY);
  URL_manual = "http://www.cg.tuwien.ac.at/~xmrm/";
  URL_CG_Home = "http://www.cg.tuwien.ac.at/home/";
  URL_TU_Vienna = "http://www.tuwien.ac.at/";
  
  whatdraw = DRAW_NOTHING;
  edit_mode = EDIT_NEW;
  edit_change_perm = 1;
  flag_set_vector = VEC_NOSET;
  co_vector=CO_OK; vec_changed=0;
  strcpy(tif_name, EMPTY);
  save_step=1;
  save_start=0;
  override=0;
  stop=0;
  wait=0;
  delay=0.0;
  Abort=0;
  mpeg_play = FALSE;
  netscape = FALSE;
  wave_nr=WAVE_RTS;
  levels=0; select_level=1;
  for (i=0; i<MAX_LEVELS; i++)
  {
    b_bias_val[i]=0.5;
  }
  akima_nr=AKIMA_MIN;
  for (i=0; i<AKIMA_MIN; i++)
  {
    akima_P[i][0]=(double)1/(AKIMA_MIN-1)*i;
    akima_P[i][1]=(double)1/(AKIMA_MIN-1)*i;
  }
}

/* Method GetDraw: */

int ControlClass::GetDraw()
{
  return whatdraw;
}

/* Method SetDraw */
void ControlClass::SetDraw(int d)
{
  whatdraw = d;
}

/* Method SetCursor */
void ControlClass::SetCursor(int Active, Window win)
{
  if (edit_mode == EDIT_REPLACE)
  {
    fl_set_cursor_color(XC_hand2,FL_BLACK,FL_YELLOW);
    fl_set_cursor(win, XC_hand2);
  }  
  else
  if (edit_mode == EDIT_DELETE)
  {
    fl_set_cursor(win, XC_pirate);
  }  
  else
  {
    if (Active)
    {
      if (edit_mode==EDIT_LINE)
        fl_set_cursor_color(XC_arrow,FL_DODGERBLUE,FL_BLACK);  
      else      
        fl_set_cursor_color(XC_arrow,FL_GREEN,FL_BLACK);  
    
      fl_set_cursor(win, XC_arrow);
    }
    else 
    {
      fl_set_cursor_color(XC_X_cursor,FL_WHITE,FL_BLACK);      
      fl_set_cursor(win, XC_X_cursor);
    }
  }
}


/* PROCEDURES: */

void Add_Extension(char *name, const char *extension)
{
  char *sub;
  
  sub = name;
  
  // if length of filename > 4 extension may already be added (by user)
  if ( strlen(name) > 4 )
  {
    // move sub pointer to 4th-to-last character
    for (int i=0; i < (strlen(name)-4); i++)
      sub += sizeof(char);
    
    // add extension if necessary
    if ( strcmp(sub, extension) )
      strcat(name, extension);
  }
  // if length of filename <= 4 extension HAS to be added
  else
    strcat(name, extension);
}

void Hide_Oneliner(int timeoutID, void *not_used)
{
  fl_hide_oneliner();
}

void AtActivate_MRM(FL_FORM *form, void *not_used)
{
  fl_reset_cursor(form->window);
  fl_set_object_lcol(fd_MRM->BT_Load_Source, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Load_Dest, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Load_Vecs, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Save_Vecs, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Save_Vecs_as, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Del_Vecs, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Swap_Vecs, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_About, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Exit, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Load_Prj, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Save_Prj, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Save_Prj_as, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Load_Area, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Calculate, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Animate, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Filename, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Load_Anim, FL_BLACK);
  fl_set_object_lcol(fd_MRM->BT_Create_MPEG, FL_BLACK);
  fl_set_object_lcol(fd_VEC_MENU->BT_SetVec, FL_BLACK);
  fl_set_object_lcol(fd_VEC_MENU->BT_EditVec, FL_BLACK);
  fl_set_object_lcol(fd_VEC_MENU->BT_SetLines, FL_BLACK);
  fl_set_object_lcol(fd_VEC_MENU->BT_DeleteVec, FL_BLACK);
}

void AtDeactivate_MRM(FL_FORM *form, void *not_used)
{
  fl_set_cursor(form->window, XC_watch);
  fl_set_object_lcol(fd_MRM->BT_Load_Source, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Load_Dest, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Load_Vecs, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Save_Vecs, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Save_Vecs_as, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Del_Vecs, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Swap_Vecs, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_About, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Exit, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Load_Prj, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Save_Prj, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Save_Prj_as, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Load_Area, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Calculate, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Animate, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Filename, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Load_Anim, FL_INACTIVE);
  fl_set_object_lcol(fd_MRM->BT_Create_MPEG, FL_INACTIVE);
  fl_set_object_lcol(fd_VEC_MENU->BT_SetVec, FL_INACTIVE);
  fl_set_object_lcol(fd_VEC_MENU->BT_EditVec, FL_INACTIVE);
  fl_set_object_lcol(fd_VEC_MENU->BT_SetLines, FL_INACTIVE);
  fl_set_object_lcol(fd_VEC_MENU->BT_DeleteVec, FL_INACTIVE);
}

// returns:
//      0: success
//      1: io error
//      2: user cancel
//      3: mem init error
int ReadPicture(const char *filename, PictureClass *pic, int what_read)
{
  TIFF *tif;
  unsigned long *raster,*raster_dst;
  unsigned long buff,adr_h,adr_l;
  unsigned char *area_src,*area_dst;
  double x,y,dx,dy;
  int i,j,pic_x,pic_y;
  int tif_w,tif_h;

  if ( !filename )
  {
    fl_use_fselector(FSEL_IMGS);
    fl_refresh_fselector();
    if ( (filename = fl_show_fselector("Load Image","","*.tif*",".tif")) == NULL)
      return 2;
  }

  // Opening TIFF-File:
  if ( (tif = TIFFOpen(filename,"r"))==0 )
    return 1;

  // Getting TIFF-Image informations
  if (TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &tif_w) != 1 || TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&tif_h) != 1 )
  {
    TIFFClose(tif);
    return 1;
  }

  if (what_read >= 1) // Read source-picture / result-picture
  {
    // Init pic:  
    pic->SetPicSize(tif_w,tif_h); 
    if (pic->InitMem() != 0)
      return 3;
    raster = pic->GetPicPointer();

    // Reading TIFF-Image into memory:
    if ( (TIFFReadRGBAImage(tif,tif_w,tif_h,raster,0))==0 )
    {
      TIFFClose(tif);
      return 1;
    }
    TIFFClose(tif);

    if ( (what_read == 1) && ((tif_w != max_x) || (tif_h != max_y)) )
    {
      // MORPH-VECTOR FORM:      
      if (max_x!=0) fl_hide_form(fd_MORPH->MORPH);
      fl_set_form_maxsize(fd_MORPH->MORPH,SHOW_MAX*2,(tif_h*SHOW_MAX)/tif_w);
      //fl_set_form_minsize(fd_MORPH->MORPH,(tif_w % 100)*2 + 100,(tif_h % 100) + 100); // TODO: WOIDL
      fl_set_form_size(fd_MORPH->MORPH,SHOW_SIZE*2,(tif_h*SHOW_SIZE)/tif_w);
      fl_show_form(fd_MORPH->MORPH,FL_PLACE_ASPECT,FL_FULLBORDER,"");
      XMoveWindow(fl_get_display(), fd_MORPH->MORPH->window, 10, 600);
      fl_set_menu_item_mode(fd_MRM->MN_Windows, 2, FL_PUP_BOX+FL_PUP_CHECK);
      fl_call_object_callback(fd_VEC_MENU->BT_SetVec);      

      // VEC_MENU FORM:
      if (max_x==0)
      {
        fl_set_form_position(fd_VEC_MENU->VEC_MENU,-100,0);
        fl_show_form(fd_VEC_MENU->VEC_MENU,FL_PLACE_GEOMETRY,FL_FULLBORDER,"");
        XMoveWindow(fl_get_display(), fd_VEC_MENU->VEC_MENU->window, fd_MORPH->morph->w+20, 600);
        fl_call_object_callback(fd_VEC_MENU->BT_SetVec);
        fl_set_menu_item_mode(fd_MRM->MN_Windows, 3, FL_PUP_BOX + FL_PUP_CHECK);        
      }

      // RESULT FORM:
      if (max_x!=0)
        fl_hide_form(fd_RESULT->RESULT);
      fl_set_form_maxsize(fd_RESULT->RESULT,SHOW_MAX,(tif_h*SHOW_MAX)/tif_w);
//      fl_set_form_size(fd_RESULT->RESULT,SHOW_SIZE,(tif_h*SHOW_SIZE)/tif_w);
      fl_set_form_size(fd_RESULT->RESULT,tif_w,tif_h);
      fl_show_form(fd_RESULT->RESULT,FL_PLACE_ASPECT,FL_FULLBORDER,"");
//      XMoveWindow(fl_get_display(), fd_RESULT->RESULT->window, fd_MORPH->morph->w+20, 600);
      XMoveWindow(fl_get_display(), fd_RESULT->RESULT->window, 
                  fd_MORPH->MORPH->w+fd_VEC_MENU->vec_menu->w+30, 600);
      fl_set_menu_item_mode(fd_MRM->MN_Windows, 1, FL_PUP_BOX+FL_PUP_CHECK);


      // Resize Area-Map if necessary:
      if (area->GetPicPointer() != NULL)
      {
        area_dst=(unsigned char *)malloc(tif_w*tif_h*sizeof(unsigned char));
        area_src=area->GetPicPointer();
        
        BilinMapArea(area_src,area_dst,max_x,max_y, tif_w,tif_h);
        
        area->SetPicPointer(area_dst);
        free(area_src);
      }        

      // AREA FORM:
      if (fd_AREAS->AREAS->visible)
        fl_hide_form(fd_AREAS->AREAS);
      fl_set_form_maxsize(fd_AREAS->AREAS,SHOW_MAX,(tif_h*SHOW_MAX)/tif_w);
      fl_set_form_size(fd_AREAS->AREAS,SHOW_SIZE,(tif_h*SHOW_SIZE)/tif_w);
      if (! fd_AREAS->AREAS->visible)
        fl_show_form(fd_AREAS->AREAS,FL_PLACE_ASPECT,FL_FULLBORDER,"");
      if ( (max_x!=0) && (fl_get_button(fd_MRM->CB_Area_Morph)) )
      {
        XUnmapWindow(fl_get_display(), fd_AREAS->AREAS->window);
        fl_call_object_callback(fd_MRM->CB_Area_Morph);
      }

      if (result_pic->GetPicPointer()==NULL) // Only once (first time)
      {
        // Clear result_pic:
        result_pic->SetPicSize(tif_w,tif_h); 
        if (result_pic->InitMem() != 0)
          return 3; 
        raster = result_pic->GetPicPointer();
        for (i=0; i<(tif_h*tif_w); i++) raster[i]=0;
      }

      if (d_pic->GetPicPointer()==NULL) // Only once (first time)
      {
        // Clear d_pic:
        d_pic->SetPicSize(tif_w,tif_h); 
        if (d_pic->InitMem() != 0)
          return 3; 
        raster = d_pic->GetPicPointer();
        for (i=0; i<(tif_h*tif_w); i++) raster[i]=0;
      }
      else
      {
        // Map dest-pic to the size of src-pic
        raster_dst = (unsigned long *)malloc(tif_w*tif_h*sizeof(unsigned long));
        raster = d_pic->GetPicPointer();

/*
        dx = (double) max_x / tif_w; dy = (double) max_y / tif_h;
        y=0; adr_h=0;
        for (j=0; j<tif_h; j++) 
        {
          x=0;
          for (i=0; i<tif_w; i++)
          {
            adr_l = (unsigned long)y * max_x + (unsigned long)x;
            buff = raster[adr_l];
            raster_dst[adr_h]=buff;
        
            x+=dx; adr_h++;
          }
          y+=dy;
        }
*/
        BilinMapPicture(raster, raster_dst, max_x, max_y, tif_w, tif_h );
        // Get pointer to remapped image:
        d_pic->SetPicPointer(raster_dst); d_pic->SetPicSize(tif_w,tif_h);
        free(raster); // free old source data
      }
      // Fetch old pointer
      raster = pic->GetPicPointer();

      s_vec->NormVec();
      d_vec->NormVec();        

      // Set max_x and max_y to new pic-size:
      pic->GetPicSize(&max_x,&max_y);
      
      s_vec->DeNormVec();
      d_vec->DeNormVec();
    }
  }
  else // Read destination-picture:
  {
    // Get memory for buffer:
    raster = (unsigned long *)malloc(tif_w*tif_h*sizeof(unsigned long));
    
    // Reading TIFF-Image into memory:                    bit 24  16   8   0
    // Internal raster-format: one unsigned long per pixel: | a | b | g | r |
    if ( (TIFFReadRGBAImage(tif,tif_w,tif_h,raster,0))==0 )
    {
      TIFFClose(tif);
      return 1;
    }
    TIFFClose(tif);
    
    // Map dest-pic to the size of src-pic
    pic->SetPicSize(max_x,max_y); 
    if (pic->InitMem() != 0)
      return 3;
    raster_dst = pic->GetPicPointer();    

/*
    dx = (double) tif_w / max_x; dy = (double) tif_h / max_y; 
    
    y=0; adr_h=0;
    for (j=0; j<max_y; j++) 
    {
      x=0;
      for (i=0; i<max_x; i++)
      {
        adr_l = (unsigned long)y * tif_w + (unsigned long)x;
        buff = raster[adr_l];
        raster_dst[adr_h]=buff;
        
        x+=dx; adr_h++;
      }
      y+=dy;
    }
*/
    BilinMapPicture(raster, raster_dst, tif_w, tif_h, max_x,max_y);

    free(raster); // free old source data
    raster = pic->GetPicPointer(); // get new (remapped) data
  }

  // Reverse picture:
  pic->GetPicSize(&pic_x,&pic_y);  
  for (j=0; j<(pic_y/2); j++)
    for (i=0; i<pic_x; i++)
    {
      adr_h=(pic_y-1-j)*pic_x+i;
      adr_l=j*pic_x+i;
      buff = raster[adr_h]; raster[adr_h] = raster[adr_l]; raster[adr_l] = buff;
    }

  if ( what_read == 1 )
    strcpy( control.filename_source, filename );

  if ( what_read == 0 )
    strcpy( control.filename_destination, filename );

  return 0;
}

/* Save Picture */
void SavePicture(char *filename, int size_w, int size_h, unsigned long *pic, int pic_nr)
{
  TIFF *tif; 
  FILE *fp;
  char *savename;
  char *extension;
  int choice;

  if ( !(savename = (char *)malloc( (strlen(filename)+9)*sizeof(char) )) )
  {
    fl_show_alert("ERROR: SavePicture()","malloc() returned NULL !","Aborting !",0);
    control.Abort = 1;
    return;
  }
  
  strcpy(savename, filename);

  extension = strrchr(savename,'/');

  // prevent creation of filenames like 'anything.###.###.tif'
  int pic_num = 0;
  char number[] = ".000.tif";
  char *filename_only;

  if ( extension )
    filename_only = ++extension;
  else
    filename_only = savename;

  while ( !(extension = strstr(filename_only,number)) && pic_num<=999 )
  {
    pic_num++;

    number[1] = '0' + pic_num/100;
    number[2] = '0' + (pic_num%100)/10;
    number[3] = '0' + (pic_num%10);
  }

  if( !extension )
    if ( extension = strstr(filename_only,".tif") )
      ;
    else
      extension = strchr(filename_only,'\0');

  *extension++ = '.';
  *extension++ = '0' + pic_nr/100; pic_nr = pic_nr % 100;
  *extension++ = '0' + pic_nr/10;  pic_nr = pic_nr % 10;
  *extension++ = '0' + pic_nr;
  strcpy( extension, ".tif" );
  
  if ((fp = fopen (savename, "r")) != NULL)
  {
    fclose(fp);
    if ( control.replace <= 1 )
    {
      choice = fl_show_choice("WARNING:",savename,"already exists !",3,"REPLACE","ABORT","REPLACE ALL",3);
      switch(choice)
      {
        case 1: control.replace = 1; break;
        case 2: control.Abort = 1; return;
        case 3: control.replace = REPLACE_ALL; break;
        default:
          fl_show_alert("ERROR:","Unknown Error !","Aborting...",1);
          control.Abort = 1;
          return;
      }
    }
  }

  // Opening TIFF-File:
  if ( (tif = TIFFOpen(savename,"w"))==0 )
  {
    fl_show_alert("ERROR:","Unable to open TIFF File !","Aborting...",1);
    control.Abort = 1;
    return;
  }
  // Setting TIFF-Image informations
  TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,size_w);
  TIFFSetField(tif,TIFFTAG_IMAGELENGTH,size_h);
  TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8);
  TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,4);
  TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_LZW); // free for non-commercial use (so I read)
  TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
  TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_RGB);
  TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
  TIFFSetField(tif,TIFFTAG_RESOLUTIONUNIT,RESUNIT_INCH);
  TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,size_h);
  TIFFSetField(tif,TIFFTAG_XRESOLUTION,1200.0);
  TIFFSetField(tif,TIFFTAG_YRESOLUTION,1200.0);

  if(TIFFWriteEncodedStrip(tif,0,(char *)pic,size_w*size_h*4)==-1)
  {
    fl_show_alert("ERROR:","Unable to save TIFF File !","Aborting...",1);
    TIFFClose(tif);
    control.Abort = 1;
    return;
  }

  TIFFClose(tif);
  
  extension = NULL;
  filename_only = NULL;
  free(savename);
}

// returns:
//      0: success
//      1: error
int ReadAreaMap(const char *filename, AreaClass *load_area)
{
  TIFF *tif;
  unsigned long *raster;
  unsigned char *grey_raster;
  unsigned char buff;
  unsigned long col,adr,adr_h,adr_l;
  int i,j;
  int tif_w,tif_h;
  double x,y,dx,dy;

  if ( !filename )
  {
    fl_use_fselector(FSEL_IMGS);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Load Detail-Map","","*.tif*",".tif")) == NULL)
      return 1;
  }

  // Opening TIFF-File:
  if ( (tif = TIFFOpen(filename,"r"))==0 )
  {
    fl_show_alert("ERROR:","Unable to open Detail-map:",filename,1);
    return 1;
  }

  // Getting TIFF-Image informations
  if (TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &tif_w) != 1 ||
      TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&tif_h) != 1 )
  {
    fl_show_alert("ERROR:","Unable to get TIFFTAGs !","",1);
    TIFFClose(tif);
    return 1;
  }

  raster = (unsigned long *)malloc(tif_w*tif_h*sizeof(unsigned long));
  if ( !raster )
  {
    fl_show_alert("ERROR:","Unable to allocate memory","for Detail-map !",1);
    TIFFClose(tif);
    return 1;
  }
  
  // Reading TIFF-Image into memory:
  if ( (TIFFReadRGBAImage(tif,tif_w,tif_h,raster,0))==0 )
  {
    fl_show_alert("ERROR:","Unable to load Detail-map:",filename,1);
    TIFFClose(tif);
    return 1;
  }
  TIFFClose(tif);


  // Init pic:
  if (load_area->InitMem(max_x,max_y) != 0)
  {
    fl_show_alert("ERROR:","Unable to allocate memory","for Detail-map !",1);
    return 1;
  }
  
  grey_raster = load_area->GetPicPointer();

  // Transform raster-image to greyscale-area-map and rescale image:
  dx = (double)tif_w / max_x; dy = (double)tif_h / max_y;   

  y=0; adr_h=0;
  for (j=0; j<max_y; j++) 
  {
    x=0;
    for (i=0; i<max_x; i++)
    {
      adr_l = (unsigned long)y * tif_w + (unsigned long)x;
      col = raster[adr_l];
      col = ( (col & 0xff) + ((col & 0xff00) >> 8) + ((col & 0xff0000) >> 16) ) /3;      
      grey_raster[adr_h]=(unsigned char)col;
        
      x+=dx; adr_h++;
    }
    y+=dy;
  }
  free(raster); // free old source data

  // reverse area map:
  for (j=0; j<(max_y/2); j++)
    for (i=0; i<max_x; i++)
    {
      adr_h=(max_y-1-j)*max_x+i;
      adr_l=j*max_x+i;
      buff = grey_raster[adr_h]; grey_raster[adr_h] = grey_raster[adr_l]; grey_raster[adr_l] = buff;
    }



  strcpy( control.filename_area_map, filename );

  return 0;
}

// returns:
//      0: success
//      1: fopen() failed
//      2: read error
//      3: user cancel
//
int Load_Vectors(const char *filename)
{
  FILE *fp;
  int num_of_vecs,i,test;
  char vec_file_V12_id[BUFSIZ];
  double *xa,*ya,*xe,*ye;  
  int *con;

  if( !filename )
  {
    fl_use_fselector(FSEL_VECS);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Load Vector-File","","*.vec",".vec")) == NULL)
      return 3;
  }
  
  if ((fp = fopen(filename, "r")) == NULL)
    return 1;
  
  // maybe it´s an old vector file ?
  test = EOF;
  if ( fgets( vec_file_V12_id, strlen(VECTOR_FILE_V12_ID)+1, fp ) )
    if ( strcmp(vec_file_V12_id, VECTOR_FILE_V12_ID) )
    {
      rewind(fp);
      test=fscanf(fp,"%*s\n%d\n\n",&num_of_vecs);
    }
    else
      test=fscanf(fp,"\n%d\n\n",&num_of_vecs);

  if (test==EOF || test!=1) 
    return 2;
  
  for (i=0; i<num_of_vecs; i++)
  {
    s_vec->GetVecArray(&xa,&ya,&xe,&ye);    
    test=fscanf(fp,"%lf %lf %lf %lf  ",&xa[i],&ya[i],&xe[i],&ye[i]);
    if (test==EOF || test!=4) 
      return 2;
  
    d_vec->GetVecArray(&xa,&ya,&xe,&ye);    
    test=fscanf(fp,"%lf %lf %lf %lf\n",&xa[i],&ya[i],&xe[i],&ye[i]);
    if (test==EOF || test!=4) 
      return 2;

  }


  // load connection arrays:
  s_vec->GetConArray(&con);
  i=0; test=fscanf(fp,"\n%d ",&con[i]); 
  if (test!=EOF) //continue reading:
  {
    if (test !=1) return 2;  
    for (i=1; i<num_of_vecs; i++) 
    { 
      test=fscanf(fp,"%d ",&con[i]); 
      if (test==EOF || test !=1) return 2;
    }
  
    test=fscanf(fp,"\n"); if (test==EOF) return 2;
  
    d_vec->GetConArray(&con);
    for (i=0; i<num_of_vecs; i++) 
    { 
      test=fscanf(fp,"%d ",&con[i]); 
      if (test==EOF || test !=1) 
        return 2;
    }
  } 
  else
  {
    s_vec->GetConArray(&con);
    for (i=0; i<num_of_vecs; i++) con[i]=0;
    d_vec->GetConArray(&con);
    for (i=0; i<num_of_vecs; i++) con[i]=0;
  }

  s_vec->SetMaxVec(num_of_vecs);
  d_vec->SetMaxVec(num_of_vecs);
  
  s_vec->DeNormVec();
  d_vec->DeNormVec();        

//    if (control.GetActiveWin() == ACTIVE_DST) control.SwitchActiveWin();
  if (control.edit_mode == EDIT_REPLACE) control.edit_mode=(control.edit_mode+1)%2;

  fclose(fp);

  strcpy( control.filename_vector, filename );
    
  return 0;
}

// returns:
//    0: success
//    1: no or not enough vectors set | user cancel | out of mem
//    2: io error
//
int Save_Vectors(const char *filename, int Save_as)
{
  FILE *fp;
  int items,i;
  double *xa,*ya,*xe,*ye;
  int *con;
  char temp_fname[BUFSIZ];
  int timeoutID;
  FL_Coord mx, my;
  unsigned int keymask;
  
  // Check if saving is possible:
  if (s_vec->GetMaxVec() == 0)
  {
    fl_show_alert("INFORMATION:","No vectors set !","Set at least one vector-pair !",0);
    return 1;
  }
  
  if (s_vec->GetMaxVec() != d_vec->GetMaxVec())
  {
    fl_show_alert("INFORMATION:","Cannot save vectors !","Set missing vector(s) in the destination image !",0);
    return 1;
  }
  
  // if 'Save' call first time: filename is still empty --> enable 'Save_as'
  if (strcmp(filename, EMPTY)==0)
    Save_as = TRUE;

  if ( (strcmp(filename, EMPTY)==0) || Save_as )
  {
    fl_use_fselector(FSEL_VECS);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Save Vector-File","","*.vec","")) == NULL) 
      return 1;
  }

  strcpy(temp_fname, filename);
  Add_Extension(temp_fname, ".vec");

  while ( Save_as )
  {
    if( fp = fopen(temp_fname, "r") )
    {
      fclose(fp);
      switch (fl_show_choice("WARNING:",temp_fname,"already exists !",3,"REPLACE","CHANGE","ABORT",-1))
      {
        case 1:
          Save_as = FALSE;
          break;
        case 2:
          if ((filename = fl_show_fselector("Save Vector-File","","*.vec","")) == NULL)
            return 1;
          strcpy(temp_fname, filename);
          Add_Extension(temp_fname, ".vec");
          break;
        case 3:
          return 1;
          break;
      }
    }
    else
      Save_as = FALSE;
  }

  strcpy(control.filename_vector, temp_fname);

  if ((fp = fopen(control.filename_vector, "w")) == NULL)
  {
    fl_show_alert("ERROR:","Unable to save vector-file:",control.filename_vector,1);
    strcpy(control.filename_vector, EMPTY);
    return 2;
  }
  s_vec->NormVec();
  d_vec->NormVec();
  
  fprintf(fp,"%s\n", VECTOR_FILE_V20_ID);
  items = s_vec->GetMaxVec();
  fprintf(fp,"%d\n\n",items);

  for (i=0; i<items; i++)
  {
    s_vec->GetVecArray(&xa,&ya,&xe,&ye);    
    fprintf(fp,"%f %f %f %f  ",xa[i],ya[i],xe[i],ye[i]);
  
    d_vec->GetVecArray(&xa,&ya,&xe,&ye);    
    fprintf(fp,"%f %f %f %f\n",xa[i],ya[i],xe[i],ye[i]);
  }

  // save connection arrays:
  fprintf(fp,"\n");  
    s_vec->GetConArray(&con);      
  for (i=0; i<items; i++) fprintf(fp,"%d ",con[i]);

  fprintf(fp,"\n");
  d_vec->GetConArray(&con);    
  for (i=0; i<items; i++) fprintf(fp,"%d ",con[i]);

  fclose(fp);
  
  s_vec->DeNormVec();
  d_vec->DeNormVec();
  
  (void) fl_get_mouse(&mx, &my, &keymask);
  fl_show_oneliner("VECTORS SAVED !", mx, my-20);
  timeoutID = fl_add_timeout(INTERVAL, Hide_Oneliner, 0);

  return 0;
}

void Load_Project(const char *filename)
{
  FILE *fp;
  char directory[BUFSIZ];
  char *help;
  char format[BUFSIZ];
  int i;
  int wrong_value = FALSE;
  struct project proj;
  
  // 
  *directory = '\0';
  if ( filename )
    if ( help = strrchr( filename, '/') )
    {
      (void) strcpy( directory, filename );
      help = strrchr(directory, '/');
      *(++help) = '\0';
      help = NULL;
    }

  if( !filename )
  {
    fl_use_fselector(FSEL_PROJ);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Load Project","","*.prj",".prj")) == NULL)
      return;
    (void) strcpy( directory, (char *) fl_get_directory() );
    (void) strcat( directory, "/" );
  }
  
  if (control.vec_changed)
    if (fl_show_question("Vectors NOT saved !\n\nSave them ?",1))
      if (Save_Vectors(EMPTY, TRUE))
        return;
      else
        control.vec_changed=0;

  strcpy(control.filename_project, filename);

  if ((fp = fopen(control.filename_project,"r")) == NULL)
  {
    fl_show_alert("ERROR:","Cannot open project-file:", control.filename_project, 0);
    strcpy(control.filename_project, EMPTY);
    return;
  }
        
  sprintf(format, "%%%is", BUFSIZ-1);

  // needed to reset directory to its original form after string has been added
  i = strlen(directory);

  fscanf(fp, "%*s%*s");
  fscanf(fp, format, proj.filename_source);
  if ( strcmp(proj.filename_source, EMPTY) )
  {
    (void) strcpy( proj.filename_source, strcat(directory, proj.filename_source) );
    directory[i] = '\0';
  }
  
  fscanf(fp, "%*s");
  fscanf(fp, format, proj.filename_destination);
  if ( strcmp(proj.filename_destination, EMPTY) )
  {
    (void) strcpy( proj.filename_destination, strcat(directory, proj.filename_destination) );
    directory[i] = '\0';
  }
    
//  fscanf(fp, "%*s");
//  fscanf(fp, format, proj.filename_vector);

  fscanf(fp, "%*s");
  fscanf(fp, format, proj.filename_area_map);
  if ( strcmp(proj.filename_area_map, EMPTY) )
    (void) strcpy( proj.filename_area_map, strcat(directory, proj.filename_area_map) );
  
  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.morph_mode);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.border_vecs);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.use_wavelets);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.advanced);

  fscanf(fp, "%*s");
  if ( proj.advanced )
  {
    for( i=0; i < MAX_LEVELS; i++)
      fscanf(fp, "%d", &proj.selected_wavelets[i]);

    fscanf(fp, "%*s");
    for( i=0; i < MAX_LEVELS; i++)
      fscanf(fp, "%lf", &proj.wavelets[i]);
  }
  else
    fscanf(fp, "%lf", &proj.wavelets[0]);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.akima_nr);
  fscanf(fp, "%*s");
  for ( i=0; i < proj.akima_nr; i++)
    fscanf(fp, "%lf %lf", &proj.akima_points[i][0], &proj.akima_points[i][1]);

  fscanf(fp, "%*s",format);
  fscanf(fp, "%lf", &proj.weight_a);
  
  fscanf(fp, "%*s");
  fscanf(fp, "%lf", &proj.weight_b);

  fscanf(fp, "%*s");
  fscanf(fp, "%lf", &proj.weight_p);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.save_start);

  fscanf(fp, "%*s");
  fscanf(fp, "%d", &proj.save_step);

  fclose(fp);

  // Source Image
  switch (ReadPicture( proj.filename_source, s_pic, 1 ))
  {
    case 1:// io error
      fl_show_alert("ERROR:","Cannot load Source image:",proj.filename_source,1);
      return;
    case 3:// mem error
      fl_show_alert("ERROR:","Memory allocation for source image failed !","Aborting...",1);
      return;
  }
  fl_redraw_object(obj_s);
  control.SetDraw(DRAW_SRCVECTORS);
  fl_redraw_object(obj_vs);
  fl_redraw_object(obj_d);
  control.SetDraw(DRAW_DSTVECTORS);
  fl_redraw_object(obj_vd);
  fl_redraw_object(obj_m);
//  control.levels=Wave_Levels();

  // Destination image NOT necessary when warping !
  if ( strcmp(proj.filename_destination, EMPTY) )
  {
    switch(ReadPicture( proj.filename_destination, d_pic,0 ))
    {
    case 1:// io error
      if( !fl_show_question("ERROR: Cannot load Destination image !\n\nContinue loading Project ?",1) )
        return;
    case 3:// mem error
      fl_show_alert("ERROR:","Memory allocation for destination image failed !","Aborting...",1);
      return;
    }
    fl_redraw_object(obj_s);
    control.SetDraw(DRAW_SRCVECTORS);
    fl_redraw_object(obj_vs);
    fl_redraw_object(obj_d);
    control.SetDraw(DRAW_DSTVECTORS);
    fl_redraw_object(obj_vd);
  }

  // Load Area map if name not EMPTY
  if ( strcmp(proj.filename_area_map, EMPTY) )
    if (ReadAreaMap(proj.filename_area_map, area)==0)
    {
      fl_set_button(fd_MRM->CB_Area_Morph,1);
      fl_call_object_callback(fd_MRM->CB_Area_Morph);
    }

  // Load vector file - ignore error - user has probably separate vec-file
  strcpy(proj.filename_vector, control.filename_project);
  strcat(proj.filename_vector, ".vec");
  switch ( Load_Vectors(proj.filename_vector) )
  {
    case 0:
      control.vec_changed=0;
      strcpy(control.filename_vector,EMPTY);
      fl_redraw_object(obj_s); fl_redraw_object(obj_d);
      control.SetDraw(DRAW_SRCVECTORS);
      fl_redraw_object(obj_vs);
      control.SetDraw(DRAW_DSTVECTORS);    
      fl_redraw_object(obj_vd);
      break;
    case 1:
      strcpy(control.filename_vector,EMPTY);
      if ( !fl_show_question("WARNING: Cannot open vector-file !\n\nContinue loading Project ?",1) )
        return;
      break;
    case 2:
      strcpy(control.filename_vector,EMPTY);
      if( !fl_show_question("WARNING: Vector file corrupt !\n\nContinue loading Project ?",1) )
        return;
      break;
  }
    
  //Wavelet-Level-Values
  if ( proj.advanced)
  {
    for ( i = 0; i < MAX_LEVELS; i++ )
    {
      if ( proj.wavelets[i] < SL_WAVE_MIN || proj.wavelets[i] > SL_WAVE_MAX )
      {
        wrong_value = TRUE;
        control.b_bias_val[i] = SL_WAVE_MIN;
      }
      else
        control.b_bias_val[i] = proj.wavelets[i];
      fl_set_button(fd_MRM->BT_Level[i],proj.selected_wavelets[i] ? 1:0);
    }

    fl_set_counter_value(fd_MRM->CT_Level_Select,1);
    fl_set_button(fd_MRM->CB_Advanced_Mode,1);
    fl_call_object_callback(fd_MRM->CB_Advanced_Mode);
  }
  else
  {
    if ( proj.wavelets[0] < SL_WAVE_MIN || proj.wavelets[0] > SL_WAVE_MAX )
    {
      wrong_value = TRUE;
      control.b_bias_val[0] = SL_WAVE_MIN;
    }
    else
      control.b_bias_val[0] = proj.wavelets[0];

    fl_set_counter_value(fd_MRM->CT_Level_Select,1);
    fl_set_button(fd_MRM->CB_Advanced_Mode,0);
    fl_call_object_callback(fd_MRM->CB_Advanced_Mode);
  }
  fl_set_slider_value(fd_MRM->SL_Level_Adjust,proj.wavelets[0]);
  if( wrong_value )
    fl_show_alert("WARNING:","Wavelet level(s) in project file out of bounds !","Minimum was set !",1);

  wrong_value = FALSE;
  // Akima-Values
  control.akima_nr = proj.akima_nr;
  for ( i = 0; i < control.akima_nr; i++)
  {
    if ( proj.akima_points[i][0] < 0.0 || proj.akima_points[i][0] > 1.0 ||\
         proj.akima_points[i][1] < 0.0 || proj.akima_points[i][1] > 1.0 )
      wrong_value = TRUE;
    control.akima_P[i] = proj.akima_points[i];
  }
  if( wrong_value || control.akima_nr < AKIMA_MIN || control.akima_nr > AKIMA_MAX )
  {
    fl_show_alert("WARNING:","AKIMA point(s) in project file out of bounds !","Default Points set !",1);
    control.akima_nr=AKIMA_MIN;
    for (i=0; i<AKIMA_MIN; i++)
    {
      control.akima_P[i][0]=(double)1/(AKIMA_MIN-1)*i;
      control.akima_P[i][1]=(double)1/(AKIMA_MIN-1)*i;
    }
  }

  //Warp-Slider Values A,B,P
  if ( proj.weight_a < WARP_A_MIN )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'a' below minimum !","Setting minimum...",0);
    control.warp_a = WARP_A_MIN;
  }
  else if ( proj.weight_a > WARP_A_MAX )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'a' exceeds maximum !","Setting maximum...",0);
    control.warp_a = WARP_A_MAX;
  }
  else
    control.warp_a = proj.weight_a;
  fl_set_slider_value(fd_SLID_CONTR->SL_Param_a, control.warp_a);

  if ( proj.weight_b < WARP_B_MIN )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'b' below minimum !","Setting minimum...",0);
    control.warp_b = WARP_B_MIN;
  }
  else if ( proj.weight_b > WARP_B_MAX )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'b' exceeds maximum !","Setting maximum...",0);
    control.warp_b = WARP_B_MAX;
  }
  else
    control.warp_b = proj.weight_b;
  fl_set_slider_value(fd_SLID_CONTR->SL_Param_b, control.warp_b);

  if ( proj.weight_p < WARP_P_MIN )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'p' below minimum !","Setting minimum...",0);
    control.warp_p = WARP_P_MIN;
  }
  else if ( proj.weight_p > WARP_P_MAX )
  {
    fl_show_alert("WARNING:","Value of Warp-Parameter 'p' exceeds maximum !","Setting maximum...",0);
    control.warp_p = WARP_P_MAX;
  }
  else
    control.warp_p = proj.weight_p;
  fl_set_slider_value(fd_SLID_CONTR->SL_Param_p, control.warp_p);
  
  //Use Wavelets
  switch(proj.use_wavelets)
  {
    case FALSE:
      fl_set_button(fd_MRM->CB_Use_Wavelets,0);
      fl_call_object_callback(fd_MRM->CB_Use_Wavelets);
      break;
    case TRUE:
      fl_set_button(fd_MRM->CB_Use_Wavelets,1);
      fl_call_object_callback(fd_MRM->CB_Use_Wavelets);
      break;
    default:
      fl_show_alert("WARNING:","Use_Wavelets_Checkbutton has wrong value !","Setting Use_Wavelets to TRUE...",0);
      fl_set_button(fd_MRM->CB_Use_Wavelets,1);
  }
  
  //Border Vectors
  switch(proj.border_vecs)
  {
    case FALSE:
      fl_set_button(fd_MRM->CB_Border_Vecs,0);
      break;
    case TRUE:
      fl_set_button(fd_MRM->CB_Border_Vecs,1);
      break;
    default:
      fl_show_alert("WARNING:","Border_Vectors_Checkbutton has wrong value !","Setting Border_Vectors to TRUE...",0);
      fl_set_button(fd_MRM->CB_Border_Vecs,1);
  }
  
  //Counters Save_Start and Save_Step
  if ( proj.save_start < CT_START_MIN )
  {
    fl_show_alert("WARNING:","Value of Save_Start_Counter below minimum !","Setting minimum...",0);
    control.save_start = (int)CT_START_MIN;
  }
  else if ( proj.save_start > CT_START_MAX )
  {
    fl_show_alert("WARNING:","Value of Save_Start_Counter exceeds maximum !","Setting maximum...",0);
    control.save_start = (int)CT_START_MAX;
  }
  else
    control.save_start = proj.save_start;
  fl_set_counter_value(fd_MRM->CT_Save_Start, (double)proj.save_start);

  if ( proj.save_step < CT_STEP_MIN )
  {
    fl_show_alert("WARNING:","Value of Save_Step_Counter below minimum !","Setting minimum...",0);
    control.save_step = (int)CT_STEP_MIN;
  }
  else if ( proj.save_step > CT_STEP_MAX )
  {
    fl_show_alert("WARNING:","Value of Save_Step_Counter exceeds maximum !","Setting maximum...",0);
    control.save_step = (int)CT_STEP_MAX;
  }
  else
    control.save_step = proj.save_step;
  fl_set_counter_value(fd_MRM->CT_Save_Step, (double)proj.save_step);
  
  //Morph Mode Checkbutton Group
  switch (proj.morph_mode)
  {
    case SIMPLE_MORPH:
      fl_set_button(fd_MRM->CB_Simple_Morph,1);
      fl_call_object_callback(fd_MRM->CB_Simple_Morph);
      break;
    case AREA_MORPH:
      fl_set_button(fd_MRM->CB_Area_Morph,1);
      fl_call_object_callback(fd_MRM->CB_Area_Morph);
      break;
    case WARP:
      fl_set_button(fd_MRM->CB_Warp,1);
      fl_call_object_callback(fd_MRM->CB_Warp);
      break;
    case ANIMATE_DETAIL:
      fl_set_button(fd_MRM->CB_Animate_Detail,1);
      fl_call_object_callback(fd_MRM->CB_Animate_Detail);
      break;
    default:
      fl_show_alert("WARNING:","Value of Morph-Mode out of bounds !","Setting Simple Morph...",0);
      fl_set_button(fd_MRM->CB_Simple_Morph,1);
      fl_call_object_callback(fd_MRM->CB_Simple_Morph);
  }

  fl_redraw_form(fd_MRM->MRM);
}

void Save_Project( const char *filename, int Save_as )
{
  FILE *fp;
  char *help;
  char temp_fname[BUFSIZ];
  int i, timeoutID;
  FL_Coord mx, my;
  unsigned int keymask;
  struct project proj;
  
  if ( strcmp(control.filename_source, EMPTY)==0 )
  {
    fl_show_alert("ERROR:","Load a SOURCE image first !","",0);
    return;
  }

  // if 'Save' call first time: filename is still empty --> enable 'Save_as'
  if (strcmp(filename, EMPTY)==0)
    Save_as = TRUE;

  if ( (strcmp(filename, EMPTY)==0) || Save_as )
  {
    fl_use_fselector(FSEL_PROJ);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Save Project","","*.prj","")) == NULL) 
      return;
  }

  strcpy(temp_fname, filename);
  Add_Extension(temp_fname, ".prj");

  while ( Save_as )
  {
    if( fp = fopen(temp_fname, "r") )
    {
      fclose(fp);
      switch (fl_show_choice("WARNING:",temp_fname,"already exists !",3,"REPLACE","CHANGE","ABORT",-1))
      {
        case 1:
          Save_as = FALSE;
          break;
        case 2:
          if ((filename = fl_show_fselector("Save Project","","*.prj","")) == NULL)
            return;
          strcpy(temp_fname, filename);
          Add_Extension(temp_fname, ".prj");
          break;
        case 3:
          return;
          break;
        default:
          fl_show_alert("ERROR:","Unknown Error !","Aborting...",1);
          return;
      }
    }
    else
      Save_as = FALSE;
  }

  strcpy(control.filename_project, temp_fname);

  strcpy(proj.filename_source, control.filename_source);
  strcpy(proj.filename_destination, control.filename_destination);
  strcpy(proj.filename_area_map, control.filename_area_map);
  
  // first, try to save vector file
  strcpy(proj.filename_vector, control.filename_project);
  strcat(proj.filename_vector, ".vec");
  if ( Save_Vectors(proj.filename_vector, FALSE) )
    return;

  if ( fl_get_button(fd_MRM->CB_Simple_Morph) ) proj.morph_mode = SIMPLE_MORPH;
  else if ( fl_get_button(fd_MRM->CB_Area_Morph) ) proj.morph_mode = AREA_MORPH;
  else if ( fl_get_button(fd_MRM->CB_Warp) ) proj.morph_mode = WARP;
  else proj.morph_mode = ANIMATE_DETAIL;

  proj.border_vecs = fl_get_button(fd_MRM->CB_Border_Vecs);
  proj.use_wavelets = fl_get_button(fd_MRM->CB_Use_Wavelets);
  proj.advanced = fl_get_button(fd_MRM->CB_Advanced_Mode);
  
  if ( proj.advanced )
    for ( i = 0; i < MAX_LEVELS; i++)
    {
      proj.selected_wavelets[i] = fl_get_button(fd_MRM->BT_Level[i]);
      proj.wavelets[i] = control.b_bias_val[i];
    }
  else
    proj.wavelets[0] = control.b_bias_val[0];

  proj.akima_nr = control.akima_nr;
  for ( i = 0; i < control.akima_nr; i++)
    proj.akima_points[i] = control.akima_P[i];

  proj.weight_a = control.warp_a;
  proj.weight_b = control.warp_b;
  proj.weight_p = control.warp_p;
  
  proj.save_start = (int)fl_get_counter_value(fd_MRM->CT_Save_Start);
  proj.save_step = (int)fl_get_counter_value(fd_MRM->CT_Save_Step);

  if ((fp = fopen(control.filename_project,"w")) == NULL)
  {
    fl_show_alert("ERROR:","Cannot open project-file:",control.filename_project,0);
    strcpy(control.filename_project, EMPTY);
    return;
  }

  fprintf(fp,"%s\n\n", PROJECT_FILE_V20_ID);
  help = strrchr(proj.filename_source, '/');
  fprintf(fp,"[Source_Image]\n%s\n\n", help ? ++help : proj.filename_source);
  help = NULL;
  help = strrchr(proj.filename_destination, '/');
  fprintf(fp,"[Destination_Image]\n%s\n\n", help ? ++help : proj.filename_destination);
//  help = NULL;
//  help = strrchr(proj.filename_vector, '/');
//  fprintf(fp,"[Vector_File]\n%s\n\n", help ? ++help : proj.filename_vector);
  help = NULL;
  help = strrchr(proj.filename_area_map, '/');
  fprintf(fp,"[Detail_Map]\n%s\n\n", help ? ++help : proj.filename_area_map);
  help = NULL;
  fprintf(fp,"[Morph_Mode]\n%i\n\n", proj.morph_mode);
  fprintf(fp,"[Border_Vectors]\n%i\n\n", proj.border_vecs);
  fprintf(fp,"[Use_Wavelets]\n%i\n\n", proj.use_wavelets);
  fprintf(fp,"[Advanced_Mode]\n%i\n", proj.advanced);
  if ( proj.advanced)
  {
    fprintf(fp,"\n[Selected_Levels]\n");
    for ( i = 0; i < MAX_LEVELS; i++)
      fprintf(fp,"%i\n", proj.selected_wavelets[i]);

    fprintf(fp,"\n[Level_Values]\n");
    for ( i = 0; i < MAX_LEVELS; i++)
      fprintf(fp,"%f\n", proj.wavelets[i]);
  }
  else
    fprintf(fp,"\n[Level_0]\n%f\n", proj.wavelets[0]);
  fprintf(fp,"\n[Number_of_AKIMA_Points]\n%i\n\n[Points]\n", proj.akima_nr);
  for ( i = 0; i < proj.akima_nr; i++)
    fprintf(fp,"%f %f\n", proj.akima_points[i][0], proj.akima_points[i][1]);
  fprintf(fp,"\n[Warp_Parameter_a]\n%f\n\n", proj.weight_a);
  fprintf(fp,"[Warp_Parameter_b]\n%f\n\n", proj.weight_b);
  fprintf(fp,"[Warp_Parameter_p]\n%f\n\n", proj.weight_p);
  fprintf(fp,"[Save_Start]\n%i\n\n", proj.save_start);
  fprintf(fp,"[Save_Step]\n%i", proj.save_step);

  fclose(fp);

  control.vec_changed = 0;
  strcpy(control.filename_vector, EMPTY);

  (void) fl_get_mouse(&mx, &my, &keymask);
  fl_show_oneliner("PROJECT SAVED !", mx, my-20);
  timeoutID = fl_add_timeout(INTERVAL, Hide_Oneliner, 0);
}

void Show_Wait(char *str)
{
  /* Show busy cursor: */
  fl_set_cursor(fd_MRM->MRM->window, XC_watch);
  fl_set_cursor(fd_MORPH->MORPH->window, XC_watch);
  fl_set_cursor(fd_RESULT->RESULT->window, XC_watch);

  /* Deactivate other forms: */
  fl_deactivate_form(fd_MRM->MRM);
  fl_deactivate_form(fd_MORPH->MORPH);
  fl_deactivate_form(fd_RESULT->RESULT);

  /* Show wait form: */
  control.wait=0;
  control.Abort=0;

  fl_call_object_callback(fd_WAIT->SL_Progress);
  fl_show_form(fd_WAIT->WAIT, FL_PLACE_CENTER,FL_FULLBORDER, str);
  XFlush(fl_get_display());

  if (fd_AREAS->AREAS->visible)
  {
    fl_set_cursor(fd_AREAS->AREAS->window, XC_watch);  
    fl_deactivate_form(fd_AREAS->AREAS);
  }
  
  if (fd_SLID_CONTR->SLID_CONTR->visible)  
  {
    fl_set_cursor(fd_SLID_CONTR->SLID_CONTR->window, XC_watch);
    fl_deactivate_form(fd_SLID_CONTR->SLID_CONTR);
  }
  
  if (fd_VEC_MENU->VEC_MENU->visible)
  {
    fl_set_cursor(fd_VEC_MENU->VEC_MENU->window,XC_watch);
    fl_deactivate_form(fd_VEC_MENU->VEC_MENU);
  }
}

void Hide_Wait()
{
  /* Show normal cursor: */
  fl_reset_cursor(fd_MRM->MRM->window);
  fl_reset_cursor(fd_MORPH->MORPH->window);
  fl_reset_cursor(fd_RESULT->RESULT->window);

  /* Activate other forms: */
  fl_activate_form(fd_MRM->MRM);
  fl_activate_form(fd_MORPH->MORPH);
  fl_activate_form(fd_RESULT->RESULT);

  /* Hide wait form: */
  fl_hide_form(fd_WAIT->WAIT);

  if (fd_AREAS->AREAS->visible)
  {
    fl_reset_cursor(fd_AREAS->AREAS->window);  
    fl_activate_form(fd_AREAS->AREAS);
  }

  if (fd_SLID_CONTR->SLID_CONTR->visible)  
  {  
    fl_reset_cursor(fd_SLID_CONTR->SLID_CONTR->window);
    fl_activate_form(fd_SLID_CONTR->SLID_CONTR);
  }

  if ( fd_VEC_MENU->VEC_MENU->visible)
  {
    fl_reset_cursor(fd_VEC_MENU->VEC_MENU->window);  
    fl_activate_form(fd_VEC_MENU->VEC_MENU);  
  }
}

void callback_Buttons (FL_OBJECT * ob,long arg)
{
  const char *filename;
  char *extension;
  char str[20];
  FILE *fp;
  TIFF *tif;
  int tif_h,tif_v=0;
  int i,pic_num,pic_count,width,height;
  char number[8];
  char cmdbuf[BUFSIZ];
  int val_Save_Start,val_Save_Step,val_NumPics;
  unsigned long *raster;
  int test;
    
  switch(arg)
  {  
  case 1: // Load_Source
    switch (ReadPicture( NULL, s_pic, 1 ))
    {
      case 1:// io error
        fl_show_alert("ERROR:","Cannot load Source image !","",1);
        return;
      case 2:// user abort
        return;
      case 3:// mem error
        fl_show_alert("ERROR:","Memory allocation for source image failed !","",1);
        return;
    }

    // Redraw Area pic:
    fl_redraw_object(obj_a);

    // Redraw Pics & Vecs
    fl_redraw_object(obj_s);
    control.SetDraw(DRAW_SRCVECTORS);
    fl_redraw_object(obj_vs);
    fl_redraw_object(obj_d);
    control.SetDraw(DRAW_DSTVECTORS);    
    fl_redraw_object(obj_vd);    
    fl_redraw_object(obj_m);
    break;

  case 2: // Load_Dest
    // Reading destination picture:
    if ((s_pic->GetPicPointer()) == NULL)
    {
      fl_show_alert("INFORMATION:","Load source image first !","",0);
      return;
    }

    switch (ReadPicture( NULL, d_pic, 0 ))
    {
      case 1:// io error
        fl_show_alert("ERROR:","Cannot load Destination image !","",1);
        return;
      case 2:// user abort
        return;
      case 3:// mem error
        fl_show_alert("ERROR:","Memory allocation for destination image failed !","",1);
        return;
    }

    fl_redraw_object(obj_s);
    control.SetDraw(DRAW_SRCVECTORS);
    fl_redraw_object(obj_vs);
    fl_redraw_object(obj_d);
    control.SetDraw(DRAW_DSTVECTORS);    
    fl_redraw_object(obj_vd);    
    break;

  case 3: // Load_Vecs
    // Reading Morph-Vectors:

    if ((s_pic->GetPicPointer()) == NULL)
    {
      fl_show_alert("INFORMATION:","Load source image first !","",0);
      return;
    }
    
    if (control.vec_changed)
    {
      if (fl_show_question("WARNING: Vectors not saved !\n\nSave them ?",1))
      {
        if (Save_Vectors(EMPTY, TRUE))
          return;
        else
          control.vec_changed=0;
      }
    }
    
    switch ( Load_Vectors(NULL) )
    {
      case 0:// OK
        control.vec_changed=0;
        break;
      case 1:// open failed
        strcpy(control.filename_vector,EMPTY);
        fl_show_alert("ERROR:","Cannot open vector-file !","Aborting...",1);
          return;
        break;
      case 2:// io error
        strcpy(control.filename_vector,EMPTY);
        fl_show_alert("ERROR:","Vector file corrupt !","Aborting...",1);
          return;
        break;
      case 3:// user cancel
        return;
    }

    fl_redraw_object(obj_s); fl_redraw_object(obj_d);
    control.SetDraw(DRAW_SRCVECTORS);
    fl_redraw_object(obj_vs);
    control.SetDraw(DRAW_DSTVECTORS);    
    fl_redraw_object(obj_vd);
    break;
  
  case 4: // Save_Vecs
    // Saving Morph-Vectors:
    if (Save_Vectors(control.filename_vector, FALSE)==0)
      control.vec_changed=0;
    break;

  case 5: // Program ends !

    if (control.vec_changed) // WORK: Alles, was irgendwie gesichert werd. muß, abfragen !!!!!!
    {
      if (fl_show_question("WARNING: Vectors not saved !\n\nSave them ?",1))
      {
        switch (Save_Vectors(EMPTY, TRUE))
        {
          case 1:
            return;
          case 2:
            if ( fl_show_question("QUESTION: Do you want to try again ?",2) )
              return;
            break;
        }
      }
    }

    /* free memory: */
    delete s_vec;
    delete d_vec;
//    delete i_vec;
  
    delete s_win;  
    delete d_win;  
    delete m_win;    
  
    delete s_pic;
    delete d_pic;
    delete result_pic;    
  
    delete MyImage;

    for (i=0; i<MAX_PIC; i++)
      delete cinema[i];

    delete area;

    /* !!! THE END !!!*/
    exit(0);
    break;

  case 6: // Load animation sequence:
    if (s_pic->GetPicPointer() == NULL)
    {
      fl_show_alert("INFORMATION","Load source image first !","",0);
      return;
    }

    fl_use_fselector(FSEL_ANIM);
    fl_refresh_fselector();
    if ((filename = fl_show_fselector("Animation Sequence","","*.tif*",".tif")) == NULL)
      return;

//    result_pic->SetPicSize(obj_m->w,obj_m->h); if (result_pic->InitMem() != 0) return -1;
    
    if( strlen(filename) == 0 )
    {
      fl_show_alert("ERROR:","Filename empty !","",1);
      return;
    }
    
    extension=strrchr(filename, '/');

//    if( *(++extension)=='\0' )
//    {
//      fl_show_alert("ERROR:","Filename mustn't end with '/' !","",1);
//      return;
//    }
//    extension--;
    
    i=0;
    strcpy(number,".000.");
    while ( !(extension = strstr(extension,number)) && i<=999 )
    {
      i++;
    
      number[1] = '0' + i/100;
      number[2] = '0' + (i%100)/10;
      number[3] = '0' + (i%10);
      extension=strrchr(filename, '/');
    }
    
    if (i==1000)
    {
      fl_show_alert("ERROR:","No Files Found !","Filename example: basename.001.tif",1);
      return;
    }
    pic_count=1;
    for( pic_num=i+1; pic_num<=MAX_PIC_NUM; pic_num++ )
    {
      if ( fp=fopen(filename, "r") )
      {
        fclose(fp);
      
        if ( strstr(extension,number))
          switch (ReadPicture( filename, result_pic, 2 ))
          {
            case 0:
              if (cinema[pic_count]->InitImage(obj_m->w,obj_m->h) != 0)
                return;
              cinema[pic_count]->MapPicture(obj_m,result_pic);
              cinema[pic_count]->ShowImage(obj_m,m_win->GetWin());
              pic_count++;
              break;
            case 1:// io error
              if (fl_show_choice("WARNING:","Invalid TIFF-File encountered !","",2,"CONTINUE","ABORT","",2)==2)
                return;
              break;
            case 3:// mem error
              fl_show_alert("ERROR:","Memory allocation for destination image failed !","Aborting",1);
              return;
          }
      }

      extension = strstr(filename,number);
      *(++extension) = '0' + pic_num/100;
      *(++extension) = '0' + (pic_num%100)/10;
      *(++extension) = '0' + (pic_num%10);
      extension = strrchr(filename, '/');
        
      number[1] = '0' + pic_num/100;
      number[2] = '0' + (pic_num%100)/10;
      number[3] = '0' + (pic_num%10);
    }

    control.HowManyPics = pic_count-1;
    fl_set_counter_value(fd_MRM->CT_Frames,control.HowManyPics);
    for (i=control.HowManyPics+1; i<MAX_PIC; i++) if (cinema[i]->InitImage(0,0) != 0) return;
    break;

  case 7: // Show Credits Form:
    fl_deactivate_form(fd_MRM->MRM);
    fl_deactivate_form(fd_MORPH->MORPH);
    fl_deactivate_form(fd_AREAS->AREAS);
    fl_deactivate_form(fd_SLID_CONTR->SLID_CONTR);
    fl_show_form(fd_CREDITS->CREDITS,FL_PLACE_CENTER,FL_FULLBORDER,PROGRAM_ID);
    break;

  case 8: // Hide Credits Form:
    fl_activate_form(fd_MRM->MRM);
    fl_activate_form(fd_MORPH->MORPH);
    fl_activate_form(fd_AREAS->AREAS);
    fl_activate_form(fd_SLID_CONTR->SLID_CONTR);
    fl_hide_form(fd_CREDITS->CREDITS);
    break;
    
  case 9: // Execute 'xmrm_mpeg'
/*AAA    const char *START_dir, *END_dir, *END_Frame;
    char *START_fname_only;
    int start_number, end_number;
    char filter[BUFSIZ];

    fl_use_fselector(FSEL_ANIM);
    fl_refresh_fselector();

    do
    {
      if ( filename = fl_show_fselector("Select starting frame...","","*.tif*",".tif") )
        START_dir = fl_get_directory();
      else
        return;

      START_fname_only = strrchr(filename,'/');
      START_fname_only++;

      pic_num = 0;
      number = ".000.";
      while ( !(extension = strstr(START_fname_only,number)) && pic_num<=MAX_PIC_NUM )
      {
        pic_num++;

        number[1] = '0' + pic_num/100;
        number[2] = '0' + (pic_num%100)/10;
        number[3] = '0' + (pic_num%10);
      }

      if( !extension )
        fl_show_alert("ERROR:","Invalid Filename !","Filename example: basename.001.tif(f)",1);
    }
    while ( !extension );

    start_number = pic_num;

    sprintf(cmdbuf, "xmrm_mpeg");
    strcat(cmdbuf, " -s ");
    strcat(cmdbuf, filename);

    (void) strcpy(filter, START_fname_only);
    if ( !(extension = strstr(filter,number)) )
    {
      fl_show_alert("ERROR:","UNEXPECTED ERROR !!!","Bailing out...",1);
      return;
    }
    *extension = '\0';
    (void )strcat(filter,"*");

    do
    {
      if ( !(END_Frame = (char *)fl_show_fselector("Select STOP-Frame...",START_dir,filter,".tif")) )
        return;
    
      END_dir = fl_get_directory();
      START_fname_only = strrchr(END_Frame,'/');
      START_fname_only++;
    
      if ( strcmp(END_dir, START_dir) )
        fl_show_alert("ERROR:","START and STOP-Frames must be in SAME directory !","",1);
      else
      {
        pic_num = 0;
        number = ".000.";
        while ( !(extension = strstr(START_fname_only,number)) && (pic_num <= MAX_PIC_NUM) )
        {
          pic_num++;

          number[1] = '0' + pic_num/100;
          number[2] = '0' + (pic_num%100)/10;
          number[3] = '0' + (pic_num%10);
        }
  
        end_number = pic_num;  
      
        if ( start_number >= end_number )
          fl_show_alert("ERROR:","START-Frame number must be LOWER","than STOP-Frame number !",1);
        else 
          if( !extension )
            fl_show_alert("ERROR:","Invalid Filename !","Filename example: basename.001.tif(f)",1);
      }
    }
    while( !extension || strcmp(START_dir, END_dir) || (start_number >= end_number) );

    strcat(cmdbuf, " -e ");
    strcat(cmdbuf, END_Frame);

    // Create MPEG-Cycle ?
    if ( fl_get_button(fd_MRM->CB_MPEG_Cycle) )
      (void) strcat(cmdbuf," -c");

    // MPEG-Player present ?
    if ( control.mpeg_play )
      (void) strcat(cmdbuf," -m");

    (void) strcat(cmdbuf," &");
*/
    i = system("xmrm_mpeg &");
//    printf("%i\n",i);

    if( i==-1 || i==127 )
      fl_show_alert("ERROR:","Execution of 'xmrm_mpeg' FAILED !","",1);

    break;

  case 10:// Delete all vectors
    if (control.vec_changed)
    {
      if (fl_show_question("WARNING: Vectors not saved !\n\nSave them ?",1))
      {
        if (Save_Vectors(EMPTY, TRUE))
          return;
      }
    }
    
    strcpy(control.filename_vector, EMPTY);
    
    control.vec_changed=0;
    s_vec->SetMaxVec(0); d_vec->SetMaxVec(0);
    fl_redraw_object(obj_s); fl_redraw_object(obj_d); 
    break;

  case 11:// Swap vectors
    if (s_pic->GetPicPointer() == NULL)
    { fl_show_alert("INFORMATION:","Cannot swap !","Load source image first !",0);
      return; }
    if ((d_pic->GetPicPointer() == NULL) && (control.Morph != 0))
    { fl_show_alert("INFORMATION:","Cannot swap !","Load destination image first !",0);
      return; }
    if (s_vec->GetMaxVec() == 0)
    { fl_show_alert("INFORMATION:","Cannot swap !","No source vector(s) defined !",0);
      return; }
    if (d_vec->GetMaxVec() == 0)
    { fl_show_alert("INFORMATION:","Cannot swap !","No destination vector(s) defined !",0);
      return; }
    if (s_vec->GetMaxVec() != d_vec->GetMaxVec())
    { fl_show_alert("INFORMATION:","Cannot swap !","Define missing destination vectors !",0);
      return; }
    MorphVecClass *swap_vec;
    PictureClass *swap_pic;
    swap_vec=s_vec; s_vec=d_vec; d_vec=swap_vec;
    swap_pic=s_pic; s_pic=d_pic; d_pic=swap_pic;
    fl_redraw_object(obj_s); fl_redraw_object(obj_s);
    control.SetDraw(DRAW_SRCVECTORS); fl_redraw_object(obj_vs);
    fl_redraw_object(obj_d); fl_redraw_object(obj_d);
    control.SetDraw(DRAW_DSTVECTORS); fl_redraw_object(obj_vd);
    break;

    if (s_pic->GetPicPointer() == NULL)
    { fl_show_alert("INFORMATION:","Cannot swap !","Load source image first !",0);
      return; }
    if ((d_pic->GetPicPointer() == NULL) && (control.Morph != 0))
    { fl_show_alert("INFORMATION:","Cannot swap !","Load destination image first !",0);
      return; }
    if (s_vec->GetMaxVec() == 0)
    { fl_show_alert("INFORMATION:","Cannot swap !","No source vector(s) defined !",0);
      return; }
    if (d_vec->GetMaxVec() == 0)
    { fl_show_alert("INFORMATION:","Cannot swap !","No destination vector(s) defined !",0);
      return; }
    
    swap_pic=s_pic; s_pic=d_pic; d_pic=swap_pic;
    // TODO WOIDL: geht noch nicht:
    char swap_name[BUFSIZ];
    strncpy(swap_name,control.filename_source,BUFSIZ); 
    strncpy(control.filename_source,control.filename_destination,BUFSIZ); 
    strncpy(control.filename_destination,swap_name,BUFSIZ);
    
    fl_redraw_object(obj_s); fl_redraw_object(obj_s);
    control.SetDraw(DRAW_SRCVECTORS); fl_redraw_object(obj_vs);
    fl_redraw_object(obj_d); fl_redraw_object(obj_d);
    control.SetDraw(DRAW_DSTVECTORS); fl_redraw_object(obj_vd);
    break;

  case 12:// Calculate
    control.replace = 0;

    // First, check if number in saved filenames will not exceed 999
    if (fl_get_button(fd_MRM->CB_Save_Calculation))
    {
      val_Save_Step = (int) fl_get_counter_value(fd_MRM->CT_Save_Step);
      val_NumPics = (int) fl_get_counter_value(fd_MRM->CT_Frames);
      val_Save_Start = (int) fl_get_counter_value(fd_MRM->CT_Save_Start);
      if (val_Save_Step*val_NumPics+val_Save_Start > 999)
      {
        fl_show_alert("INFORMATION:","Numbers in saved files will exceed 999 !","Lower Frame-Number or Stepsize !",0);
        return;
      }
    }

    if (s_pic->GetPicPointer() == NULL)
    {
      fl_show_alert("INFORMATION:","Cannot calculate !","Load Source image first",0);
      return;
    }

    // Wenn Wavelet(), dann ab hier wegkommentieren !
    
    if ((d_pic->GetPicPointer() == NULL) && (control.Morph != 0))
    {
      fl_show_alert("INFORMATION","Cannot calculate !","Load Destination image first !",0);
      return;
    }
    
    if ( (control.Morph == MORPH_AREA) && (area->GetPicPointer() == NULL) )
    {
      fl_show_alert("INFORMATION:","Cannot calculate !","Load Detail-map first",0);
      return;
    }
          
    if (s_vec->GetMaxVec() == 0)
    {
      fl_show_alert("INFORMATION:","Cannot calculate !","No vectors defined !",0);
      return;
    }
    if (s_vec->GetMaxVec() != d_vec->GetMaxVec())
    {
      fl_show_alert("INFORMATION:","Cannot calculate !","Set missing vector(s) in the destination image !",0);
      return;
    }
    if ((strcmp(control.tif_name, EMPTY)==0) && (fl_get_button(fd_MRM->CB_Save_Calculation)))
    {
      fl_show_alert("INFORMATION:","Choose a filename first","if you want to save the frames !",0);
      return;
    }
    if ( (cinema[1]->GetImage() != NULL) && (! fl_get_button(fd_MRM->CB_Save_Calculation)) )
    {
      if (!fl_show_question("WARNING: Calculation will destroy animation sequence !\n\nContinue ?",1)) return;
    }

    strcpy(str,"CALCULATING");
    Show_Wait(str);

    if (control.AnimateOrShow)
    {
      if (!fl_get_button(fd_MRM->CB_Save_Calculation))
      {
        // Delete old images:
        for (i=control.HowManyPics+1; i<MAX_PIC; i++)
          if (cinema[i]->InitImage(0,0) != 0) return;

        // Allocate memory for new images:
        for (i=1; i<=control.HowManyPics; i++)
          if (cinema[i]->InitImage(obj_m->w,obj_m->h) != 0) return;
      }

      // Calculate new picture sequence:
      if (control.Morph == MORPH_WAVE)
      {
        if (control.wave_nr==WAVE_RTS)
          Interpol_Wave_RTS(control.HowManyPics,1,control.HowManyPics,obj_m);
        else
          Interpol_Wave(control.HowManyPics,1,control.HowManyPics,obj_m);
      }
      else
      {
        if (control.wave_nr==WAVE_RTS)      
          Interpol_Morph_RTS(control.HowManyPics,1,control.HowManyPics,obj_m);
        else
          Interpol_Morph(control.HowManyPics,1,control.HowManyPics,obj_m);        
      }
    }
    else
    {
      if (!fl_get_button(fd_MRM->CB_Save_Calculation))
      {
        // Delete old images:
        for (i=2; i<MAX_PIC; i++)
          if (cinema[i]->InitImage(0,0) != 0) return;
        
        // Allocate memory for new image:
        if (cinema[1]->InitImage(obj_m->w,obj_m->h) != 0) return;
      }

      // Calculate one picture:        
      if (control.Morph == MORPH_WAVE)
      {
        if (control.wave_nr==WAVE_RTS)            
          Interpol_Wave_RTS(control.HowManyPics,control.WhatPic,control.WhatPic,obj_m);
        else
          Interpol_Wave(control.HowManyPics,control.WhatPic,control.WhatPic,obj_m);
      }
      else
      {
        if (control.wave_nr==WAVE_RTS)                  
          Interpol_Morph_RTS(control.HowManyPics,control.WhatPic,control.WhatPic,obj_m);
        else
          Interpol_Morph(control.HowManyPics,control.WhatPic,control.WhatPic,obj_m);          
      }
    }
    Hide_Wait();

//    Interpol_Morph(1,1,1,obj_m); // Nur für Wavelet()
    break;

  case 13:// Animation sequence
    static struct timeval start,current;
    double time_diff;

    if (cinema[1]->GetImage() == NULL)
    {
      fl_show_alert("INFORMATION:","No animation sequence !","",0);
      break;
    }
    else
    {
      width=cinema[1]->image_x; height=cinema[1]->image_y;
      
      // Look if CINEMA window has wrong size:
      if ((obj_m->w != width) && (obj_m->h != height))
      {
        fl_set_form_size(fd_RESULT->RESULT,width,height);
        fl_check_forms();
        
        sprintf(str,"%d x %d",width,height);
        fl_set_form_title(fd_RESULT->RESULT,str);
      }
    }
      

    for (i=1; i<=control.HowManyPics; i++)
      if (cinema[i]->GetImage() != NULL)
      {
        gettimeofday(&start,(struct timezone *)NULL);
        cinema[i]->ShowImage(obj_m,m_win->GetWin());
        do
        {
          gettimeofday(&current,(struct timezone *)NULL);
          time_diff = (double)(current.tv_sec - start.tv_sec) + (double)(current.tv_usec-start.tv_usec)/1000000.0;
        }
        while (time_diff < control.delay);
      }
    if (control.Cycle)
    {
      for (i=control.HowManyPics; i>=1; i--)
        if (cinema[i]->GetImage() != NULL)
        {
          gettimeofday(&start,(struct timezone *)NULL);
          cinema[i]->ShowImage(obj_m,m_win->GetWin());
          do
          {
            gettimeofday(&current,(struct timezone *)NULL);
            time_diff = (double)(current.tv_sec - start.tv_sec) + (double)(current.tv_usec-start.tv_usec)/1000000.0;
          }
          while (time_diff < control.delay);
        }
    }
    break;

  case 14:// Choose filename to save pics
    control.replace = 0;

    if ( (fl_get_button(fd_MRM->CB_Save_Animation)) && (cinema[1]->GetImage()==NULL) )
    {
      // Look if there are images in cinema
      fl_show_alert("INFORMATION:","No animation sequence !","",0);
      break;
    }

    fl_use_fselector(FSEL_ANIM);
    fl_refresh_fselector();
    if ( filename=fl_show_fselector("Enter filename","","*.tif*",".tif") )
    {
      if( strlen(filename) == 0 )
      {
        fl_show_alert("ERROR:","Filename empty !","",1);
        return;
      }
        
//      if( strlen(filename) > (BUFSIZ-1) )
//      {
//        fl_show_alert("ERROR:","Path+Filename too long !","",1);
//        return;
//      }

//      ptr=strrchr(filename, '/');
//      if( *(++ptr)=='\0' )
//      {
//        fl_show_alert("ERROR:","Filename mustn't end with '/' !","",1);
//        return;
//      }

      strcpy(control.tif_name, filename);
      
      if (fl_get_button(fd_MRM->CB_Save_Animation))
      {
        // Calculate number of images
        pic_num=0; while (cinema[pic_num+1]->GetImage() != NULL) pic_num++;

        strcpy(str,"SAVE PICS");
        Show_Wait(str);
        
        for (i=1; i<=pic_num; i++)
        {
          if (!control.Abort)
          {
            if ( (raster = cinema[i]->RemapPicture(obj_m)) == NULL) break;
        
            SavePicture(control.tif_name, cinema[i]->image_x, cinema[i]->image_y, raster,
                        (i-1)*control.save_step+control.save_start);
                      
            /* Set wait slider: */
            control.wait=(double)i/pic_num;
            fl_call_object_callback(fd_WAIT->SL_Progress);
            fl_redraw_form(fd_WAIT->WAIT);
            fl_check_forms();
          }
        }
        Hide_Wait();
      }
    }
    break;

  case 15:// Save_Vecs_as
    if (Save_Vectors(EMPTY, TRUE)==0)
      control.vec_changed=0;
    break;
    
//case 16-25: See default-branch !!!
    
  case 28:// OpenProject:
    Load_Project(NULL);
    break;
    
  case 29:// Save_Project
    Save_Project( control.filename_project, FALSE );
    break;
    
  case 30:// Save Project as...:
    Save_Project( EMPTY, TRUE );
    break;

  case 31:// Load Area Map:
    if (s_pic->GetPicPointer() == NULL)
    {
      fl_show_alert("INFORMATION:","Load source image first","",0);
      return;
    }
  
    if ( ReadAreaMap(NULL, area)==0 )
    {
      fl_set_button(fd_MRM->CB_Area_Morph,1);
      fl_call_object_callback(fd_MRM->CB_Area_Morph);
    }
    else
      return;
    
//    fl_redraw_object(obj_a);
    break;
        
  case 32:// Hide Warp-Slider window //todo
//    fl_set_button(fd_MRM->CB_Warp_Parameters,0);
//    fl_call_object_callback(fd_MRM->CB_Warp_Parameters);
      fl_hide_form(fd_SLID_CONTR->SLID_CONTR);
      fl_set_menu_item_mode(fd_MRM->MN_Windows, 5, FL_PUP_BOX);
    break;

  case 33:// BT_SetVec:
    if ( (control.edit_change_perm == 0) && (control.edit_mode == EDIT_LINE) )
    {
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vs);
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vd);      
    }

    if (control.edit_change_perm)
    {
      fl_wintitle(fd_MORPH->MORPH->window,"SET VECTOR");
      fl_set_button(fd_VEC_MENU->BT_SetVec,1);
      fl_set_button(fd_VEC_MENU->BT_EditVec,0);
      fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
      fl_set_button(fd_VEC_MENU->BT_SetLines,0);

      control.edit_mode=EDIT_REPLACE;
      control.flag_set_vector=VEC_NOSEARCH; fl_redraw_object(obj_vs);
      control.flag_set_vector=VEC_NOSEARCH; fl_redraw_object(obj_vd);      

      control.edit_mode=EDIT_NEW;
      control.flag_set_vector=VEC_NOSET;
    }
    break;
    
  case 34:// BT_EditVec:
    if ( (control.edit_change_perm == 0) && (control.edit_mode == EDIT_LINE) )
    {
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vs);
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vd);      
    }

    if (control.edit_change_perm)
    {
      fl_wintitle(fd_MORPH->MORPH->window,"EDIT VECTOR");
      fl_set_button(fd_VEC_MENU->BT_SetVec,0);
      fl_set_button(fd_VEC_MENU->BT_EditVec,1);
      fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
      fl_set_button(fd_VEC_MENU->BT_SetLines,0);
      control.edit_mode=EDIT_REPLACE;

      control.flag_set_vector=VEC_NOSET;
    }
    break;

  case 35:// BT_DeleteVec:
    if ( (control.edit_change_perm == 0) && (control.edit_mode == EDIT_LINE) )
    {
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vs);
      control.flag_set_vector = VEC_CLEAR; fl_redraw_object(obj_vd);      
    }

    if (control.edit_change_perm)
    {
      fl_wintitle(fd_MORPH->MORPH->window,"DELETE VECTOR");
      fl_set_button(fd_VEC_MENU->BT_SetVec,0);
      fl_set_button(fd_VEC_MENU->BT_EditVec,0);
      fl_set_button(fd_VEC_MENU->BT_DeleteVec,1);            
      fl_set_button(fd_VEC_MENU->BT_SetLines,0);
      control.edit_mode=EDIT_DELETE;

      control.flag_set_vector=VEC_NOSET;
    }
    break;

  case 36:// BT_SetLines:
    if (control.edit_change_perm)
    {
      fl_wintitle(fd_MORPH->MORPH->window,"SET LINE");
      fl_set_button(fd_VEC_MENU->BT_SetVec,0);
      fl_set_button(fd_VEC_MENU->BT_EditVec,0);
      fl_set_button(fd_VEC_MENU->BT_DeleteVec,0);            
      fl_set_button(fd_VEC_MENU->BT_SetLines,1);

      control.edit_mode=EDIT_REPLACE;
      control.flag_set_vector=VEC_NOSEARCH; fl_redraw_object(obj_vs);
      control.flag_set_vector=VEC_NOSEARCH; fl_redraw_object(obj_vd);      

      control.edit_mode=EDIT_LINE;
      control.flag_set_vector=VEC_NOSET;      
    }
    break;
  
  case 37:// BT_Drop:
    sprintf(cmdbuf,"netscape %s &", control.URL_CG_Home);
    test = system(cmdbuf);
    if ( test==-1 || test==127 )
    {
      fl_show_alert("ERROR:","Execution of Netscape failed !","",1);
    }
    break;

  case 38:// BT_TU_Logo:
    sprintf(cmdbuf,"netscape %s &", control.URL_TU_Vienna);
    test = system(cmdbuf);
    if ( test==-1 || test==127 )
    {
      fl_show_alert("ERROR:","Execution of Netscape failed !","",1);
    }
    break;
  
  default:
    if ( (arg-15 == 1) || (arg-15 == MAX_LEVELS) )
      fl_set_button(ob,1);
    else if (arg-15 == control.select_level)
    {
      i=(arg-15)-1; // printf("i=: %d\n",i);
      // Search for previous activated button:
      while (! fl_get_button(fd_MRM->BT_Level[i-1])) i--;
      //printf("New level selected: %d\n",i);
      
      fl_set_counter_value(fd_MRM->CT_Level_Select,i);
      control.select_level=i;
      fl_set_slider_value(fd_MRM->SL_Level_Adjust,control.b_bias_val[control.select_level-1]);
      
      fl_call_object_callback(fd_MRM->CT_Level_Select);
    }

    fl_call_object_callback(fd_MRM->Wave_Plot);
    fl_redraw_object(fd_MRM->Wave_Plot);
  }
}

void Hide_or_show_VEC_MENU_Win(int right_button_pressed)
{
  static int win_vecmenu_x, win_vecmenu_y;

  if ( !right_button_pressed && fl_get_menu_item_mode(fd_MRM->MN_Windows, 3)==(FL_PUP_BOX + FL_PUP_CHECK) )
  {
    XMapWindow(fl_get_display(), fd_VEC_MENU->VEC_MENU->window);
    XMoveWindow(fl_get_display(), fd_VEC_MENU->VEC_MENU->window, win_vecmenu_x, win_vecmenu_y);
    fl_set_menu_item_mode(fd_MRM->MN_Windows, 3, FL_PUP_BOX + FL_PUP_CHECK);        
  }
  else
  {
    fl_get_win_origin(fd_VEC_MENU->VEC_MENU->window, &win_vecmenu_x, &win_vecmenu_y);
    XUnmapWindow(fl_get_display(), fd_VEC_MENU->VEC_MENU->window);
    fl_set_menu_item_mode(fd_MRM->MN_Windows, 3, FL_PUP_BOX);
  }
}
    
void callback_Menus(FL_OBJECT *obj, long arg)
{
  static int mouse_x = 0;
  int mouse_y;
  unsigned int keymask;
  int item;
  static int win_result_x, win_result_y, win_morph_x, win_morph_y;
  static int win_areas_x, win_areas_y;
  char cmdbuf[BUFSIZ];
  int test;
    
  switch (arg)
  {
    // File-Menu
    case 0:
      item = fl_get_menu(obj);
      switch (item)
      {
        case 1://Load Project
          fl_call_object_callback(fd_MRM->BT_Load_Prj);
          break;
        case 2://Save Project
          fl_call_object_callback(fd_MRM->BT_Save_Prj);
//          Save_Project( control.filename_project, FALSE );
          break;
        case 3://Save Project as
          fl_call_object_callback(fd_MRM->BT_Save_Prj_as);
//          Save_Project( EMPTY, TRUE );
          break;
        case 4://Load Source
          fl_call_object_callback(fd_MRM->BT_Load_Source);
          break;
        case 5://Load Destination
          fl_call_object_callback(fd_MRM->BT_Load_Dest);
          break;
        case 6://Load Area Map
          fl_call_object_callback(fd_MRM->BT_Load_Area);
          break;
        case 7://Load Vectors
          fl_call_object_callback(fd_MRM->BT_Load_Vecs);
          break;
        case 8://Save Vectors
          fl_call_object_callback(fd_MRM->BT_Save_Vecs);
//          if (Save_Vectors(control.filename_vector, FALSE)==0)
//            control.vec_changed=0;
//          (void) Save_Vectors(control.filename_vector, FALSE);
          break;
        case 9://Save Vectors as
          fl_call_object_callback(fd_MRM->BT_Save_Vecs_as);
//          if (Save_Vectors(EMPTY, TRUE)==0)
//            control.vec_changed=0;
//          (void) Save_Vectors(EMPTY, TRUE);
          break;
        case 10://Exit
          fl_call_object_callback(fd_MRM->BT_Exit);
          break;
      }
      break;

    // Wavelet-Types-Menu  
//WOIDL+
    case 1:
      item = fl_get_menu(obj);
      if ( item>=1 && item<=12)
      {
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 1, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 2, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 3, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 4, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 5, FL_PUP_RADIO);        
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 6, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 7, FL_PUP_RADIO);
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 8, FL_PUP_RADIO);        
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 9, FL_PUP_RADIO);        
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 10, FL_PUP_RADIO);        
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 11, FL_PUP_RADIO);                                
        fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 12, FL_PUP_RADIO);                                        
      }
      switch (item)
      {
        case 1://Fast RTS-Transform
          control.wave_nr=100;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 1, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 2://Biorthogonal Spline Wavelets 1-3
          control.wave_nr=1;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 2, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 3://Biorthogonal Spline Wavelets 1-5
          control.wave_nr=2;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 3, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 4://Biorthogonal Spline Wavelets 3-3
          control.wave_nr=3;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 4, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 5://Biorthogonal Spline Wavelets 3-7
          control.wave_nr=4;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 5, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 6://Biorthogonal Spline Wavelets 2-2
          control.wave_nr=5;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 6, FL_PUP_RADIO + FL_PUP_CHECK);
          break;          
        case 7://Biorthogonal Spline Wavelets 2-4
          control.wave_nr=6;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 7, FL_PUP_RADIO + FL_PUP_CHECK);
          break;          
        case 8://Pseudocoiflets
          control.wave_nr=7;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 8, FL_PUP_RADIO + FL_PUP_CHECK);
          break;          
        case 9://Battle Lemarie
          control.wave_nr=8;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 9, FL_PUP_RADIO + FL_PUP_CHECK);
          break;          
        case 10://Haar
          control.wave_nr=0;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 10, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 11://Biorthogonal Spline Wavelets 3-1inv
          control.wave_nr=9;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 11, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
        case 12://Biorthogonal Spline Wavelets 3-7inv
          control.wave_nr=10;
          fl_set_menu_item_mode(fd_MRM->MN_Wavelet_Type, 12, FL_PUP_RADIO + FL_PUP_CHECK);
          break;
      }
     break;
//WOIDL-
    // Windows-Menu
    case 2:
      item = fl_get_menu(obj);
      switch (item)
      {
        case 1://Animation Win
          if ( fl_get_menu_item_mode(fd_MRM->MN_Windows, 1)==(FL_PUP_BOX + FL_PUP_CHECK) )
          {
            XMapWindow(fl_get_display(), fd_RESULT->RESULT->window);
            XMoveWindow(fl_get_display(), fd_RESULT->RESULT->window, win_result_x, win_result_y);
          }
          else
          {
            fl_get_win_origin(fd_RESULT->RESULT->window, &win_result_x, &win_result_y);
            XUnmapWindow(fl_get_display(), fd_RESULT->RESULT->window);
          }
          break;
        case 2://Source & Dest Win
          if ( fl_get_menu_item_mode(fd_MRM->MN_Windows, 2)==(FL_PUP_BOX + FL_PUP_CHECK) )
          {
            XMapWindow(fl_get_display(), fd_MORPH->MORPH->window);
            XMoveWindow(fl_get_display(), fd_MORPH->MORPH->window, win_morph_x, win_morph_y);
          }
          else
          {
            fl_get_win_origin(fd_MORPH->MORPH->window, &win_morph_x, &win_morph_y);
            XUnmapWindow(fl_get_display(), fd_MORPH->MORPH->window);
          }
          break;
        case 3://VEC_MENU Win:
          // extra function because used by prehandler in xmrm_main.cc too
          Hide_or_show_VEC_MENU_Win(0);
          break;
        case 4://Area Map Win
          if ( fl_get_button(fd_MRM->CB_Area_Morph) )
            if ( fl_get_menu_item_mode(fd_MRM->MN_Windows, 4)==(FL_PUP_BOX + FL_PUP_CHECK) )
            {
              XMapWindow(fl_get_display(), fd_AREAS->AREAS->window);
              XMoveWindow(fl_get_display(), fd_AREAS->AREAS->window, win_areas_x, win_areas_y);
            }
            else
            {
              fl_get_win_origin(fd_AREAS->AREAS->window, &win_areas_x, &win_areas_y);
              XUnmapWindow(fl_get_display(), fd_AREAS->AREAS->window);
            }
          break;
        case 5://Warp Parameters Win
            if (fl_form_is_visible(fd_SLID_CONTR->SLID_CONTR))
            {
              fl_hide_form(fd_SLID_CONTR->SLID_CONTR);
              fl_set_menu_item_mode(fd_MRM->MN_Windows, 5, FL_PUP_BOX);
            }
            else
            {
              if( !mouse_x )
              {
                (void) fl_get_mouse(&mouse_x, &mouse_y, &keymask);
                fl_set_form_position(fd_SLID_CONTR->SLID_CONTR, mouse_x+10, mouse_y+30);
              }
  
              fl_show_form(fd_SLID_CONTR->SLID_CONTR,FL_PLACE_GEOMETRY,FL_FULLBORDER,"WARP PARAMETERS");
              fl_set_menu_item_mode(fd_MRM->MN_Windows, 5, FL_PUP_BOX + FL_PUP_CHECK);
            }
          //fl_set_button(fd_MRM->CB_Warp_Parameters, fl_get_button(fd_MRM->CB_Warp_Parameters) ? 0:1);
          //fl_call_object_callback(fd_MRM->CB_Warp_Parameters);
          break;
      }
      break;

    // Help-Menu
    case 3:
      item = fl_get_menu(obj);
      switch (item)
      {
        case 1://Manual (Netscape)
          sprintf(cmdbuf,"netscape %s &", control.URL_manual);
          test = system(cmdbuf);
          if ( test==-1 || test==127 )
          {
            fl_show_alert("ERROR:","Execution of Netscape failed !","",1);
          }
          break;
        case 2://About
          fl_call_object_callback(fd_MRM->BT_About);
          break;
      }
      break;
  }
}
