Click here to Skip to main content
15,883,843 members
Articles / Multimedia / OpenGL

Interactive Water Effect Multitouch

Rate me:
Please Sign up or sign in to vote.
4.60/5 (10 votes)
1 Feb 2011CPOL2 min read 38.7K   2.4K   22  
Interactive Water Effect Multitouch with Tuio Library
#include <windows.h>		// Header File For Windows

#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

// Linux/Unix specific

#include <time.h>
//#include <unistd.h>


// OPENGL stuff

#ifdef XMESA
#include <GL/xmesa.h>
#endif

#define _GDI32_
//#include <GL/glx.h>
#include <gl\gl.h>			// Header File For The OpenGL32 Library
#include <gl\glu.h>			// Header File For The GLu32 Library
//#include <gl\glaux.h>		// Header File For The Glaux Library
#include <GL/glut.h>


static int fullscreen = 1;
static int voodoo_gfx = 0;
static int softrender = 0;
static int videoram = 32;
static int xres, yres;




// custom objects

#include "flotte.h"

//----------------------------------
// an instance of 'dmFlotte' object
//----------------------------------

dmFlotte *gFlotte = NULL;

static int win;

static int    flag_func = 0;
static float  mx=0.0f, my=0.0f;

static float  mrota = 0.0f;
static float  totalrot = 0.0f;
static int    mbutton = -1;
static float  pX = 0.0f;
static float  pY = 0.0f;
static int    waveFlag = 0;
static int    vsizeX = 1024;
static int    vsizeY = 768;

#include "TuioListener.h"
#include "TuioClient.h"

using namespace TUIO;


class TuioDemo : public TuioListener { 
	
public:
	TuioDemo(int port)
	{
	  tuioClient = new TuioClient(port);
	  tuioClient->addTuioListener(this);
	  tuioClient->connect();

	if (!tuioClient->isConnected()) 
	{
	}

	}
	~TuioDemo() {
		tuioClient->disconnect();
		delete tuioClient;
	}
	
	void addTuioObject(TuioObject *tobj) { } 
	void updateTuioObject(TuioObject *tobj) { } 
	void removeTuioObject(TuioObject *tobj){ } 
	
	void addTuioCursor(TuioCursor *tcur);
	void updateTuioCursor(TuioCursor *tcur);
	void removeTuioCursor(TuioCursor *tcur);
	
	void refresh(TuioTime frameTime) { } 

	void showWave(dmFlotte *flotte)
	{		
		std::list<TuioCursor*> lstCursor = tuioClient->getTuioCursors();
		std::list<TuioCursor*>::iterator tcur;
		for (tcur=lstCursor.begin(); tcur!= lstCursor.end(); tcur++) {					
		    flotte->setWave((*tcur)->getX(),-(*tcur)->getY(),  128);
		}
	}
		
	TuioClient *tuioClient;
};

TuioDemo *tuioListner = NULL;

//---------------------------
// callbacks ...
//---------------------------


void display(void)
{

    // slow down fluid model if too quick to look like water

	if (gFlotte->bench(10.0f))
    { 

		tuioListner->showWave(gFlotte); 
       /*if (waveFlag)
	   {
		  // opposite face of the plane
          if (  (abs(int(totalrot) % 360) > 90)  && (abs(int(totalrot) % 360) < 270) )   
		  {
             gFlotte->setWave(pX, -pY,  512);
		  }
          else // plane moreover in front of us
		  {
             gFlotte->setWave(-pX,-pY,  128);
		  }
	   } 
	   */

//      gFlotte->runWave(0.0f, 2.0f, 4.0f, 16);
//       gFlotte->runWave(400.0f, 5.0f, 3.0f, 64);
//       gFlotte->runWave(800.0f, 3.0f, 2.0f, 84);
//	   gFlotte->runWave(1000.0f, 4.0f, 3.0f, 100);

       gFlotte->update();

	   gFlotte->nexttime();
    }


	gFlotte->build();


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    gFlotte->display();


    glFlush();


    glutSwapBuffers();

}





void rota(void)
{
	if (mrota != 0.0f)
    {
       totalrot += mrota; // Y axis rotation

       glRotatef(mrota,0.0f,1.0f,0.0f);
    }

	glutPostRedisplay();
}




void mouseclick(int button, int state, int x, int y)
{
//   if (state == GLUT_DOWN)
//   {
      mbutton = button;
//   }

}


