/* view3d.cc */

#include "view3d.h"
#include "simple3d.h"

static bool graphics_on = false;

list<dc_view *> view_list;

void activate_gfx( void ) {
  if( !graphics_on ) {
    graphics_on = true;

    list_item li;
    forall_items( li, view_list ) {
      dc_view *view = view_list.inf( li );
      view->view_window = new window( view->screen_wid, view->screen_hgt, 
				      view->view_name );
      view->view_window->display( view->screen_wid, view->screen_hgt );
    } 
  }
}

bool gfx_on( void ) { return graphics_on; }

const double camera_fov = 50./360 * 6.2832;
const double camera_c = disp_size / ( 2 * tan( camera_fov / 2 ) );

dc_view::dc_view( void ) {
  
  R = matrix::unity(3); wpos = nil;
  view_window = nil;
}

dc_view::dc_view( cstring s, triple &p, const matrix &r = 
		  matrix::unity(3) ) {
  R = matrix::unity(3); wpos = nil;
  view_window = nil;
  init( s, p, r );
}

void dc_view::init( cstring name, triple &pos, const matrix &r = 
		    matrix::unity(3) ) {
  if( r.nrows() == 3 && r.ncolumns() == 3 ) {
    R = r;
  } else {
    dc_trace( TRACE_WARNING ) {
      cerr << "dc_view::init -- dc_view passed invalid rotation matrix " << r 
	   << "\n";
    }
    R = matrix::unity(3);
  }
  wpos = &pos;

  screen_wid = 500;
  screen_hgt = 550;

  world_wid = 30;
  world_hgt = 33;

  view_name = name;

  if( view_window ) { 
    view_window->close();
    delete( view_window );
    view_window = nil;
  }

  if( graphics_on ) {
    view_window = new window( screen_wid, screen_hgt, view_name );
    view_window->display( screen_wid, screen_hgt );
  }

  li = view_list.append( this );
}

dc_view::~dc_view( void ) {
  if( view_window ) {
    view_window->close();
    delete( view_window );
  }

  view_list.del_item( li );
}

bool  dc_view::project( ctriple wp, point &p ) {
  triple cwp = R * wp - ( *wpos + R * triple( 0, 0, 15 ) );

  if( cwp(2) < camera_c ) {
    /* xp = ( parallel_to_plane / normal_to_plane ) * c */
    p = point( disp_size / 2 - ( ( cwp(0) / cwp(2) ) * camera_c ),
	       disp_size / 2 - ( ( cwp(1) / cwp(2) ) * camera_c ) );
    return false;
  }
  return true;
}

void dc_view::draw_line( ctriple wp1, ctriple wp2, const color &c ) {
  point p1, p2;
  if( view_window && !( project( wp1, p1 ) || project( wp2, p2 ) ) ) {
    view_window->draw_segment( p1, p2, c );
  }
}

void dc_view::draw_poly( list <triple> &pts, const color &C ) {
  if( pts.size() <= 2 ) return;

  list_item li = pts.first();
  triple t1 = pts.head(), 
         t2 = pts.inf( li = pts.succ( li ) );
  while( 1 ) {
    draw_line( t1, t2, C );
    t1 = t2;
    li = pts.succ( li );
    if( li ) t2 = pts.inf( li );
    else {
      draw_line( t1, pts.head(), C );
      break;
    }
  }
}

/* Insert new drawing funtion here */
void dc_view::draw_poly( triple [], int, const matrix &r, ctriple x, 
			 const color & ) {
  static double T[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 };

  T[0] = r(0,0);
  T[1] = r(0,1);
  T[2] = r(0,2);
  T[3] = x(0);
  T[4] = r(1,0);
  T[5] = r(1,1);
  T[6] = r(1,2);
  T[7] = x(1);
  T[8] = r(2,0);
  T[9] = r(2,1);
  T[10] = r(2,2);
  T[11] = x(2);

  cerr << "DRAW_POLY( TRIPLE[], INT, CMATRIX, CONST COLOR & ) doesn't do anything\n";
  exit( 1 );
}

void dc_view::rotate( matrix &r ) {
  dc_trace( TRACE_WARNING ) {
    cerr << "dc_view::rotate -- dc_view passed invalid rotation matrix " << r 
	 << "\n";
  } else
  R = R * r;
}

void dc_view::set_label( cstring label ) { 
  view_name = label; 
  if( view_window ) view_window->set_frame_label( label );
}
