/* * This program is under the GNU GPL. * Use at your own risk. * * written by David Bucciarelli (humanware@plus.it) * Humanware s.r.l. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <time.h> #include <GL/glut.h> #ifndef M_PI #define M_PI 3.14159265 #endif #include "particles.h" extern "C" { #include "readtex.h" } #ifdef _WIN32 #include <windows.h> #include <mmsystem.h> #endif #ifdef XMESA #include "GL/xmesa.h" static int fullscreen=1; #endif static int WIDTH=640; static int HEIGHT=480; static int NUMPART=7500; #define FRAME 50 static float fogcolor[4]={1.0,1.0,1.0,1.0}; #define DIMP 40.0 #define DIMTP 32.0 static float q[4][3]={ {-DIMP,0.0,-DIMP}, {DIMP,0.0,-DIMP}, {DIMP,0.0,DIMP}, {-DIMP,0.0,DIMP} }; static float qt[4][2]={ {-DIMTP,-DIMTP}, {DIMTP,-DIMTP}, {DIMTP,DIMTP}, {-DIMTP,DIMTP} }; static int win=0; static int fog=1; static int help=1; static GLuint groundid; static float obs[3]={2.0,1.0,0.0}; static float dir[3]; static float v=0.0; static float alpha=-90.0; static float beta=90.0; static particleSystem *ps; static float gettime() { static clock_t told=0; clock_t tnew,ris; tnew=clock(); ris=tnew-told; told=tnew; return(ris/(float)CLOCKS_PER_SEC); } static float gettimerain() { static clock_t told=0; clock_t tnew,ris; tnew=clock(); ris=tnew-told; told=tnew; return(ris/(float)CLOCKS_PER_SEC); } static void calcposobs(void) { dir[0]=sin(alpha*M_PI/180.0); dir[2]=cos(alpha*M_PI/180.0)*sin(beta*M_PI/180.0); dir[1]=cos(beta*M_PI/180.0); obs[0]+=v*dir[0]; obs[1]+=v*dir[1]; obs[2]+=v*dir[2]; rainParticle::setRainingArea(obs[0]-7.0f,-0.2f,obs[2]-7.0f,obs[0]+7.0f,8.0f,obs[2]+7.0f); } static void printstring(void *font, const char *string) { int len,i; len=(int)strlen(string); for(i=0;i<len;i++) glutBitmapCharacter(font,string[i]); } static void reshape(int width, int height) { WIDTH=width; HEIGHT=height; glViewport(0,0,(GLint)width,(GLint)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70.0,width/(float)height,0.1,30.0); glMatrixMode(GL_MODELVIEW); } static void printhelp(void) { glEnable(GL_BLEND); glColor4f(0.0,0.0,0.0,0.5); glRecti(40,40,600,440); glDisable(GL_BLEND); glColor3f(1.0,0.0,0.0); glRasterPos2i(300,420); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Help"); glRasterPos2i(60,390); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"h - Toggle Help"); glRasterPos2i(60,360); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"f - Toggle Fog"); glRasterPos2i(60,330); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Arrow Keys - Rotate"); glRasterPos2i(60,300); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"a - Increase velocity"); glRasterPos2i(60,270); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"z - Decrease velocity"); glRasterPos2i(60,240); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"l - Increase rain length"); glRasterPos2i(60,210); printstring(GLUT_BITMAP_TIMES_ROMAN_24,"k - Increase rain length"); } static void drawrain(void) { static int count=0; static char frbuf[80]; float fr; glEnable(GL_DEPTH_TEST); if(fog) glEnable(GL_FOG); else glDisable(GL_FOG); glDepthMask(GL_TRUE); glClearColor(1.0,1.0,1.0,1.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); calcposobs(); gluLookAt(obs[0],obs[1],obs[2], obs[0]+dir[0],obs[1]+dir[1],obs[2]+dir[2], 0.0,1.0,0.0); glColor4f(1.0,1.0,1.0,1.0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,groundid); glBegin(GL_QUADS); glTexCoord2fv(qt[0]); glVertex3fv(q[0]); glTexCoord2fv(qt[1]); glVertex3fv(q[1]); glTexCoord2fv(qt[2]); glVertex3fv(q[2]); glTexCoord2fv(qt[3]); glVertex3fv(q[3]); glEnd(); // Particle System glDisable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); glEnable(GL_BLEND); ps->draw(); ps->addTime(gettimerain()); glShadeModel(GL_FLAT); if((count % FRAME)==0) { fr=gettime(); sprintf(frbuf,"Frame rate: %f",FRAME/fr); } glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glDisable(GL_FOG); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-0.5,639.5,-0.5,479.5,-1.0,1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1.0,0.0,0.0); glRasterPos2i(10,10); printstring(GLUT_BITMAP_HELVETICA_18,frbuf); glRasterPos2i(350,470); printstring(GLUT_BITMAP_HELVETICA_10,"Rain V1.0 Written by David Bucciarelli (humanware@plus.it)"); if(help) printhelp(); reshape(WIDTH,HEIGHT); glPopMatrix(); glutSwapBuffers(); count++; } static void special(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT: alpha+=2.0; break; case GLUT_KEY_RIGHT: alpha-=2.0; break; case GLUT_KEY_DOWN: beta-=2.0; break; case GLUT_KEY_UP: beta+=2.0; break; } } static void key(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; case 'a': v+=0.01; break; case 'z': v-=0.01; break; case 'l': rainParticle::setLength(rainParticle::getLength()+0.025f); break; case 'k': rainParticle::setLength(rainParticle::getLength()-0.025f); break; case 'h': help=(!help); break; case 'f': fog=(!fog); break; #ifdef XMESA case ' ': XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW); fullscreen=(!fullscreen); break; #endif } } static void inittextures(void) { GLubyte *img; GLint width,height; GLenum format; GLenum gluerr; glGenTextures(1,&groundid); glBindTexture(GL_TEXTURE_2D,groundid); if(!(img=LoadRGBImage("../images/s128.rgb",&width,&height,&format))){ fprintf(stderr,"Error reading a texture.\n"); exit(-1); } glPixelStorei(GL_UNPACK_ALIGNMENT,4); if((gluerr=(GLenum)gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)(img)))) { fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr)); exit(-1); } glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); } static void initparticle(void) { ps=new particleSystem; rainParticle::setRainingArea(-7.0f,-0.2f,-7.0f,7.0f,8.0f,7.0f); for(int i=0;i<NUMPART;i++) { rainParticle *p=new rainParticle; p->randomHeight(); ps->addParticle((particle *)p); } } int main(int ac,char **av) { fprintf(stderr,"Rain V1.0\nWritten by David Bucciarelli (humanware@plus.it)\n"); /* Default settings */ WIDTH=640; HEIGHT=480; glutInitWindowPosition(0,0); glutInitWindowSize(WIDTH,HEIGHT); glutInit(&ac,av); glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE); if(!(win=glutCreateWindow("Rain"))) { fprintf(stderr,"Error opening a window.\n"); exit(-1); } reshape(WIDTH,HEIGHT); inittextures(); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_FOG); glFogi(GL_FOG_MODE,GL_EXP); glFogfv(GL_FOG_COLOR,fogcolor); glFogf(GL_FOG_DENSITY,0.1); #ifdef FX glHint(GL_FOG_HINT,GL_NICEST); #endif initparticle(); glutKeyboardFunc(key); glutSpecialFunc(special); glutDisplayFunc(drawrain); glutIdleFunc(drawrain); glutReshapeFunc(reshape); glutMainLoop(); return(0); }