/*
	distort.c
	Drew Olbrich, 1992

	This program demonstrates how texture mapping can be
	used for interactive image distortion effects.

	In this demo, an arbitrarily-sized image is mapped onto
	a large array of texture mapped polygons.  The pop-up menu
	can be used to choose between different kinds of distortion.

	Port to OpenGL
	Nate Robins, 1997

	Port to Amiga/MiniGL
	Szczepan Kuzniarz, 2001
*/




#include <stdio.h>
#include <stdlib.h>
#include <mgl/gl.h>

#include "texture.h"
#include "defs.h"

static EFFECT *effect = &DEFAULT_EFFECT;

int mousex, mousey;     /* current mouse values */
int dragging = 0;
int win_size_x = WIN_SIZE_X, win_size_y = WIN_SIZE_Y;




int kprintf( char *format, ... )
{
  return 0;
};




/*
	Load the image to distort, make a texture out of it, and enable 
	texturing.
 */

void image_init( char *fn )
{
  unsigned int *buf;
  int width, height, depth;

  buf = read_texture( fn, &width, &height, &depth );
  if( buf == NULL )
  {
    fprintf( stderr, "distort: Can't load image file \"%s\".\n", fn );
    exit( -1 );
  }

  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  glTexImage2D( GL_TEXTURE_2D, 0, depth, width, height, 
	        0, GL_RGBA, GL_UNSIGNED_BYTE, buf );
  glEnable( GL_TEXTURE_2D );
  
  free( buf );
}




/*
	Escape at all costs.
 */

void keyboard( char key )
{
  switch( key )
  {
    case 27:  mglExit();
              break;

    case 'r': effect = &rubber;
              glEnable( GL_DEPTH_TEST );
              effect->init();
              break;

    case 'w': effect = &ripple;
              glDisable( GL_DEPTH_TEST );
              effect->init();
              break;
  };
}




/*
	Respond to the mouse events.
 */

void mouse_and_motion( GLint x, GLint y, GLbitfield button )
{
  mousex = x;
  mousey = win_size_y - y;

  if( button & MGL_BUTTON_LEFT )
  {
    if( !dragging )
    {
      effect->click( mousex, mousey, 1 );
      dragging = 1;
    };
  }
  else
  {
    effect->click( mousex, mousey, 0 );
    dragging = 0;
  };
}




/*
	Show the world our stuff.
 */

void display( void )
{
  effect->dynamics( mousex, mousey );
  mglLockDisplay();
  effect->redraw();
  mglUnlockDisplay();
  mglSwitchDisplay();
}




/*
	Open and initialize an OpenGL window.
 */

void display_init()
{
  mglChooseVertexBufferSize( 1000 );
  mglChooseNumberOfBuffers( 3 );
  mglChoosePixelDepth( 24 );
  mglChooseWindowMode( GL_TRUE );
  mglEnableSync( GL_TRUE );
  mglLockMode( MGL_LOCK_MANUAL );
  mglCreateContext( 0, 0, WIN_SIZE_X, WIN_SIZE_Y );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( -0.5, win_size_x - 0.5, -0.5, win_size_y - 0.5, CLIP_NEAR, CLIP_FAR );

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  glViewport( 0, 0, win_size_x, win_size_y );
  
  effect->init();

  mglIdleFunc( display );
  mglMouseFunc( mouse_and_motion );
  mglKeyFunc( keyboard );
}




/*
	If a command line argument is provided, it is interpreted
	as the name of an alternate source image.
 */

void main(int argc, char **argv)
{
  MGLInit();

  display_init();

  if( argc == 1 )
    image_init( DEFAULT_IMAGE_FN );
  else
    image_init( argv[1] );

  mglMainLoop();
  mglDeleteContext();

  MGLTerm();
}
