/* snow.c - Don Yang (uguu.org) 11/04/01 */ /*@ -compdef -realcompare -type -usedef @*/ #include #include #include #include #include #include #include #include #include #define FIELD_SIZE 512.0 #define FIELD_HEIGHT 256.0 #define DROP_TIME 16.0 #define SNOWFLAKE_COUNT 128 #define SNOWFLAKE_SIZE 8.0 #define PATH_STEP_COUNT 8 #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define WINDOW_POS_X 100 #define WINDOW_POS_Y 100 #define PERSP_SCALE 1.0 #define PERSP_NEAR 10.0 #define PERSP_FAR 2000.0 #define CAMERA_DISTANCE 1000.0 #define Rand() ((double)(rand() & 4095) / 4095.0) typedef struct { GLdouble x, y, z, ax, ay, az; /* Current position and rotation */ GLdouble sx, sy, sz, ex, ey, ez; /* Start and end coordinates */ GLdouble rx, ry, rz; /* Delta rotation */ GLuint obj; /* Display list */ double st; /* Start time */ } Snowflake; static int Window; static double PI; static Snowflake Snow[SNOWFLAKE_COUNT]; /************************************************************** RandomPath */ static void RandomPath(double *r, double *a) { int i; r[0] = SNOWFLAKE_SIZE; a[0] = 0; for(i = 1; i < PATH_STEP_COUNT - 1; i++) { r[i] = (Rand() * 0.6 + 0.4) * SNOWFLAKE_SIZE; a[i] = Rand() * PI / 6.0; } r[i] = 0.4 * SNOWFLAKE_SIZE; a[i] = PI / 6.0; } /* RandomPath() */ /********************************************************* CreateSnowflake */ static void CreateSnowflake(Snowflake *f, double ct) { double r[PATH_STEP_COUNT], a[PATH_STEP_COUNT]; int i, j; f->x = f->sx = Rand() * FIELD_SIZE * 2 - FIELD_SIZE; f->y = f->sy = FIELD_HEIGHT; f->z = f->sz = Rand() * FIELD_SIZE * 2 - FIELD_SIZE; f->ex = Rand() * FIELD_SIZE * 2 - FIELD_SIZE; f->ey = -FIELD_HEIGHT - Rand() * FIELD_SIZE * 2; f->ez = Rand() * FIELD_SIZE * 2 - FIELD_SIZE; f->ax = Rand() * 360.0; f->rx = Rand() * 10.0; f->ay = Rand() * 360.0; f->ry = Rand() * 10.0; f->az = Rand() * 360.0; f->rz = Rand() * 10.0; f->st = ct; assert(f->obj != 0); RandomPath(r, a); glNewList(f->obj, GL_COMPILE); glBegin(GL_LINE_LOOP); for(i = j = 0; i < 6; i++) { for(; j < PATH_STEP_COUNT - 1; j++) { glVertex3d(r[j] * cos((i * PI / 3.0) + a[j]), r[j] * sin((i * PI / 3.0) + a[j]), 0.0); } for(; j > 0; j--) { glVertex3d(r[j] * cos(((i + 1) * PI / 3.0) - a[j]), r[j] * sin(((i + 1) * PI / 3.0) - a[j]), 0.0); } } glEnd(); glEndList(); } /* CreateSnowflake() */ /****************************************************** TransformSnowflake */ static void TransformSnowflake(Snowflake *f, double ct) { double t; /* Translate snow flake. Position obtained by interpolating using current time instead of adding constant delta, so they ought to fall at constant velocity on all machines. */ f->y = f->sy + (f->ey - f->sy) * (t = (ct - f->st) / DROP_TIME); if( f->y < -FIELD_HEIGHT ) { CreateSnowflake(f, ct); } else { f->x = f->sx + (f->ex - f->sx) * t; f->z = f->sz + (f->ez - f->sz) * t; /* Rotation is not interpolated by time, so snowflakes may wobble randomly */ f->ax += f->rx; f->ay += f->ry; f->az += f->rz; } } /* TransformSnowflake() */ /***************************************************************** Animate */ static void Animate(void) { struct timeb t; double ct; int i; (void)ftime(&t); ct = (double)(t.time) + (t.millitm / 1000.0); for(i = 0; i < SNOWFLAKE_COUNT; i++) TransformSnowflake(&Snow[i], ct); glutSetWindow(Window); glutPostRedisplay(); } /* Animate() */ /****************************************************************** Render */ static void Render(void) { double dw, dh; int w, h, i; glutSetWindow(Window); glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, w = glutGet(GLUT_WINDOW_WIDTH), h = glutGet(GLUT_WINDOW_HEIGHT)); if( w > h ) { dw = (double)w / (double)h; dh = 1.0; } else { dw = 1.0; dh = (double)h / (double)w; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-dw * PERSP_SCALE, dw * PERSP_SCALE, -dh * PERSP_SCALE, dh * PERSP_SCALE, PERSP_NEAR, PERSP_FAR); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, -CAMERA_DISTANCE, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glColor4f(0.8f, 0.9f, 1.0f, 0.5f); for(i = 0; i < SNOWFLAKE_COUNT; i++) { glPushMatrix(); glTranslated(Snow[i].x, Snow[i].y, Snow[i].z); glRotated(Snow[i].ax, 1.0, 0.0, 0.0); glRotated(Snow[i].ay, 0.0, 1.0, 0.0); glRotated(Snow[i].az, 0.0, 0.0, 1.0); glCallList(Snow[i].obj); glPopMatrix(); } glutSwapBuffers(); glFlush(); } /* Render() */ /***************************************************************** Reshape */ static void Reshape(/*@unused@*/int w, /*@unused@*/int h) { glutSetWindow(Window); glutPostRedisplay(); } /* Reshape() */ /******************************************************************** Quit */ static void Quit(/*@unused@*/unsigned char c, /*@unused@*/int u, /*@unused@*/int v) { int i; glFlush(); for(i = 0; i < SNOWFLAKE_COUNT; i++) glDeleteLists(Snow[i].obj, 1); exit(EXIT_SUCCESS); } /* Quit() */ /************************************************************** Initialize */ static void Initialize(void) { struct timeb t; double ct; int i; glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(WINDOW_POS_X, WINDOW_POS_Y); Window = glutCreateWindow("winter wish"); glutSetWindowTitle("winter wish"); glutSetWindow(Window); glutDisplayFunc(Render); glutIdleFunc(Animate); glutReshapeFunc(Reshape); glutKeyboardFunc(Quit); /* All keypresses exits program */ (void)ftime(&t); ct = (double)(t.time) + (t.millitm / 1000.0); for(i = 0; i < SNOWFLAKE_COUNT; i++) { Snow[i].obj = glGenLists(1); assert(Snow[i].obj != 0); CreateSnowflake(&Snow[i], ct); Snow[i].ey -= FIELD_HEIGHT * 2; /* Make first generation fall faster */ } glEnable(GL_BLEND); glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_NORMALIZE); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE); } /* Initialize() */ /******************************************************************** main */ int main(int argc, char **argv) { srand((unsigned)time(NULL)); PI = atan2(0, -1); glutInit(&argc, argv); Initialize(); glutMainLoop(); return 0; } /* main() */