//all the event handlers for rc's GUI.
#include "globalstate.h"
#include "ui_thread.h"
#include "render_worker.h"
#include "render_thread.h"
#include "kdtree.h"
#include "log.h"
#ifndef DISABLE_LOG
#include "visman.h"
#endif

void InputChanged(FL_OBJECT *obj, long which)
{
  char coord[100];
  float size;
  int area;

  switch (which)
    {
    case 0:
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%f", &size))
	{
	  UI_Thread::_CB_Object->_frusta_plane_size = size;
	  fl_set_counter_value(UI_Thread::_CB_Object->_Debug_Form->FrustaPlaneSizeCounter,
			       UI_Thread::_CB_Object->_frusta_plane_size);
	}
      break;
    case 1: //animate speed
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%f", &size))
	{
	  UI_Thread::_CB_Object->_animate_speed = size;
	}
      break;      
    case 2: //frustum num
      int newnum;
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%d", &newnum))
	{
	  if (newnum >= 0)
	    {
	    UI_Thread::_CB_Object->_which_frustum = newnum;
	    fl_set_counter_value (UI_Thread::_CB_Object->_Debug_Form->FrustaNumCounter, UI_Thread::_CB_Object->_which_frustum);
	    }
	}
      break;      
    case 3: //cache area cutoff
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%d", &area))
	{
	  truly_GS->_cf_cache_area_cutoff = area;
	}
      break;
    case 4: //rays/sec
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%d", &area))
	{
	  truly_GS->_desired_num_pixels_per_frame = area;
	  fl_set_slider_value (UI_Thread::_CB_Object->_Main_Form->NumPixelsPerFrameSlider, area);
	}
      break;
    case 5: //min frusta size
      strcpy (coord, fl_get_input (obj));
      if (1 == sscanf (coord, "%d", &area))
	{
	  truly_GS->_min_frusta_size = area;
	}
      break;
    default:
      cerr << "unhandled input #" << which << " changed!" << endl;
      break;
    }
}

void CurPixelChoice(FL_OBJECT *obj, long which)
{
  if (which == 2) //edit box changed
    {
      if (1)
	//      if (!(UI_Thread::_CB_GS->_kddraw_flags & DRAW_USE_MOUSE_POS))
	{
	  char coord[100];
	  strcpy (coord, fl_get_input (obj));
	  int x, y;
	  if (2 == sscanf (coord, "%d, %d", &x, &y))
	    {
	      if (x >= 0 && y >= 0 && x < truly_GS->_x_winsize && y < truly_GS->_y_winsize)
		{
		  UI_Thread::_CB_Object->_show_x = x;
		  UI_Thread::_CB_Object->_show_y = y;
		}
	    }
	}
      return;
    }

  int on = fl_get_button (obj);

  if (which == 5)
    {
      if (on)
	UI_Thread::_CB_GS->_kddraw_flags |= DRAW_OBJ_OVER_CURSOR;
      else
	UI_Thread::_CB_GS->_kddraw_flags &= ~DRAW_OBJ_OVER_CURSOR;
      return;
    }
  if (!on) return;

  UI_Thread::_CB_GS->Lock(); 
  if (which == 0) //use coords
    {
    UI_Thread::_CB_GS->_kddraw_flags &= ~DRAW_USE_MOUSE_POS;
    }
  else if (which == 1)//use mouse pos
    {
    UI_Thread::_CB_GS->_kddraw_flags |= DRAW_USE_MOUSE_POS;
    }
  else if (which == 3) //of current pixel
    UI_Thread::_CB_GS->_kddraw_flags |= DRAW_FRUSTA_FROM_CURRENT_PIXEL;
  else if (which == 4) //of frusta #
    UI_Thread::_CB_GS->_kddraw_flags &= ~DRAW_FRUSTA_FROM_CURRENT_PIXEL;
  else
    cerr << "unknown CurPixelChoice param in ui_thread.C" << endl;
  UI_Thread::_CB_GS->UnLock();

}

