function cameramenu(varargin)
%CAMERAMENU  Interactively manipulate camera.
%   CAMERAMENU creates a new menu that enables interactive
%   manipulation of a scene's camera and light by dragging the
%   mouse on the figure window; the camera properties of the
%   current axes (gca) are affected. Several camera properties
%   are set when the menu is initialized. 
%
%   CAMERAMENU('noreset') creates the menu without setting any
%   camera properties.
% 
%   CAMERAMENU('close') removes the menu.
%
%   Note: Either mouse button can be used to move the camera or
%   light. Clicking the right mouse button will stop camera or
%   light movements.
%
%   Note: Rendering performance is affected by presence of OpenGL 
%   hardware.
%
%   See also ROTATE3D, ZOOM.

%   Copyright (c) 1984-98 by The MathWorks, Inc.
%   $Revision: 1.10 $  $Date: 1998/10/21 22:36:33 $


Udata = getUdata;

if nargin==0 
  axis('vis3d')
  axis(axis)
  camproj perspective
  renmode = get(gcf, 'renderermode');
  try
    set(gcf, 'renderer', 'opengl');
  catch
    warning('OpenGL renderer not available.')
  end
  % Workaround for bug: if Opengl does not load, the renderermode 
  % is not reset to previous value.
  if ~strcmp(lower(get(gcf, 'renderer')), 'opengl')
    set(gcf, 'renderermode', renmode)
  end
  arg = 'init';
  scribeclearmode(gcf,'cameramenu', 'nomode');
else
  arg = lower(varargin{1});
  if ~strcmp(arg, 'init') & ~strcmp(arg, 'motion') & isempty(Udata)
    cameramenu('init')
    Udata = getUdata;
    if ~strcmp(arg, 'nomode')
      scribeclearmode(gcf,'cameramenu', 'nomode');
    end
  end
end

switch arg
case 'down'
   pt = get(gcf, 'currentpoint');pt = pt(1,1:2);
   Udata.figStartPoint = pt;
   Udata.figLastPoint  = pt;
   Udata.figLastLastPoint = pt;
   Udata.buttondown = 1;
   Udata.moving = 0;

   if strcmp(Udata.movedraw, 'box') & isempty(Udata.savestate.ax)
     Udata.savestate.children = findobj(gca, 'visible', 'on');
     Udata.savestate.fig = get(gcf);
     Udata.savestate.ax = get(gca);
     if ~strcmp(get(gcf, 'renderer'), 'OpenGL')
       set(gcf, 'renderer', 'painters')
     end
     set(get(gca,'children'), 'vis', 'off')
     set(gca, 'color', 'none', 'visible', 'on');
     figColor = get(gcf, 'color');
     if sum(figColor .* [.3 .6 .1]) > .5
       contrastColor = 'k';
     else
       contrastColor = 'w';
     end
     if isequal(figColor, get(gca, 'xcolor'))
       set(gca, 'xcolor', contrastColor);
     end
     if isequal(figColor, get(gca, 'ycolor'))
       set(gca, 'ycolor', contrastColor);
     end
     if isequal(figColor, get(gca, 'zcolor'))
       set(gca, 'zcolor', contrastColor);
     end
     ticks('off')
     box('on')
   end

   setUdata(Udata)

   validateScenelight
   updateScenelightOnOff(Udata.scenelightOn)
   
   
case 'motion'
  if isstruct(Udata) & Udata.buttondown 
    
    pt = get(gcf, 'currentpoint');pt = pt(1,1:2);
    deltaPix  = pt-Udata.figLastPoint;
    deltaPixStart  = pt-Udata.figStartPoint;
    Udata.figLastLastPoint = Udata.figLastPoint;
    Udata.figLastPoint = pt;
    
    Udata.time = clock;
    
    mode = lower(Udata.mode);
    hvmode = lower(Udata.mouseconstraint);
    if hvmode(1) == 'h'
      deltaPix(2) = 0;
      deltaPixStart(2) = 0;
    elseif hvmode(1) == 'v'
      deltaPix(1) = 0;
      deltaPixStart(1) = 0;
    end
    
    setUdata(Udata)
    switch mode
      case 'orbit'
	orbitPangca(deltaPix, 'o');
      case 'orbit scenelight'
	orbitLightgca(deltaPix);
      case 'pan'
	orbitPangca(deltaPix, 'p');
      case 'dolly horiz/vert'
	dollygca(deltaPix);
      case 'zoom'
	zoomgca(deltaPix);
      case 'dolly in/out'
	forwardBackgca(deltaPix, 'c');
      case 'roll'
	rollgca(deltaPix, pt);
      case 'walk'
	Udata.moving=1;
	setUdata(Udata)
	walkgca(deltaPixStart);
    end
  end
case 'up'
  Udata.buttondown = 0;
  Udata.moving   = 0;
  pt = get(gcf, 'currentpoint');pt = pt(1,1:2);
  deltaPix  = pt-Udata.figLastLastPoint;
  deltaPixStart  = pt-Udata.figStartPoint;
  Udata.figLastPoint = pt;
  
  mode = lower(Udata.mode);
  hvmode = lower(Udata.mouseconstraint);
  if hvmode(1) == 'h'
    deltaPix(2) = 0;
    deltaPixStart(2) = 0;
  elseif hvmode(1) == 'v'
    deltaPix(1) = 0;
    deltaPixStart(1) = 0;
  end
  
  setUdata(Udata)
  if etime(clock, Udata.time)<.1 & any(deltaPix) & ...
	~strcmp('alt', get(gcf, 'selectiontype'))
    Udata.moving = 1;
    setUdata(Udata)
    switch mode
      case 'orbit'
	orbitPangca(deltaPix, 'o');
      case 'orbit scenelight'
	orbitLightgca(deltaPix);
      case 'pan'
	orbitPangca(deltaPix, 'p');
      %case 'roll'
	%rollgca(deltaPix);
    end
  end
     
  if strcmp(Udata.movedraw, 'box') & ~isempty(Udata.savestate.ax)
    set(Udata.savestate.children, 'vis', 'on')
    set(gcf, 'Renderer',     Udata.savestate.fig.Renderer    );
    set(gcf, 'RendererMode', Udata.savestate.fig.RendererMode);
    set(gca, 'Color',     Udata.savestate.ax.Color    )
    set(gca, 'Visible',   Udata.savestate.ax.Visible  )
    set(gca, 'XColor',    Udata.savestate.ax.XColor   )
    set(gca, 'YColor',    Udata.savestate.ax.YColor   )
    set(gca, 'ZColor',    Udata.savestate.ax.ZColor   )
    set(gca, 'Xtick',     Udata.savestate.ax.XTick    )
    set(gca, 'XtickMode', Udata.savestate.ax.XTickMode)
    set(gca, 'Ytick',     Udata.savestate.ax.YTick    )
    set(gca, 'YtickMode', Udata.savestate.ax.YTickMode)
    set(gca, 'Ztick',     Udata.savestate.ax.ZTick    )
    set(gca, 'ZtickMode', Udata.savestate.ax.ZTickMode)
    set(gca, 'Box',       Udata.savestate.ax.Box      )
    Udata.savestate.ax = [];
    setUdata(Udata)
   end
   
case 'stopmoving'
  Udata.moving = 0;
  setUdata(Udata)
case 'updatemenu'
  updateMenu
case 'changemode'
  if strcmp(Udata.mode, get(gcbo, 'Label'))
    cameramenu('nomode')
    Udata = getUdata;
  else
    Udata.mode = get(gcbo, 'Label');
    scribeclearmode(gcf,'cameramenu', 'nomode');
  end
  if strcmp(Udata.mode, 'Walk')
    camproj perspective
  end
  setUdata(Udata)
  updateMenu
case 'changecoordsys'
  Udata.coordsys = get(gcbo, 'Label');
  setUdata(Udata)

  if length(Udata.coordsys)==1
    coordsysval =  lower(Udata.coordsys) - 'x' + 1;
    
    d = [0 0 0];
    d(coordsysval) = 1;
    
    up = camup;
    if up(coordsysval) < 0
      d = -d;
    end
    
    % Check if the camera up vector is parallel with the view direction;
    % if not, set the up vector
    if any(crossSimple(d,campos-camtarget))
      camup(d)
      updateScenelightPosition;
    end  
  end
  updateMenu  
case 'changescenelight'
  val = toggleOnOff(gcbo);
  if ~val & strcmp(Udata.mode, 'Orbit Scenelight')
    Udata.mode = 'Orbit';
    setUdata(Udata)
  end
  validateScenelight
  updateScenelightOnOff(val)
  updateScenelightPosition
case 'changeaxesvisible'
  toggleOnOff(gcbo)
  axis(get(gcbo, 'checked'))
case 'changeaxesbox'
  if toggleOnOff(gcbo)
    axis('on')
  end
  box(get(gcbo, 'checked'))
case 'changeaxesgrid'
  if toggleOnOff(gcbo)
    axis('on')
    ticks('on')
  end
  grid(get(gcbo, 'checked'))
case 'changeaxesticks'
  if toggleOnOff(gcbo)
    axis('on')
  else
    grid('off')
  end
  ticks(get(gcbo, 'checked'))
case 'changeaxesprojection'
  camproj(get(gcbo, 'Label'))
case 'changeaxescolor'
  str = get(gcbo, 'Label');
  str = str(1:end-3);
  if str(1)=='W'
    str = 'color';
  else
    str(2) = [];
  end
  set(gca, str, uisetcolor(get(gca, str)))
case 'changerenderer'
  set(gcf, 'renderer', get(gcbo, 'label'))
case 'changerenderermode'
  if toggleOnOff(gcbo)
    set(gcf, 'renderermode', 'auto')
  else
    set(gcf, 'renderermode', 'manual')
  end
case 'changemovedraw'
  if toggleOnOff(gcbo)
    Udata.movedraw = 'box';
  else
    Udata.movedraw = 'same';
  end
  setUdata(Udata)
case 'changefigcolor'
  set(gcf, 'color', uisetcolor(get(gcf, 'color')))
case 'changedoublebuffer'
  toggleOnOff(gcbo)
  set(gcf, 'doublebuffer', get(gcbo, 'checked'))
case 'changenosort'
  if toggleOnOff(gcbo)
    set(gca, 'drawmode', 'fast')
  else
    set(gca, 'drawmode', 'normal')
  end
case 'resetscenelight'
  Udata.scenelightAz = 0;
  Udata.scenelightEl = 0;
  setUdata(Udata)
  validateScenelight
  updateScenelightPosition
case 'resetall'
  if ishandle(Udata.scenelight)     delete(Udata.scenelight);     end
  initUdata;
  updateMenu
  cameramenu('resetcamera');
case 'resetcamera'
  resetCameraProps
  cameramenu('resetscenelight');
case 'changemouseconstraint'
  Udata.mouseconstraint = get(gcbo, 'Label');
  setUdata(Udata)
  updateMenu
case 'checkcdata'
  objs=[findobj(gca, 'type', 'patch'); findobj(gca, 'type', 'surface')];
  for j = 1:length(objs)
    obj = objs(j);
    if strcmp(get(obj, 'visible'), 'on') & isempty(get(obj, 'cdata'))
      warndlg('Not all visible surfaces and patches have cdata', '')
      return
    end
  end
  eval(varargin{2});
case 'noreset'
  cameramenu('init');
case 'nomode'
  Udata.mode = '';
  restoreWindowCallbacks(Udata.wcb);
  setUdata(Udata)
  updateMenu
  restoreWindowCursor(Udata.cursor);
case 'init'
  emptyUdata = isempty(Udata);
  wcb = getWindowCallBacks;
  cursor = getWindowCursor;
  initWindowCallbacks
  menus = findobj(gcf, 'type', 'uimenu');
  cammenu = findobj(menus, 'tag', 'cm598');
  if isempty(cammenu)
    createMenu
  end
  if ~emptyUdata&ishandle(Udata.scenelight)    
    delete(Udata.scenelight);      
  end
  initUdata
  Udata = getUdata;
  if emptyUdata
    Udata.wcb = wcb;
    Udata.cursor = cursor;
  end
  setUdata(Udata)
  updateMenu
