% Define a camera
%
function CameraFun(LookFrom, LookTo, UpVectApprox, d, f, h)

%LookFrom -- Camera position
%LookTo -- Camera Aim point
%UpVectApprox -- Approx up vector
%d -- dist from camera to near clip plane
%f -- dist from camera to far clip plane
%h -- height of view volume
%
% View vector
N = (LookTo - LookFrom)/norm(LookTo - LookFrom) ;

% Up Vector -- make approx-up perpendicular to N
% (Should have a check for colinearity)
UpVectApprox = UpVectApprox/norm(UpVectApprox) ; 
V = UpVectApprox - (UpVectApprox * N') * N ;
V = V/norm(V) ;

% Right Vector
U = cross(N,V) ;

% Build view matrix as a 4x4 translate*rotate
Tview = ...
[ [1 0 0 0]; ...
  [0 1 0 0]; ...
  [0 0 1 0]; ...
  [-LookFrom, 1]; ...
] ...
*[ [U,0]' , [V,0]', [N,0]', [0 0 0 1]'] ;

% Build perspective matrix as a 4x4
Tpersp = ...
[ ...
  [d/h 0   0          0]; ...
  [0   d/h 0          0]; ...
  [0   0   f/(f-d)    1]; ...
  [0   0   -d*f/(f-d) 0]; ...
] ;

% Build total camera tranform (only works  if all pts are in front of camera)
Tcam = Tview*Tpersp ;

% Define a tetrahedron
%VertexList=[ 1 1 1 ; 1 -1 -1 ; -1 -1 1 ; -1 1 -1] ;
%FaceList=[ 0 2 1 ; 0 1 3 ; 0 3 2 ; 1 2 3 ] ;
% Matlab likes a 1-based list
%FaceList=FaceList + 1 ;

%Define a cube
VertexList=[ 0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1;] ;
FaceList=[ 1 2 6 5; 2 3 7 6; 3 4 8 7; 4 1 5 8; 1 2 3 4; 5 6 7 8; ] ;

% Number of points and faces
nPt=size(VertexList(:,1)) ;
nFace=size(FaceList(:,1)) ;

% Transform the points to screen coordinates
VertexList(:,4)= 1  ;				% Homogenize
ScreenVertex = VertexList * Tcam ;		% Transform
ScreenVertex(:,1) = ScreenVertex(:,1)./ScreenVertex(:,4);  % Perspective divide
ScreenVertex(:,2) = ScreenVertex(:,2)./ScreenVertex(:,4);  % Perspective divide
ScreenVertex(:,3) = ScreenVertex(:,3)./ScreenVertex(:,4);  % Perspective divide
ScreenVertex(:,4) = ScreenVertex(:,4)./ScreenVertex(:,4);  % Perspective divide

% Clear the old drawing
cla 

% Plot lines on the screen
for i=1:nFace
	% Draw each face separately
	FaceX = [ScreenVertex(FaceList(i,1),1) ...
		 ScreenVertex(FaceList(i,2),1) ...
		 ScreenVertex(FaceList(i,3),1) ...
		 ScreenVertex(FaceList(i,4),1) ...
		 ScreenVertex(FaceList(i,1),1) ...
		] ;
	FaceY = [ScreenVertex(FaceList(i,1),2) ...
		 ScreenVertex(FaceList(i,2),2) ...
		 ScreenVertex(FaceList(i,3),2) ...
		 ScreenVertex(FaceList(i,4),2) ...
		 ScreenVertex(FaceList(i,1),2) ...
		] ;
	depth = ScreenVertex(FaceList(i,1),3) ; % approx depth cueing
	depth = depth * (depth>0) ;		% clamp zero if depth<0
	depth(find(depth>1.0)) = 1.0 ;		% clamp one if depth>1
	line (FaceX, FaceY, 'Color', ones(3,1)*depth ) ;
end


