Hosting by Solid Eight Studios ,PhotoTangler Collage Maker

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 #include #include #include #include #include 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.