case 'close'
  restoreWindowCallbacks(Udata.wcb);
  restoreWindowCursor(Udata.cursor);
  cameramenu('stopmoving')
  if ishandle(Udata.scenelight)     delete(Udata.scenelight);     end
  if ishandle(Udata.mainMenuHandle) delete(Udata.mainMenuHandle); end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function orbitPangca(xy, mode)
Udata = getUdata;

%mode = 'o';  orbit
%mode = 'p';  pan


coordsys = lower(Udata.coordsys);
if coordsys(1)=='u'
  coordsysval = 0;
else
  coordsysval = coordsys(1) - 'x' + 1;
end

xy = -xy;

if mode=='p' % pan
  panxy = xy*camva/500;
end
  
if coordsysval>0
  d = [0 0 0];
  d(coordsysval) = 1;
  
  up = camup;
  upsidedown = (up(coordsysval) < 0);
  if upsidedown 
    xy(1) = -xy(1);
    d = -d;
  end

  % Check if the camera up vector is parallel with the view direction;
  % if not, set the up vector
  if any(crossSimple(d,campos-camtarget))
    camup(d)
  end  
end

flag = 1;

while sum(abs(xy))> 0 & isstruct(Udata) & (flag | Udata.moving==1)
  flag = 0;
  
  if mode=='o' %orbit
    if coordsysval==0 %unconstrained
      camorbit(xy(1), xy(2), coordsys)
    else
      camorbit(xy(1), xy(2), 'data', coordsys)
    end
  else %pan
    if coordsysval==0 %unconstrained
      campan(panxy(1), panxy(2), coordsys)
    else
      campan(panxy(1), panxy(2), 'data', coordsys)
    end
  end
  
  updateScenelightPosition;
  drawnow;
  Udata = getUdata;
end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function orbitLightgca(xy)
Udata = getUdata;

if sum(abs(xy))> 0 & ~Udata.scenelightOn
  updateScenelightOnOff(1)
  Udata = getUdata;
end

% Check if the light is on the other side of the object
az = mod(abs(Udata.scenelightAz),360);
if az > 90 & az < 270
  xy(2) = -xy(2);
end

flag = 1;

while sum(abs(xy))> 0 & isstruct(Udata) & (flag | Udata.moving==1)
  flag = 0;
  
  Udata.scenelightAz = mod(Udata.scenelightAz + xy(1), 360);
  Udata.scenelightEl = mod(Udata.scenelightEl + xy(2), 360);
  
  if abs(Udata.scenelightEl) > 90
    Udata.scenelightEl = 180 - Udata.scenelightEl;
    Udata.scenelightAz = 180 + Udata.scenelightAz;
    xy(2) = -xy(2);
  end

  setUdata(Udata)
  updateScenelightPosition
  
  drawnow
  Udata = getUdata;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function walkgca(xy)
Udata = getUdata;

coordsys = lower(Udata.coordsys);
if coordsys(1)=='u'
  coordsysval = 0;
else
  coordsysval = coordsys(1) - 'x' + 1;
end

if coordsysval>0
  d = [0 0 0];
  d(coordsysval) = 1;

  up = camup;
  if up(coordsysval) < 0
    d = -d;
  end
end

q = max(-.9, min(.9, xy(2)/700));
cva = camva;

flag = 1;

while sum(abs(xy))> 0 & isstruct(Udata) & (flag | Udata.moving==1)
  flag = 0;
  
  if coordsysval==0 %unconstrained
    campan(xy(1)*cva/700, 0, 'camera')
    v = q*(camtarget-campos);
  else
    campan(xy(1)*cva/700, 0, 'data', d)
    camup(d);
    
    v = q*(camtarget-campos);
    v(coordsysval) = 0;
  end
  camdolly(v(1), v(2), v(3), 'movetarget', 'data')
  updateScenelightPosition;
  
  drawnow;
  Udata = getUdata;
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function dollygca(xy)
camdolly(-xy(1), -xy(2), 0, 'movetarget', 'pixels')
updateScenelightPosition;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% not used
%
function flipgca(xy)
Udata = getUdata;

xy = -xy;

flag = 1;

while isstruct(Udata) & (flag | Udata.moving==1)
  flag = 0;

  camorbit(xy(1), xy(2), 'camera')
  
  updateScenelightPosition;
  
  drawnow
  Udata = getUdata;
end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function zoomgca(xy)
q = max(-.9, min(.9, sum(xy)/70));
camzoom(1+q);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function forwardBackgca(xy, mode)

q = max(-.9, min(.9, sum(xy)/70));

if mode=='b'
  camdolly(0,0,q);
else
  camdolly(0,0,q, 'f');
end

updateScenelightPosition;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function rollgca(dxy, pt)
Udata = getUdata;

% find the pixel center of the axes
units = get(gca, 'units');
set(gca, 'units', 'pix');
pos = get(gca, 'pos');
center = pos(1:2)+pos(3:4)/2;
set(gca, 'units', units);

startpt = pt - dxy;

v1 = pt-center;
v2 = startpt-center;

v1 = v1/norm(v1);
v2 = v2/norm(v2);
theta = acos(sum(v2.*v1)) * 180/pi;
cross =  crossSimple([v1 0],[v2 0]);
if cross(3) >0
  theta = -theta;
end

flag = 1;

while isstruct(Udata) & (flag | Udata.moving==1)
  flag = 0;
  
  camroll(theta);
  
  updateScenelightPosition;

  drawnow
  Udata = getUdata;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function createMenu


Udata.mainMenuHandle = uimenu('Label','&Camera', ...
    'callback', 'cameramenu(''updatemenu'')');

%Udata.mainMenuHandle=uicontextmenu( ...
%    'callback', 'cameramenu(''updatemenu'')');
%set(gcf, 'uicontextmenu', Udata.mainMenuHandle)


%%
%% Mode
%%
Udata.modeMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Mouse Mode');
uimenu(Udata.modeMenuHandle, ...
    'Label','Orbit', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Orbit Scenelight', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Pan', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Dolly Horiz/Vert', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Dolly In/Out', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Zoom', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Roll', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Walk', ...
    'callback', 'cameramenu(''changemode'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','X', 'tag', 'coordsys', 'separator', 'on', ...
    'callback', 'cameramenu(''changecoordsys'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Y', 'tag', 'coordsys',...
    'callback', 'cameramenu(''changecoordsys'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Z', 'tag', 'coordsys',...
    'callback', 'cameramenu(''changecoordsys'')');
uimenu(Udata.modeMenuHandle, ...
    'Label','Unconstrained', 'tag', 'coordsys',...
    'callback', 'cameramenu(''changecoordsys'')');

%%
%% Mouse constraint
%%
Udata.mouseConstraintMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Mouse Constraint');
uimenu(Udata.mouseConstraintMenuHandle, ...
    'Label','Horizontal', ...
    'callback', 'cameramenu(''changemouseconstraint'')');
uimenu(Udata.mouseConstraintMenuHandle, ...
    'Label','Vertical', ...
    'callback', 'cameramenu(''changemouseconstraint'')');
uimenu(Udata.mouseConstraintMenuHandle, ...
    'Label','Unconstrained', ...
    'callback', 'cameramenu(''changemouseconstraint'')');

%%
%% Stop moving
%%
Udata.stopmovingMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Stop Moving', ...
    'callback', 'cameramenu(''stopmoving'')');

%%
%% Scenelight
%%
Udata.scenelightMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Scenelight', ...
    'callback', 'cameramenu(''changescenelight'')');

%%
%% Reset
%%
Udata.resetMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Reset');
uimenu(Udata.resetMenuHandle, ...
    'Label','Reset Modes/Camera Properties', ...
    'callback', 'cameramenu(''resetall'')');
uimenu(Udata.resetMenuHandle, ...
    'Label','Reset Camera Properties', ...
    'callback', 'cameramenu(''resetcamera'')');
