⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 particle.c

📁 学习c++必备
💻 C
字号:
/*     particle.c    Nate Robins, 1997    An example of a simple particle system. */#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <GL/glut.h>#ifdef _WIN32#define drand48() ((float)rand()/RAND_MAX)#endif/* #define SCREEN_SAVER_MODE */#define PS_GRAVITY -9.8#define PS_WATERFALL 0#define PS_FOUNTAIN  1typedef struct {    float x, y, z;    float radius;} PSsphere;typedef struct {    float position[3];			/* current position */    float previous[3];			/* previous position */    float velocity[3];			/* velocity (magnitude & direction) */    float dampening;			/* % of energy lost on collision */    int alive;				/* is this particle alive? */} PSparticle;PSparticle* particles = NULL;PSsphere    sphere = { 0, 1, 0, 0.25 };int num_particles = 5000;int type = PS_WATERFALL;int points = 1;int do_sphere = 0;int frame_rate = 1;float frame_time = 0;float flow = 500;float slow_down = 1;float spin_x = 0;float spin_y = 0;int point_size = 3;/* timedelta: returns the number of seconds that have elapsed since   the previous call to the function. */floattimedelta(void){    static long begin = 0;    static long finish, difference;#if defined(_WIN32)#include <sys/timeb.h>    static struct timeb tb;    ftime(&tb);    finish = tb.time*1000+tb.millitm;#else#include <limits.h>#include <unistd.h>#include <sys/types.h>#include <sys/times.h>    static struct tms tb;    finish = times(&tb);#endif    difference = finish - begin;    begin = finish;    return (float)difference/(float)1000;  /* CLK_TCK=1000 */}/* text: draws a string of text with an 18 point helvetica bitmap font   at position (x,y) in window space (bottom left corner is (0,0). */voidtext(int x, int y, char* s) {    int lines;    char* p;    glDisable(GL_DEPTH_TEST);    glMatrixMode(GL_PROJECTION);    glPushMatrix();    glLoadIdentity();    glOrtho(0, glutGet(GLUT_WINDOW_WIDTH), 	    0, glutGet(GLUT_WINDOW_HEIGHT), -1, 1);    glMatrixMode(GL_MODELVIEW);    glPushMatrix();    glLoadIdentity();    glColor3ub(0, 0, 0);    glRasterPos2i(x+1, y-1);    for(p = s, lines = 0; *p; p++) {	if (*p == '\n') {	    lines++;	    glRasterPos2i(x+1, y-1-(lines*18));	}	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p);    }    glColor3ub(128, 0, 255);    glRasterPos2i(x, y);    for(p = s, lines = 0; *p; p++) {	if (*p == '\n') {	    lines++;	    glRasterPos2i(x, y-(lines*18));	}	glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p);    }    glMatrixMode(GL_PROJECTION);    glPopMatrix();    glMatrixMode(GL_MODELVIEW);    glPopMatrix();    glEnable(GL_DEPTH_TEST);}intfequal(float a, float b){    float epsilon = 0.1;    float f = a - b;        if (f < epsilon && f > -epsilon)	return 1;    else	return 0;}voidpsTimeStep(PSparticle* p, float dt){    if (p->alive == 0)	return;    p->velocity[0] += 0;    p->velocity[1] += PS_GRAVITY*dt;    p->velocity[2] += 0;    p->previous[0] = p->position[0];    p->previous[1] = p->position[1];    p->previous[2] = p->position[2];    p->position[0] += p->velocity[0]*dt;    p->position[1] += p->velocity[1]*dt;    p->position[2] += p->velocity[2]*dt;}voidpsNewParticle(PSparticle* p, float dt){    if (type == PS_WATERFALL) {	p->velocity[0] = 1*(drand48()-0.5);	p->velocity[1] = 0;	p->velocity[2] = 0.5*(drand48()-0.0);	p->position[0] = 0;	p->position[1] = 2;	p->position[2] = 0;	p->previous[0] = p->position[0];	p->previous[1] = p->position[1];	p->previous[2] = p->position[2];	p->dampening = 0.45*drand48();	p->alive = 1;    } else if (type == PS_FOUNTAIN) {	p->velocity[0] = 2*(drand48()-0.5);	p->velocity[1] = 6;	p->velocity[2] = 2*(drand48()-0.5);	p->position[0] = 0;	p->position[1] = 0;	p->position[2] = 0;	p->previous[0] = p->position[0];	p->previous[1] = p->position[1];	p->previous[2] = p->position[2];	p->dampening = 0.35*drand48();	p->alive = 1;    }    psTimeStep(p, 2*dt*drand48());}/* psBounce: the particle has gone past (or exactly hit) the ground   plane, so calculate the time at which the particle actually   intersected the ground plane (s).  essentially, this just rolls   back time to when the particle hit the ground plane, then starts   time again from then.   -  -   o A  (previous position)   |  |    \   |  s     \   o  (position it _should_ be at) -   t  |      \ /                                | t - s    |  - ------X--------                         -   |           \   -            o B  (new position)                  A + V*s = 0 or s = -A/V   to calculate where the particle should be:   A + V*t + V*(t-s)*d   where d is a damping factor which accounts for the loss   of energy due to the bounce. */voidpsBounce(PSparticle* p, float dt){    float s;    if (p->alive == 0)	return;    /* since we know it is the ground plane, we only need to       calculate s for a single dimension. */    s = -p->previous[1]/p->velocity[1];    p->position[0] = (p->previous[0] + p->velocity[0] * s + 		      p->velocity[0] * (dt-s) * p->dampening);    p->position[1] = -p->velocity[1] * (dt-s) * p->dampening; /* reflect */    p->position[2] = (p->previous[2] + p->velocity[2] * s + 		      p->velocity[2] * (dt-s) * p->dampening);    /* damp the reflected velocity (since the particle hit something,       it lost some energy) */    p->velocity[0] *=  p->dampening;    p->velocity[1] *= -p->dampening;		/* reflect */    p->velocity[2] *=  p->dampening;}voidpsCollide(PSparticle* p){    float vx = p->position[0] - sphere.x;    float vy = p->position[1] - sphere.y;    float vz = p->position[2] - sphere.z;    float distance;    if (p->alive == 0)	return;    distance = sqrt(vx*vx + vy*vy + vz*vz);    if (distance < sphere.radius) {#if 0	vx /= distance;  vy /= distance;  vz /= distance;	d = 2*(-vx*p->velocity[0] + -vy*p->velocity[1] + -vz*p->velocity[2]);	p->velocity[0] += vx*d*2;	p->velocity[1] += vy*d*2;	p->velocity[2] += vz*d*2;	d = sqrt(p->velocity[0]*p->velocity[0] + 		 p->velocity[1]*p->velocity[1] +		 p->velocity[2]*p->velocity[2]);	p->velocity[0] /= d;	p->velocity[1] /= d;	p->velocity[2] /= d;#else	p->position[0] = sphere.x+(vx/distance)*sphere.radius;	p->position[1] = sphere.y+(vy/distance)*sphere.radius;	p->position[2] = sphere.z+(vz/distance)*sphere.radius;	p->previous[0] = p->position[0];	p->previous[1] = p->position[1];	p->previous[2] = p->position[2];	p->velocity[0] = vx/distance;	p->velocity[1] = vy/distance;	p->velocity[2] = vz/distance;#endif    }}voidreshape(int width, int height){    float black[] = { 0, 0, 0, 0 };    glViewport(0, 0, width, height);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    gluPerspective(60, 1, 0.1, 1000);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    gluLookAt(0, 1, 3, 0, 1, 0, 0, 1, 0);    glFogfv(GL_FOG_COLOR, black);    glFogf(GL_FOG_START, 2.5);    glFogf(GL_FOG_END, 4);    glEnable(GL_FOG);    glFogi(GL_FOG_MODE, GL_LINEAR);    glPointSize(point_size);    glEnable(GL_POINT_SMOOTH);    glEnable(GL_BLEND);    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);    glEnable(GL_COLOR_MATERIAL);    glEnable(GL_DEPTH_TEST);    glEnable(GL_LIGHT0);    timedelta();}voiddisplay(void){    static int i;    static float c;    static char s[32];    static int frames = 0;    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);    glPushMatrix();    glRotatef(spin_y, 1, 0, 0);    glRotatef(spin_x, 0, 1, 0);    glEnable(GL_LIGHTING);    if (do_sphere) {	glPushMatrix();	glTranslatef(sphere.x, sphere.y, sphere.z);	glColor3ub(0, 255, 128);	glutSolidSphere(sphere.radius, 16, 16);	glPopMatrix();    }    glDisable(GL_LIGHTING);    glBegin(GL_QUADS);    glColor3ub(0, 128, 255);    glVertex3f(-2, 0, -2);    glVertex3f(-2, 0, 2);    glVertex3f(2, 0, 2);    glVertex3f(2, 0, -2);    glEnd();    if (points) {	glBegin(GL_POINTS);		for (i = 0; i < num_particles; i++) {	    if (particles[i].alive == 0)		continue;	    c = particles[i].position[1]/2.1*255;	    glColor3ub((GLubyte) c, (GLubyte) (128+c*0.5), 255);	    glVertex3fv(particles[i].position);	}	glEnd();    } else {	glBegin(GL_LINES);	for (i = 0; i < num_particles; i++) {	    if (particles[i].alive == 0)		continue;	    c = particles[i].previous[1]/2.1*255;	    glColor3ub((GLubyte) c, (GLubyte) (128+c*0.5), 255);	    glVertex3fv(particles[i].previous);	    c = particles[i].position[1]/2.1*255;	    glColor3ub((GLubyte) c, (GLubyte) (128+c*0.5), 255);	    glVertex3fv(particles[i].position);	}	glEnd();    }    /* spit out frame rate. */    if (frame_rate) {	frames++;	if (frames > 7) {	    sprintf(s, "%g fps", (float)7/frame_time);	    frame_time = 0;	    frames = 0;	}	text(5, 5, s);    }    glPopMatrix();    glutSwapBuffers();}voididleFunc(void){    static int i;    static int living = 0;		/* index to end of live particles */    static float dt;    dt = timedelta();    frame_time += dt;#if 1    /* slow the simulation if we can't keep the frame rate up around       10 fps */    if (dt > 0.1) {	slow_down = 0.75;    } else if (dt < 0.1) {	slow_down = 1;    }#endif    dt *= slow_down;    /* resurrect a few particles */    for (i = 0; i < flow*dt; i++) {	psNewParticle(&particles[living], dt);	living++;	if (living >= num_particles)	    living = 0;    }    for (i = 0; i < num_particles; i++) {	psTimeStep(&particles[i], dt);	/* collision with sphere? */	if (do_sphere) {	    psCollide(&particles[i]);	}	/* collision with ground? */	if (particles[i].position[1] <= 0) {	    psBounce(&particles[i], dt);	}	/* dead particle? */	if (particles[i].position[1] < 0.1 && 	    fequal(particles[i].velocity[1], 0)) {	    particles[i].alive = 0;	}    }    glutPostRedisplay();}voidvisible(int state){    if (state == GLUT_VISIBLE) {        timedelta();	glutIdleFunc(idleFunc);    } else {	glutIdleFunc(NULL);    }}voidbail(int code){    free(particles);    exit(code);}#ifdef SCREEN_SAVER_MODE/* ARGSUSED */voidss_keyboard(char key, int x, int y){    bail(0);}/* ARGSUSED */voidss_mouse(int button, int state, int x, int y){    bail(0);}/* ARGSUSED */voidss_passive(int x, int y){    static int been_here = 0;    /* for some reason, GLUT sends an initial passive motion callback       when a window is initialized, so this would immediately       terminate the program.  to get around this, see if we've been       here before. (actually if we've been here twice.) */    if (been_here > 1)	bail(0);    been_here++;}#else/* ARGSUSED1 */voidkeyboard(unsigned char key, int x, int y){    static int fullscreen = 0;    static int old_x = 50;    static int old_y = 50;    static int old_width = 320;    static int old_height = 320;    switch (key) {    case 27:        bail(0);	break;    case 'w':	type = PS_WATERFALL;	break;    case 'f':	type = PS_FOUNTAIN;	break;    case 's':	do_sphere = !do_sphere;	break;    case 'l':	points = !points;	break;    case 'P':	point_size++;	glPointSize(point_size);	break;	    case 'p':	point_size--;	if (point_size < 1)	    point_size = 1;	glPointSize(point_size);	break;	    case '+':	flow += 100;	if (flow > num_particles)	    flow = num_particles;	printf("%g particles/second\n", flow);	break;    case '-':	flow -= 100;	if (flow < 0)	    flow = 0;	printf("%g particles/second\n", flow);	break;    case '~':	fullscreen = !fullscreen;	if (fullscreen) {	    old_x = glutGet(GLUT_WINDOW_X);	    old_y = glutGet(GLUT_WINDOW_Y);	    old_width = glutGet(GLUT_WINDOW_WIDTH);	    old_height = glutGet(GLUT_WINDOW_HEIGHT);	    glutFullScreen();	} else {	    glutReshapeWindow(old_width, old_height);	    glutPositionWindow(old_x, old_y);	}	break;    }}#endifint old_x, old_y;/* ARGSUSED */voidmouse(int button, int state, int x, int y){    old_x = x;    old_y = y;    glutPostRedisplay();}voidmotion(int x, int y){    spin_x = x - old_x;    spin_y = y - old_y;    glutPostRedisplay();}intmain(int argc, char** argv){    glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);    glutInitWindowPosition(50, 50);    glutInitWindowSize(320, 320);    glutInit(&argc, argv);    if (argc > 1 && !strcmp(argv[1], "-fullscreen")) {      glutGameModeString("640x480:16@60");      glutEnterGameMode();    } else {      glutCreateWindow("Particles");    }    glutDisplayFunc(display);    glutReshapeFunc(reshape);#ifdef SCREEN_SAVER_MODE    glutPassiveMotionFunc(ss_passive);    glutKeyboardFunc(ss_keyboard);    glutMouseFunc(ss_mouse);    glutSetCursor(GLUT_CURSOR_NONE);    glutFullScreen(); #else    glutMotionFunc(motion);    glutMouseFunc(mouse);    glutKeyboardFunc(keyboard);#endif    if (argc > 1) {	if (strcmp(argv[1], "-h") == 0) {	    fprintf(stderr, "%s [particles] [flow] [speed%%]\n", argv[0]);	    exit(0);	}	sscanf(argv[1], "%d", &num_particles);	if (argc > 2)	    sscanf(argv[2], "%f", &flow);	if (argc > 3)	    sscanf(argv[3], "%f", &slow_down);    }          particles = (PSparticle*)malloc(sizeof(PSparticle) * num_particles);    glutVisibilityFunc(visible);    glutMainLoop();    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -