/* aya3.c - Don Yang (uguu.org) 10/04/06 */ #include #include #include #include #include #include #define WINDOW_TITLE "Aya" #define PIXEL_ASPECT 1.0 #define TEXTURE_SIZE 64 #define SPRITE_SIZE 0.07 #define MAX_EMITTER_AGE 1.5 #define MAX_RADIUS 2.1 static double PI; static double ColorCurveR[] = { 0.9, 0.98, 1.0, 0.0, -1.0 }; static double ColorCurveGB[] = { 0.32, 0.98, 0.36, 0.12, 0.54, 0.12, 0.58, 0.98, 0.9, 0.98, 1.0, 0.0, -1.0 }; static double ColorCurveA[] = { 0.56, 0.99, 0.58, 0.70, 0.9, 0.0, -1.0 }; static unsigned char TextureImage[TEXTURE_SIZE * TEXTURE_SIZE * 4]; static GLuint TextureHandle; static GLuint SpriteHandle; static double CurrentTime; typedef struct { double t0, x, y, r0, r1; } Emitter; static Emitter GlobalEmitter; double x, y, r, c, ix0, iy0, ix1, iy1; int i, j, k; unsigned char *p; #define INTERPOLATE(t, x0, x1) ((t) * ((x1) - (x0)) + (x0)) #define RANDOM(x0, x1) \ ((x0) + ((x1) - (x0)) * (double)(rand() & 0x3fff) / 16383.0) static void RenderFirstFrame(void); static void Render(void); static void Animate(void); static void Reshape(int w, int h); static void Quit(unsigned char c, int u, int v); static double StepFunc(double t, double *curve); static void UpdateClock(void); int main(int argc, char **argv) { glutInit(&argc, argv); /* Init */ PI = atan2(0.0, -1.0); /* InitTexture */ p = memset(TextureImage, 0, TEXTURE_SIZE * TEXTURE_SIZE * 4); for(i = 0; i < TEXTURE_SIZE; i++) { x = ((double)i - (TEXTURE_SIZE / 2)) / (TEXTURE_SIZE / 2); for(j = 0; j < TEXTURE_SIZE; j++) { y = ((double)j - (TEXTURE_SIZE / 2)) / (TEXTURE_SIZE / 2); r = sqrt(x * x + y * y); c = StepFunc(r, ColorCurveR); k = (int)(255 * c); if( k > 255 ) k = 255; *(p++) = (unsigned char)k; c = StepFunc(r, ColorCurveGB); k = (int)(255 * c); if( k > 255 ) k = 255; *(p++) = (unsigned char)k; *(p++) = (unsigned char)k; c = StepFunc(r, ColorCurveA); k = (int)(255 * c); if( k > 255 ) k = 255; *(p++) = (unsigned char)k; } } glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutSetWindow(glutCreateWindow(WINDOW_TITLE)); glutDisplayFunc(RenderFirstFrame); glutIdleFunc(Animate); glutReshapeFunc(Reshape); glutKeyboardFunc(Quit); glutMainLoop(); return 0; } static void RenderFirstFrame(void) { UpdateClock(); srand((unsigned int)CurrentTime); glGenTextures(1, &TextureHandle); glBindTexture(GL_TEXTURE_2D, TextureHandle); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEXTURE_SIZE, TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)TextureImage); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glNewList(SpriteHandle = glGenLists(1), GL_COMPILE); glBegin(GL_TRIANGLE_FAN); glTexCoord2d(0.0, 0.0); glVertex2d(-SPRITE_SIZE, -SPRITE_SIZE); glTexCoord2d(1.0, 0.0); glVertex2d( SPRITE_SIZE, -SPRITE_SIZE); glTexCoord2d(1.0, 1.0); glVertex2d( SPRITE_SIZE, SPRITE_SIZE); glTexCoord2d(0.0, 1.0); glVertex2d(-SPRITE_SIZE, SPRITE_SIZE); glEnd(); glEndList(); GlobalEmitter.t0 = CurrentTime; GlobalEmitter.x = GlobalEmitter.y = GlobalEmitter.r0 = GlobalEmitter.r1 = 0.0; glutDisplayFunc(Render); Render(); } static void Render(void) { UpdateClock(); glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT); i = glutGet(GLUT_WINDOW_WIDTH); j = glutGet(GLUT_WINDOW_HEIGHT); glViewport(0, 0, i, j); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if( i > j ) { gluOrtho2D((-i * PIXEL_ASPECT) / j, (i * PIXEL_ASPECT) / j, -1.0, 1.0); } else { gluOrtho2D(-1.0, 1.0, -j / (i * PIXEL_ASPECT), j / (i * PIXEL_ASPECT)); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* DrawSprites */ ix0 = (CurrentTime - GlobalEmitter.t0) / MAX_EMITTER_AGE; for(i = 0; i < 23; i++) { ix1 = ix0 - (i / 23.0); if( ix1 < 0.0 ) continue; r = ix1 * MAX_RADIUS; for(j = 0; j < 32; j++) { iy1 = INTERPOLATE(ix1, GlobalEmitter.r0 + j * PI * 2.0 / 32.0, GlobalEmitter.r1 + j * PI * 2.0 / 32.0); if( (i & 1) != 0 ) iy1 += PI * 2.0 / 64.0; x = r * cos(iy1) + GlobalEmitter.x; y = r * sin(iy1) + GlobalEmitter.y; glPushMatrix(); glTranslated(x, y, 0.0); glCallList(SpriteHandle); glPopMatrix(); } } if( ix0 > 2.2 ) { /* InitSprites */ GlobalEmitter.t0 = CurrentTime; GlobalEmitter.r0 = GlobalEmitter.r1 = RANDOM(0.0, PI * 2.0); if( (rand() & 3) == 0 ) GlobalEmitter.r1 += RANDOM(-PI / 3.0, PI / 3.0); GlobalEmitter.x = RANDOM(-0.5, 0.5); GlobalEmitter.y = RANDOM(-0.5, 0.5); } glutSwapBuffers(); glFlush(); } static void Animate(void) { glutPostRedisplay(); } static void Reshape(int w, int h) { glutPostRedisplay(); } static void Quit(unsigned char c, int u, int v) { glFlush(); glDeleteLists(SpriteHandle, 1); glDeleteTextures(1, &TextureHandle); exit(EXIT_SUCCESS); } static double StepFunc(double t, double *curve) { ix0 = *curve++; iy0 = *curve++; if( t < ix0 ) return iy0; for(;;) { ix1 = *curve++; if( ix1 < ix0 ) break; iy1 = *curve++; if( t < ix1 ) return (iy1 - iy0) * (t - ix0) / (ix1 - ix0) + iy0; ix0 = ix1; iy0 = iy1; } return iy0; } static void UpdateClock(void) { struct timeval t; gettimeofday(&t, NULL); CurrentTime = (double)t.tv_sec + (double)(t.tv_usec / 1000000.0); }