void FrustaHit(FL_OBJECT *obj, long which)
{
  int on = fl_get_button (obj);
  int flag; 
  
  switch (which)
    {
    case 0:
      flag = DRAW_FRUSTA_CELLS;
      break;
    case 1: //show frusta cells up to
      flag = DRAW_FRUSTA_UP_TO;
      break;
    case 2: //show frusta cells only of
      flag = DRAW_FRUSTA_UP_TO;
      on = !on;
      break;
    case 3:
      flag = DRAW_FRUSTUM_EXIT_PTS;
      break;
    case 4:
      flag = DRAW_FRUSTUM_ANIMATE;
      break;
    case 5:
      flag = DRAW_FRUSTA_PLANES;
      break;
    case 6:
      flag = DRAW_FRUSTA_BACK_PLANES;
      break;
    case 7:
      flag = DRAW_FRUSTA_OBJECTS;
      break;
    case 8:
      flag = DRAW_FRUSTUM_CELL;
      break;
    case 9:
      flag = DRAW_FRUSTA_SCRN_SPACE;
      break;
    case 10:
      flag = DRAW_FRUSTA_INFO;
      break;
    case 11:
      flag = DRAW_CELL_FRUSTA_CACHE;
      break;
    case 12:
      flag = DRAW_CF_CACHE_OBJS;
      break;
    case 13:
      flag = DRAW_CF_CACHE_HITS;
      break;
    case 14:
      flag = DRAW_CACHE_EFFICIENCY_PERC;
      break;
    case 15:
      flag = DRAW_SCREEN_SPACE_FRUSTA_LEAVES;
      break;
    case 16:
      flag = DRAW_CACHE_NOT_TOTAL_USE;
      break;
    case 17:
      flag = DRAW_CELL_OVER_CURSOR;
      break;
    case 18:
      flag = DRAW_CACHE_HIT_PERC;
      break;
    case 19:
      flag = DRAW_KID_RAYS;
      break;
    case 20:
      flag = DRAW_FIVE_FRUSTUM_RAYS;
      break;
    case 21:
      flag = DRAW_FRUSTA_OBJS_MISSED;
      break;
    case 22:
      flag = DRAW_FRUSTA_BBOXES_MISSED;
      break;
    case 23:
      flag = DRAW_OBJS_VIS;
      break;
    case 24:
      flag = DRAW_OBJS_NOT_VIS;
      break;
    case 25:
      flag = DRAW_INTERSECTED_OBJ_SS_BBOX;
      break;
    case 26:
      flag = DRAW_VIS_INTERSECTED_OBJ;
      break;
    case 27:
      flag = DRAW_NOT_VIS_INTERSECTED_OBJ;
      break;
    case 28:
      flag = DRAW_LOG_QUERY;
      break;
    default:
      cerr << "frusta draw button " << which << " hit?!" << endl;
      return;
    }
  
  UI_Thread::_CB_GS->Lock(); 
  if (on)
    UI_Thread::_CB_GS->_frusta_flags |= flag;
  else
    UI_Thread::_CB_GS->_frusta_flags &= ~flag;
  UI_Thread::_CB_GS->UnLock();
}

void KDTreeHit(FL_OBJECT *obj, long which)
{
  int on = fl_get_button (obj);
  int flag; 
  
  switch (which)
    {
    case 0:
      flag = DRAW_RAY_OF_CURRENT_PIXEL;
      break;
    case 1:
      flag = DRAW_CELLS;
      break;
    case 2:
      flag = DRAW_OBJECTS;
      break;
    case 3:
      flag = DRAW_QUICK_REJECT_OBJECTS;
      break;
    case 4:
      flag = DRAW_ALL;
      break;
    case 5:
      break;
    case 6:
      flag = DRAW_LIGHTS;
      break;
    case 7:
      flag = DRAW_SHADOW;
      break;
    case 8: //show cell bbox
      flag = DRAW_CELL_BBOX;
      break;
    case 9:
      flag = DRAW_CELL_SHADED;
      break;
    case 10:
      flag = DRAW_ALL_RAYS;
      break;
    case 11:
      flag = DRAW_OBJS_MISSED;
      break;
    case 12:
      flag = DRAW_FRUSTA_GRID;
      break;
    case 13:
      flag = DRAW_FILM_PLANE;
      break;
    case 14:
      flag = DRAW_IMAGE_IN_FILM_PLANE;
      break;
    case 15:
      flag = DRAW_KID_CELLS;
      break;
    case 16:
      flag = DRAW_ONLY_LARGE_CELLS;
      break;
    case 17:
      flag = DRAW_OBJS_TOUCHED;
      break;
    case 18:
      flag = DRAW_BBOXES_MISSED;
      break;
    case 19:
      flag = DRAW_CELLS_ENTERED;
      break;
    case 20:
      flag = DRAW_CUR_PIXEL;
      break;
    case 21:
      flag = DRAW_WIREFRAME_OBJS;
      break;
    case 22:
      flag = DRAW_PARENT_STOPS;
      break;
    case 23:
      flag = DRAW_CELL_SCREEN_SPACE;
      break;
    case 24:
      flag = DRAW_TIGHTEST_CELL_BBOX;
      break;
    case 25:
      flag = DRAW_RAYS_W_FRUSTUM_COLOR;
      break;
    case 26:
      flag = DRAW_RAYS_FROM_EYE_PT;
      break;
    case 27:
      flag = DRAW_CLOSEST_CELL_BBOX;
      break;
    case 28:
      flag = DRAW_NEXT_CELLS;
      break;
    case 29: //show cell contents
      flag = DRAW_CELL_CONTENTS;
      break;
    default:
      cerr << "k-d tree draw button " << which << " hit?!" << endl;
      return;
    }

  UI_Thread::_CB_GS->Lock(); 
  if (on)
    UI_Thread::_CB_GS->_kddraw_flags |= flag;
  else
    UI_Thread::_CB_GS->_kddraw_flags &= ~flag;
  UI_Thread::_CB_GS->UnLock();
}

