/* 
 * Fireworks in OpenGL (very simple, messy play-around-with code.. sorry)
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <GL/glut.h>
#include <math.h>


/* #define SCREEN_SAVER_MODE */


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
reshape(int width, int height)
{
    int i = 0;

    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);

    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 * 5);
        stars[i].vy = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * 5);
    } while (
        (stars[i].vx*stars[i].vx + stars[i].vy*stars[i].vy) > 25);

    stars[i].r = rand()%255;
    stars[i].g = rand()%255;
    stars[i].b = rand()%255;
    }
}

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 {
        stars[i].x = x;
        stars[i].y = y;
           do {
        stars[i].vx = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * 5);
        stars[i].vy = (rand()%2 ? 1 : -1) * (rand() / (float)RAND_MAX * 5);
        } while (
        (stars[i].vx*stars[i].vx + stars[i].vy*stars[i].vy) > 25);
    }
    }

    cnt++;

    if(!continuous)
        if (cnt > CNT_MAX)
            x = w + 100, y = h + 100;
    
    glutSwapBuffers();
}

void
idle(void)
{
    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("Starfield");
    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;
}
