function MandelbrotDemo % MandelbrotDemo -- GPU visualization of the fractal Mandelbrot set. % % This demo illustrates the use of "procedural textures" with Psychtoolbox. % A procedural texture is a texture that is not directly represented by an image % matrix in memory, but the image content of the texture is generated on % the fly during drawing of the texture by means of a small algorithm - a % shader. The shader implements some mathematical formula or model which is % evaluated to generate image content, or it reads content of a data % matrix and transforms it into a picture. Psychtoolbox supports both, % purely virtual textures of unlimited size that are purely algorithmically % generated, and hybrid textures where an algorithm transforms the textures % content into something to be drawn. % % The algorithm has to be implemented by a GLSL shader program - a vertex shader, % primitive shader, fragment shader or any combination of them. The shader % program is read from a file, compiled and then attached to the texture on % texture creation time. Procedural textures only work with graphics % hardware that has sufficiently advanced support for at least hardware % fragment shaders. % % This demo implements the mathematical formula for visualization of the % famous fractal Mandelbrot set in a fragment shader. The shader gets % attached to a purely virtual texture. The texture is drawn via the % standard Screen('DrawTexture') command -- your graphics processor % generates the image content of the Mandelbrot set on the fly during % drawing of the texture via evaluation of the mandelbrot formula. % Selecting a subregion (the sourceRect parameter of 'DrawTexture') allows % to zoom into a specific subregion of the Mandelbrot set. % % The implementation uses up to 150 iterations of the equation for each % drawn pixel, so it may be slow on old hardware. % % In the demo, use gentle mouse movements to scroll around in the set and % the left- right- mouse button to zoom into/out of the set. Press any key % on the keyboard to exit the demo. % % Wikipedia http://www.wikipedia.org has a nice explanation of the % Mandelbrot set under the search term "Mandelbrot set". % % The shader used for this demo is part of the "Orange book" - The guide to % the OpenGL Shading language. The code is copyright 3DLabs. See the % 3DLabs-License.txt file in the PsychDemos/OpenGLDemos/GLSLDemoShaders/ % subfolder for the license. % History: % 19.05.2007 Written (MK) % Acquire a handle to OpenGL, so we can use OpenGL commands in our code: global GL; % Make sure this is running on OpenGL Psychtoolbox: AssertOpenGL; % Choose screen with maximum id - the secondary display: screenid = max(Screen('Screens')); % Open a fullscreen onscreen window on that display, choose a background % color of 128 = gray with 50% max intensity: [win winRect]= Screen('OpenWindow', screenid, 128); % Query width and height of window: [tw, th] = Screen('WindowSize', win); % Load the shader program from source file 'MandelbrotShader.frag.txt', % compile it and get a handle to the GLSL program: MandelbrotShader = LoadGLSLProgramFromFiles([ PsychtoolboxRoot 'PsychDemos/MandelbrotShader'], 1); % Create purely virtual procedural texture. The texture has a width x % height x depth of 1 x 1 x 1 texels (the only interesting area in the % mandelbrot complex number plane). Attach the GLGL MandelbrotShader % program which defines the texture algorithmically: mandelbrottex = Screen('SetOpenGLTexture', win, [], 0, GL.TEXTURE_RECTANGLE_EXT, 1, 1, 1, MandelbrotShader); % Activate the shader and setup some fractal parameters: glUseProgram(MandelbrotShader); glUniform2f(glGetUniformLocation(MandelbrotShader, 'center'), -0.57, -0.01); glUniform1f(glGetUniformLocation(MandelbrotShader, 'zoom'), 1); % Shader set up, deactivate it: glUseProgram(0); % Set good start values for zoom factor and position: zoom = 1; srcRect = CenterRectOnPoint([-0.5 -0.5 0.5 0.5]/zoom, 0.5, 0.5); Screen('DrawTexture', win, mandelbrottex, srcRect, winRect); % Position the mouse cursor at the center of the screen: SetMouse(tw/2, th/2, win); % Show some usage info text: Screen('TextSize', win, 24); Screen('TextStyle', win, 1); DrawFormattedText(win, 'MandelbrotDemo\n\nGently move the mouse cursor to navigate in the Mandelbrot-Plane\nPress Left-/Right- mouse button to zoom in/out\n\nPress any key to quit\n\nPress mouse button to start.', 'center', 'center', [255 255 0]); % Initial flip to show help text and sync us to the retrace: Screen('Flip', win); % Wait for mouse click to start animation loop: GetClicks(win); % Sync us to retrace and flip: vbl = Screen('Flip', win); ts = vbl; count = 0; % Animation loop. Runs until any key is pressed: while ~KbCheck % Increment framecounter: count = count + 1; % Query mouse position and state: [x y buttons] = GetMouse(win); % Left mouse button pressed? if buttons(1) % Increase zoom factor: zoom = zoom + 0.01 * zoom; end % Right mouse button pressed? if buttons(2) % Decrease zoom factor: zoom = zoom - 0.01 * zoom; end % Map the current mouse pointer position to the area of the texture % that should be drawn - the area of interest in the complex number % plane: xt = (x/tw) * RectWidth(srcRect) + srcRect(RectLeft); yt = (y/th) * RectHeight(srcRect) + srcRect(RectTop); srcRect = CenterRectOnPoint([-0.5 -0.5 0.5 0.5]/zoom, xt, yt); % Draw the selected subregion srcRect of the Mandelbrot texture and % zoom it up to cover the whole window area winRect: Screen('DrawTexture', win, mandelbrottex, srcRect, winRect); % Show updated image via buffer flip at next retrace: vbl = Screen('Flip', win, vbl+0.005); end % Done. Print some runtime stats: avgfps = count / (GetSecs - ts) % Close the window, release all ressources: sca; % Done.