- /
- 
        Trick or Treat
        on 31 Oct 2024
        
        
 
    - 25
- 128
- 1
- 1
- 1948
 Cite your audio source here (if applicable): 
drawframe(1);drawframe(23);
 Write your drawframe function below
function drawframe(f)
persistent P L
a=@arrayfun;
r=@repmat;
n=12; % Hidden face steps
s=(96-n)/2; % Remaining half-rotation length
f1=r([r(s/2+1,1,n/4),s/2+1:s,1:s/2,r(s/2+1,1,n/4)],1,2); f1=f1(f); % Face state index
% Draw the face for the mask
% Mouth
x=[-.5:.1:.5,flip(-.5:.1:.5)];
y=[.25 -.5 -.4 -.8 -.65 -.95,flip([.25 -.5 -.4 -.8 -.65]),.25 -.1 0 -.4 -.25 -.5,flip([.25 -.1 0 -.4 -.25])];
% Right eye
x1=[-.35 -.05 -.05 -.35];
y1=[.15 0 0 .7];
% Left eye
x2=[.35 .05 .05 .35];
y2=[.15 0 0 .7];
th=linspace(0,4*pi,97);
if f==1
    figure(Color='k')
    axes(Po=[0 0 1 1],Vis=0)
    axis equal off
    hold on
    [~,~,~,P]=p(x,F(y,f1,s+1),x1,F(y1,f1,s+1),x2,F(y2,f1,s+1),r);
    a(@(x)light(St='l',Po=[0 0 0],Col='g'),1:4)
    L=a(@(x)light('St','l','Po',2*[sin(th(f)) -cos(th(f)) 0]),1:3);
    lighting g
    campos([0 -75 5]);
    camtarget([0 0 .1]);
    camva(1.8)
else
    % Update face mask
    [P.XData,P.YData,P.ZData]=p(x,F(y,f1,s+1),x1,F(y1,f1,s+1),x2,F(y2,f1,s+1),r);
    % Rotate light
    set(L,'Po',2*[sin(th(f)) -cos(th(f)) 0]);
end
end
    function [X,Y,Z,P]=p(x,y,x1,y1,x2,y2,r)
    % Pumpkin
    l=@linspace;
    n=600;
    % Body
    [X,Y,Z]=sphere(n);
    % Shape pumpkin ribs (ridges)
    R=(1-(1-mod(0:20/n:20,2)).^2/12);
    X=R.*X;Y=R.*Y;Z=R.*Z;
    % Apply face mask
    [X,Y,Z]=M(X,Y,Z,x,y,x1,y1,x2,y2);
    Z=(.8+(0-l(1,-1,n+1)'.^4)*.3).*Z;
    % Stem
    s=[1.5 1 repelem(.7, 6)].*[r([.1 .06],1,round(n/20)) .1]';
    [t,p]=meshgrid(0:pi/15:pi/2,l(0,pi,round(n/10)+1));
    x=r(-(.4-cos(p).*s).*cos(t)+.4,2,1);
    z=r((.5-cos(p).*s).*sin(t)+.55,2,1);
    y=[-sin(p).*s;sin(p).*s];
    if nargout>3
        P=surf(X,Y,Z,FaceC=[1 .4 .1],EdgeC='n',SpecularS=.5,AmbientS=0,DiffuseS=.2);
        S=surf(x,y,z,FaceC='#008000',EdgeC='n');
    end
    end
    function [X,Y,Z]=M(X,Y,Z,x,y,x1,y1,x2,y2)
    % Masking function
    % Surface is in the form of
    % -1 -1 . . . -1 -1
    %  .  . . . .  .  .
    %  .  . . . .  .  .
    %  1  1 . . .  1  1
    % Easy enough to mask w/ inpolygon (mask projected onto pumpkin)
    i=@inpolygon;
    % Rotate to align ribs with face
    [X,Y,Z]=R(X,Y,Z,[-pi/2 0 0]);
    % Mask
    mask=ones(size(Z));
    mask((i(X,Y,x,y)|i(X,Y,x1,y1)|i(X,Y,x2,y2))&Z>=0)=NaN;
    Z=Z.*mask;
    % Rotate back
    [X,Y,Z]=R(X,Y,Z,[pi/2 0 0]);
    end
    function [X,Y,Z]=R(X,Y,Z,t)
    % Rotation matrices from scratch because why not
    Rx=[1 0 0;0 cos(t(1)) -sin(t(1));0 sin(t(1)) cos(t(1))];
    Ry=[cos(t(2)) 0 sin(t(2));0 1 0;-sin(t(2)) 0 cos(t(2))];
    Rz=[cos(t(3)) -sin(t(3)) 0;sin(t(3)) cos(t(3)) 0;0 0 1];
    for i=1:size(X,1)
        for j=1:size(X,2)
            r=Rx*Ry*Rz*[X(i,j);Y(i,j);Z(i,j)];
            X(i,j)=r(1);
            Y(i,j)=r(2);
            Z(i,j)=r(3);
        end
    end
    end
    function y = F(y,f,s)
    % Face motion
    y=reshape(y',[],2)';
    y(2,:)=flip(y(2,:));
    y=arrayfun(@(x)linspace(y(1,x),y(2,x),s)',1:size(y,2),Un=0);
    y=[y{:}];
    y=[y(f,:);y(end-f+1,:)];
    y=[y(1,:),flip(y(2,:))];
    end    


 

 
             
             
             
            