/* yomiko7.c - Don Yang (uguu.org) 03/20/02 */ #include #include #include #include #include #define Interpolate(fmin, fmax, t) \ ((((float)((fmax) - (fmin))) * (float)(t)) + (fmin)) #define Random(rmin, rmax) \ Interpolate(rmin, rmax, ((float)(rand() & 4095)) / 4095.0) typedef struct { float x, y, z, x0, y0, z0, vx, vy, vz; int rx, ry, rx0, ry0; } ObjM; float PI, CameraAngle, CameraPosition, dw, dh, dx[2], aa, ab, ac, bb, bc, ca, cb, cc, cx, sx, cy, sy, t, u, v, f[11][4] = { {.8,.8,.8, 1}, {.8,.8, 1, 1}, {.8, 1,.8, 1}, { 1,.8,.8, 1}, { 1, 1,.8, 1}, { 1,.8, 1, 1}, {.8, 1, 1, 1}, { 1, 1, 1, 1}, { 0, 1, 1, 0}, { 0,-1,-1, 0}, { 0, 0, 0, 0} }, vertices[4][3] = { {-5, 0,-5}, {-5, 0, 5}, { 5, 0, 5}, { 5, 0,-5} }; int StartTime, CurrentTime, PreviousTime, TimeOffset, WindowWidth, WindowHeight, DrawOutline, PaperCount, AnimateStartTime, AnimateChangeTime, CutAngle, i, j, k; struct timeb z; struct { float v[4][3], n[3]; } Poly[128][128], *r; ObjM Paper[2048], Paper0[2048], *p, *q; void (*AnimateStateFunc)(void); void Animate_TransitionToCut(void); void Wrap(void) { for(; p->x < -320; p->x += 640); for(; p->z < -320; p->z += 640); for(; p->x > 320; p->x -= 640); for(; p->z > 320; p->z -= 640); } void Cut(int count) { dx[1] = 1000 * Poly[32][CutAngle].v[0][2]; for(dx[0] = 1000 * Poly[32][CutAngle].v[0][i = 0]; i < count; i++) { p->x = p->x0 + dx[0] * t; p->z = p->z0 + dx[1] * t; Wrap(); p++; } } void Drift(int count) { dx[1] = sin(PI * t * 17); for(dx[0] = sin(PI * t * 10); i < count; i++) { p->x = p->x0 + p->vx * t * 3; p->y = p->y0 + p->vy * t * 3; p->z = p->z0 + p->vz * t * 3; Wrap(); if( p->y < -320 ) { p->y0 += 640; p->x0 = Random(-320, 320); p->z0 = Random(-320, 320); p->vx = Random(-96, 96); p->vz = Random(-96, 96); p->vy = Random(-640,-320); } u = (i & 2) ? (p->x += Poly[0][p->ry].v[0][0] * dx[i & 1] * 2.5) + (p->z += Poly[0][p->ry].v[0][2] * dx[i & 1] * 2.5) + (p->rx = ((int)(10 * dx[i & 1]) + 128) & 127) : (p->x -= Poly[0][p->ry].v[0][0] * dx[i & 1] * 2.5) + (p->z -= Poly[0][p->ry].v[0][2] * dx[i & 1] * 2.5) + (p->rx = ((int)(-10 * dx[i & 1]) + 128) & 127); p++; } } void Freeze(void) { p = Paper; for(i = 0; i < 2048; i++) { p->x0 = p->x; p->y0 = p->y; p->z0 = p->z; p->rx0 = p->rx; p->ry0 = p->ry; p++; } } void Animate(void) { i = CurrentTime - PreviousTime - 31; if( i > 4 || i < -4 ) { PaperCount -= i / 4; if( PaperCount < 128 ) PaperCount = 128; if( PaperCount > 2048 ) PaperCount = 2048; } DrawOutline = (i < 16 && PaperCount == 2048); CameraAngle = (((float)(CurrentTime % 50000)) / 25000.) * PI; CameraPosition = sin((((float)(CurrentTime % 20000)) / 10000.) * PI); t = (CurrentTime - AnimateStartTime) / (float)(AnimateChangeTime - AnimateStartTime); p = Paper; i = 0; AnimateStateFunc(); glutPostRedisplay(); } void Animate_Drift(void) { if( CurrentTime > AnimateChangeTime ) { Drift(2048); Freeze(); CutAngle = rand() & 127; AnimateChangeTime = (AnimateStartTime = CurrentTime) + 768 + (rand() & 127); AnimateStateFunc = Animate_TransitionToCut; } else { Drift(PaperCount); } } void Animate_TransitionToDrift(void) { if( CurrentTime > AnimateChangeTime ) { Drift(2048); Freeze(); AnimateChangeTime = (AnimateStartTime = CurrentTime) + 21000 + (rand() & 4095); AnimateStateFunc = Animate_Drift; } else { Drift(PaperCount); u = t; t = -0.5 * t * t + t + 1; p = Paper0; Cut(PaperCount); p = Paper; q = Paper0; for(i = 0; i < PaperCount; i++) { p->x = Interpolate(q->x, p->x, u); p->y = Interpolate(q->y, p->y, u); p->z = Interpolate(q->z, p->z, u); p->rx = (int)((i & 1) ? Interpolate(q->rx0, 0, u) : Interpolate(q->rx0, 128, u)) & 127; p->ry = (int)((i & 2) ? Interpolate(q->ry0, p->ry0, u) : Interpolate(q->ry0, p->ry0 + 128, u)) & 127; p++; q++; } } } void Animate_Cut(void) { if( CurrentTime > AnimateChangeTime ) { Cut(2048); Freeze(); memcpy(Paper0, Paper, 2048 * sizeof(ObjM)); p = Paper; for(i = 0; i < 2048; i++) { p->vx = Random(-160, 160); p->vz = Random(-160, 160); p->vy = Random(-640, -320); p->rx0 = 0; p->ry0 = rand() & 127; p++; } AnimateChangeTime = (AnimateStartTime = CurrentTime) + 9000 + (rand() & 4095); AnimateStateFunc = Animate_TransitionToDrift; } else { Cut(PaperCount); } } void Animate_Still(void) { if( CurrentTime > AnimateChangeTime ) { AnimateChangeTime = (AnimateStartTime = CurrentTime) + 9000 + (rand() & 4095); AnimateStateFunc = Animate_Cut; } } void Animate_TransitionToCut(void) { for(i = 0; i < PaperCount; i++) { p->rx = (int)((i & 1) ? Interpolate(p->rx0, 32, t) : Interpolate(p->rx0, 160, t)) & 127; p->ry = (int)((i & 2) ? Interpolate(p->ry0, CutAngle, t) : Interpolate(p->ry0, CutAngle + 128, t)) & 127; p++; } if( CurrentTime > AnimateChangeTime ) { p = Paper; for(i = 0; i < 2048; i++) { p->rx = p->rx0 = 32; p->ry = p->ry0 = CutAngle; p++; } AnimateChangeTime = (AnimateStartTime = CurrentTime) + 1000; AnimateStateFunc = Animate_Still; } } void Render(void) { ftime(&z); PreviousTime = CurrentTime; CurrentTime = (z.time - TimeOffset) * 1000 + z.millitm; glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(k = 0, 0, WindowWidth, WindowHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-dw, dw, -dh, dh, 10, 2000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLightfv(GL_LIGHT0, GL_POSITION, f[5]); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, f[6]); gluLookAt( 640 * sin(CameraAngle), 320 * CameraPosition, 640 * cos(CameraAngle), 0, 0, 0, 0, 1, 0); for(; k < 8; k++) { glLightfv(GL_LIGHT0, GL_AMBIENT, f[k]); glBegin(GL_QUADS); p = &Paper[k]; for(i = k; i < PaperCount; i += 8) { glNormal3fv(Poly[p->rx][p->ry].n); for(j = 0; j < 4; j++) glVertex3f( Poly[p->rx][p->ry].v[j][0] + p->x, Poly[p->rx][p->ry].v[j][1] + p->y, Poly[p->rx][p->ry].v[j][2] + p->z); p += 8; } glEnd(); } if( DrawOutline ) { glDisable(GL_LIGHTING); p = Paper; for(i = 0; i < PaperCount; i++) { glBegin(GL_LINE_LOOP); for(j = 0; j < 4; j++) glVertex3f( Poly[p->rx][p->ry].v[j][0] + p->x, Poly[p->rx][p->ry].v[j][1] + p->y, Poly[p->rx][p->ry].v[j][2] + p->z); glEnd(); p++; } glEnable(GL_LIGHTING); } glutSwapBuffers(); glFlush(); } void Reshape(int w, int h) { WindowWidth = w; WindowHeight = h; u = w > h ? (dw = w / (float)h) + (dh = 1) : (dw = 1) + (dh = h / (float)w); glutPostRedisplay(); } void Quit(unsigned char c, int u, int v) { exit(0); } int main(int argc, char **argv) { glutInit(&argc, argv); PI = atan2(0, -1); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutSetWindow(glutCreateWindow("yomiko")); glutDisplayFunc(Render); glutIdleFunc(Animate); glutReshapeFunc(Reshape); glutKeyboardFunc(Quit); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_DIFFUSE, f[7]); glLightfv(GL_LIGHT0, GL_SPECULAR, f[7]); glColor4fv(f[10]); for(r = &Poly[0][i = 0]; i < 128; i++) for(j = 0; j < 128; j++) { memcpy(r->v, vertices, sizeof(float) * 12); t = PI / 64.; cc = (bb = cx = cos(u = i * t)) * (aa = cy = cos(v = j * t)); ab = (bc = -(sx = sin(u))) * (sy = sin(v)); ac = cx * sy; ca = -sy; cb = sx * cy; for(k = 0; k < 4; k++) { v = ca * r->v[k][0] + cb * r->v[k][1] + cc * r->v[k][2]; r->v[k][0] = aa * r->v[k][0] + ab * r->v[k][1] + ac * r->v[k][2]; r->v[k][1] = bb * r->v[k][1] + bc * r->v[k][2]; r->v[k][2] = v; } r->n[0] = ab; r->n[1] = bb; r->n[2] = cb; r++; } PaperCount = 512; p = Paper; for(DrawOutline = i = 0; i < 2048; i++) { p->x0 = Random(-320, 320); p->y0 = Random(-320, 320); p->z0 = Random(-320, 320); p->vx = Random(-96, 96); p->vz = Random(-96, 96); p->vy = Random(-640, -320); p->rx0 = p->rx = rand() & 127; p->ry0 = p->ry = rand() & 127; p++; } ftime(&z); srand(TimeOffset = z.time); PreviousTime = (CurrentTime = StartTime = z.millitm) - 31; CameraAngle = 0; AnimateChangeTime = (AnimateStartTime = CurrentTime) + 9000 + (rand() & 4095); AnimateStateFunc = Animate_Drift; glutMainLoop(); return 0; }