%Perspective.m
%This program paints copies of a photo on three 
%sides of a cube using a perspective projection. 
%It is important to know that this program has 
%been designed to emphasize the mathematics we have
%been discussing and it does not use MATLAB's 
%built-in tools for rendering three dimensional objects. 
%Readers who are knowledgeable about MATLAB or 
%another programming language may wish to
%design a more efficient program. 
%Although a z-buffer is not needed for this particular 
%object, one is included in order to make the
%program more easily adaptable.
%In the first line the photo is read into memory. 
%The word 'infile' should be replaced by the 
%filename of your image file which must be stored 
%in the current directory. Next, we find the 
%dimensions of the input photo. We also find the 
%edge size to make a square.
inpic = imread('infile');
row = size(inpic,1);
col = size(inpic,2);
s = min(row,col);
%In the following lines we fix the coordinates of the viewer's eye 
%and fix the viewing plane. The
%values are somewhat arbitrary and you should experiment to get a good effect.
a = 4*row;
b = 2*col;
c = 2*row;				%(a,b,c) is the position of the viewer's eye.
d = row;				%x=d is the viewing plane.
%We enter estimated bounds on the computed coordinates, 
%initialize the output file by assigning
%the color (255,255,255) to each pixel
%(rescales to (1,1,1) -- white),
%and initialize the z-buffer
%array by entering Inf for infinity.
ymin = 1;
ymax = 2*col;	%We guess ymin < y < ymax for all projected points (x,y,z).
zmin = 1;
zmax = 2*row;	%We guess zmin < z < zmax for all projected points (x,y,z).
outpic(1:round(1+zmax-zmin),1:round(1+ymax-ymin),1:3) = 255;
zbuffer(1:round(1+zmax-zmin),1:round(1+ymax-ymin)) = Inf;
%Now we loop through the input array and assign the color 
%values to the three points of the
%output corresponding to the three faces of the cube
%that are to appear. It is important to note
%that the same block of code is repeated each time the
%values of x0, y0, and z0 are assigned.
for i=1:s		%This s is the number of rows of the square image.
 for j=1:s		%This s is the number of columns of the square image.
%Front face:
 x0=s;	y0=j;	z0=s-i+1;
%Perspective projection routine starts here.
x=d;	y=b+((d-a)/(x0-a))*(y0-b);	z=c+((d-a)/(x0-a))*(z0-c);
distance=sqrt((x0-a)^2+(y0-b)^2+(z0-c)^2);
	if (ymin<=y & y<=ymax & zmin<=z & z<=zmax)
 		if distance < zbuffer(round(1+zmax-z),round(1+y-ymin))
 			outpic(round(1+zmax-z),round(1+y-ymin),:)=inpic(i,j,:);
 		zbuffer(round(1+zmax-z),round(1+y-ymin))=distance;
 		end
	end
%Perspective projection routine ends here.
%Right face:
 x0=s-j+1;	y0=s;	z0=s-i+1;
%Perspective projection routine starts here.
x=d;	y=b+((d-a)/(x0-a))*(y0-b);	z=c+((d-a)/(x0-a))*(z0-c);
distance=sqrt((x0-a)^2+(y0-b)^2+(z0-c)^2);
	if (ymin<=y & y<=ymax & zmin<=z & z<=zmax)
 		if distance < zbuffer(round(1+zmax-z),round(1+y-ymin))
 			outpic(round(1+zmax-z),round(1+y-ymin),:)=inpic(i,j,:);
 		zbuffer(round(1+zmax-z),round(1+y-ymin))=distance;
 		end
	end
%Perspective projection routine ends here.
%Top face:
 x0=i;	y0=j;	z0=s;
%Perspective projection routine starts here.
x=d;	y=b+((d-a)/(x0-a))*(y0-b);	z=c+((d-a)/(x0-a))*(z0-c);
distance=sqrt((x0-a)^2+(y0-b)^2+(z0-c)^2);
	if (ymin<=y & y<=ymax & zmin<=z & z<=zmax)
 		if distance < zbuffer(round(1+zmax-z),round(1+y-ymin))
 			outpic(round(1+zmax-z),round(1+y-ymin),:)=inpic(i,j,:);
 		zbuffer(round(1+zmax-z),round(1+y-ymin))=distance;
 		end
	end
%Perspective projection routine ends here.
 end
 end
%Finally, the output image is sent to the screen and also saved to a file.    
%Runtime is shorter if you
%do not send the image to the screen. Just put a "%" in front of that line
%to disable it. On the other
%hand, you may want to view the image on the screen but not save it to a file.
%In that case disable
%the imwrite line.
image(outpic/255); axis equal
imwrite(outpic/255,'outfile.jpg','jpg')