#ifdef __GNUG__
#pragma implementation
#pragma interface
#endif

#include "AnimateGLCanvas.h"

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

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

using namespace std;

/*********************** LsysGLCanvas Class ********************
 ****(this also provides the user interface for the Lsystem ****/

BEGIN_EVENT_TABLE(AnimateGLCanvas, wxGLCanvas)
  EVT_SIZE(AnimateGLCanvas::OnSize)
  EVT_PAINT(AnimateGLCanvas::OnPaint)
  EVT_ERASE_BACKGROUND(AnimateGLCanvas::OnEraseBackground)
  EVT_KEY_DOWN(AnimateGLCanvas::OnKeyDown)
END_EVENT_TABLE()

AnimateGLCanvas::AnimateGLCanvas(wxWindow           *parent, 
				 const unsigned int *columns,
				 const unsigned int *rows,
				 vect3<GLfloat>     *background_colour,
				 vect3<GLfloat>     *line_colour,
				 const wxPoint&     pos, 
				 const wxSize&      size):
  wxGLCanvas(parent, -1, pos, size, 0 , ""),
  Cols(columns),
  Rows(rows)
{
  BGcolour = background_colour;
  LineColour = line_colour;
  Inited=false;
  Refresh(FALSE);
}

AnimateGLCanvas::~AnimateGLCanvas(void)
{

}

void AnimateGLCanvas::OnKeyDown( wxKeyEvent& event )
{
  //event.Skip();
  GetParent()->ProcessEvent(event); //work around bug in wxGLCanvas
}

void AnimateGLCanvas::OnPaint( wxPaintEvent& event )
{
  /* must always be here */
  wxPaintDC dc(this);
  #ifndef __WXMOTIF__
  if (!GetContext()) return;
#endif
  SetCurrent();
  
  if (Inited==false)
    {
      InitGL();
      Inited=true;
    };
}

void AnimateGLCanvas::OnSize(wxSizeEvent& event)
{
    int width, height;
    GetClientSize(& width, & height);
    
#ifndef __WXMOTIF__
    if (GetContext())
#endif
    {
        SetCurrent();
        glViewport(0, 0, width, height);
    };
}

void AnimateGLCanvas::OnEraseBackground(wxEraseEvent& event)
{
    /* Do nothing, to avoid flashing on MSW */
}

void AnimateGLCanvas::InitGL()
{
  glDisable(GL_LIGHTING);
  glShadeModel(GL_FLAT);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
}

void AnimateGLCanvas::ShowBreeding( unsigned int start_col, 
				    unsigned int start_row,
				    unsigned int target_col,
				    unsigned int target_row,
				    GLint pic_start_x, 
				    GLint pic_start_y, 
				    GLint pic_end_x, 
				    GLint pic_end_y, 
				    GLsizei pic_width, 
				    GLsizei pic_height, 
				    GLenum pic_format, 
				    GLenum pic_type, 
				    GLvoid *pixels, 
				    unsigned int frames)
{
  if ((start_row  >= *Rows) || 
      (target_row >= *Rows) || 
      ((*Rows)%2!=1)        ){
    //error
    return;
  };   

  if ((start_col  >= *Cols) || 
      (target_col >= *Cols) || 
      ((*Cols)%2!=1)        ){
    return;
  };    
  
#ifndef __WXMOTIF__
  if (!GetContext()) return;
#endif
  SetCurrent();

  /* Set up information */
  unsigned int i, bottom_of_selected, top_of_selected, right_of_selected, left_of_selected;
  unsigned short int h_lines, v_lines;
  int height,width,pos,frames_minus_j;
  int *h_start, *h_end, *v_start, *v_end;

  GetClientSize(&width, &height);
  h_lines=*Rows-1;
  v_lines=*Cols-1;
  h_start = new int[h_lines];
  h_end   = new int[h_lines];
  v_start = new int[v_lines];
  v_end   = new int[v_lines];
  bottom_of_selected = start_row * height/ *Rows;
  top_of_selected    = (start_row+1)*height/ *Rows;
  left_of_selected   = start_col*width/ *Cols;
  right_of_selected  = (start_col+1)*width/ *Cols;
  
  //horizontal lines
  for (i=0;i<h_lines;i++) {
    if (i<target_row) //below
      h_start[i]=bottom_of_selected;
    else              //above
      h_start[i]=top_of_selected;
    h_end[i]  =(i+1)*height/ *Rows;
  }; 
  
  //vertical lines
  for (i=0;i<v_lines;i++) {
    if (i<target_col) //left
      v_start[i]=left_of_selected;
    else              //right
      v_start[i]=right_of_selected;  
    v_end[i]=(i+1)*width/ *Cols;
  };
  
  this->Show(TRUE);
  
  /* do the animation */
  //set 1:1 mapping
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0.0, (GLfloat) width, 0.0, (GLfloat) height);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  //begin drawing
  glColor3f((*LineColour)[0], (*LineColour)[1], (*LineColour)[2]);
  for (int j=frames;j>=0;j--) {
    frames_minus_j=frames-j;
    glRasterPos2s( (j*pic_start_x + frames_minus_j * pic_end_x)/frames,
		   (j*pic_start_y + frames_minus_j * pic_end_y)/frames);

    glClearColor((*BGcolour)[0], (*BGcolour)[1], (*BGcolour)[2], 0.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawPixels(pic_width, pic_height, pic_format, pic_type, pixels);
    
    glBegin(GL_LINES);
    // draw horizontal lines
    for (i=0;i<h_lines;i++) {
	pos=(j*h_start[i] + frames_minus_j*h_end[i])/ frames;
	glVertex2s(0,pos);
	glVertex2s(width,pos);
      };
  
    // draw vertical line
      for (i=0;i<v_lines;i++) {
	pos=(j*v_start[i] + frames_minus_j*v_end[i])/ frames;
	glVertex2s(pos,0);
	glVertex2s(pos,height);
      };
    glEnd();
    
    glFlush();

    /*Swap*/
    SwapBuffers();
  };  
  
  delete []h_start;
  delete []h_end;
  delete []v_start;
  delete []v_end;

}
