clear all
figure(1); cla;

%Define a cube in world coordinates
% for Lorenz system, 
% x range -25 to 25
% y range -25 to 25
% z range 0 to 50
VertexList= 25*[ 0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1;] ;
% you may want to hard-code this for a cube
% entries are the indices of the vertex list above
% to form six squares
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)) ;
% =================================================================
% The code below converts world coordinates into screen coordinates
% for display on VGA.
% A virtual camera is defined which is located at the LookFrom location
% The virtual camera is pointed at the LookTo location
% You get to define an apporximate up vector, in this case, the y axis
% The virtual camera transforms the world coordinates into normaillzed
% view coordinates using homogenous coordinates and matrix transforms.
% The world coordinates are translated, rotated and scaled onto the screen 
% =================================================================

% normalized coordinates
% in VGA you would calculate these, then mult by 640x480 or so
axis( [-1 1 -1 1]); 
axis square ;
% Define a camera motion
%
for i=1:300
    cla
    % move the x position of the camera a little
    delta = 30*sawtooth(2*pi*i/200, 0.5);
    % Camera position
    LookFrom = [10.0+delta 30 100];	
    LookTo = [12 12 12];	% Camera Aim point
    UpVectApprox = [0,10,0]; % Approx up vector
    
    % dist camera to far clip plane -- not used for orthogonal
    f = 1000 	;	
    % d/h is the screen scaling factor
    h = 100    ;		% height of view volume
    d = 5  	;		% dist camera to near clip plane
    %
    
    % View vector -- the direction the virtual camera is looking
    N = (LookTo - LookFrom)/norm(LookTo - LookFrom) ;
    %
    % Up Vector -- make approx-up perpendicular to N
    % by subtracting away the projection of N on the approx-up vector
    % (Should have a check for colinearity)
    UpVectApprox = UpVectApprox/norm(UpVectApprox) ;
    V = UpVectApprox - (UpVectApprox * N') * N ;
    V = V/norm(V) ;
    %
    % form the vector that points toward screen-right direction
    % Right Vector
    U = cross(N,V) ;
    %
    % Build view matrix as a 4x4 translate*rotate
    % the rotation uses basis-vector rotation
    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 orthogonal matrix as a 4x4
    Torth = ...
        [ ...
        [d/h 0   0    0]; ...
        [0   d/h 0    0]; ...
        [0   0   0    0]; ...
        [0   0   0    1]; ...
        ] ;
    
    % Build total camera tranform 
    % (only works  if all pts are IN FRONT OF camera)
    %Tcam = Tview*Tpersp ;
    Tcam = Tview*Torth ;
    
    % Transform the points to screen coordinates
    VertexList(:,4)= 1  ;				% Homogenize
    ScreenVertex = VertexList * Tcam ;		% Transform
% only need the following for perspective 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
    
    % Plot lines on the screen by extracting x,y coordinates for the
    % corners and drawing lines between them along the face edges
    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
        %line (FaceX, FaceY, 'Color', ones(3,1)*depth ) ;
        line (FaceX, FaceY) ;
    end
    
    drawnow
end

