This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Twisty Bulge Project Submitted by

This is a small program I wrote which implements a nice effect reminiscent of the art of Vasarely. This picture shows four shots from the program. It's a square grid which twists and bulges with time. Lots of screensavers are built on this code and it's a nice effect to add to your demos.
The Algorithm:
The idea is to consider points inside a square of side 2, and to distort those that lie inside a unit circle ( the sums of squares of the x and y coordinates are not greater than unity ). This distortion takes two forms, twist and bulge.
Firstly, each point inside the unit circle is put into the form (rCosA, rSinA) where A is the angle made by that point with the positive x-acis, adn r <=1 is its distance from the center. It it then moved to position r^pCosA, r^pSinA for some value p.
Secondly, the point is rotated by a further angle (1-r)*rotation.
This is done for every intersection on the grid. I've added in texture mapping and a couple of options,
Key: t - toggle texture mapping
Key: l - lines only
Key: Space - toggle between the Twist vs Bulge
It's seen in all kinds of demos I hope you find it useful.
Regards,
Francis
mainflake@cornflakezone.com
http://www.cornflakezone.com

Currently browsing [TwistyBulge.zip] (125,123 bytes) - [vasarly.cpp] - (8,407 bytes)

    //////////////////////////////////////////////////////////////
    //															//
    //		-= The Cornflake Zone =-							//
    //															//
    //			-==============-								//
    //															//
    //		Twisting Bulging Effect using OpenGL 				//
    //		Written by Francis Shanahan, October 14th 2000		//
    //															//
    //		If you find this code useful mail me at				//
    //		mainflake@cornflakezone.com							//
    //		http://www.cornflakezone.com						//
    //															//
    //////////////////////////////////////////////////////////////

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include <GL/glut.h>
    #include <GL/glaux.h>

    static char *programname = "Cornflake Zone - Twisty Bulge";

    #define WINDOW_WIDTH	300
    #define WINDOW_HEIGHT	300

    #define EPSILON			0.000001
    #define MY_PI			3.1415926535

    // These vectors store the coordinates.
    float intX[50][50];
    float intY[50][50];

    // This alters the size of the generated square.
    #define size 1

    // Storage for 1 textures
    GLuint	cflaketexture;

    // A switch to decide if we're twisting or bulging
    int twistbulge = 1;

    // If we're texture mapped or not
    int usetexture = 0;

    // If we're drawing in lines or polygons.
    int lines = 1;

    /********************************************************************
    *
    *	myarctan()
    *
    *	returns the arctan of y/x
    *  This function is faster than the system "atan2()", which is why
    *	we don't use the system function.
    *
    */

    float
    myarctan(float x, float y)
    {
        if (fabs(x) < EPSILON) {
    		if (fabs(y) < EPSILON) {
    			return(0.0);
            }
    		else if (y > 0.0) {
    			return(1.570796327f);  /*(pi*0.5);*/
            }
    		else {
    			return(4.712388980f);  /*(pi*1.5);*/
            }
        } else if (x<0.0) {
    		return(atan(y/x)+ MY_PI);
        } else {
            return(atan(y/x));
        }
    }

    /*************************************************************************
    *
    *	TwistyBulge()
    *
    *	This is the meat of the program. we generate X and Y coords then
    *	manipulate the points inside a unit circle.
    *
    */

    void
    TwistyBulge(float p, float rotation)
    {
        int iy, ix;
        int i=0,j=0;
        float r,theta,x=-1, y;
    	float ax[4],ay[4];

    	// These loops generate the coordinates.
        for (ix = 0; ix < 28 ; ix++) {
    		y=-1;

    		for (iy =0; iy < 20 ; iy++) {
    			// Get the radius of the current point
    			r=sqrt(x*x+y*y);

    			// Get the current rotation
    			theta = myarctan(x,y);

    			// If we're inside the unit circle
    			if (r < 1.0) {
    				if(p!=1.0) {

    					// manipulate the radius
    					// this is the bulging part.
    					r=exp(log(r)*p);
    				}
    				// this is the rotation part.
    				theta+=(1.0-r)*rotation ;
                }

    			// Finally set the coordinates
    			intX[i][j]= (size * r * cos(theta));
    			intY[i][j]= (size * r * sin(theta));

    			j++;
    			y += 0.1;
    		}

    		x+=0.075;
    		j=0;
    		i++;
        }

    	// At this point all vertices have been calculated.
    	// We just need to draw them

    	// If we're to draw the lines only
    	if ( lines ) {
    		glBegin(GL_LINES);
    	} else {
    		glBegin(GL_TRIANGLES);

    		// If texture mapping is on then bind the texture
    		if (usetexture) {
    			glColor3f( 1,1,1);
    			glBindTexture(GL_TEXTURE_2D, cflaketexture);
    		}
    	}

    	// Now we draw the grid
        for (j=1;j<19;j++){
    		for (i=1;i<28;i++) {

    			// These are the x and y coordinates.
    			// I've coded it like this for readability
    			ax[0]= intX[i-1][j]     ;
    			ax[1]= intX[i][j]       ;
    			ax[2]= intX[i][j+1]     ;
    			ax[3]= intX[i-1][j+1]   ;

    			ay[0]= intY[i-1][j]     ;
    			ay[1]= intY[i][j]       ;
    			ay[2]= intY[i][j+1]     ;
    			ay[3]= intY[i-1][j+1]   ;

    			// If we're to draw the lines only
    			if ( lines ) {

    				glColor3f( 1.0f, 1.0f, 1.0f);

    				// Draw the first line
    				glVertex3f(ax[0] , ay[0], 0);
    				glVertex3f(ax[1] , ay[1], 0);

    				// Draw the second line
    				glVertex3f(ax[0] , ay[0], 0);
    				glVertex3f(ax[3] , ay[3], 0);

    			} else {
    				// We draw polygons.

    				if (usetexture) {
    					// We draw texture coords with the polygons

    					// Draw the first polygon
    					glTexCoord2f( (float)(i  )/28 , (float)(j  ) / 19); glVertex3f(ax[0] , ay[0], 0);
    					glTexCoord2f( (float)(i+1)/28 , (float)(j  ) / 19); glVertex3f(ax[1] , ay[1], 0);
    					glTexCoord2f( (float)(i+1)/28 , (float)(j+1) / 19); glVertex3f(ax[2] , ay[2], 0);

    					// Draw the second textured polygon
    					glTexCoord2f( (float)(i  )/28 , (float)(j  ) / 19); glVertex3f(ax[0] , ay[0], 0);
    					glTexCoord2f( (float)(i  )/28 , (float)(j+1) / 19); glVertex3f(ax[3] , ay[3], 0);
    					glTexCoord2f( (float)(i+1)/28 , (float)(j+1) / 19); glVertex3f(ax[2] , ay[2], 0);

    				} else {
    					// Just draw plain polygons
    					glColor3f( 0.89f, 0.36f, 0.0f);

    					// Draw the first polygon
    					glVertex3f(ax[0] , ay[0], 0);
    					glVertex3f(ax[1] , ay[1], 0);
    					glVertex3f(ax[2] , ay[2], 0);

    					glColor3f( 0.3f, 0.3f, 0.3f);
    					// Draw the second polygon
    					glVertex3f(ax[0] , ay[0], 0);
    					glVertex3f(ax[3] , ay[3], 0);
    					glVertex3f(ax[2] , ay[2], 0);
    				}
    			}
    		}
        }
    	glEnd();
    }

    /*************************************************************************
    *
    *	idle()
    *
    */
    void
    idle(void)
    {
    	glutPostRedisplay();
    }

    /*************************************************************************
    *
    *	LoadGLTextures()
    *
    *	Real simple keyboard handler
    *
    */
    void
    keyboard(unsigned char ch, int x, int y)
    {
    	switch (ch) {
    	case 27:             /* escape */
    		exit(0);
    		break;
    	case ' ':
    		twistbulge^=1;
    		break;
    	case 't':
    		usetexture^=1;
    		lines = 0;

    		if (usetexture) {
    			glEnable(GL_TEXTURE_2D);
    		} else {
    			glDisable(GL_TEXTURE_2D);
    		}
    		break;
    	case 'l':
    		lines^=1;
    		break;
    	}

    }

    /*************************************************************************
    *
    *	display()
    *
    *	Main display function
    *
    *
    */

    void
    display(void)
    {
    	static float twist=0.0; // My twist factor
    	static float bulge=1; // The bulge factor
    	static float off=0.1; // The increment ( offset )

    	// Clear the screen
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    	// This is just a simple switch to decide if
    	// we're twisting or bulging.
    	if (twistbulge) {
    		twist+=off;
    		// These are magic numbers, you can play around with them
    		// to find what works best for you
    		if (twist<=-2.4) off=0.05;
    		if (twist>= 2.4) off=-0.05;
    	} else {
    		bulge+=off;
    		if (bulge<=0.2) off=0.05;
    		if (bulge>=3.6) off=-0.05;
    	}

    	// Render the scene
    	TwistyBulge( bulge, twist);

    	//glFlush();
    	glutSwapBuffers();

    }

    /*************************************************************************
    *
    *	LoadGLTextures()
    *
    *	Load Bitmaps And Convert To Textures
    *
    */
    GLvoid LoadGLTextures()
    {
    	// Load Texture
    	AUX_RGBImageRec *texture1;

    	texture1 = auxDIBImageLoad("Data/cflakezone.bmp");
    	if (!texture1)
    	{
    		exit(1);
    	}

    	// Create Linear Filtered Texture
    	glBindTexture(GL_TEXTURE_2D, cflaketexture);
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    	glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1->sizeX, texture1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1->data);

    }

    /*************************************************************************
    *
    *	glInit()
    *
    *	Sets up OpenGL
    *
    */
    void glInit(){
    	// Load The Texture(s)
    	LoadGLTextures();

    	// Enable Texture Mapping
    	glEnable(GL_TEXTURE_2D);

    	/* setup context */
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();

    	// Calculate The Aspect Ratio Of The Window
    	gluPerspective(45.0f, WINDOW_WIDTH /
    		WINDOW_HEIGHT,0.1f,100.0f);

    	// Translate back a little for a better view.
    	glTranslatef(0,0, -2.5);

    	glShadeModel(GL_SMOOTH);

    	// Clear color is Black
    	glClearColor(0.0, 0.0, 0.0, 1);
    }
    int
    main(int argc, char **argv)
    {
    	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    	glutInit(&argc, argv);

    	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

    	glutCreateWindow(programname);

    	glutKeyboardFunc(keyboard);
    	glutDisplayFunc(display);
    	glutIdleFunc(idle);

    	glInit();

    	glutMainLoop();
    	return 0;             /* ANSI C requires main to return int. */
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.