void mousemoveclick(int x, int y)
{
   static int prevX = 0;


   switch (mbutton)
   {

      // plane rotation
      case GLUT_RIGHT_BUTTON:

         if (x < prevX)
            mrota = -1.0f;
         else if (x > prevX)
            mrota = 1.0f;

        prevX = x;
        waveFlag = 0;
        break;

      // hole tracing
      case GLUT_LEFT_BUTTON:

        pX =-float(x)/vsizeX; //(float( x) - vsizeX/2.0f)/vsizeX ;
        pY = float(y)/vsizeY; //(float( y) - vsizeY/2.0f)/vsizeY;

        waveFlag = 1;

        break;

      default:
        waveFlag = 0;

   }
}


void mousemovenoclick(int x, int y)
{
   mbutton = -1;
   mrota = 0.0f;
   waveFlag = 0;
}



void initView(void);




void key(unsigned char aKey, int x, int y)
{
   switch(aKey)
   {
      case 's':
      case  'S':
           initView();
           break;

      case 27: /* Exit if we press ESC */
           glutDestroyWindow(win);
		   delete gFlotte;
	       exit(0);
	   break;

   }
}



void initView(void)
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glTranslatef(-0.15f, -0.25, -5.5f);
	totalrot = 0.0f;
}


//...................................................
// try to detect if we have hardware geometry engine
// or at least similar cpu time
//...................................................

bool geometry_engine_detect(void)
{
    char *gfx_model = NULL;
	char *gfx_vendor = NULL;
	bool  tl = true; // T&L by default

	gfx_vendor = strdup((char*)glGetString(GL_VENDOR));
	gfx_model  = strdup((char*)glGetString(GL_RENDERER));


	
	if (strstr(gfx_model, "Generic"))      // softwarer renderer
    { 
	   tl = false;
	   softrender = 1;
	   videoram = 4;
    } 
	//.................
    // PC/MAC hardware
	//.................

#ifndef IRIX

    else if (strstr(gfx_model, "Voodoo"))  // Voodoo graphics
    {
	   tl = false;

       if (strstr(gfx_model, "Voodoo_Graphics"))
       {
		  voodoo_gfx = 1;
		  videoram = 4;
	   }
	   else if (strstr(gfx_model, "Voodoo2"))
       {
          voodoo_gfx = 1;
		  videoram = 8;
       }  
	}
	else if (strstr(gfx_vendor, "Matrox")) // Matrox G400 and G200
    {
       if (strstr(gfx_model, "G200")) 
	   {	   
          tl = false;
		  videoram = 8;
	   }
	   else  if (strstr(gfx_model, "G400"))
       {
		  tl = false;
		  videoram = 16;
       }  
    }   
	else if (strstr(gfx_vendor, "ATI"))    // ATI cards RagePro / Rage128
    {
       if (strstr(gfx_model, "Rage"))
          tl = false;

	   if (strstr(gfx_vendor, "RagePro"))
          videoram = 8;
       else if (strstr(gfx_vendor, "Rage128"))
          videoram = 32; 

    }   
	else if (strstr(gfx_model, "Savage"))  // S3 Savage, Savage4000
    {
       tl = false;
	   videoram = 8;
    }   
	else if (strstr(gfx_model, "TNT"))     // NVidia TNT, TNT2
    {
       tl = false;
	   if (strstr(gfx_model, "TNT2"))
		   videoram = 32;
       else
		   videoram = 16;
    }
	else if (strstr(gfx_model, "Riva")) // NVidia Riva128
    {
       tl = false;  
	   videoram = 8;
    }
	else if (strstr(gfx_model, "PowerVR")) // NEC PowerVR
    {
       tl = false;
	   videoram = 4;
    }
	else if (strstr(gfx_model, "Rendition")) // Rendition Verite
    {
       tl = false;  
	   videoram = 4;
    }
	else if (strstr(gfx_model, "Quadro"))  // NVidia/SGI professional, lot of RAM
    {
 	   videoram = 64;
    }
	else if (strstr(gfx_model, "Wildcat")) // 3DLabs professional, lot of RAM
    {
 	   videoram = 64;
    }
	else if (strstr(gfx_model, "Oxygen")) // 3DLabs professional, lot of RAM
    {
 	   videoram = 64;
    }
	else if (strstr(gfx_model, "Cobalt")) // SGI professional, lot of RAM
    {
 	   videoram = 64;
    }




#endif

#ifdef IRIX
    //................................................................ 
	// SGI hardware - old hardwares that will not support 40000 polys
	// other like IR (Infinite Reality), O2, Octane, Octane2 will be ok
	//................................................................

	else if (strstr(gfx_model, "VGXT"))      // Iris-4D VGX
    {
       tl = false;
    }
	else if (strstr(gfx_model, "LIGHT"))     // Indigo Starter
    {
       tl = false;
    }
	else if (strstr(gfx_model, "NEWPORT"))   // Indy 
    {
       tl = false;
    }
	else if (strstr(gfx_model, "EXTREME"))   // carte Elan
    {
       tl = false;
    }
	else if (strstr(gfx_model, "GL4DRE"))    // Reality Engine
    {
       tl = false;
    }
#endif


    if (gfx_vendor) free(gfx_vendor);
    if (gfx_model)  free(gfx_model);
 

    return tl;
}



void myReshape(int w, int h)
{
	if (voodoo_gfx > 0) // Voodoo 1, 2
    {
       w = 640;
       h = 480;
    }


    vsizeX = w;
    vsizeY = h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, 1.0f*(GLfloat)w/(GLfloat)h, 1.0f, 30.0f);


    initView();
}



void visible(int vis)
{
   if (vis == GLUT_VISIBLE)
   {
      glutIdleFunc(rota);
   }
   else
   {
      glutIdleFunc(NULL);
   }	   
}




void TuioDemo::addTuioCursor(TuioCursor *tcur) { 
		mouseclick(GLUT_LEFT_BUTTON, 0, tcur->getScreenX(xres), tcur->getScreenX(yres))	;   
	} 
void TuioDemo::updateTuioCursor(TuioCursor *tcur) { 
//		 mousemoveclick(tcur->getScreenX(xres), tcur->getScreenX(yres));
	pX =-tcur->getX();// float(x)/vsizeX; //(float( x) - vsizeX/2.0f)/vsizeX ;
        pY = tcur->getY();// float(y)/vsizeY; //(float( y) - vsizeY/2.0f)/vsizeY;
        waveFlag = 1;
	} 
void TuioDemo::removeTuioCursor(TuioCursor *tcur){	
	waveFlag = 0;
		//mousemovenoclick(0,0);
	} 

