function remapCLUTId = PsychHelperCreateRemapCLUT(cmd, arg1, arg2) % remapCLUTId = PsychHelperCreateRemapCLUT(cmd, arg); % % Helper function for Psychtoolbox imaging pipeline, called by % PsychImaging(), not meant to be called by normal user code! % % If 'cmd' command code is zero, then: % % Build a 3 rows by arg1 texels RGBA8 lookup texture for mapping of RGB % pixel values in range 0 to (arg-1) to RGBA8 framebuffer pixels. This % texture is used as CLUT texture for the % RGBMultiLUTLookupCombine_FormattingShader.frag.txt in the image % processing chains of the imaging pipeline. If arg2 is set to 1 instead of % zero, a 32 bpc float texture is used instead of 8 bpc integer. % % If 'cmd' command code is 1, then the clut texture with id arg1 is updated % with the content of clut table arg2. % % History: % 03.04.2011 Written (MK). % 22.11.2015 Fix uninitialized mem bug, that luckily never caused a crash. % Init with an identity mapping linear ramp instead of all zeros. (MK) % This routine assumes that a mogl GL context is properly set up: global GL; % Keep our working lut buffers persistent, for speedup during runtime: persistent rlut; persistent glut; persistent blut; if cmd == 1 % New gamma table received from Screen()'s 'LoadNormalizedGammatable' % command. Need to update our clut texture, so this applies during next % execution of Screen('Flip'): % Update lookup table: 3 LUT's (Red,Green,Blue) with nslots slots with 4 % output color components RGBA8 per entry, ie., a 32 bpp value: nslots = size(arg2, 1); % Update red, green and blue luts. Assignment needs to preserve % single() format aka GL.FLOAT: rlut(1,:) = single(arg2(:,1)); glut(2,:) = single(arg2(:,2)); blut(3,:) = single(arg2(:,3)); % Build final clut memory buffer for texture update: clut = [ rlut(:) ; glut(:) ; blut(:) ]; % Bind clut texture for update: remapCLUTId = arg1; glActiveTexture(GL.TEXTURE1_ARB); glBindTexture(GL.TEXTURE_RECTANGLE_EXT, remapCLUTId); glTexSubImage2D(GL.TEXTURE_RECTANGLE_EXT, 0, 0, 0, nslots, 3, GL.RGBA, GL.FLOAT, clut); glBindTexture(GL.TEXTURE_RECTANGLE_EXT, 0); glActiveTexture(GL.TEXTURE0_ARB); % Ready. return; end if cmd == 0 % Build initial clut texture during init call from PsychImaging(): nslots = arg1; % Preinit our lut arrays, so we save (re-)allocation time in the % realtime path for command code 1: rlut = single(zeros(4, nslots)); glut = single(zeros(4, nslots)); blut = single(zeros(4, nslots)); % Build final clut memory buffer for texture update: clut = [ rlut(:) ; glut(:) ; blut(:) ]; % High precision > 8 bpc clut requested? internalFormat = GL.RGBA; if arg2 > 0 % Yes. High precision supported? win = Screen('GetOpenGLDrawMode'); winfo = Screen('GetWindowInfo', win); if winfo.GLSupportsTexturesUpToBpc >= 32 % Yes: Use full 32 bits single precision rgba: internalFormat = GL.RGBA_FLOAT32_APPLE; fprintf('EnableCLUTMapping: Using a 32 bit float CLUT -> 23 bits effective linear mapping precision per color channel.\n'); else % No: Stick to 8 bpc and warn user: fprintf('EnableCLUTMapping: ERROR! High precision CLUT requested, but hardware does not support this!\n'); fprintf('EnableCLUTMapping: Aborting. Use different hardware or fix your scripts PsychImaging(...''EnableCLUTMapping'' ...); function.'); error('EnableCLUTMapping: Aborting. Use different hardware or fix your scripts PsychImaging(...''EnableCLUTMapping'' ...); function.'); end end % Create and setup texture with arg1 slots: remapCLUTId = glGenTextures(1); glActiveTexture(GL.TEXTURE1_ARB); glBindTexture(GL.TEXTURE_RECTANGLE_EXT, remapCLUTId); glTexImage2D(GL.TEXTURE_RECTANGLE_EXT, 0, internalFormat, nslots, 3, 0, GL.RGBA, GL.FLOAT, clut); glBindTexture(GL.TEXTURE_RECTANGLE_EXT, 0); glActiveTexture(GL.TEXTURE0_ARB); % Self-Call to init to a linear identity ramp: identity = zeros(nslots, 3); for i = 0:nslots-1 identity(i+1, :) = [i, i, i] / (nslots - 1); end PsychHelperCreateRemapCLUT(1, remapCLUTId, identity); return; end error('PsychHelperCreateRemapCLUT: Invalid/Unknown command code specified!'); end