uimenu(Udata.resetMenuHandle, ...
    'Label','Reset Target Point', ...
    'callback', 'camtarget auto; camtarget(camtarget); cameramenu(''resetscenelight'')');
uimenu(Udata.resetMenuHandle, ...
    'Label','Reset Scenelight', ...
    'callback', 'cameramenu(''resetscenelight'')');


%%
%% Scene
%%
Udata.sceneMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Scene');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Fit All', ...
    'callback', 'camlookat');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Lighting None',  'separator', 'on',...
    'callback', 'lighting none');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Lighting Flat', ...
    'callback', 'lighting flat');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Lighting Gouraud', ...
    'callback', 'lighting gouraud');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Lighting Phong', ...
    'callback', 'lighting phong');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Shading Faceted', 'separator', 'on',...
    'callback', 'cameramenu(''checkcdata'', ''shading faceted'')');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Shading Flat',...
    'callback', 'cameramenu(''checkcdata'', ''shading flat'')');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Shading Interp',...
    'callback', 'cameramenu(''checkcdata'', ''shading interp'')');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Clipping On', 'separator', 'on',...
    'callback', 'set(findobj(gca), ''clipping'', ''on'')');
uimenu(Udata.sceneMenuHandle, ...
    'Label','Clipping Off',...
    'callback', 'set(findobj(gca), ''clipping'', ''off'')');

%%
%% Axes
%%
Udata.axesMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Axes');
uimenu(Udata.axesMenuHandle, ...
    'Label','Visible', ...
    'callback', 'cameramenu(''changeaxesvisible'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Box', ...
    'callback', 'cameramenu(''changeaxesbox'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Ticks', ...
    'callback', 'cameramenu(''changeaxesticks'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Grid', ...
    'callback', 'cameramenu(''changeaxesgrid'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Walls Color...','separator', 'on',...
    'callback', 'cameramenu(''changeaxescolor'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','X Color...',...
    'callback', 'cameramenu(''changeaxescolor'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Y Color...',...
    'callback', 'cameramenu(''changeaxescolor'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Z Color...',...
    'callback', 'cameramenu(''changeaxescolor'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Orthographic','separator', 'on',  ...
    'callback', 'cameramenu(''changeaxesprojection'')');
uimenu(Udata.axesMenuHandle, ...
    'Label','Perspective',...
    'callback', 'cameramenu(''changeaxesprojection'')');

%%
%% Renderer
%%
Udata.rendererMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Renderer Options');
uimenu(Udata.rendererMenuHandle, ...
    'Label','Painters', ...
    'callback', 'cameramenu(''changerenderer'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','  Double Buffer', ...
    'callback', 'cameramenu(''changedoublebuffer'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','  No Sort', ...
    'callback', 'cameramenu(''changenosort'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','Zbuffer', ...
    'callback', 'cameramenu(''changerenderer'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','OpenGL', ...
    'callback', 'cameramenu(''changerenderer'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','Auto', ...
    'callback', 'cameramenu(''changerenderermode'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','Move As Box','separator', 'on',  ...
    'callback', 'cameramenu(''changemovedraw'')');
uimenu(Udata.rendererMenuHandle, ...
    'Label','Background Color...','separator', 'on', ...
    'callback', 'cameramenu(''changefigcolor'')');

%%
%% Remove menu
%%
Udata.removeMenuHandle = uimenu(Udata.mainMenuHandle, ...
    'Label','Remove Menu', ...
    'callback', 'cameramenu(''close'')');


set(Udata.mainMenuHandle, 'tag', 'cm598');
setUdata(Udata)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function updateMenu
Udata = getUdata;

menu = Udata.mainMenuHandle;
if isempty(Udata.mode)
  str = '&Camera';
elseif strmatch(Udata.mode, {'Orbit' 'Pan' 'Walk'}) 
  str = ['&Camera (' Udata.mode ', '  Udata.coordsys ')' ];
else	
  str = ['&Camera (' Udata.mode ')' ];
end

set(menu, 'label', str)

children = get(Udata.mainMenuHandle, 'children');
set(children, 'checked', 'off');

