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.