1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
function SimpleHDRLinuxStereoDemo(imfilename)
% SimpleHDRLinuxStereoDemo([imfilename]) - Load and show a HDR image on a compatible
% HDR stereo display setup.
%
% Press any key to terminate the demo.
%
% 'imfilename' - Optional filename of the HDR image to load. This will load
% a standard HDR demo image bundled with Matlab, if omitted, or abort if
% the default demo image is missing. Currently only '.hdr' RGBE images are
% supported.
%
% See SimpleHDRDemo for explanations. This is the same demos, but displaying
% stereoscopically on Linux + X11 via the special Linux hack enabled by the
% Linux only PsychImaging task
%
% PsychImaging('AddTask', 'General', 'UseStaticHDRHack', hdrMeta);
%
% See help PsychImaging in the 'UseStaticHDRHack' section for explanations,
% background info and setup instructions.
%
% History:
%
% 18-Dec-2020 mk Written. Derived from SimpleHDRDemo.
if ~IsLinux || IsWayland
fprintf('Sorry, this demo only works on Linux/X11, not under Wayland or other operating systems.\n');
return;
end
% Make sure we run on Psychtoolbox-3. Abort otherwise. Use unified key names for
% keyboard input across all supported operating systems. Use normalized color range,
% not the old 0-255 8 bit color convention:
PsychDefaultSetup(2);
% imfilename provided?
if nargin < 1 || isempty(imfilename)
% No: Try some default file from our bundled OpenEXR sample images:
imfilename = [PsychtoolboxRoot 'PsychDemos/OpenEXRImages/Desk.exr'];
end
% Does imfilename exist?
if ~exist(imfilename, 'file')
error('Specified HDR image file does not exist under path %s.', imfilename);
end
% Read HDR file, abort on error. Must be in a file format recognized by HDRRead:
[img, info] = HDRRead(imfilename);
% Show metadata:
disp(info);
% Find screen to display on: We choose the one with the highest number,
% assuming this is the HDR display:
screenid = max(Screen('Screens'));
% Set a cleanup function: If the variable 'canary' goes out of scope due to
% script termination (error or user abort), call "sca" which will close the display:
canary = onCleanup(@sca);
% Define static HDR metadata to use for the whole duration of this demo session:
hdrMeta.MetadataType = 0;
hdrMeta.MinLuminance = 0.050;
hdrMeta.MaxLuminance = 600;
hdrMeta.ColorGamut = [0.6400, 0.3000, 0.1500, 0.3127 ; 0.3300, 0.6000, 0.0600, 0.3290];
% Convert img from its source colorspace to the display colorspace defined for
% the mastering display. info.ColorGamut is the color gamut parsed from the
% image file, or a default color gamut as mandated by the image file format
% spec for the image file:
[foo, img] = ConvertRGBSourceToRGBTargetColorSpace(info.ColorGamut, hdrMeta.ColorGamut, img);
switch info.format
case 'rgbe'
% HACK: Multiply by 179.0 as a crude approximation of Radiance
% units to nits: This is not strictly correct, but will do to get a
% nice enough picture for demo purpose. See 'help HDRRead' for the
% motivation for the 179 multiplicator for Radiance images:
% This is always RGB, no alpha channel to deal with.
img = img * 179;
case 'openexr'
% Known scaling factor for scaling pixel values into units of nits?
% Otherwise it is best to just leave it as is:
if info.sampleToNits > 0
% Only scale RGB channels, not the alpha channel.
img(:,:,1:3) = img(:,:,1:3) * info.sampleToNits;
end
otherwise
error('Unknown image format. Do not know how to convert into units of Nits.');
end
% Compute and assign maximum and max mean luminance of the image:
[maxFALL, maxCLL] = ComputeHDRStaticMetadataType1ContentLightLevels(img);
hdrMeta.MaxFrameAverageLightLevel = maxFALL;
hdrMeta.MaxContentLightLevel = maxCLL;
% Open a double-buffered fullscreen onscreen stereo window in HDR mode on the HDR
% display, with black background color. Color values will be specified in
% units of nits, the display is done according to HDR10 standard, ie.
% Color space is BT2020, SMPTE ST-2084 PQ encoding is used to drive the
% display, output color signals have 10 bpc precision. Use a dual-display or
% side-by-side single display stereo configuration:
PsychImaging('PrepareConfiguration');
PsychImaging('AddTask', 'General', 'EnableHDR', 'Nits', 'HDR10'); %, 'Dummy');
PsychImaging('AddTask', 'General', 'UseStaticHDRHack', hdrMeta);
win = PsychImaging('OpenWindow', screenid, 0, [], [], [], 4);
HideCursor(win);
% Build a 32 bpc single-precision float texture from the image
% array by setting the (optional) 'floatprecision' flag to 2.
% texid = Screen('MakeTexture', win, img, [], [], 2);
%
% Or simply don't, because the 'floatprecision' flag defaults to 2
% in HDR display mode anyway if omitted, for your convenience:
texid = Screen('MakeTexture', win, img);
% Some variable rotation angle for the image, for some simplistic animation:
rotAngle = 0;
% Some framecounter for stats:
framecounter = 0;
% Initial Flip to sync us to retrace:
vbl = Screen('Flip', win);
tstart = vbl;
% Animation loop: Show a rotating HDR image, until key press:
while ~KbCheck
% Draw left eye stim:
Screen('SelectStereoDrawBuffer', win, 0);
% Draw our HDR texture at specified rotation angle, centered in the window:
Screen('DrawTexture', win, texid, [], [], rotAngle);
% Draw some 2D filled oval, with a bounding box of [left,top,right,bottom]
% = [500 500 600 600], and a color value of [R, G, B] = [300 nits, 300 nits, 0 nits],
% ie. a yellow oval with 300 nits:
Screen('FillOval', win, [300 300 0], [500 500 600 600]);
% Draw right eye stim:
Screen('SelectStereoDrawBuffer', win, 1);
% Draw our HDR texture at specified rotation angle, centered in the window:
Screen('DrawTexture', win, texid, [], [], rotAngle);
% Draw some 2D filled oval, with a bounding box of [left,top,right,bottom]
% = [520 500 620 600], and a color value of [R, G, B] = [300 nits, 300 nits, 0 nits],
% ie. a yellow oval with 300 nits. This is shifted 40 pixels to the left, wrt.
% the otherwise identical left-eye stimulus to create a teeny tiny bit of stereo:
Screen('FillOval', win, [300 300 0], [460 500 560 600]);
% Show updated HDR framebuffer at next vertical retrace:
vbl = Screen('Flip', win, vbl);
% Increase rotation angle to make it a bit more interesting:
rotAngle = rotAngle + 0.1;
% Count our frames:
framecounter = framecounter + 1;
end
% We are done. Release all textures, close all windows, shutdown:
sca;
% Print the stats:
duration = vbl - tstart;
averagefps = framecounter / duration;
fprintf('Displayed %i stereo-frames in %f seconds, for an average framerate of %f fps.\n', framecounter, duration, averagefps);
fprintf('Bye bye!\n');
|