%%
%% Mode
%%
children = get(Udata.modeMenuHandle, 'children');
set(children, 'checked', 'off')
menu = findobj(children, 'Label', Udata.mode);
set(menu, 'checked', 'on')
menu = findobj(children, 'Label', Udata.coordsys);
set(menu, 'checked', 'on')
children = get(Udata.modeMenuHandle, 'children');
menus = findobj(children, 'tag', 'coordsys');
if ~isempty(Udata.mode)
  set(menus, 'enable', bool2OnOff(strmatch(Udata.mode, {'Orbit' 'Pan' 'Walk'})))
else
  set(menus, 'enable', 'off')
end

%%
%% Stop Moving
%%
set(Udata.stopmovingMenuHandle, 'enable', bool2OnOff(Udata.moving))

%%
%% Scenelight
%%
if ~ishandle(Udata.scenelight)
   Udata.scenelightOn = 0;
end
set(Udata.scenelightMenuHandle, 'checked', bool2OnOff(Udata.scenelightOn));

%%
%% Mouse motion constraint
%%
children = get(Udata.mouseConstraintMenuHandle, 'children');
set(children, 'checked', 'off')
menu = findobj(children, 'Label', Udata.mouseconstraint);
set(menu, 'checked', 'on')

%%
%% Axes
%%
children = get(Udata.axesMenuHandle, 'children');
set(children, 'checked', 'off')
menu = findobj(children, 'Label', 'Visible');
set(menu, 'checked', get(gca, 'visible'))
menu = findobj(children, 'Label', 'Box');
set(menu, 'checked', get(gca, 'box'))
menu = findobj(children, 'Label', 'Grid');
set(menu, 'checked', get(gca, 'xgrid'))
menu = findobj(children, 'Label', 'Ticks');
set(menu, 'checked', bool2OnOff(~isempty(get(gca, 'xtick'))))
menu = findobj(children, 'Label', capitalize(camproj));
set(menu, 'checked', 'on')

%%
%% Renderer
%%
children = get(Udata.rendererMenuHandle, 'children');
set(children, 'checked', 'off')
menu = findobj(children, 'Label', capitalize(get(gcf, 'renderer')));
set(menu, 'checked', 'on')
menu = findobj(children, 'Label', 'Auto');
set(menu, 'checked', bool2OnOff(strcmp(get(gcf, 'renderermode'), 'auto')))

enable = bool2OnOff(strcmp(get(gcf, 'renderer'), 'painters'));
menu = findobj(children, 'Label', '  Double Buffer');
set(menu, 'checked', get(gcf, 'doublebuffer'), ...
    'enable', enable)
menu = findobj(children, 'Label', '  No Sort');
set(menu, 'checked', bool2OnOff(strcmp(get(gca, 'drawmode'), 'fast')), ...
    'enable', enable)
menu = findobj(children, 'Label', 'Move As Box');
set(menu, 'checked', bool2OnOff(strcmp(Udata.movedraw, 'box')))


if ~isempty(Udata.mode)
  cdata = [
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan 1   nan nan nan nan nan nan nan nan 1   nan nan nan 
    nan nan 1   1   nan nan nan nan nan nan nan nan 1   1   nan nan 
    nan 1   2   1   1   1   1   1   1   1   1   1   1   2   1   nan 
    1   2   2   2   2   2   2   2   2   2   2   2   2   2   2   1   
    1   2   2   2   2   2   2   2   2   2   2   2   2   2   2   1   
    nan 1   2   1   1   1   1   1   1   1   1   1   1   2   1   nan 
    nan nan 1   1   nan nan nan nan nan nan nan nan 1   1   nan nan 
    nan nan nan 1   nan nan nan nan nan nan nan nan 1   nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 
    ];
  
  hvmode = lower(Udata.mouseconstraint);
  if hvmode(1) == 'h'
    cdata = cdata;
  elseif hvmode(1) == 'v'
    cdata =cdata';
  else  % make cross
    cdata([5 6 11 12],4 ) = nan;
    cdata([5 6 11 12],13) = nan;
    a = cdata;
    b = cdata';
    newcdata = nan*zeros(16);
    newcdata(a==1 | b==1) = 1;
    newcdata(a==2 | b==2) = 2;
    cdata = newcdata;
  end
  
  set(gcf, 'pointer', 'custom', 'pointershapecdata', cdata, ...
      'pointershapehotspot', [8 8]);
  initWindowCallbacks
  