void DCounterHit(FL_OBJECT *obj, long which)
{
  float val = fl_get_counter_value(obj);

  switch (which)
    {
    case 0:
      UI_Thread::_CB_Object->_which_frustum = (int)val;
      break;
    case 1:
      UI_Thread::_CB_Object->_which_rw = (int)val;
      break;
    case 2:
      UI_Thread::_CB_Object->_frusta_plane_size = val;
      break;
    default:
      cerr << "counter " << which << " in debug window was hit?!" << endl;
      break;
    }
}

void StyleHit (FL_OBJECT *obj, long which)
{
  int on = fl_get_button (obj);
  int flag; 
  
  switch (which)
    {
    case 0:
      flag = STYLE_THREAD_OWNED;
      break;
    case 1:
      flag = STYLE_THREAD_DID;
      break;
    case 2:
      flag = STYLE_CELLS_WALKED;
      break;
    case 3:
      flag = STYLE_DEPTH_COMPLEXITY;
      break;
    case 4:
      flag = STYLE_PIXELS_DONE;
      break;
    case 5:
      flag = STYLE_KDTREE_USED;
      break;
    case 6:
      flag = STYLE_DEPTH_COMPLEXITY_W_BBOX;
      break;
    case 7:
      flag = STYLE_NO_KDTREE;
      break;
    case 8:
      flag = STYLE_CELL_HIT;
      break;
    case 9:
      flag = STYLE_SMALL_CELL_HIT;
      break;
    case 10:
      flag = STYLE_NOT_SMALL_CELL_HIT;
      break;
    case 11:
      flag = STYLE_BBOXES_MISSED;
      break;
    case 12:
      flag = STYLE_OBJS_MISSED;
      break;
    case 13:
      flag = STYLE_OBJS_HIT;
      break;
    case 14:
      flag = STYLE_OBJCELL;
      break;
    default:
      cerr << "style button " << which << " hit?!" << endl;
      return;
    }

  UI_Thread::_CB_GS->Lock(); 
  if (on)
    UI_Thread::_CB_GS->_style_flags |= flag;
  else
    UI_Thread::_CB_GS->_style_flags &= ~flag;
  UI_Thread::_CB_GS->UnLock();
}

#define SET_GS_INT(buddy)  UI_Thread::_CB_GS->Lock(); \
  UI_Thread::_CB_GS->buddy = (int)fl_get_slider_value(obj); \
  UI_Thread::_CB_GS->UnLock()

#define SET_GS_REAL(buddy)  UI_Thread::_CB_GS->Lock(); \
  UI_Thread::_CB_GS->buddy = fl_get_slider_value(obj); \
  UI_Thread::_CB_GS->UnLock()

#define SET_GS(var, call) UI_Thread::_CB_GS->Lock(); \
  UI_Thread::_CB_GS->var = call; \
  UI_Thread::_CB_GS->UnLock()

