function [vertices, faces, facevertexcdata, renderer] = u3d_pre_surface(ax)
%U3D_PRE_SURFACE    Preprocess surface output to u3d.
%    U3D_PRE generates the input for the MESH_TO_LATEX function from
%    Alexandre Gramfort from your surface-graphs. The surface graphs 3d-model can be
%    displayed in u3d - format in pdf or if you don't delete the u3d-files
%    which are generated by MESH_TO_LATEX you can use deepview from
%    righthemisphere(http://www.righthemisphere.com/products/client-products/deep-view) 
%    to embed the modell in Microsoft-Office products (Word, Excel, PowerPoint). 
%
% usage 
%   [vertices, faces, facevertexcdata] = U3D_PRE_SURFACE
%   [vertices, faces, facevertexcdata] = U3D_PRE_SURFACE(h)
%
% optional input
%   ax = axes object handle
%
% output
%   vertices = row vectors of point positions, as row cell array
%              for multiple surfaces
%            = {1 x #surfaces}
%            = {[#vertices x 3], ... }
%   faces = for each surface triangle face, indices of its 3 vertices,
%           these indices refer to the columns of matrix vertices,
%           as row cell array for multiple surfaces
%         = {1 x #surfaces}
%         = {[#faces x 3], ... }
%   facevertexcdata = RGB color information at each vertex,
%                     as row cell array for multiple surfaces
%                   = {1 x #surfaces}
%                   = {[#vertices x 3], ... }
%
% See also fig2idtf, u3d_pre_line, u3d_pre_patch, u3d_pre_quivergroup,
%          u3d_pre_contourgroup.
%
% File:      u3d_pre_surface.m
% Original Author: Sven Koerner, koerner(underline)sven(add)gmx.de
% Author:    Ioannis Filippidis, jfilippidis@gmail.com (added support for multiple surfaces)
% Date:      2012.06.10 - 
% Language:  MATLAB R2012a
% Purpose:   preprocess surface children of axes for u3d export
% Copyright:
%
% License to use and modify this code is granted freely to all interested,
% as long as the original author is referenced and attributed as such.
% The original author maintains the right to be solely associated with this work.

%% input
if nargin < 1
    sh = findobj('type', 'surface');
else
    objs = get(ax, 'Children');
    sh = findobj(objs, 'type', 'surface');
end

if isempty(sh)
    disp('No surfaces found.');
    vertices            = [];
    faces               = [];
    facevertexcdata     = [];
    renderer = [];
    return
end

%% process each surface
N = size(sh, 1); % number of surfaces
vertices = cell(1, N);
faces = cell(1, N);
facevertexcdata = cell(1, N);
renderer = cell(1, N);
for i=1:N
    disp(['     Preprocessing surface No.', num2str(i) ] );
    h = sh(i, 1);
    
    [v, f, fvx, r] = single_surf_preprocessor(h);
    
    vertices{1, i} = v;
    faces{1, i} = f;
    facevertexcdata{1, i} = fvx;
    renderer{1, i} = r;
end

function [vertices, faces, facevertexcdata, renderer] = single_surf_preprocessor(h)
%% shading -> renderer in adobe reader
edgecolor = get(h, 'EdgeColor');
if strcmp(edgecolor, 'none')
    renderer = 'Solid';
else
    renderer = 'SolidWireframe';
end

%% get defined data-points
X = get(h, 'XData');
Y = get(h, 'YData');
Z = get(h, 'ZData');

realcolor = get_surf_color(h);

[faces, vertices, facevertexcdata] = surf2patch(X, Y, Z, realcolor, 'triangles');

%% remove nan vertices and faces
% remove faces using at least one vertex with some nan coordinate
nan_vertices = any(isnan(vertices), 2);
nan_faces = nan_vertices(faces);
nan_faces = any(nan_faces, 2);
nan_faces = ~nan_faces;
faces = faces(nan_faces, :);

% vertices with nan are not used anymore
% just make them contain numbers
% DO NOT REMOVE them! This would destroy face indexing
vertices(isnan(vertices) ) = 0;
vertices = vertices.';

%% surface concatenation (obsolete - although it reduces file size)
%{
[n, m] = size(X, 1);
Vi = n *m; % number of vertices
Fi = 2 *(n-1) *(m -1); % number of faces, due to wraping (closing of the surface)
disp(['     Object Vertex # = ', num2str(Vi) ] )
disp(['     Object Face # = ', num2str(Fi) ] )

tempfvc.faces = tempfvc.faces +V; % shift to account for previous vertices

% append to previous
fvc.vertices = [fvc.vertices; tempfvc.vertices];
fvc.faces = [fvc.faces; tempfvc.faces];
fvc.facevertexcdata = [fvc.facevertexcdata; tempfvc.facevertexcdata];

F = size(faces, 1);
[C1, C2] = size(facevertexcdata);

V = size(fvc.vertices, 1); %V = V +Vi;

disp(['     Vertex # = ', num2str(V) ] )
disp(['     Face # = ', num2str(F) ] )
disp(['     Vertex Colors = ', num2str(C1), ' x ', num2str(C2) ] )
%}

function [realcolor] = get_surf_color(h)
% texture mapping ?
facecolor = get(h, 'FaceColor');
if strcmp(facecolor, 'texturemap')
    realcolor = [];
    return
end

% texturemapping is when CData is an image and has different size than
% XData and the number of faces, so it is not treated here yet.

%% CData
cdata = get(h, 'CData');
k = size(cdata, 3);

% true color ?
if k == 3
    disp('CData is already True Color.')
    cdata(isnan(cdata) ) = 1;
    realcolor = cdata;
    return
end

% not indexed colors ?
if k ~= 1
    error('u3dsurf:cdata', 'size(CData, 3) \notin {1, 3}')
end

%% indexed color to RGB true color
ax = get(h, 'Parent');
realcolor = scaled_ind2rgb(cdata, ax);

function [realcolor] = scaled_ind2rgb(cdata, ax)
[n, m] = size(cdata);
cdata = double(cdata);

cmap = colormap(ax);
nColors = size(cmap, 1);
[cmin, cmax] = caxis(ax);

idx = (cdata -cmin) / (cmax -cmin) *nColors;
idx = ceil(idx);
idx(idx < 1) = 1;
idx(idx > nColors) = nColors;

%% handle nans in idx
nanmask = isnan(idx);
idx(nanmask) = 1; %temporarily replace w/ a valid colormap index

%% realcolor and output
realcolor = zeros(n, m);
for i = 1:3
    c = cmap(idx, i);
    c = reshape(c, n, m);
    realcolor(:, :, i) = c;
end
