/usr/share/psychtoolbox-3/PsychDemos/ContrastModulatedNoiseTheClumsyStyleDemo.m is in psychtoolbox-3-common 3.0.9+svn2579.dfsg1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | function ContrastModulatedNoiseTheClumsyStyleDemo(noisesize, staticnoise)
% ContrastModulatedNoiseTheClumsyStyleDemo([noisesize=512] [, staticnoise=0])
%
% This demo shows how to render contrast modulated noise with old, outdated
% graphics hardware. A rectangular image with random noise of size
% 'noisesize' by 'noisesize' pixels is created, then drawn to the display.
%
% We use alpha-blending tricks to modulate the contrast of the noise in
% realtime. In this demo you can move the mouse pointer to drag around a
% "modulation disk" of 50 pixels diameter. Noise inside the disk has a
% different contrast 'fgcontrast' from the rest of the image, which has a
% contrast of 'bgcontrast' (see top of code for fgcontrast and bgcontrast).
%
% You can press the cursor left and cursor right keys to decrement or
% increment the contrast inside the disk in steps of 0.01 units. Press
% cursor up key to set the inside disk contrast equal to outside disk
% contrast. Press ESCAPE key to finish the demo.
%
% The optional 'staticnoise' flag - if set to 1 - will render a static
% noise image instead of one that changes at each frame. That's faster
% because one doesn't need to recreate the noise texture each frame.
%
% How this works? Basically we use standard Screen 2D drawing commands to
% draw a "contrast values weight map" into the alpha-channel, so the
% alpha-channel encodes contrast values between 0.0 and 1.0 in steps of
% 1/256th. Then we draw a noise texture of fixed contrast into the
% framebuffer and the alpha-blending hardware takes care of modulating the
% contrast of the drawn noise texture with the values from the
% alpha-channel.
%
% Hardware requirements: ATI Radeon 8500 or later, NVidia Geforce2 or later
% on MacOS/X. Not Intel-GMA 950 of Intel MacBook!
%
% Limitations: This demo is meant to run on outdated graphics hardware, so
% it can't make use of the Psychtoolbox imaging pipeline, which would allow
% for a very elegant, flexible and fast implementation. We use a multi-pass
% approach here to work around hardware restrictions as much as possible.
% Some of the limitations of this approach: Contrast modulation is
% restricted to 0.0 - 1.0 and accuracy is limited to 256 levels. Clamping
% of your noise matrix (has to fit in the "normal" 8 bit 256 gray level
% range) can change the noise distribution in unwanted ways. The multi-pass
% approach used here is pretty inefficient, so redraw rates are pretty low,
% e.g., max. 15 fps on a fast MacBookPro with ATI Radeon X1600.
%
% If you have recent graphics hardware (ATI Radeon X1000 or later, NVidia
% Geforce 6000 and later), take a look at ContrastModulatedNoiseTheElegantStyleDemo.m
% instead. That demo takes advantage of the imaging pipeline, greatly
% simplifying stimulus programming and lifting basically all restrictions
% of the approach presented here. Achievable redraw rates are also much
% higher that way!
% History:
% 5.9.2007 Written (MK).
% Running on PTB-3?
AssertOpenGL;
if nargin < 1
noisesize = [];
end
if isempty(noisesize)
noisesize = 512;
end
if nargin < 2
staticnoise = [];
end
if isempty(staticnoise)
staticnoise = 0;
end
bgcontrast = 0.2;
fgcontrast = 0.4;
% Assign control keys: Cursor Left and Right for increasing/decreasing
% contrast of the noise:
KbName('UnifyKeyNames');
leftArrow = KbName('LeftArrow');
rightArrow = KbName('RightArrow');
upArrow = KbName('UpArrow');
escape = KbName('ESCAPE');
% Open onscreen window on screen with maximum id: The window gets a
% background clear color of RGB==128==neutral 50% grey and a alpha-value of
% zero. The alpha channel will be used to store the ...
screenid=max(Screen('Screens'));
try
% Initialize OpenGL, but only for 2D drawing. We need this to be able
% to use the low-level OpenGL command glBlendFunc():
InitializeMatlabOpenGL([],[],1);
[win, winRect] = Screen('OpenWindow', screenid, 128);
% Create an offscreen window for noise with values >= 0:
positivenoise = Screen('OpenOffscreenWindow', win, [0 0 0 0]);
% Create an offscreen window for noise with values < 0:
negativenoise = Screen('OpenOffscreenWindow', win, [0 0 0 0]);
i=0;
tonset = [];
% Initially place the mouse cursor at the center of the window:
[x, y] = RectCenter(winRect);
SetMouse(x, y, win);
HideCursor;
% Main stimulus drawing loop:
while 1
% Increment framecounter:
i=i+1;
% Query mouse position: This will be the center of our "modulation disk":
[x, y] = GetMouse(win);
% Compute target rectangle for our drawn modulation oval:
dstrect = CenterRectOnPoint([0 0 50 50], x, y);
% If staticnoise is set to 1 then we only generate the noise
% textures once -- This way we can disentangle "noise creation
% overhead" from actual drawing overhead:
if i==1 | staticnoise == 0
% Generate a noisesize x noisesize matrix of random noise, mean zero,
% stddev 1.0:
noisematrix = randn(noisesize) * 255;
% The following conversion has a problem: We map the magnitudes
% between zero and 1.0 to 0-255. Values outside that magnitude
% range will create pixel values > 255 and will be therefore
% wrapped around (remapped) to the range 0-255. This will alter
% the noise distribution considerably! Alternatively one could
% generate noise with a way smaller standard deviation to avoid
% this in most cases...
% Convert to texture which only contains the positive values:
positivenoisetex = Screen('MakeTexture', win, max(0, noisematrix));
% Convert to texture which only contains the negative values, but
% mirrored to become positive values:
negativenoisetex = Screen('MakeTexture', win, -1 * min(0, noisematrix));
end
% Enable standard additive blending:
glBlendEquation(GL.FUNC_ADD);
% We use the alpha-channels of the offscreen windows to define the
% modulationgains for the noise. Example: Alpha value zero = contrast
% zero. Alpha value 255 = Maximum contrast of 1.0, Alpha value 128 =
% Contrast of 128/255 == about 50% or 0.5.
% First we need to initialize the whole windows alpha-channel with the
% default "background" contrast bgcontrast. We disable alpha-blending
% for this purpose:
Screen('Blendfunction', positivenoise, GL_ONE, GL_ZERO);
Screen('FillRect', positivenoise, [0 0 0 255 * bgcontrast]);
% Now we overdraw some regions of the alpha-channel with our "modulation"
% image - a image that contains alpha values which encode a different
% contrast 'fgcontrast'. After this drawing op, the alpha-channel will
% contain the final "contrast modulation landscape":
%Screen('DrawDots', positivenoise, [x y], 50, [0 0 0 255 * fgcontrast], [], 1);
Screen('FillOval', positivenoise, [0 0 0 255 * fgcontrast], dstrect);
% Now we draw the positivenoise texture and use alpha-blending of
% the drawn noise color pixels with the destination alpha-channel,
% thereby multiplying the incoming color values with the stored
% alpha values -- effectively a contrast modulation:
Screen('Blendfunction', positivenoise, GL_DST_ALPHA, GL_ZERO);
% The extra zero at the end forcefully disables bilinear filtering. This is
% not strictly neccessary on correctly working hardware, but an extra
% precaution to make sure that the noise values are blitted
% one-to-one into the offscreen window:
Screen('DrawTexture', positivenoise, positivenoisetex, [], [], [], 0);
% Now the positivenoise offscreen window contains a correctly
% contrast modulated noise image - but only the positive noise
% values. We now repeat the procedure for the negative noise
% values:
Screen('Blendfunction', negativenoise, GL_ONE, GL_ZERO);
Screen('FillRect', negativenoise, [0 0 0 255 * bgcontrast]);
% Now we overdraw some regions of the alpha-channel with our "modulation"
% image - a image that contains alpha values which encode a different
% contrast 'fgcontrast'. After this drawing op, the alpha-channel will
% contain the final "contrast modulation landscape":
% Screen('DrawDots', negativenoise, [x y], 50, [0 0 0 255 * fgcontrast], [], 1);
Screen('FillOval', negativenoise, [0 0 0 255 * fgcontrast], dstrect);
% Now we draw the positivenoise texture and use alpha-blending of
% the drawn noise color pixels with the destination alpha-channel,
% thereby multiplying the incoming color values with the stored
% alpha values -- effectively a contrast modulation:
Screen('Blendfunction', negativenoise, GL_DST_ALPHA, GL_ZERO);
% The extra zero at the end forcefully disables bilinear filtering. This is
% not strictly neccessary on correctly working hardware, but an extra
% precaution to make sure that the noise values are blitted
% one-to-one into the offscreen window:
Screen('DrawTexture', negativenoise, negativenoisetex, [], [], [], 0);
% Now for the compositing of the final image into our onscreen
% windows backbuffer: First draw positive noise image in additive
% mode -- adding contrast modulated positive noise pixels to the
% grey 50% background color:
Screen('Blendfunction', win, GL_ONE, GL_ONE);
Screen('DrawTexture', win, positivenoise, [], [], [], 0);
% Now draw negative noise image in subtractive mode: Subtract noise
% pixels from the current content of the framebuffer:
glBlendEquation(GL.FUNC_REVERSE_SUBTRACT);
Screen('DrawTexture', win, negativenoise, [], [], [], 0);
% Enable standard additive blending:
glBlendEquation(GL.FUNC_ADD);
% At this point, the final image should be ready in the backbuffer
% of our onscreen window. Ready to flip it onscreen:
tonset(i) = Screen('Flip', win);
% Release our noise textures in the dynamic-noise case.
if ~staticnoise
Screen('Close', positivenoisetex);
Screen('Close', negativenoisetex);
end
% Keyboard queries:
[isdown secs keycode] = KbCheck;
if isdown
if keycode(escape)
break;
end
if keycode(leftArrow)
fgcontrast = max(0, fgcontrast - 0.01);
end
if keycode(rightArrow)
fgcontrast = min(1, fgcontrast + 0.01);
end
if keycode(upArrow)
fgcontrast = bgcontrast;
end
end
% Ready. Next loop iteration:
end
% Done. Close screen and finish:
ShowCursor;
Screen('CloseAll');
% Compute avg. computation time for redraw:
avgredrawtime = mean(diff(tonset)) * 1000
plot(diff(tonset));
% Done.
return;
catch
% Error. Close screen, show cursor, rethrow error:
ShowCursor;
Screen('CloseAll');
psychrethrow(psychlasterror);
end
|