function AlphaRotateDemo(numFrames, ifis)
% AlphaRotateDemo(numFrames, ifis)
%
% numFrames Number of grating textures to use for the drifting grating...
%
% ifis = Number of monitor refreshes to wait between drawing single
% textures...
%
%
% OS X: ___________________________________________________________________
%
% Display a rotating grating using the new Screen('DrawTexture') command.
% In the OS X Psychtoolbox Screen('DrawTexture') replaces
% Screen('CopyWindow').     
%
% This illustrates an application of Alpha blending by masking the rotating
% grating with a gaussian transparency mask.
%
% In each frame, first the grating is drawn. Then a texture acting as a
% transparency mask is drawn "over" the grating, masking out selected
% parts of the grating.
%
% _________________________________________________________________________
% 
% see also: PsychDemos, MovieDemo

% HISTORY
%  6/28/04    awi     Adapted from Denis Pelli's DriftDemo.m for OS 9 
%  7/18/04    awi     Added Priority call.  Fixed.
%  9/8/04     awi     Added Try/Catch, cosmetic changes to comments and see also.
%  1/9/05     mk      Adapted from awi's DriftDemoOSX.                 
%  5/13/05    mk      Alpha-Blending reenabled, new VBL-Syncing enabled...
%  5/23/05    mk      Bugs fixed that made it fail on Matlab 6

if nargin<2
    ifis=2;
end;

if nargin<1
    numFrames=1
end;

try
	% This script calls Psychtoolbox commands available only in OpenGL-based 
	% versions of the Psychtoolbox. (So far, the OS X Psychtoolbox is the
	% only OpenGL-base Psychtoolbox.)  The Psychtoolbox command AssertPsychOpenGL will issue
	% an error message if someone tries to execute this script on a computer without
	% an OpenGL Psychtoolbox
	AssertOpenGL;
	
	% Get the list of screens and choose the one with the highest screen number.
	% Screen 0 is, by definition, the display with the menu bar. Often when 
	% two monitors are connected the one without the menu bar is used as 
	% the stimulus display.  Chosing the display with the highest dislay number is 
	% a best guess about where you want the stimulus displayed.  
	screens=Screen('Screens');
	screenNumber=max(screens);

    % Open a double-buffered fullscreen window:
	w=Screen('OpenWindow',screenNumber);
    [width, height]=Screen('WindowSize', w);

    % Enable alpha blending with proper blend-function. We need it
    % for drawing of our alpha-mask (gaussian aperture):
    Screen('BlendFunction', w, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	% Find the color values which correspond to white and black.  Though on OS
	% X we currently only support true color and thus, for scalar color
	% arguments,
	% black is always 0 and white 255, this rule is not true on other platforms will
	% not remain true on OS X after we add other color depth modes.  
	white=WhiteIndex(screenNumber);
	black=BlackIndex(screenNumber);
	gray=(white+black)/2;
	if round(gray)==white
		gray=black;
	end
	inc=white-gray;
	
	% compute each frame of the grating and convert those frames, stored in
	% MATLAB matrices, into Psychtoolbox OpenGL textures using 'MakeTexture';
	% numFrames= temporal period, in frames, of the drifting grating
    s=min(width, height) / 4;
	[x,y]=meshgrid(-s:s-1, -s:s-1);
	angle=30*pi/180; % 30 deg orientation.
	f=0.01*2*pi; % cycles/pixel
    a=cos(angle)*f;
	b=sin(angle)*f;
                
    % Build grating textures:
    for i=1:numFrames
		phase=(i/numFrames)*2*pi;
        m=sin(a*x+b*y+phase);
        gratingtex=(gray+inc*m);
        tex(i)=Screen('MakeTexture', w, gratingtex);
    end
    
    tavg=0;
    
    % We create a Luminance+Alpha matrix for use as transparency mask:

    % Layer 1 (Luminance) is filled with luminance value 'gray' of the
    % background.
    maskblob=ones(2*s, 2*s, 2) * gray;
    % Layer 2 (Transparency aka Alpha) is filled with gaussian transparency
    % mask.
    maskblob(:,:,2)=255 - exp(-((x/90).^2)-((y/90).^2))*255;

    % Build a single transparency mask texture:
    masktex=Screen('MakeTexture', w, maskblob);
    
    % Query the real duration of a monitor refresh interval, gained through
    % some measurement during Screen('OpenWindow')...
    ifi_duration = Screen('GetFlipInterval', w)
    
	% Run the movie animation for a fixed period of max 20 seconds.  
	movieDurationSecs=20;

    frameRate=Screen('FrameRate',screenNumber);
	if(frameRate==0)  % if MacOSX does not know the frame rate the 'FrameRate' will return 0. 
        frameRate=60; % 60 Hz is a good guess for flat-panels...
    end    

    movieDurationFrames=round(movieDurationSecs * frameRate / ifis);
	movieFrameIndices=mod(0:(movieDurationFrames-1), numFrames) + 1;

    % Switch to realtime:
    priorityLevel=MaxPriority(w);
    Priority(priorityLevel)

    % Prepare screen for animation:
    % Draw gray full-screen rectangle to clear to a defined
    % background color:
    Screen('FillRect',w, gray);

    % Show the gray background, return timestamp of flip in 'vbl'
    vbl = Screen('Flip', w);

    % Animation loop:
    for i=1:movieDurationFrames
        t1=GetSecs;
        % Draw grating for current frame:
        % Please note the new (optional) 5th parameter 'i'!
        % This specifies the rotation angle (in degree) of the texture.
        Screen('DrawTexture', w, tex(movieFrameIndices(i)), [], [], i);

        % Overdraw -- and therefore alpha-blend -- with gaussian alpha
        % mask:
        Screen('DrawTexture', w, masktex);
        
        % Show result on screen: We only want to show a new frame every
        % ifis monitor refresh intervals. Therefore we calculate a proper
        % presentation time that is '(ifis - 0.5) * ifi_duration' after the
        % time 'vbl' when the previous frame was shown.
        % This is the equivalent of WaitBlanking on old PTB:
        vbl=Screen('Flip', w, vbl + (ifis - 0.5) * ifi_duration);
        
        t1=GetSecs - t1;
        if (i>numFrames)
            tavg=tavg+t1;
        end;
        
        % We also abort on keypress...
        if KbCheck
            break;
        end;
	end;

    % Shut down realtime-mode:
    Priority(0);

    tavg=tavg / (movieDurationFrames - numFrames)

    % We're done: Close all windows and textures:
    sca;
    
catch
    %this "catch" section executes in case of an error in the "try" section
    %above.  Importantly, it closes the onscreen window if its open.
    Priority(0);
    sca;
    psychrethrow(psychlasterror);
end %try..catch..
