function [Trial_List] = SlantExperiment(Trial_List,filename,starttrial,stereoMode,screenDims) 

% -------------------------------------------------------------------------
%
%   Trial_List =
%   SlantExperiment(Trial_List,filename,starttrial,stereoMode,screenDims)
%
%   Performs the actual demo experiment with either a 2-interval 2AFC or a
%   1-interval AFC task depending on the dimensions of the input
%   Trial_List (see below).
%
%   Input parameters:
%   Trial_List  Specifies the conditions for each trial. Each row in
%               Trial-List represents a single trial, whereas each column
%               specifies the parameters for that trial as follows:
%               [1] cues used: 0 = texture only, 1 = disparity only; 2 = both
%               [2] base slant
%               [3] conflict in base slant
%               [4] comparison slant
%              ([5]) which first 0 = base slant first; 1 = comparison first
%                   2-Interval case only; For 1-interval case is left out
%               [5/6] response 0 = turned leftward; 1 = turned rightward
%
%               Depending on the number of columns the program will execute
%               either a 2-interval paradigm (6 columns) or a 1-interval
%               paradigm (5 colums)
%
%   filename    The filename in which to store the (intermediate) results
%
%   starttrial  The trial at which to start (default is 1). This parameter
%               can be used to continue the experiment at the point at
%               which it was interrupted.
%
%   stereoMode  the stereo mode to use (default is 8). See the list below
%               for the correct setting depending on the anaglyph glasses
%               you're using
%               6 == Red-Green
%               7 == Green-Red
%               8 == Red-Blue
%               9 == Blue-Red
%
%   screenDims  The physical dimensions of the monitor you are using for
%               the experiment. screenDims should contain 2 values in mm:
%               [screen width, screen height]
%
%   by Loes van Dam, 2014
%   Loes.van_Dam@uni-bielefeld.de
%
% -------------------------------------------------------------------------


if nargin < 4 || isempty(stereoMode),
    stereoMode = 8;
end
if nargin < 3 || isempty(starttrial),
    starttrial = 1;
end

% -------------------------------------------------------------------------
%   General Settings for use in PsychToolbox and open display window
% -------------------------------------------------------------------------

AssertOpenGL;                       % Abort if isn't executed on Psychtoolbox-3
InitializeMatlabOpenGL(0,0);        % setup PsychToolbox for 3D rendering support

KbName('UnifyKeyNames');            % Enable unified mode of KbName

rightKey    = KbName('RightArrow'); % setup right arrow key
leftKey     = KbName('LeftArrow');  % setup left arrow key
escapeKey   = KbName('ESCAPE');     % setup escape key to obart
spaceBar    = KbName('space');      % setup spacebar for trial start

KbCheck;                            % this loads the method for checking for button presses
GetSecs;                            % this loads the method for implementing time

screenid = max(Screen('Screens'));  % find screen for display

if nargin < 5 || isempty(screenDims),
    [screenWidth, screenHeight]=Screen('DisplaySize', screenid);
else
    screenWidth = screenDims(1);
    screenHeight = screenDims(2);
end
viewingDistance = 570.0;    % mm
viewingConditions = [screenWidth,screenHeight,viewingDistance];

%PsychImaging('PrepareConfiguration');
%[win, winRect]=PsychImaging('OpenWindow', screenid, BlackIndex(screenid), [], [], [], stereoMode);

[win, winRect]=Screen('OpenWindow', screenid, BlackIndex(screenid), [], [], [], stereoMode);

[winCenter(1), winCenter(2)] = RectCenter(winRect); % get window center (used for text display only)
winWidth = winRect(3)-winRect(1);
winHeight = winRect(4)-winRect(2);

glViewport( 0, 0, winWidth, winHeight );

clipNear = 0.1;                                     % set clipping depth for 3D depth
clipFar = 10000;
frust_w = (screenWidth  / 2.0) / viewingDistance;   % for setting the frustum
frust_h = (screenHeight / 2.0) / viewingDistance;
IOD = 60.0;                                         % Interoccular Distance (average)

ListenChar(2);                                      % prevent button presses from leaking
HideCursor;                                         % hide the cursor
    
mm2pixX = winWidth / screenWidth;                   % for converting mm to pixels
mm2pixY = winHeight / screenHeight;                 % for converting mm to pixels

Screen('BlendFunction', win, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); % enable alpha blending for antialising

if ~IsLinux
    Screen('TextFont', win, 'Arial');               % set Text Font
    Screen('TextSize', win, 24);                    % set Text Size
    Screen('TextStyle', win, 1);                    % set Text Style, e.g. 1 = bold, 2 = italic etc
end
    
% -------------------------------------------------------------------------
%   Show text and fixation dot before experiment start
% -------------------------------------------------------------------------

sizeFixDot = 2;                                     % size of the fixation dot in mm

glPushMatrix;
glTranslatef(0,-50,0);
DrawFormattedText(win, 'Ready?', 'center', 'center', [0 255 0 255]);
glPopMatrix;
Screen('FillOval', win, [], sizeFixDot * mm2pixX * [-1,-1,1,1] + [winCenter,winCenter]);
Screen('Flip', win);                                % Switch the buffers
KbWait;                                             % Wait for button press to start

% -------------------------------------------------------------------------
%   What follows is the actual stimulus loop
% -------------------------------------------------------------------------

% determine number of intervals to use in the experiment
if length(Trial_List(1,:)) == 6,
    responseID = 6;
    nrInts = 2;
else
    responseID = 5;
    nrInts = 1;
end

abort = 0;                                      % set flag to zero; will be set to one when escape is pressed
Total_Nr_Trials = length(Trial_List(:,1));
pause = 1;

for trial = starttrial:Total_Nr_Trials,
    % make a pause every 300 trials
    
    if trial==(starttrial+300*pause) && (Total_Nr_Trials-trial)>50
        pause = pause+1;
        
        glPushMatrix;
        glTranslatef(0,-50,0);
        DrawFormattedText(win, 'Please take a break - then press a key to continue', 'center', 'center', [255 255 255]);
        glPopMatrix;
        Screen('FillOval', win,[255 255 255], sizeFixDot * mm2pixX * [-1,-1,1,1] + [winCenter,winCenter]);
        Screen('Flip', win);                                % Switch the buffers
        WaitSecs(5.0);                                      % wait at leat 5 seconds (to avoid responding to previous response)
        KbWait;                                             % Wait for button press to start
        
    end
    
    whichCues = Trial_List(trial,1);            % which cues are we going to use in this trial
    
    for interval = 1:nrInts,                    % loop for presenting first or second interval
        if nrInts == 2,
            switch interval + 2*Trial_List(trial,5),                       % draw comparison or base slant first
                case {1,4},
                    alpha_tex = Trial_List(trial,2)+Trial_List(trial,3)/2; % texture defined slant base
                    alpha_dis = Trial_List(trial,2)-Trial_List(trial,3)/2; % disparity defined slant base
                case {2,3},
                    alpha_tex = Trial_List(trial,2)+Trial_List(trial,4);   % texture defined slant comparison
                    alpha_dis = Trial_List(trial,2)+Trial_List(trial,4);   % disparity defined slant comparison
            end
        else
            alpha_tex = Trial_List(trial,2)+Trial_List(trial,4)+Trial_List(trial,3)/2; % texture defined slant
            alpha_dis = Trial_List(trial,2)+Trial_List(trial,4)-Trial_List(trial,3)/2; % disparity defined slant
        end


%        stim_width = 70 + 30 * rand;            % randomly set the stimulus width to remove familiar size as a cue;
%        stim_width = 50;            % randomly set the stimulus width to remove familiar size as a cue;
        stim_width = 50 + 30 * rand;            % randomly set the stimulus width to remove familiar size as a cue;
        stim_width = 10*round(stim_width/10);
        stim_height = 50;
        stim_width_max = 80;%100;

        % -------------------------------------------------------------------------
        %   Create Texture
        % -------------------------------------------------------------------------

        Xcoordinates = -stim_width_max:10:stim_width_max;
        Ycoordinates = -stim_height:10:stim_height;
        [X,Y] = meshgrid(Xcoordinates,Ycoordinates); % create a grid
        X = X + -1.0 + 2 * rand(size(X)); % jitter the X coordinates
        Y = Y + -1.0 + 2 * rand(size(Y)); % jitter the Y coordinates

        [vx,vy] = voronoi(X(:),Y(:));   % Create vertices for a voronoi texture

        vxyID = find(((sum(abs(vx))/(2*stim_width)).^2 + (sum(abs(vy))/(2*stim_height)).^2) < 1); % select voronoi elements within elips range
        vx = vx(:,vxyID); 
        vy = vy(:,vxyID);

        vxy = [vx',vy'];                % reshape vertices for Psychtoolbox display
        vxy = vxy(:,[1,3,2,4]);
        vxy = reshape(vxy',2,length(vx)*2);

        % -------------------------------------------------------------------------
        %   Create random dots for disparity only condition
        % -------------------------------------------------------------------------

%         dot_density = 0.01;             % the dot density in mm^-2;
%         nr_dots     = ceil(dot_density * (2*stim_width) * (2*stim_height)); % the number of dots in the display
%         dot_size    = ceil(0.5*mm2pixX);% the size of a single dot in the stereo display
% 
%         dot_coordinates = [ -stim_width  + 2*stim_width *rand(1,nr_dots);...
%                             -stim_height + 2*stim_height*rand(1,nr_dots)]; % generate the random dot pattern
% 
%         dotID = find(((dot_coordinates(1,:)/stim_width).^2 + (dot_coordinates(2,:)/stim_height).^2) < 1); % select dots within elips range
%         dot_coordinates = dot_coordinates(:,dotID);
%         dot_color = [255,255,255];

% %        dot_size    = ceil(0.5*mm2pixX);% the size of a single dot in the stereo display
%         dot_size    = 1;% in mm the size of a single dot in the stereo display
%         Xcoordinates = -stim_width:dot_size:stim_width;
%         Ycoordinates = -stim_height:dot_size:stim_height;
%         [X,Y] = meshgrid(Xcoordinates,Ycoordinates); % create a grid of dots
% 
%         dot_coordinates = [ X(:)';...
%                             Y(:)']; % generate the random dot pattern
% 
%         dotID = find(((dot_coordinates(1,:)/stim_width).^2 + (dot_coordinates(2,:)/stim_height).^2) < 1); % select dots within elips range
%         dot_coordinates = dot_coordinates(:,dotID);
% %        dot_color = round(128+128*rand(1,length(dotID)));
%         dot_color = round(64+64*rand(1,length(dotID)));
%         dot_color = (dot_color' * ones(1,3))';

        % -------------------------------------------------------------------------
        %   Create randomly oriented lines for disparity only condition
        % -------------------------------------------------------------------------

        line_density = 0.01;             % the line density in mm^-2;
        nr_lines     = ceil(line_density * (2*stim_width) * (2*stim_height)); % the number of lines in the display
        line_size    = ceil(5*mm2pixX);% the size of a single line in the stereo display

        line_coordinates = [ -stim_width  + 2*stim_width *rand(1,nr_lines);...
                             -stim_height + 2*stim_height*rand(1,nr_lines)]; % generate the random line pattern

        lineID = find(((line_coordinates(1,:)/stim_width).^2 + (line_coordinates(2,:)/stim_height).^2) < 1); % select dots within elips range
        line_coordinates = line_coordinates(:,lineID);
        line_orientations = 2*pi*rand(1,length(lineID));
                
        lineXYA = line_coordinates + line_size*[cos(line_orientations);sin(line_orientations)]/2;
        lineXYB = line_coordinates - line_size*[cos(line_orientations);sin(line_orientations)]/2;
        linecoords = [lineXYA;lineXYB];
        line_coordinates = reshape(linecoords,2,length(linecoords(1,:))*2);
        
        clear('lineXYA','lineXYB','linecoords');
        
        % -------------------------------------------------------------------------
        %   Draw for each eye separately
        % -------------------------------------------------------------------------
        Screen('Flip', win);        
        for theEye = [-1,1],
            if theEye == -1,
                Screen('SelectStereoDrawBuffer', win, 0);   % select buffer for left eye
            else
                Screen('SelectStereoDrawBuffer', win, 1);   % select buffer for right eye
            end
            if ~(theEye == 1 && whichCues == 0),            % check whether to draw right eye image (for texture only draw only left eye)
                glPushMatrix;
                glMatrixMode(GL.PROJECTION);
                glLoadIdentity;
                gluPerspective(2*atan(screenHeight/(2*viewingDistance))*180/pi,(screenWidth/screenHeight), clipNear, clipFar);
                glMatrixMode(GL.MODELVIEW);
                glLoadIdentity;
                gluLookAt(0.0,0.0,viewingDistance,...
                          0.0,0.0,0.0,...
                          0.0,1.0,0.0);

                glPushMatrix;
                if whichCues > 0,                           % check if stereo is used, if yes do horizontal scaling
                    addedDepth = 25;
                    glTranslatef(theEye*(IOD*addedDepth/(viewingDistance+addedDepth))/2, 0, 0);
                    stereoscale = 1 + theEye * IOD*tan(alpha_dis*pi/180)/(2*(viewingDistance+addedDepth));
                    glScalef(stereoscale,1.0,1.0);          % scale for disparity
                end
                if whichCues ~= 1,                          % don't draw texture for disparity only conditions
                    glRotatef(alpha_tex,0.0,1.0,0.0);       % rotate for perspective
                    Screen('DrawLines', win, vxy,[],[],[],1);
                end
                if whichCues == 1,                          % draw dots for disparity only conditions
%                    Screen('DrawDots', win, dot_coordinates,dot_size*mm2pixX,dot_color,[],0);
                    Screen('DrawLines', win, line_coordinates,[],[],[],1);
                end
                glPopMatrix;
                Screen('FillOval', win, [], sizeFixDot * [-1,-1,1,1] );
                glPopMatrix;
            end
        end

        Screen('Flip', win);            % show what we've drawn
        WaitSecs(1.5);                  % display Stimulus for 1.0 sec
        
        % -------------------------------------------------------------------------
        %   At end of 1st interval draw blank screen for interstimulus interval (ISI)
        % -------------------------------------------------------------------------

        if interval == 1,
            for theEye = [-1,1],
                if theEye == -1,
                    Screen('SelectStereoDrawBuffer', win, 0); % select buffer for left eye
                else
                    Screen('SelectStereoDrawBuffer', win, 1); % select buffer for right eye
                end
                Screen('FillOval', win, [], sizeFixDot * [-1,-1,1,1] ); % draw only fixation dot for both eyes
            end
            Screen('Flip', win);
            WaitSecs(0.3);                  % Wait for the duration of the ISI
        end
        
    end     % end of interval loop

    % -------------------------------------------------------------------------
    %   Get the response
    % -------------------------------------------------------------------------

    for theEye = [-1,1],
        if theEye == -1,
            Screen('SelectStereoDrawBuffer', win, 0);   % select buffer for left eye
        else
            Screen('SelectStereoDrawBuffer', win, 1);   % select buffer for right eye
        end
        glPushMatrix;
        glTranslatef(0,-50,0);
        if nrInts == 2,
            DrawFormattedText(win, 'Turned leftward or rightward', 'center', 'center', WhiteIndex(screenid));
        else
            DrawFormattedText(win, 'Left side or Right side nearer', 'center', 'center', WhiteIndex(screenid));
        end
        glPopMatrix;
        Screen('FillOval', win, [], sizeFixDot * mm2pixX * [-1,-1,1,1] + [winCenter,winCenter]);
    end
    Screen('Flip', win);                    % flip screen for display

    FlushEvents;                            % empty the key etc buffer
    while (1)
        [ keyIsDown, seconds, keyCode ] = KbCheck;
        if keyIsDown,
            if keyCode(escapeKey),          % escape aborts the program
                abort = 1;
                break;
            end
            if keyCode(leftKey),            % response is 2nd more left in front
                response = 0;
                break;
            end
            if keyCode(rightKey),           % response is 2nd more right in front
                response = 1;
                break;
            end
        end
    end
    if abort == 1,
        break;                              % if aborted break out of trial loop
    else
        Trial_List(trial,responseID) = response;     % store the response in our triallst
        save( filename, 'Trial_List');      % save Trial_List to mat-file
    end
    
    
end                                         % end of the trial loop

% -------------------------------------------------------------------------
%   If dataset is complete store it in a format ready to use in analysis
% -------------------------------------------------------------------------

if trial == Total_Nr_Trials,                % dataset is complete
    finfile = filename(1:(end-4));          % filename without the '.mat'

    if ~exist('FinalizedDataSets','dir'),
        mkdir('FinalizedDataSets');
    end
    
    finfile = ['FinalizedDataSets',filesep,finfile,'.txt'];
    
    if nrInts == 2,
        % the following switches the responses 0 into 1 and vice versa for trials 
        % with baseslant first. This way the responses are changed into comparison
        % more rightward responses rather than based on the interval order.
        Trial_List(Trial_List(:,5) == 0,6) = abs(Trial_List(Trial_List(:,5) == 0,6)-1);
    end

    % -------------------------------------------------------------------------
    %   Put into right format for the Analysis
    %
    %   First put the matrix in the right format for the analysis:
    %   [C-S, P(C>S), N, S, [cues on/off], [Conf added], [noise level] ]
    %
    %   since for slant-perception a different baseslant leads to differences
    %   in JND, we will treat the different baseslants as different noise
    %   conditions instead of different standard conditions
    % -------------------------------------------------------------------------

    datlst = [  Trial_List(:,[4,responseID]),...
                ones(Total_Nr_Trials,1),...
                Trial_List(:,2)*0,...
                Trial_List(:,1) == 0 | Trial_List(:,1) == 2,...
                Trial_List(:,1) == 1 | Trial_List(:,1) == 2,...
                 Trial_List(:,3)/2,...
                -Trial_List(:,3)/2,...
                Trial_List(:,2),...
                Trial_List(:,2)
                ];
    
    dlmwrite(finfile,datlst,'\t');
end



% -------------------------------------------------------------------------
%   Clean up the experiment
% -------------------------------------------------------------------------

%DrawFormattedText(win, 'Experiment Finished', 'center', 'center', WhiteIndex(screenid));
%Screen('Flip', win);    % flip screen for display
%KbWait;                 % wait for button press
Screen('CloseAll');     % close the display window
ListenChar(0);          % give keyboard function back to matlab
ShowCursor;             % show the cursor