void QuitHit(FL_OBJECT *, long)
{
  UI_Thread::_CB_GS->Lock();
  UI_Thread::_CB_GS->_done = 1;
  UI_Thread::_CB_GS->UnLock();
}

void ThreadNumChanged(FL_OBJECT *obj, long)
{
  SET_GS_INT (_num_render_workers);
}

void FrameRateChanged(FL_OBJECT *obj, long)
{
  SET_GS_REAL (_desired_frame_rate);
}

void AmbientChanged(FL_OBJECT *obj, long)
{
  SET_GS (_do_ambient, fl_get_button (obj));
}

void DiffuseChanged(FL_OBJECT *obj, long)
{
  SET_GS (_do_diffuse, fl_get_button (obj));
}

void SpecularChanged(FL_OBJECT *obj, long)
{
  SET_GS (_do_specular, fl_get_button (obj));
}

void ReflectionDepthChanged(FL_OBJECT *obj, long)
{
  UI_Thread::_CB_GS->Lock(); 
  UI_Thread::_CB_GS->_reflection_depth = (int)fl_get_counter_value(obj);
  UI_Thread::_CB_GS->UnLock();
}

void RefractionDepthChanged(FL_OBJECT *obj, long)
{
  UI_Thread::_CB_GS->Lock(); 
  UI_Thread::_CB_GS->_refraction_depth = (int)fl_get_counter_value(obj);
  UI_Thread::_CB_GS->UnLock();
}

void WinSizeChanged(FL_OBJECT *obj, long)
{
  //assumes first choice is 65x65 and the square side size
  //doubles after that.
  int choice = fl_get_choice (obj);
  int x = 64;
  while (choice > 1)
    {
      x*=2;
      choice--;
    }
  cerr << "Winsize changed to " << x+1 << " square" << endl;

  SET_GS (_x_winsize, (x+1));
  SET_GS (_y_winsize, (x+1));

  int newmaxpixels = (x+1) * (x+1);

  
  UI_Thread::_CB_GS->Lock(); 
  
  if (UI_Thread::_CB_GS->_desired_num_pixels_per_frame > newmaxpixels)
    {
    UI_Thread::_CB_GS->_desired_num_pixels_per_frame = newmaxpixels;
    fl_set_slider_value (UI_Thread::_CB_Object->_Main_Form->NumPixelsPerFrameSlider, newmaxpixels);
    }

  fl_set_slider_bounds(UI_Thread::_CB_Object->_Main_Form->NumPixelsPerFrameSlider, newmaxpixels, 0.);

  fl_set_xyplot_ybounds (UI_Thread::_CB_Object->_Main_Form->NumPixelsXY, 0, newmaxpixels);
  
  fl_set_chart_bounds (UI_Thread::_CB_Object->_Main_Form->RaysDoneChart, 0., newmaxpixels);

  UI_Thread::_CB_GS->UnLock();
  UI_Thread::_CB_Object->_glwin->SetSize (x+1, x+1);
  
}

void TextureChoiceChanged(FL_OBJECT *obj, long)
{
  int choice = fl_get_choice (obj);

  switch (choice)
    {
    case 1:
      cerr << "texturing now off" << endl;
      break;
    case 2:
      cerr << "texturing now nearest" << endl;
      break;
    case 3:
      cerr << "texturing now bilinear" << endl;
      break;
    default:
      cerr << "DUH!?" << endl;
      return;
    }

  SET_GS (_texturing, choice);
}

void ShadowDepthChanged(FL_OBJECT *obj, long)
{
  UI_Thread::_CB_GS->Lock(); 
  UI_Thread::_CB_GS->_shadow_depth = (int)fl_get_counter_value(obj);
  UI_Thread::_CB_GS->UnLock();
}

void NumPixelsPerFrameChanged(FL_OBJECT *obj, long)
{
  SET_GS_INT (_desired_num_pixels_per_frame);
}

void PegHit(FL_OBJECT *, long val)
{
  SET_GS (_peg_frame_rate, val);
}

void HWCutoffChanged(FL_OBJECT *obj, long)
{
  UI_Thread::_CB_GS->Lock(); 
  UI_Thread::_CB_GS->_hw_interp_cutoff_ratio = (int)fl_get_counter_value(obj);
  UI_Thread::_CB_GS->UnLock();
}


void HeadlightHit(FL_OBJECT *obj, long)
{
  UI_Thread::_CB_GS->_scene.GetLights().HeadlightToggle ((int)fl_get_button(obj));
}