end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Udata = getUdata
%h = gcf;
h = findobj(get(gcf,'children'), 'type', 'uimenu', 'tag', 'cm598');
if ~isempty(h)
  Udata = get(h(1), 'userdata');
else
  Udata = [];
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function setUdata(Udata)
%h = gcf;
h = findobj(get(gcf,'children'), 'type', 'uimenu', 'tag', 'cm598');
if ~isempty(h)
  set(h(1), 'userdata', Udata);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function initUdata
Udata = getUdata;

Udata.mode = 'Orbit';
Udata.coordsys = 'Z';
Udata.mouseconstraint = 'Unconstrained';
Udata.movedraw = 'same';
Udata.savestate.ax = [];

Udata.buttondown = 0;
Udata.moving = 0;
Udata.time = 0;
Udata.scenelightOn=0;
Udata.scenelight=-1;
Udata.scenelightAz = 0;
Udata.scenelightEl = 0;

setUdata(Udata);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function updateScenelightPosition
Udata = getUdata;
if Udata.scenelightOn
  camlight(Udata.scenelight, Udata.scenelightAz, Udata.scenelightEl);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function updateScenelightOnOff(val)
Udata = getUdata;
Udata.scenelightOn = val;
set(Udata.scenelight, 'vis', bool2OnOff(val))
setUdata(Udata);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function validateScenelight
Udata = getUdata;
if ~ishandle(Udata.scenelight)
  Udata.scenelight = camlight;
  set(Udata.scenelight, 'vis', 'off')
  setUdata(Udata)
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function initWindowCallbacks
set(gcf, 'windowbuttondownfcn',   'cameramenu(''down''  )')
set(gcf, 'windowbuttonmotionfcn', 'cameramenu(''motion'')')
set(gcf, 'windowbuttonupfcn',     'cameramenu(''up''    )')


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret = getWindowCallBacks
ret{1} = get(gcf, 'windowbuttondownfcn'   );
ret{2} = get(gcf, 'windowbuttonmotionfcn' );
ret{3} = get(gcf, 'windowbuttonupfcn'     );


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret = restoreWindowCallbacks(cb)
set(gcf, 'windowbuttondownfcn',   cb{1});
set(gcf, 'windowbuttonmotionfcn', cb{2});
set(gcf, 'windowbuttonupfcn',     cb{3});


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret = getWindowCursor
ret{1} = get(gcf, 'pointer'  );
ret{2} = get(gcf, 'pointershapecdata' );


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret = restoreWindowCursor(cursor)
set(gcf, 'pointer'  ,         cursor{1});
set(gcf, 'pointershapecdata', cursor{2});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret=bool2OnOff(val)
if val
  ret = 'on';
else
  ret = 'off';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret=toggleOnOff(h)
newval = strcmp(get(h, 'checked'), 'off');
set(h, 'checked', bool2OnOff(newval));
if nargout>0
  ret = newval;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret=capitalize(str)
ret = [upper(str(1)) str(2:end)];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ticks(arg)
switch arg
  case 'off' 
    set(gca, 'xtick', [], 'ztick', [], 'ytick', [])
  case 'on'
    set(gca, 'xtickmode', 'a', 'ztickmode','a', 'ytickmode', 'a')
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% simple cross product
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function c=crossSimple(a,b)
c(1) = b(3)*a(2) - b(2)*a(3);
c(2) = b(1)*a(3) - b(3)*a(1);
c(3) = b(2)*a(1) - b(1)*a(2);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function resetCameraProps
camva auto; campos auto; camtarget auto; daspect auto; camup auto; 
view(3);
daspect(daspect); camva(camva); 
axis tight;
camproj perspective