function [out] = spm_eeg_render(m,options)
% Visualisation routine for the cortical surface
% FORMAT [out] = spm_eeg_render(m,options)
%
% INPUT:
% m       - patch structure (with fields .faces et .vertices)
%           or GIFTI format filename
% options - structure with optional fields:
%           .texture      - texture to be projected onto the mesh
%           .clusters     - cortical parcellation (cell variable containing
%                           the vertex indices of each cluster) 
%           .clustersName - name of the clusters
%           .figname      - name to be given to the figure
%           .ParentAxes   - handle of the axes within which the mesh should
%                           be displayed
%           .hfig         - handle of existing figure. If this option is
%                           provided, then spm_eeg_render adds the (textured)
%                           mesh to the figure hfig, and a control for its
%                           transparency.
%
% OUTPUT:
% out     - structure with fields:
%           .hfra    - frame structure for movie building
%           .handles - structure containing the handles of the created
%                      uicontrols and mesh objects
%           .m       - the structure used to create the mesh.
%__________________________________________________________________________
%
% This function is a visualisation routine, mainly for texture and
% clustering on the cortical surface.
% NB: The texture and the clusters cannot be visualised at the same time.
%__________________________________________________________________________

% Jean Daunizeau
% Copyright (C) 2008-2022 Wellcome Centre for Human Neuroimaging


%----------------------------------------------------------------------%
%------------- Common features for any visualisation ------------------%
%----------------------------------------------------------------------%

% Check mesh format
try
    if ~isstruct(m)
        m = export(gifti(m),'patch');
    end
catch
    if ischar(m), fprintf('File: %s\n',m); end
    error('Unknown mesh format.')
end


% Default options
handles.fi = figure(...
    'visible','off',...
    'color',ones(1,3),...
    'NumberTitle','Off',...
    'Name','Mesh visualisation',...
    'tag','spm_eeg_render');
ns = 0;
texture = 'none';
clusters = 'none';
subplotBIN = 0;
addMesh = 0;
tag = '';
visible = 'on';
ParentAxes = axes('parent',handles.fi);
try, options; catch, options = [];end
% Now get options
if ~isempty(options)
    % get texture if provided
    try texture = options.texture;end
    % get ParentAxes
    try ParentAxes = options.ParentAxes;end
    % get tag
    try tag = options.tag;end
    % get flag for visibility: useful for displaying all objects at once
    try visible = options.visible;end
    % get custers if provided
    try
        clusters = options.clusters;
        IND = zeros(1,length(m.vertices));
        K = length(clusters);
        for k = 1:K
            IND(clusters{k}) = k+1./K;
        end
        texture = IND';
    end
    % get figname if provided
    try
        set(handles.fi,'NumberTitle','Off','Name',options.figname);
    end
    % get figure handle (should be parent of ParentAxes)
    try
        figure(options.hfig)
        if isempty(ParentAxes)
            ParentAxes = axes('parent',options.hfig,...
                'nextplot','add');
        end
        close(handles.fi);
        handles.fi = options.hfig;
        addMesh = 1;
        try % get number of transparency sliders in current figure...
            hh=get(handles.fi,'children');
            ns=length(findobj(hh,'userdata','tag_UIC_transparency'));
        catch
            ns=1;
        end
    end
    
end

handles.ParentAxes = ParentAxes;
oldRenderer = get(handles.fi,'renderer');
try
    if ismac
        set(handles.fi,'renderer','zbuffer');
    else
        set(handles.fi,'renderer','OpenGL');
    end
catch
    set(handles.fi,'renderer','OpenGL');
end

% Plot mesh and texture/clusters
if isequal(texture,'none')
    figure(handles.fi)
    handles.p = patch(m,...
        'facecolor', [.5 .5 .5], 'EdgeColor', 'none',...
        'FaceLighting','gouraud',...
        'parent',ParentAxes,...
        'userdata',oldRenderer,...
        'visible',visible,...
        'tag',tag);
else
    texture = texture(:);
    figure(handles.fi)
    if isequal(length(texture),length(m.vertices))
        handles.p = patch(m,...
            'facevertexcdata',texture,...
            'facecolor','interp',...
            'EdgeColor', 'none',...
            'FaceLighting','gouraud',...
            'parent',ParentAxes,...
            'userdata',oldRenderer,...
            'visible',visible,...
            'tag',tag,...
            'deleteFcn',@doDelMesh);
        col = colormap(ParentAxes,jet(256));
        udd.tex = texture;
        udd.cax = caxis(ParentAxes);
    else
        texture = 'none';
        disp('Warning: size of texture does not match number of vertices!')
        handles.p = patch(m,'facecolor', [.5 .5 .5], 'EdgeColor', 'none',...
            'parent',ParentAxes,...
            'userdata',oldRenderer,...
            'visible',visible,...
            'tag',tag,...
            'deleteFcn',@doDelMesh);
    end
end


daspect(ParentAxes,[1 1 1]);
axis(ParentAxes,'tight');
axis(ParentAxes,'off')
try,camva(ParentAxes,'auto');end
set(ParentAxes,'view',[25,45]);

% build internal userdata structure
udd.p = handles.p;


%----------------------------------------------------------------------%
%---------------------- GUI tools and buttons -------------------------%
%----------------------------------------------------------------------%


% Transparency sliders
pos = [20 100 20 245];
pos(1) = pos(1) + ns.*25;
handles.transp = uicontrol(handles.fi,...
    'style','slider',...
    'position',pos,...
    'min',0,...
    'max',1,...
    'value',1,...
    'sliderstep',[0.01 0.05],...
    'userdata',handles.p,...
    'tooltipstring',['mesh #',num2str(ns+1),' transparency control'],...
    'callback',{@doTransp},...
    'BusyAction','cancel',...
    'Interruptible','off',...
    'visible',visible,...
    'tag',tag);
set(handles.transp,'units','normalized')
handles.tag = uicontrol(handles.fi,...
    'style','text',...
    'visible','off',...
    'tag',tag,...
    'userdata','tag_UIC_transparency');

udd.transp = handles.transp;


% Clustering buttons and popup menu
if ~isequal(clusters,'none')
    if subplotBIN
        subplot(2,1,1)
    end
%     set(p,'FaceColor','flat');
    col=lines;
    nc = floor(256./K);
    col = [repmat([0.8157 0.6666 0.5762],nc/2,1);...
        kron(col(1:K,:),ones(nc,1))];
    if K > 1
        col(end-nc/2:end,:) = [];
    end
    colormap(ParentAxes,col);
    tex = zeros(length(m.vertices),length(clusters)+1);
    tex(:,1) = texture;
    string = cell(length(clusters)+1,1);
    string{1} = 'all clusters';
    for i = 1:length(clusters)
        if ~isfield(options,'clustersName')
            string{i+1} = ['cluster ',num2str(i)];
        else
            string{i+1} = options.clustersName{i};
        end
        tex(clusters{i},i+1) = 1;
    end
    udd.tex = tex;
    udd.tex0 = tex;
    udd.p = handles.p;
    udd.col = col;
    udd.nc = length(clusters);
    handles.pop = uicontrol(handles.fi,...
        'style','popupmenu',...
        'position',[20 20 100 40],...
        'string',string,...
        'callback',{@doSelectCluster},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'visible',visible,'tag',tag);
    set(handles.pop,'units','normalized')
    handles.sli = uicontrol(handles.fi,...
        'style','slider',...
        'position',[50 10 30 20],'max',udd.nc,...
        'sliderstep',[1./(udd.nc+0) 1./(udd.nc+0)],...
        'callback',{@doSwitch2nextCluster},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'visible',visible,'tag',tag);
    set(handles.sli,'units','normalized')
    udd.pop = handles.pop;
    udd.sli = handles.sli;
    set(handles.pop,'userdata',udd);
    set(handles.sli,'userdata',udd);
end

% Texture thresholding sliders
if  ~isequal(texture,'none') && isequal(clusters,'none')
    if subplotBIN
        subplot(2,1,1)
    end
    udd.tex0 = texture;
    udd.col = col;
    handles.hc = colorbar('peer',ParentAxes);
    set(handles.hc,'visible',visible)
    increment = 0.01;
    % right slider
    handles.s1 = uicontrol(handles.fi,...
        'style','slider',...
        'position',[440 28    20   380],...
        'min',0,'max',length(udd.col),'value',0,...
        'sliderstep',[increment increment],...
        'tooltipstring','texture thresholding control',...
        'callback',{@doThresh},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'visible',visible,'tag',tag);
    set(handles.s1,'units','normalized')
    udd.s1 = handles.s1;
    % left slider
    handles.s2 = uicontrol(handles.fi,...
        'style','slider',...
        'position',[420 28    20   380],...
        'min',1,'max',length(udd.col),...
        'value',length(udd.col),...
        'sliderstep',[increment increment],...
        'tooltipstring','texture thresholding control',...
        'callback',{@doThresh},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'visible',visible,'tag',tag);
    set(handles.s2,'units','normalized')
    udd.s2 = handles.s2;
    set(handles.s1,'userdata',udd);
    set(handles.s2,'userdata',udd);
end



set(handles.fi,'visible','on');
drawnow
% if ~addMesh
    try,camlight;end
% end

%cameratoolbar(handles.fi,'setmode','orbit')

out.hfra = getframe(gcf);
out.handles = handles;
out.m = m;

%--------- subfunctions : BUTTONS CALLBACKS ------------%


function doDelMesh(btn,evd)
renderer=get(btn,'userdata');
set(gcf,'renderer',renderer);

function doTransp(btn,evd)
v00=get(btn,'value');
p00=get(btn,'userdata');
set(p00,'facealpha',v00);


function doThresh(btn,evd)
udd00 = get(btn,'userdata');
ind00 = round(get(udd00.s1,'value'));
ind200 = round(get(udd00.s2,'value'));
if(ind200>ind00)
    udd00.col(1:ind00,:)=0.5*ones(ind00,3);
    udd00.col(ind200+1:end,:)=0.5*ones(size(udd00.col(ind200+1:end,:)));
else
    udd00.col(ind200:ind00,:)=0.5*ones(size(udd00.col(ind200:ind00,:)));
end
colormap(udd00.col);
udd00.cax = caxis;


function doSelectCluster(btn,evd)
udd00 = get(btn,'userdata');
ind00=get(gcbo,'value');
set(udd00.sli,'value',ind00-1);
set(udd00.p,'facevertexcdata',udd00.tex(:,ind00));
if ind00 == 1
    colormap(udd00.col);
else
    col00 = colormap(jet);
    col00(1:end/2,:)=0.5*ones(size(col00(1:end/2,:)));
    colormap(col00);
end
udd00.cax = caxis;


function doSwitch2nextCluster(btn,evd)
v00=get(btn,'value')+1;
udd00=get(gcbo,'userdata');
ind00=min([v00 udd00.nc+1]);
set(udd00.pop,'value',ind00);
set(udd00.p,'facevertexcdata',udd00.tex(:,ind00));
if ind00 == 1
    colormap(udd00.col);
else
    col00 = colormap(jet);
    col00(1:end/2,:)=0.5;
    colormap(col00);
end
udd00.cax = caxis;