void PegasMaxHit(FL_OBJECT *obj, long which)
{
#if 0
  const float one_meg_f = (1024. * 1024.);

  struct mallinfo mi = mallinfo();
  fprintf ( stdout,
    "::arena %7.3fMb; inuse %7.3fMb; frlst %7.3fMb\n",
        mi.arena / one_meg_f,
        (mi.usmblks + mi.uordblks) / one_meg_f,
        (mi.fsmblks + mi.fordblks) / one_meg_f);
#endif

  int on = fl_get_button (obj);
  switch (which)
    {
    case 0: //shadows
    case 1: //reflection
    case 2: //refraction
      return;
    }
}

void DontHit(FL_OBJECT *obj, long which)
{
  static int trouble = 0;
  int on = fl_get_button (obj);
  int flag; 
  
  switch (which)
    {
    case 0:
      flag = DISABLE_LOAD_BALANCING;
      break;
    case 1:
      flag = DISABLE_INTERPOLATE;
      break;
    case 2:
      flag = DISABLE_DRAW;
      break;
    case 3:
      flag = DISABLE_FRAME_CONTINUE;
      break;
    case 4:
      flag = DISABLE_FRAME_BLEND;
      break;
    case 5:
      flag = FORCE_NEW_FRAME;
      on = 1;
      break;
    case 6:
      flag = DISABLE_FRAME_ADD_FEATURE;
      break;
    case 7:
      flag = DISABLE_ANIMATION;
      SET_GS(_next_frame_hit,0);
      break;
    case 8:
      flag = DISABLE_FC;
      break;
    case 9:
      flag = DISABLE_STRADDLERS;
      break;
    case 10:
      flag = DISABLE_FLOOD_YES;
      break;
    case 11:
      flag = DISABLE_VIEWVEC_T;
      break;
    case 12:
      flag = DISABLE_LP;
      break;
    case 13:
      flag = DISABLE_HYBRID_FC;
      break;
    case 14:
      flag = DISABLE_LP_SUBDIV;
      break;
    case 15:
      flag = DISABLE_CONTINUOUS_SHADE;
      on = !on; //interpret the button in reverse
      break;
    case 16:
      flag = ENABLE_PLANE_CACHE_IN;
      break;
    case 17:
      flag = ENABLE_PLANE_CACHE_OUT;
      break;
    case 18:
      flag = DISABLE_PLANE_CACHE;
      break;
    case 19:
      flag = DISABLE_CELL_FRUSTUM_CACHE;
      break;
    case 20:
      flag = DISABLE_CLIP_BBOX;
      break;
    case 21: //don't make me come over there!
      trouble++;
      if (trouble == 1)
	cerr << "You don't want to do that." << endl;
      else if (trouble == 2)
	cerr << "I think you're asking me to come over there." << endl;
      else if (trouble == 3)
	cerr << "yup, there's no doubt." << endl;
      else
	{
	  cerr << "You really didn't want to do that." << endl;
	  WorkRec *die = NULL;
	  die->GetFloodParent();
	}
      break;
    case 22:
      flag = DISABLE_DOUBLE_CHECK;
      break;
    case 23:
      flag = DISABLE_KDTREE;
      break;
    case 24:
      flag = DISABLE_KDTRAVERSAL_CACHE;
      break;
    case 25:
      flag = DISABLE_UNCACHED_BBOX_TESTS;
      break;
    case 26:
      flag = DISABLE_RAY_CF_CACHE;
      break;
    case 27:
      flag = ENABLE_FCULLED_RAY_BBOX_TESTS;
      break;
    case 28:
      flag = ENABLE_LOCK;
      break;
    case 29:
      flag = DISABLE_SMALL_CELL_WORK;
      break;
    case 30:
      flag = ENABLE_LP_ROOT_FRUSTUM;
      break;
    case 31:
      flag = ENABLE_BETTER_RAY_LISTS;
      break;
    case 32:
      flag = ENABLE_OBJ_SCRN_SPACE_BBOX_CALC;
      break;
    default:
      cerr << "dont button " << which << " hit?!" << endl;
      return;
    }

  UI_Thread::_CB_GS->Lock(); 
  if (on)
    UI_Thread::_CB_GS->_disabled_flags |= flag;
  else
    UI_Thread::_CB_GS->_disabled_flags &= ~flag;
  UI_Thread::_CB_GS->UnLock();
}

