/* This is a quick and dirty de-obfuscation of my 1998 IOCCC entry. For comparison, you may want to look at the original which won the "Best Object Orientation" award: http://www.ioccc.org/1998/chaos.c This de-obfuscation is a quick hack done while tired five years after I originally wrote it. As a result, it's a bit erratic, and some of the comments might not be entirely accurate. My apologies. In short, the program uses the curses text library to display and rotate 3d objects. The algorithms used are standard 3d graphics algorithms, however, if you're unfamiliar with them they look a bit daunting. Once running, use any of h,j,k,y,u, or i to rotate and a or z to zoom in and out. Copyright 2002 Alan De Smet http://www.highprogrammer.com/alan/ */ #include #include #include /* The array X is declared as float, but actually holds some integers * interleaved with the other data. This helps extract integer values out of * the array. */ #define V ((int *)(X+N)) /* Loop for a up to but not through b */ #define for_loop(a,b) for(a = 0; a < b; a++) /* Partially translate a coordinate from 3d space to 2d space */ #define trans_3d_to_2d(a) (X[K] * H[a*4]+ X[K+1] * H[a*4+1]+ X[K+2] * H[a*4+2]) /* If button 'e' was pressed, apply a 6 degree rotation. The variable f * controls the direction of rotation (set to empty for "forward", set to - for * "backward". The variables a, b, and c control which access the rotation is * applied to. The constant numbers are simply the sin and cosine of 6 * degrees. (Actually, the cosine is slightly off, a bug whose source I don't * remember. Fortunately, it doesn't seem to be a problem.) T is used */ #define test_key_and_rotate(e,f,a,b,c) \ if(M==e) { \ T[a*4+c] = T[b*4+c] = T[c*4+a] = T[c*4+b] = !(T[c*5] = 1); \ T[a*4+b] = -(T[b*4+a] = f .1045284632); T[b*5] = T[a*5] = .9945418726; \ for_loop(M,3) \ for_loop(E,4) \ for_loop(K,3) \ R[M*4+E] += H[K*4+E] * T[M*4+K]; \ memcpy(H,R,12*sizeof(float)); \ } /* Q is briefly used to during initialization, but spends most of its life as a * sort of backing store for the display. */ char Q[3792]; int K, M=0, E, B; long Z; /* H, T, and R represent 3d coordinate systems and are 4x3 matrices. A 3d * coordinate system can represent a rotation, scaling, sizing, and other * things. H represents the current rotation of the object. H is initialized * as the identity matrix meaning "no rotation, translation, or anything else." * * R holds the rotation we're about to add to H during a single frame. T is * the temporary rotation before we add it to R. */ float H[] = { 1,0,0,0,0,1,0,0,0,0,1,0 }, T[12], R[12], /* Miscellaneous variables */ C, D, I, J, S, /* * X holds both the original 3d space floating point coordinates and the 2d * space integer coordates when the result is displayed on the screen. */ * X, /* Represents the "zoom" (actually represents how close the camera is to the * object. */ G=4; FILE * W; int main(int N,char ** Y) { /* The "default" object to be rotated. Also the source of where "AlWuzEre" * is drawn from when you quit (it seemed like a good idea at the time). * Instead of reading the data out of this string, we scan our own * binary for it. This is clumsy and can theoretically fail, but in * practice it doesn't, it keep the file reading code simple, and * make the program a bit more cryptic. */ char P[] = "AlWuzEre 72 -1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 -1 1 1 1 -1 1 -1 -1 -1 1 -1 -1 1 1 1 1 -1 -1 1 -1 1 -1 1 -1 -1 1 1 -1 -1 -1 -1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 -1 1 -1 1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 "; strcpy(Q,P); if(!(W = fopen(Y[N<2?0:1],"r"))) { printf("Can't read\n"); exit(-1); } fseek(W,0,SEEK_END); Z = ftell(W); fseek(W,0,SEEK_SET); strcpy(Q+9, "%d"); while(fscanf(W,Q,&N) != 1) { fseek(W,1,SEEK_CUR); if(ftell(W) >= Z) { printf("Bad input\n"); exit(-1); } } /* Allocate space to hold both the original line coordinates in 3d space * floating point coordinates and the 2s integer coordinates. (Actually * allocates more space than necessary for easy of implementation.) * * As the program runs, most calculations will be done on this array. */ X = (float *)malloc(N * (sizeof(int)>sizeof(float)?sizeof(int):sizeof(float)) * 2); if(!X) { printf("No memory\n"); exit(-1); } for_loop(K,N) fscanf(W,"%f",X+K); fclose(W); initscr(); halfdelay(30); noecho(); /* The main loop */ CH: /* Initialize the rotation matrix to 0. Rotation will be * acculated in R in the calls to test_key_and_rotate. */ memset(R,0,12*sizeof(float)); test_key_and_rotate('h', ,1,2,0) test_key_and_rotate('j', ,2,0,1) test_key_and_rotate('k', ,1,0,2) test_key_and_rotate('y',-,1,2,0) test_key_and_rotate('u',-,2,0,1) test_key_and_rotate('i',-,1,0,2) G += M=='a'?-.1:M=='z'?.1:0; /* zoom in and out */ if(M=='q') { printf("%.9s\n",P); exit(0); } memset(Q,0,3792); erase(); /* Translate from 3d space to screen space. */ for_loop(K,N) { C = 40 / (trans_3d_to_2d(2)+G); /* The +40 and +24 center the display on the screen. * It's +24 instead of the +12 you might expect because I * treat each character as being 2 pixels high, using diferent * characters to represent their states. */ V[K] = (int)(trans_3d_to_2d(0) * C) + 40; V[K+1] = (int)(trans_3d_to_2d(1) * C) + 24; K+=2; } /* Draw the 2d lines to screen. Treat each character as two * pixels, using ` to turn on the top pixel, . to turn on the * bottom pixel, and : to turn on both. Because multiple lines * may independently turn on the top and bottom pixels of a character, * we need to keep track of what we have drawn before in Q. */ for_loop(B,N) { C = V[B++]; D = V[B++]; E = V[++B] - C; M = V[++B] - D; B++; S = (float)abs((abs(E)>abs(M))?E:M); I=E/S; J=M/S++; for_loop(K,S) { E = (int)(C+0.5); M = (int)(D+0.5); if(E>=0 && M>=0 && E<79 && M<48) { Q[E + M * 79] = 1; mvaddch((M&1?M-1:M)/2, E, Q[E+(M+(M&1?-1:1))*79]?':':(M&1?'.':'`')); } C+=I; D+=J; } } move(0,0); /* Get the cursor out of the way */ refresh(); /* Update the screen */ /* Get the next character. Use halfdelay to automatically * start rotation if no input shows up. */ M = getch(); halfdelay(M==ERR?1:30); M = M==ERR?'u':M; goto CH; }