function DrawMirroredTextDemo(upsideDown) % DrawMirroredTextDemo([upsideDown=0]) % _______________________________________________________ % % Trivial example of drawing mirrored text. This demonstrates how to use % low-level OpenGL API functions to apply geometric transformations to % the drawn objects. % % Will draw a text string, once in normal orientation, and once mirrored. % The mirrored text is either mirrored left<->right, or upside down if you % set the optional 'upsideDown' flag to 1. At each key press, the text % will be redrawn at an increasing size, until after a couple of redraws % the demo will end. % % The demo also draws a bounding box around the text string to demonstrate % how you can find out about the bounds of a text string via % Screen('TextBounds'). % % The mirroring is implemented by first defining a geomtric transformation % which will apply to all further drawn shapes and text strings. Then the % text string is drawn via Screen('DrawText') -- thereby affected by the % geometric transform. Then the transform is undone to "normal". % % How does this work? % % 1. The command Screen('glPushMatrix'); makes a "backup copy" of the % current transformation state -- the default way of drawing. % % 2. The command Screen('glTranslate', w, xc, yc, 0); translates the % origin of the coordinate system (which is normally located at the % upper-left corner of the screen) into the geometric center of the % location of the text string. We find the center xc,yc by retrieving the % bounding box of the text string Screen('TextBounds'), then calculating % the center of that box [xc, yc]. % % 3. The Screen('glScale', w, x, y, z); will scale all further drawn % objects by a factor 'x' in x-direction (horizontal), 'y' in y-direction % (vertical), 'z' in z-direction (depths). Scaling happen with respect to % the current origin. As we just set the origin to be the center of the % text string in step 2, the object will "scale" around that point. A % value of -1 effectively switches the direction along the 'x' axis for a % horizontal flip, or along the 'y' axis for an upside down vertical flip. % Values with a magnitude other than 1 would scale the whole text up or % down in size. % % 4. The command Screen('glTranslate', w, -xc, -yc, 0); translates the % origin of the coordinate system back to the upper-left corner of the % screen. This to make sure that all coordinates provided later on are % wrt. to the usual reference frame. % % Steps 2,3 and 4 are internally merged to one mathematical transformation: % The flipping of all drawn shapes and objects around the screen position % [xc,yc] -- the center of the text string. % % 5. We Screen('DrawText') the text string --> The flipping applies. % % 6. We undo the whole transformation via Screen('glPopMatrix') thereby % restoring the original "do nothing" transformation from the backup copy % which was created in step 1. All further drawing is therbey unaffected % by the flipping, so we can draw the second copy of the text and the % bounding box. % % Besides the scaling and translation transform for moving, rescaling and % flipping drawn objects and shapes, there is also the Screen('glRotate') % transform to apply rotation around axis. % % This transformations apply to any drawing command, not only text strings! % _________________________________________________________________________ % % see also: PsychDemos % 3/8/04 awi Wrote it. % 7/13/04 awi Added comments section. % 9/8/04 awi Added Try/Catch, cosmetic changes to documentation. % 11/1/05 mk Derived from DrawSomeTextOSX. if nargin < 1 upsideDown = []; end if isempty(upsideDown) upsideDown = 0; end text = 'Hello World! QqPpYyGgJj Press key multiple times to exit.'; x = 100; y = 100; try % Choosing the display with the highest dislay number is % a best guess about where you want the stimulus displayed. screens=Screen('Screens'); screenNumber=max(screens); w=Screen('OpenWindow', screenNumber,0,[],32,2); Screen('FillRect', w, [0, 0, 0]); Screen('TextFont',w, 'Courier New'); Screen('TextStyle', w, 1); % Loop through all text sized from 20 to 80 pixels... for mysize=20:5:80 % Setup text size: Screen('TextSize',w, mysize); % Draw text 'normal' Screen('DrawText', w, text, x, y + 100, [255, 255, 255]); % Paint a green frame around it, just to demonstrate the % 'TextBounds' command: textbox = Screen('TextBounds', w, text); textbox = OffsetRect(textbox, x, y); Screen('FrameRect', w, [0, 255, 0, 255], textbox); % Setup mirror transformation for horizontal flipping: % xc, yc is the geometric center of the text. [xc, yc] = RectCenter(textbox); % Make a backup copy of the current transformation matrix for later % use/restoration of default state: Screen('glPushMatrix', w); % Translate origin into the geometric center of text: Screen('glTranslate', w, xc, yc, 0); % Apple a scaling transform which flips the diretion of x-Axis, % thereby mirroring the drawn text horizontally: if upsideDown Screen('glScale', w, 1, -1, 1); else Screen('glScale', w, -1, 1, 1); end % We need to undo the translations... Screen('glTranslate', w, -xc, -yc, 0); % The transformation is ready for mirrored drawing of text: % Draw text again, this time mirrored as it is affected by the % mirror transform that has been setup above: Screen('DrawText', w, text, x, y, [255, 255, 0]); % Restore to non-mirror mode, aka the default transformation % that you've stored on the matrix stack: Screen('glPopMatrix', w); % Now all transformations are back to normal and we can proceed % ordinarily... % Flip the display: Screen('Flip',w); % Wait for keypress: KbStrokeWait; % Next iteration... end; % Done! sca; catch %this "catch" section executes in case of an error in the "try" section %above. Importantly, it closes the onscreen window if its open. sca; psychrethrow(psychlasterror); end % try..catch