void SliderChanged(FL_OBJECT *obj, long which)
{
  if (which == 0)
    {
    SET_GS_REAL(_max_thread_ratio);
    }
  else
    cerr << "unknown slider event!" << endl;
}

void CounterChanged(FL_OBJECT *obj, long which)
{
  switch (which)
    {
    case 0:
      SET_GS(_job_chunk_size, (int)fl_get_counter_value(obj));
      break;
    case 1:
      SET_GS(_rotational_velocity, fl_get_counter_value(obj));
      break;
    case 2:
      SET_GS(_translational_velocity, fl_get_counter_value(obj));
      break;
    case 3:
      SET_GS(_ss_level, (int)fl_get_counter_value (obj));
      break;
    case 4:
      float newfov;
      newfov = fl_get_counter_value (obj);
      if (newfov >= 89)
	fl_set_object_label (UI_Thread::_CB_Object->_Main_Form->FOVTxt, "BIG VIEW!");
      else if (newfov > 70)
	fl_set_object_label (UI_Thread::_CB_Object->_Main_Form->FOVTxt, "Approaching Big View!");
      else 
	fl_set_object_label (UI_Thread::_CB_Object->_Main_Form->FOVTxt, "");
      newfov *= M_PI / 180.;
      truly_GS->_user.GetCamera().SetFovX (newfov);
      truly_GS->_user.GetCamera().SetFovY (newfov);
      break;
    case 5: //dist from eye for film plane
      UI_Thread::_CB_Object->_fp_dist = fl_get_counter_value (obj);
      break;
    case 6: //exit pt box size
      UI_Thread::_CB_Object->_exit_box_size = fl_get_counter_value (obj);
      break;
    case 7: //subdiv level
      UI_Thread::_CB_Object->_frusta_level = (int)fl_get_counter_value (obj);
      break;
    default:
      cerr << "unknown counter event!" << endl;
      break;
    }
}

