#include <gl.h>
#include <device.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "globals.h"
#include "util.h"
#include "lights.h"
#include "states.h"
#include "geom.h"
#include "init.h"

/* initial WINDOW parameters */
#define WIN_LEFT 100
#define WIN_WIDTH 500
#define WIN_BOTTOM 300
#define WIN_HEIGHT 500

/* sets up the menus and windows, initializes all of the
   variables, globals variables, states of the event handler
   and renderer, and sets up the viewing perspective.
   also handles the arguements */
void Initialize(int argc, char *argv[])
{
  int i;
  Colorindex dummy = 0;
  
  if (argc < 1)
    {
      fprintf(stderr, "USAGE: %s\n", argv[0]);
      exit(-1);
    }

  init_event_state(&gevents);
  init_render_state(&gstate);

  gstate.scale_factor = 1.0;
  gstate.shading = GOURAUD;
  gstate.persp = 1;
  gstate.aspect_on = 1;
  gstate.zbuffer_on = 1;
  gstate.alpha_on = 1;
  gstate.lights_on = 1;
  gstate.left = -1.0;
  gstate.right = 1.0;
  gstate.bottom = -1.0;
  gstate.top = 1.0;
  gstate.near = 0.01;
  gstate.far = 100.0;
  gstate.angle = 450.0;
  gstate.twist = 0.0;
  Point(gstate.cop, 0.0, 0.0, 5.0);
  Point(gstate.dcop, 0.0, 0.0, 0.0);
  Point(gstate.vrp, 0.0, 0.0, 0.0);
  Point(gstate.dvrp, 0.0, 0.0, 0.0);
  gstate.theta = get_theta(gstate.cop, gstate.vrp);
  gstate.phi = get_phi(gstate.cop, gstate.vrp, gstate.theta);
  gstate.cv_rad = distance(gstate.cop, gstate.vrp);
  gstate.sensitivity = 1.0;
  gstate.backface_on = 1;
  gstate.concave_on = 1;
  gstate.twoside = 0.0;
  gstate.eye_sep = 0.25;
  image_file = "TILES/tex0.rgb";

  gstate.axis = NO_AXIS;
  cursor_type = finger;

  gstate.timeout = 5;
  gstate.auto_rotate = 0;
  gstate.auto_wobble = 0;
  gstate.wobble_amplitude = 10.0;
  gstate.wobble_period = 10.0;

  /* background info */
  gstate.bg_file = "BKGRND/sunset.rgb";
  gstate.bg_on = 0;

  gstate.dither_on = 0;
  
  /* parse the arguments */
  for (i=1; i<argc; i++)
    {
      if (!strcmp(argv[i], "-motif"))
	{
	  gstate.motif_mode = 1;
	}
      else if (!strcmp(argv[i], "-auto"))
	{
	  gstate.auto_rotate = 1;
	}
      else if (!strcmp(argv[i], "-image"))
	{
	  i++;
	  if (argc < (i+1))
	    {
	      fprintf(stderr, "Error: image file not specified!\n");
	      exit(-1);
	    }
	  sprintf(image_file, "%s", argv[i]);
	}
      else if (!strcmp(argv[i], "-bgi"))
	{
	  i++;
	  if (argc < (i+1))
	    {
	      fprintf(stderr, "Error: background file not specified!\n");
	      exit(-1);
	    }
	  sprintf(gstate.bg_file, "%s", argv[i]);
	}
      else if (!strcmp(argv[i], "-bgc"))
	{
	  i++;
	  if (argc < (i+3))
	    {
	      fprintf(stderr, "Error: background rgb not specified!\n");
	      exit(-1);
	    }
	  else
	    {
	      gstate.bg_r = atoi(argv[i++]);
	      gstate.bg_g = atoi(argv[i++]);
	      gstate.bg_b = atoi(argv[i++]);
	    }
	}
      else
	{
	  fprintf(stderr,
		  "USAGE: render [-options[args]]\n\n"
		  "    -bgc r g b        sets the background color\n"
		  "    -image rgb_file   texture maps the rgb_file\n"
		  "    -bgi bg_file      background image file\n"
		  "    -motif            uses motif widgets\n"
		  "    -auto             enables automatic rotation\n"
		  "\n");
	  exit(-1);
	}
    }

  /* the main window */
  prefposition(WIN_LEFT, WIN_LEFT+WIN_WIDTH, WIN_BOTTOM, WIN_BOTTOM+WIN_HEIGHT);
  foreground();
  gstate.winview = winopen("slick");
  gconfig();

  winconstraints();

  RGBmode();
  doublebuffer();
  gconfig();

  /*
  overlay(2);
  drawmode(OVERDRAW);
  RGBmode();
  doublebuffer();
  gconfig();

  underlay(2);
  drawmode(UNDERDRAW);
  RGBmode();
  doublebuffer();
  gconfig();
  */

  /* man GCONFIG */
  /* set up the framebuffers */

  /* start in normal draw mode */
  drawmode(NORMALDRAW);
  
  shademodel(GOURAUD);
  linewidth(1);
  win_stat(gstate.winview, gstate.orgview, gstate.sizeview);

  mmode(MVIEWING);
  if (gstate.alpha_on)
    blendfunction(BF_SA, BF_MSA);
  else
    blendfunction(BF_ONE, BF_ZERO);
  backface(gstate.backface_on);
  concave(gstate.concave_on);
  zfunction(ZF_LESS);
  zbuffer(gstate.zbuffer_on);
  glcompat(GLC_ZRANGEMAP, 0);
  lsetdepth(getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
  /* depth-cue range */
  lRGBrange(20, 20, 20, 255, 255, 255, getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
  depthcue(FALSE);
  fogvertex(FG_OFF, 0);
  zclear();
  polymode(PYM_FILL);
  swapinterval(1);
  nmode(NAUTO);
  linewidth(1);
  subpixel(FALSE);
  pntsmooth(SMP_OFF);
  linesmooth(SML_OFF);
  polysmooth(PYSM_OFF);
  dither(DT_ON);

  /* queue the following devices for the user interface */
  qdevice(LEFTSHIFTKEY);  /* used for z-rotation with left mouse ... */
  qdevice(RIGHTSHIFTKEY); /* ... and scaling with right mouse */
  qdevice(LEFTMOUSE);     /* used for rotation about x-y axes*/
  qdevice(MIDDLEMOUSE);   /* used for rotation about z-axis (left-right) and scaling (up-down) */
  qdevice(RIGHTMOUSE);    /* used for translation on x-y plane */
  /* the arrow keys are used for rotation */
  qdevice(LEFTARROWKEY);
  qdevice(DOWNARROWKEY);
  qdevice(RIGHTARROWKEY);
  qdevice(UPARROWKEY);
  /* the pad keys are also used for different rotations depending of mode */
  qdevice(PAD0);
  qdevice(PAD1);  /* un used for now */
  qdevice(PAD2);
  qdevice(PAD3);  /* un used for now */
  qdevice(PAD4);
  qdevice(PAD5);  /* un used for now */
  qdevice(PAD6);
  qdevice(PAD7);  /* un used for now */
  qdevice(PAD8);
  qdevice(PAD9);  /* un used for now */
  qdevice(SPACEKEY);      /* brakes for the car in game mode */
  qdevice(EQUALKEY);      /* increase mouse sensitivity */
  qdevice(MINUSKEY);      /* decrease mouse sensitivity */
  /* if we're not in motif mode, then we need to queue more devices
     so that we can change various options with the keyboard */
  if (!gstate.motif_mode)
    {
      qdevice(AKEY);          /* toggle aspect ratio on/off */
      qdevice(BKEY);          /* toggle backfacing on/off */
      qdevice(CKEY);          /* toggle concave on/off */
      qdevice(DKEY);          /* toggle depth-cueing on/off */
      qdevice(EKEY);          /* toggle eyemode on/off */
      qdevice(FKEY);          /* toggle fog on/off */
      qdevice(GKEY);          /* toggle smoothing on/off */
      qdevice(HKEY);          /* toggle background blitting on/off */
      qdevice(LKEY);          /* toggle lights on/off */
      qdevice(MKEY);          /* toggle texmap on/off */
      qdevice(PKEY);          /* toggle perspective/parallel projection */
      qdevice(QKEY);          /* toggle twosided materials on/off */
      qdevice(SKEY);          /* toggle shading model gouraud/flat */
      qdevice(TKEY);          /* toggle transparency on/off */
      qdevice(WKEY);          /* toggle polygon/wireframe */
      qdevice(ZKEY);          /* toggle zbuffer on/off */
      qdevice(TWOKEY);        /* toggle stereo off/on */
      qdevice(RETKEY);        /* save image */
      qdevice(ESCKEY);        /* exit program */
    }

  /* initialize lights, materials, textures, and fog */
  init_materials();
  init_lights();

  /* set memory size for objects */
  chunksize(1024);

  Scherk = genobj();
  Collins = genobj();

  CurrObj = Collins;
  gstate.num_polygons = make_display_list(CurrObj, geometry_display_list);
  CurrObj = Scherk;
  gstate.num_polygons = make_display_list(CurrObj, geometry_display_list);

  /* set up the background data */
  gstate.bg_data = longimagedata(gstate.bg_file);
  sizeofimage(gstate.bg_file, &gstate.bg_size[X], &gstate.bg_size[Y]);

  rectzoom((float)(gstate.sizeview[X])/(float)gstate.bg_size[X],
	   (float)(gstate.sizeview[Y])/(float)gstate.bg_size[Y]);

/*  curstype(C16X2); C16X1, C16X2, C32X1, C32X2, CCROSS */

  /* set up the cursor, if not user defined, set to the finger */
  drawmode(CURSORDRAW);
  curstype(C16X1);
  mapcolor(1, 240, 200, 0);
  mapcolor(2, 0, 255, 255);
  mapcolor(3, 0, 255, 0);

  winset(gstate.winview);
  curstype(C32X1);
  defcursor(1, finger);
  curorigin(1, 7, 31);
  setcursor(1, dummy, dummy);

  drawmode(NORMALDRAW);

  set_viewport(gstate);
  set_view(gstate);

  win_clear(gstate.bg_r, gstate.bg_g, gstate.bg_b);
  swapbuffers();
  gflush();
}

void init_materials()
{
  define_texture();
/*  define_fog(0.0, cv_rad, cv_rad*4.0, 0.4, 0.4, 0.4);*/
/*  define_fog(0.0, 3.0, 25.0, 0.0, 0.0, 0.0);*/
}

void init_lights()
{
  gstate.num_lights = 0;
  make_ambient_light(.2, .2, .2, 1.0, 0.0, 0.0, gstate.twoside);
  make_directional_light(0.8, 0.8, 0.8, 0.0, 0.0, 0.0, -1.0, -1.0, -1.0);
}