/* * Fireworks in OpenGL (very simple, messy play-around-with code.. sorry) */ #include #include #include #include #include /* gravitational constant -- not to scale ;) */ #define G 0.07 /* this controls the size of the initial blob of particles * i.e. the size of the explosion */ #define EXPL 3 enum { SCROLL_LEFT = 1, SCROLL_RIGHT, SCROLL_UP, SCROLL_DOWN } type = SCROLL_RIGHT; typedef struct _star { float x, y; float vx, vy; int r, g, b; } star; star* stars = NULL; int num_stars = 500; int x, y; int w, h; int cnt = 0; int continuous = 0; #define CNT_MAX 0 void init_stars() { /* initialize stars' velocities * make sure they start off in a circle, rather than the square the * random values tend to put them in */ int i; for (i = 0; i < num_stars; i++) { stars[i].x = x; stars[i].y = y; do { stars[i].vx = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * EXPL); stars[i].vy = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * EXPL); } while ( (stars[i].vx*stars[i].vx + stars[i].vy*stars[i].vy) > EXPL*EXPL); stars[i].r = rand()%255; stars[i].g = rand()%255; stars[i].b = rand()%255; } } void reshape(int width, int height) { w = width; h = height; x = w/2; y = h/2; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3ub(255, 255, 255); init_stars(); } void explode(int i) { stars[i].x = x; stars[i].y = y; do { stars[i].vx = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * EXPL); stars[i].vy = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * EXPL); } while ( (stars[i].vx*stars[i].vx + stars[i].vy*stars[i].vy) > EXPL*EXPL); } void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < num_stars; i++) { stars[i].x += stars[i].vx; stars[i].y += stars[i].vy; if (stars[i].x < w && stars[i].x > 0 && stars[i].y > 0 && stars[i].y < h) { glBegin(GL_LINE_STRIP); glColor3ub(0, 0, 0); glVertex2i(stars[i].x-stars[i].vx*4, stars[i].y-stars[i].vy*4); glColor3ub( stars[i].r , stars[i].g , stars[i].b ); glVertex2i(stars[i].x, stars[i].y); glEnd(); } else { explode(i); } /* do some sort of gravity simulation */ stars[i].vy -= G; } cnt++; if(!continuous) if (cnt > CNT_MAX) x = w + 100, y = h + 100; glutSwapBuffers(); } int framecnt = 0; /* count idle frames and explode randomly */ int delay=100; /* how many frames should we wait for */ void idle(void) { int i; if(!(++framecnt % delay)) { x = rand()%w; y = rand()%(h/2) + h/2; /* have explosions only in the upper half of the screen */ for(i = 0; i < num_stars; i++) if(stars[i].x > w && stars[i].x < 0 && stars[i].y < 0 && stars[i].y > h) explode(i); delay = rand()%50 + 50; /* next explosion in at least 50 frames */ } glutPostRedisplay(); } void bail(int code) { free(stars); exit(code); } #ifdef SCREEN_SAVER_MODE void ss_keyboard(char key, int x, int y) { bail(0); } void ss_mouse(int button, int state, int x, int y) { bail(0); } void ss_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 void ss_mouse(int button, int state, int ix, int iy) { if(button == 2) continuous = continuous == 0 ? 1 : 0; cnt = 0; x = ix; y = h - iy; } void keyboard(unsigned char key, int x, int y) { 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': glutPositionWindow(old_x, old_y); glutReshapeWindow(old_width, old_height); break; case 'f': if (glutGet(GLUT_WINDOW_WIDTH) < glutGet(GLUT_SCREEN_WIDTH)) { 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(); } break; } } #endif int main(int argc, char** argv) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(50, 50); glutInitWindowSize(512, 512); glutInit(&argc, argv); glutCreateWindow("FireWorks + gravity"); glutDisplayFunc(display); glutReshapeFunc(reshape); #ifdef SCREEN_SAVER_MODE glutPassiveMotionFunc(ss_passive); glutKeyboardFunc(ss_keyboard); glutMouseFunc(ss_mouse); glutSetCursor(GLUT_CURSOR_NONE); glutFullScreen(); #else glutKeyboardFunc(keyboard); glutMouseFunc(ss_mouse); #endif if (argc > 1) { if (strcmp(argv[1], "-h") == 0) { fprintf(stderr, "%s [stars]\n", argv[0]); exit(0); } sscanf(argv[1], "%d", &num_stars); } stars = (star*)malloc(sizeof(star) * num_stars); glutIdleFunc(idle); glutMainLoop(); return 0; }