void ButtonHit(FL_OBJECT *, long which)
{
  WorkRec * GetWorkRec (void);

  WorkRec *cur, *parent;
  WorkRec *start;

  _KDTreeNode *curcell;

  static UI_Thread *ui = UI_Thread::_CB_Object;
  const KDTree *kdtree = (KDTree *)truly_GS->_scene.getObjs();      
  const Bounds3d &bbox = kdtree->bbox();

  Vec4 dir;

  int x, y;
  Ray ray;

  char scratch [20];
  switch (which)
    {
    case 0:
      SET_GS(_next_frame_hit,1);
      break;
    case 1:
      //to parent
      cur = GetWorkRec();
      if (cur && cur->_parent) 
	{
	  ui->_which_frustum = cur->_parent->_f_num;
	  ui->_which_rw = cur->_parent->_rw_own;
	  fl_set_counter_value (ui->_Debug_Form->FrustaNumCounter, ui->_which_frustum);
	  fl_set_counter_value (ui->_Debug_Form->RWNumCounter, ui->_which_rw);
	}
      break;
    case 2:
      //to next sibling
      cur = GetWorkRec();
      if (cur && cur->_parent) 
	{
	  int i;
	  parent = cur->_parent;
	  for (i = 0; i < 4; i++)
	    {
	      if (parent->_kids[i] == cur)
		{
		  ui->_which_frustum = parent->_kids[(i+1) % 4]->_f_num;
		  ui->_which_rw = parent->_kids[(i+1) % 4]->_rw_own;
		  fl_set_counter_value (ui->_Debug_Form->FrustaNumCounter, ui->_which_frustum);
		  fl_set_counter_value (ui->_Debug_Form->RWNumCounter, ui->_which_rw);
		  break;
		}
	    }
	  if (i == 4)
	    cerr << "couldn't find self (" << cur->_f_num << " of thr " << cur->_rw_own << " as child of parent!";
	}
      break;
    case 3:
      //to first child
      cur = GetWorkRec();
      if (cur && cur->_kids[0]) 
	{
	  ui->_which_frustum = cur->_kids[0]->_f_num;
	  ui->_which_rw = cur->_kids[0]->_rw_own;
	  fl_set_counter_value (ui->_Debug_Form->FrustaNumCounter, ui->_which_frustum);
	  fl_set_counter_value (ui->_Debug_Form->RWNumCounter, ui->_which_rw);
	}
      break;
    case 4:
      //to current pixel
      cur = GetWorkRec();
      if (cur)
	{
	  ui->_which_frustum = cur->_f_num;
	  ui->_which_rw = cur->_rw_own;
	  fl_set_counter_value (ui->_Debug_Form->FrustaNumCounter, ui->_which_frustum);
	  fl_set_counter_value (ui->_Debug_Form->RWNumCounter, ui->_which_rw);
	}
      break;
    case 5:
      void GetCurPixelWR (int &rwown, int &frustumnum);
      int frustumnum, rwown;
      //towards current pixel
      GetCurPixelWR(rwown, frustumnum);

      if (rwown < 0) break;

      start = FRUSTUM (rwown, frustumnum);

      //     cerr << "start is " << frustumnum << ", aka " << start->_f_num << endl;
      rwown = ui->_which_rw;
      frustumnum = ui->_which_frustum;
      cur = FRUSTUM (rwown, frustumnum);
//      cerr << "cur is " << frustumnum << ", aka " << cur->_f_num << endl;

      if (start == cur) break;

      if (start->_parent != cur)
	{
	  //	  cerr << "start parent != cur" << endl;
	  while (start->_parent && start->_parent != cur)
	    {
	      start = start->_parent;
	    } 
	  if (!start->_parent) //cur pixel doesn't lead to current frustum!
	    break;
	  //otherwise, we went up at least once and we're good.
	}
      else
	{
	  //	  cerr << "start parent == cur" << endl;
	}
	
      ui->_which_frustum = start->_f_num;
      ui->_which_rw = start->_rw_own;
      fl_set_counter_value (ui->_Debug_Form->FrustaNumCounter, ui->_which_frustum);
      fl_set_counter_value (ui->_Debug_Form->RWNumCounter, ui->_which_rw);
      break;
    case 6: //reset main render view
      truly_GS->_user.GetCamera().Set (truly_GS->_initR, truly_GS->_initD, truly_GS->_initU);
      break;
    case 7: //reset debug view
      ui->InitDebugView();
      break;
    case 8: //eye pt debug view
      ui->EyePtDebugView();
      break;
    case 9: //show state
      ui->PrintState();
      break;
    case 10: //to parent cell
      curcell = ui->_current_cell;
      ui->NewCurCell (curcell->Parent());
      break;
    case 11: //to left child
      curcell = ui->_current_cell;
      ui->NewCurCell (curcell->LoKid());
      break;
    case 12: //to right child
      curcell = ui->_current_cell;
      ui->NewCurCell (curcell->HiKid());
      break;
    case 13: //follow ray
      ui->_CS->_prev->_plane_cache->ComputeEyeRayDirection (ui->_show_x, ui->_show_y, dir);
      int face, direction;
      float t;
      ray = Ray (ui->_CS->_prev->_camera.R(), dir);
      if (!ui->_current_cell->_bounds.Intersect (ray, t, face, direction))
	break;
      ui->NewCurCell (kdtree->Traverse (ray, face, direction, ui->_current_cell));
      break;
    case 14: //take current cell
      cur = GetWorkRec();
      ui->NewCurCell(cur->_cur_cell);
      break;
    case 15: //take hit cell
      RayCache *info;
      info = GET_RAY_INFO_PTR (ui->_show_x, ui->_show_y);
      ui->NewCurCell(info->objhit.hitcell);
      break;
    case 16: //focus on center of scene
      ui->_center_of_interest = (bbox[0] + bbox[1]) * .5;
      break;
    case 17: //print cell stats
      cout << 100.0 * float(ui->_current_cell->_num_times_touched.Total()) / float (ui->_current_cell->_actual.Area()) << "% reqs/cell area" << endl;
      cout << 100.0 * float(ui->_current_cell->_num_frustum_hits.Total()) / float (ui->_current_cell->_num_times_touched.Total()) << "% hits/reqs" << endl;
      ui->_current_cell->_num_times_touched.print ("# times the cell was touched");
      ui->_current_cell->_num_frusta_clipped.print ("was frusta clipped (1/0)");
      ui->_current_cell->_num_reqs.print ("# frusta requested, by frustum size:");
      ui->_current_cell->_num_frustum_hits.print ("# frusta hits, by frustum size");
      ui->_current_cell->_num_frustum_subdivides.print ("# frusta subdivided, by frustum size");
      ui->_current_cell->_num_quick_subdivides.print ("# quick subdivides, by frustum size");
      ui->_current_cell->_num_objs_partitioned.print ("# objs partitioned, by frustum size");
      ui->_current_cell->_num_objs_returned.print ("# objs returned, by frustum size");
      ui->_current_cell->_num_objs_not_returned.print ("# objs culled, by frustum size");
      //      cerr << "# objs not returned: " << ui->_current_cell->_objs->Size() * ui->_current_cell->_num_times_touched.Total() - 
      //	ui->_current_cell->_num_objs_returned.Total() << endl;
      cerr << "screen-space area: " << ui->_current_cell->_actual << " enclosed by " << ui->_current_cell->_enc << endl;
      cerr << "unclipped was: " << ui->_current_cell->_unclipped_actual << endl;
      break;
    case 18: //focus on current cell
      ui->_center_of_interest = (ui->_current_cell->_bounds[0] + ui->_current_cell->_bounds[1]) * .5;
      break;
    case 19: //print overall stats
      void PrintStats (CycleState &CS);
      PrintStats (*ui->_CS);
      break;
    case 20: //R
      x = ui->_show_x;
      if (x < (truly_GS->_x_winsize - 1))
	{
	  ui->_show_x++;
	  sprintf (scratch, "%d, %d", ui->_show_x, ui->_show_y);
	  fl_set_input (ui->_Debug_Form->CoordEdit, scratch);
	}
      break;
    case 21: //L
      x = ui->_show_x;
      if (x > 0)
	{
	  ui->_show_x--;
	  sprintf (scratch, "%d, %d", ui->_show_x, ui->_show_y);
	  fl_set_input (ui->_Debug_Form->CoordEdit, scratch);
	}
      break;
    case 22: //D
      y = ui->_show_y;
      if (y > 0)
	{
	  ui->_show_y--;
	  sprintf (scratch, "%d, %d", ui->_show_x, ui->_show_y);
	  fl_set_input (ui->_Debug_Form->CoordEdit, scratch);
	}
      break;
    case 23: //U
      y = ui->_show_y;
      if (y < (truly_GS->_y_winsize -1 ))
	{
	  ui->_show_y++;
	  sprintf (scratch, "%d, %d", ui->_show_x, ui->_show_y);
	  fl_set_input (ui->_Debug_Form->CoordEdit, scratch);
	}
      break;
    case 24: //clear log
#ifndef DISABLE_LOG
      extern VisManager *visman;
      visman->ClearLog();
#endif
      break;
    default:
      cerr << "unknown button " << which << " hit." << endl;
      return;
    }
}

void DontHit2(FL_OBJECT *obj, long which)
{
  int on = fl_get_button (obj);
  int flag; 
  
  switch (which)
    {
    case 0:
      flag = ENABLE_1_AXIS_CHECK;
      break;
    case 1:
      flag = ENABLE_THROW_BAD_AREA_RATIO_TO_GL;
      break;
    case 2:
      flag = ENABLE_THROW_BAD_HIT_RATIO_TO_GL;
      break;
    case 3: //enable_logging
      extern int logging_on;
      logging_on = on;
      return;
    case 4:
      flag = ENABLE_3_AXIS_CHECK;
      break;
    case 5:
      flag = ENABLE_COLLECT_INTERSECT;
      break;
    default:
      cerr << "dont2 button " << which << " hit?!" << endl;
      return;
    }

  UI_Thread::_CB_GS->Lock(); 
  if (on)
    UI_Thread::_CB_GS->_disabled_flags2 |= flag;
  else
    UI_Thread::_CB_GS->_disabled_flags2 &= ~flag;
  UI_Thread::_CB_GS->UnLock();
}

void LogHit(FL_OBJECT *obj, long which)
{
  int on = fl_get_button (obj);
  
  if (on)
    logging_on |= (1 << which);
  else
    logging_on &= ~(1 << which);
}

void QueryHit (FL_OBJECT *obj, long which)
{
  static UI_Thread *ui = UI_Thread::_CB_Object;

  int on = fl_get_button (obj);
  if (on)
    ui->_cur_query = (UI_Thread::QueryReq)which;
}
