% brsEnc
%
% Takes in an image array and converts it to a frame-buffer ready to be
% sent to the Brightside HDR display.   
%
% Usage:
%
% [lcd_image led_image] = brsEnc(image, OPTIONS)
%
% Required arguments:
%   image: An color image/image stack intended for the Brightside HDR display, with size
%          height x width x 3 x (# images).  
%
% Optional arguments:
%   Specify optional arguments using '<argument_name>',<argument_value> pairs.  
%   Possible argument names and the values expected for the argument are:
%
%  led_max:  Scalar value in the range [5,255] signifying the maximum
%            allowed LED brightness.  Defaults to 190. (-u in disp14enc)
%  led_exp:  Exponent for approximating LED response curve.  Defaults to
%            0.5. (-p)
%  exp_auto: Set to '1' to use an uncalibrated fallback exposure.  (-E)
%  exp:  Set a fixed exposure setting.  Use a scalar for absolute exposure,
%         and a string like '+5' or '-5' to use powers-of-two exposures
%         (f-stops).  (-e)
%  exp_mult: Exposure multiplier (-m)

function [lcd_image led_image] = brsEnc(image, varargin)

t_start = clock;

%% Script constants
dstsiz = [1080 1920];       % LCD Pixels
nleds = 1380;               % total # of LEDs
bltsiz = [31 89];           % LED lay-out(in rectangular lattice)
resdir = 'disp14';          % Default device data directory

gamma = .5;                 % Do not konw why .5 is used for Gamma.

%% Read in optional arguments
if mod(length(varargin),2) == 1
   disp 'Optional argument missing value'
   help brsEnc
   return
end

for i=1:length(varargin)/2
   argname = lower(varargin{i*2-1});
   value = varargin{i*2};
   switch argname
       case 'led_max' % Maximum LED drive value
           if (ledmax > 255 || ledmax < 5)
               disp 'Illegal range for led_max [5-255]'
               return
           end
           ledmax = value;
        case 'led_exp' % LED gamma exponent
           gamma = value;
       case 'exp_auto' % Turn on/off exposure stabilization 
           stabilize = value;
       case 'exp' % Set fixed exposure instead of automatically selecting one
           if (ischar(value))
               exposure = 2^eval(value);
           else
               exposure = value;
           end
       case 'exp_mult' % Multiply exposure by a fixed value
           exp_mul=value;
       otherwise
           disp 'Unknown option'
           help hdrEnc
           return
   end
end

%% Check for existance of important files

type([resdir '/descrip.txt'])
keyfiles = { 'lcdresp.dat', 'ledresp0.dat', 'ledresp.dat', 'ledord.dat' };
for i=1:length(keyfiles)
    if ~exist([resdir '/' keyfiles{i}],'file')
        disp(['Missing essential file ' resdir '/' keyfiles{i}])
        return
    end
end

%% Create response inversion lookups
% All the inverse response curve derived using Kanako's measurements.
% Load LCD response curve, calculate normalized inverse curve
lcdrespRGB = load([resdir '/lcdrespRGB.dat']);
lcdmaxR = lcdrespRGB(find(lcdrespRGB(:,1)==255),2);
lcdmaxG = lcdrespRGB(find(lcdrespRGB(:,1)==255),3);
lcdmaxB = lcdrespRGB(find(lcdrespRGB(:,1)==255),4);
lcdinvR = zeros(size(lcdrespRGB,1),2);
lcdinvG = zeros(size(lcdrespRGB,1),2);
lcdinvB = zeros(size(lcdrespRGB,1),2);
lcdinvR(:,1) = lcdrespRGB(:,2)/lcdmaxR;
lcdinvR(:,2) = lcdrespRGB(:,1)/255;
lcdinvG(:,1) = lcdrespRGB(:,3)/lcdmaxG;
lcdinvG(:,2) = lcdrespRGB(:,1)/255;
lcdinvB(:,1) = lcdrespRGB(:,4)/lcdmaxB;
lcdinvB(:,2) = lcdrespRGB(:,1)/255;

% Load LED response curve, calculate normalized inverse curve
ledresp0=load([resdir '/ledresp0.dat']);
ledmax2 = ledresp0(find(ledresp0(:,1)==255),2);
ledinv=zeros(size(ledresp0));
ledinv(:,1) = ledresp0(:,2)/ledmax2;
ledinv(:,2) = ledresp0(:,1);

%% Step1. Create properly-sized HDR original
    resized = brsResize(image,dstsiz);
    % figure; imagesc(resized); colormap(gray(256))
    
%% Step2. Create "ideal" backlight image, assuming square led lattice
    % LED gamma exponent used in DISP14 . do not know what this value 0.5 means. 
    ideal_backlight = brsGetLuminance(resized, gamma);
    % figure; imagesc(ideal_backlight); colormap(gray(256))

%% Step3. Solve for best values on hex array with cross-talk
    hexagonal_backlight = brsGetCrosstalk(ideal_backlight);
    % The original function uses convolution with neighbors.
    % hexagonal_backlight = brsGetCrosstalk2(ideal_backlight);
    % the modified version uses Least-Squares to estimate optimal(ideal)
    % backlight LED values.
    % figure; imagesc(hexagonal_backlight); colormap(gray(256))
    
%% Get maximum value to normalize output
    stabilize = 0;                              % Autoexposure setting
    blmax = max(hexagonal_backlight(:));        % Maximum backlight brightness
%    fgmax = max(max(resized(:,:,2)));          % Maximum green channel value from source
    fgmax = max(max(max(resized(:,:,:))));      % greg Ward's program uses the Green channel, but using the max will not hurt.
    exposure = 0;                               % Set fixed exposure instead of automatically selecting one
    exp_mul = 0;                                % Multiply exposure by a fixed value
    [LED_luminance_max LCD_luminance_max] = brsGetMaximumLuminance(blmax,fgmax,stabilize,exposure,exp_mul,gamma);

%% normalize backlight values        
    normalized_hexagonal_backlight = min(1,hexagonal_backlight/LED_luminance_max);
    % figure; imagesc(normalized_hexagonal_backlight); colormap(gray(256))

%% Convert backlight drive values to 0-ledmax using LED response
    ledmax=255;                                 % Maximum allowed LED drive value
    led_image = brsGetLEDImage(normalized_hexagonal_backlight,ledinv,ledmax );
    % figure; imagesc(led_image); colormap(gray(256))
    % final LED image to match the brsPutLedImage() format.

%% Compute Backlight distribution using PSF of a single LED.
    %backlight2 = brsGetBacklightImage(normalized_hexagonal_backlight);
    backlight2 = brsGetBacklightImage2(normalized_hexagonal_backlight);
    % figure; imagesc(backlight2); colormap(gray(256))
    % backlight2 is the image at the spatial resolution of the LCD [1080
    % 1920] from the hexagonal resolution [31 89]

%% Computer LCD front image. XXX color correction factors added for yellow LED cast
    lcd_image = brsGetLCDImage(resized,backlight2,dstsiz,LCD_luminance_max,lcdinvR,lcdinvG,lcdinvB );
    % figure; imagesc(lcd_image); colormap(gray(256))

%% Done - display elapsed time
t_end = clock;
disp(sprintf('Encoding Done succesfully - elapsed time: %.2f seconds',etime(t_end,t_start)));
%save hdrEnc;

end