//---------------------------
// main entry point
//---------------------------

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance
					HINSTANCE	hPrevInstance,		// Previous Instance
					LPSTR		lpCmdLine,			// Command Line Parameters
					int			nCmdShow)			// Window Show State
{

//int main(int argc, char *argv[])
//{
	int  high_def = FLOT_HIGHRES;
	int  poly_count = 4;
	int  poly_div = 1;
	bool geom_engine = true;
	char gfx_vendor[1024];
	char gfx_model[1024];
	bool gfx_multitex = true;


	tuioListner = new TuioDemo(3333);



    printf("\n\n-------------------------------------------------------------\n");
    printf("DS Aqua 0.91 - linux release version - february 2001  \n");
    printf("-------------------------------------------------------------\n\n");
    printf("quick code by Laurent Lardinois (Type One) \n");
    printf("IT Consultant - Project Manager - Research & Development\n");
    printf("contact me at : llardin@dsimprove.be\n\n");
    printf("DS Improve SPRL (http://www.dsimprove.com) \n\n");
    printf("-Press ESC to exit.\n");
    printf("-Keep RIGHT mouse button down and move the mouse to rotate the plane\n");
    printf("-Keep LEFT bouton down and move the mouse to perturb the fluid\n");
    printf("-Press S to set to initial rotation\n\n");


	// create dummy context
	glutInitWindowPosition(0,0);
//	glutInit(&argc,argv);
	int argc = 0;
	char **argv=(char **)malloc(sizeof(char *));
	argv[0] = (char *)malloc(sizeof(char)*10);
	argv[0][0] = 0;
//	glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
	if (!(win=glutCreateWindow("water")))
    {
      fprintf(stderr,"Error, couldn't open window\n");
      exit(-1);
    }

    geom_engine = geometry_engine_detect();

	strcpy(gfx_vendor, (char*)glGetString(GL_VENDOR)); 
	strcpy(gfx_model, (char*)glGetString(GL_RENDERER));

	if (glutExtensionSupported("GL_ARB_multitexture"))
    {
       gfx_multitex = true;
    }
	else
    {
       gfx_multitex = false;
    }

    
	// test Matrox G200/G400, OpenGL multitex buggy driver with DECAL...

	if (strstr(gfx_vendor, "Matrox"))
	{ 	
       if (strstr(gfx_model, "G200"))
          gfx_multitex = false;
	   else  if (strstr(gfx_model, "G400"))
		  gfx_multitex = false;
    }


	if (voodoo_gfx > 0) // if voodoo, we have o rebuild window
    {
	   glutDestroyWindow(win);
    }


    // following code has effect on Voodoo Graphics only

	if (voodoo_gfx > 0)
    {
       /* Tell Mesa GLX to use 3Dfx driver in fullscreen mode. */
       putenv("MESA_GLX_FX=fullscreen");

       /* Disable 3Dfx Glide splash screen */
       putenv("FX_GLIDE_NO_SPLASH=");
    }


   
	printf("vendor: %s\n", gfx_vendor); 
	printf("model: %s\n", gfx_model);

    // this line forces low res tesselation (3D on RedHat 7 and NVidia kernel
    // seems buggy with high tesselation, however it works perfect with
    // SGI SuSE 6.4 and Propack 1.3)

#ifdef FORCE_LOWRES
    geom_engine = false;
#endif
	
    if (geom_engine)
	{
	   high_def = FLOT_HIGHRES;
	   poly_count = 4;
	   poly_div = 1;

       printf("hardware T&L class machine\n");  
    }
	else if (!softrender)
    {
	   high_def = FLOT_MEDIUMRES;
	   poly_count = 1;
	   poly_div = 1;

       printf("no hardware T&L class machine\n");  
    }
	else if (softrender)
    {
	   high_def = FLOT_LOWRES;
	   poly_count = 1;
       poly_div = 4; 

       printf("software rendering class machine\n");
	   printf("really sloooow - are you sure you have a 3D accelerator ?\n");
	   printf("if you have a 3D accelerator then update your driver with an OpenGL ICD\n");
	   
    }

    
	if (voodoo_gfx > 0)
    {
       printf("screen resolution (voodoo1/voodoo2): 640x480\n");
    }
	else
    {
	   xres = glutGet(GLUT_SCREEN_WIDTH);
	   yres = glutGet(GLUT_SCREEN_HEIGHT);

       printf("screen resolution : %dx%d\n", xres, yres);

	   switch(videoram)
	   {
	      case 4:
			  if (xres > 640)
              {
			     printf("performance can be low (lack of memory for OpenGL acceleration)\n");
				 printf("if you get such problem try to switch to 640x480 x 16 bits or lower\n"); 	  
              }
			  break;

          case 8:
			  if (xres > 800)
              {
			     printf("performance can be low (lack of memory for OpenGL acceleration)\n");
				 printf("if you get such problem try to switch to 800x600 x 16 bits or lower\n"); 	  
              }
			  break;

          case 16:
			  if (xres > 1024)
              {
			     printf("performance can be low (lack of memory for OpenGL acceleration)\n");
				 printf("if you get such problem try to switch to 1024x768 x 16 bits or lower\n"); 	  
              }
			  break; 
			  
          case 32:
			  if (xres >= 1152)
              {
			     printf("performance can be low (lack of memory for OpenGL acceleration)\n");
				 printf("if you get such problem try to switch to 1024x768 or lower\n"); 	  
              }
			  break;
       }
    }
 

    if (gfx_multitex)
	{
       printf("fluid : %d ARB bi-textured triangles\n\n\n", (FLOTSIZE*FLOTSIZE*2*poly_count)/poly_div);
	}
	else
    {
	   printf("fluid : %d single-textured triangles\n\n\n", (FLOTSIZE*FLOTSIZE*2*poly_count*2)/poly_div);
    }




//    sleep(5);


	
	if (voodoo_gfx > 0) // rebuild window for voodoo
    {
       glutInitWindowPosition(0,0);
	   glutInitWindowSize(640, 480);
	   glutInit(&argc,argv);
	   //glutInit(&argc,NULL);
       //glutInit(&argc,argv);
       glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);

       if (!(win=glutCreateWindow("water")))
	   {
          fprintf(stderr,"Error, couldn't open window\n");
          exit(-1);
	   }
	}

    /*
    * Want the X window to fill the screen so that we don't have to
    * worry about losing	the mouse input focus.
    * Note that we won't actually see the X window since we never draw
    * to it, hence, the original X screen's contents aren't disturbed.
    */

//    if (argc == 1)   // fullscreen by default
    {
       glutFullScreen();
    }


    gFlotte = new dmFlotte(NULL, high_def);


    glutReshapeFunc(myReshape);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);

    glutMouseFunc(mouseclick);
    glutMotionFunc(mousemoveclick);
    glutPassiveMotionFunc(mousemovenoclick);
 
    if (voodoo_gfx == 0)
       glutVisibilityFunc(visible);
    else if (voodoo_gfx > 0)
	   glutIdleFunc(rota);  // can not be hidden with voodoo


	//.....................
	// resize screen
	// to fit capabilities
	//.....................



    glutMainLoop();


    delete gFlotte;


    return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) http://www.cmb-soft.com/
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions