1/*
2 * Copyright (c) 1991, 1992, 1993 Silicon Graphics, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that (i) the above copyright notices and this permission notice appear in
7 * all copies of the software and related documentation, and (ii) the name of
8 * Silicon Graphics may not be used in any advertising or
9 * publicity relating to the software without the specific, prior written
10 * permission of Silicon Graphics.
11 *
12 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF
13 * ANY KIND,
14 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR
18 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <math.h>
29#include "glut_wrap.h"
30
31
32#ifndef PI
33#define PI 3.141592657
34#endif
35
36enum {
37    NORMAL = 0,
38    WEIRD = 1
39};
40
41enum {
42    STREAK = 0,
43    CIRCLE = 1
44};
45
46#define MAXSTARS 400
47#define MAXPOS 10000
48#define MAXWARP 500
49#define MAXANGLES 6000
50
51
52typedef struct _starRec {
53    GLint type;
54    float x[2], y[2], z[2];
55    float offsetX, offsetY, offsetR, rotation;
56} starRec;
57
58
59GLenum doubleBuffer;
60GLint windW, windH;
61
62GLenum flag = NORMAL;
63GLint starCount = MAXSTARS / 2;
64float speed = 1.0;
65GLint nitro = 0;
66starRec stars[MAXSTARS];
67float sinTable[MAXANGLES];
68
69
70static float Sin(float angle)
71{
72
73    return (sinTable[(GLint)angle]);
74}
75
76static float Cos(float angle)
77{
78
79    return (sinTable[((GLint)angle+(MAXANGLES/4))%MAXANGLES]);
80}
81
82static void NewStar(GLint n, GLint d)
83{
84
85    if (rand()%4 == 0) {
86	stars[n].type = CIRCLE;
87    } else {
88	stars[n].type = STREAK;
89    }
90    stars[n].x[0] = (float)(rand() % MAXPOS - MAXPOS / 2);
91    stars[n].y[0] = (float)(rand() % MAXPOS - MAXPOS / 2);
92    stars[n].z[0] = (float)(rand() % MAXPOS + d);
93    if (rand()%4 == 0 && flag == WEIRD) {
94	stars[n].offsetX = (float)(rand() % 100 - 100 / 2);
95	stars[n].offsetY = (float)(rand() % 100 - 100 / 2);
96	stars[n].offsetR = (float)(rand() % 25 - 25 / 2);
97    } else {
98	stars[n].offsetX = 0.0;
99	stars[n].offsetY = 0.0;
100	stars[n].offsetR = 0.0;
101    }
102}
103
104static void RotatePoint(float *x, float *y, float rotation)
105{
106    float tmpX, tmpY;
107
108    tmpX = *x * Cos(rotation) - *y * Sin(rotation);
109    tmpY = *y * Cos(rotation) + *x * Sin(rotation);
110    *x = tmpX;
111    *y = tmpY;
112}
113
114static void MoveStars(void)
115{
116    float offset;
117    GLint n;
118    static double t0 = -1.;
119    double t, dt;
120    t = glutGet(GLUT_ELAPSED_TIME) / 1000.;
121    if (t0 < 0.)
122       t0 = t;
123    dt = 85.*(t - t0);
124    t0 = t;
125
126    offset = speed * 60.0;
127
128    for (n = 0; n < starCount; n++) {
129	stars[n].x[1] = stars[n].x[0];
130	stars[n].y[1] = stars[n].y[0];
131	stars[n].z[1] = stars[n].z[0];
132	stars[n].x[0] += stars[n].offsetX*dt;
133	stars[n].y[0] += stars[n].offsetY*dt;
134	stars[n].z[0] -= offset*dt;
135        stars[n].rotation += stars[n].offsetR*dt;
136        if (stars[n].rotation > MAXANGLES) {
137            stars[n].rotation = 0.0;
138	}
139        else if (stars[n].rotation < 0.0) {
140           stars[n].rotation += 360.0;
141        }
142    }
143}
144
145static GLenum StarPoint(GLint n)
146{
147    float x0, y0, x1, y1, width;
148    GLint i;
149
150    x0 = stars[n].x[0] * windW / stars[n].z[0];
151    y0 = stars[n].y[0] * windH / stars[n].z[0];
152    RotatePoint(&x0, &y0, stars[n].rotation);
153    x0 += windW / 2.0;
154    y0 += windH / 2.0;
155
156    if (x0 >= 0.0 && x0 < windW && y0 >= 0.0 && y0 < windH) {
157	if (stars[n].type == STREAK) {
158	    x1 = stars[n].x[1] * windW / stars[n].z[1];
159	    y1 = stars[n].y[1] * windH / stars[n].z[1];
160	    RotatePoint(&x1, &y1, stars[n].rotation);
161	    x1 += windW / 2.0;
162	    y1 += windH / 2.0;
163
164	    glLineWidth(MAXPOS/100.0/stars[n].z[0]+1.0);
165	    glColor3f(1.0, (MAXWARP-speed)/MAXWARP, (MAXWARP-speed)/MAXWARP);
166	    if (fabs(x0-x1) < 1.0 && fabs(y0-y1) < 1.0) {
167		glBegin(GL_POINTS);
168		    glVertex2f(x0, y0);
169		glEnd();
170	    } else {
171		glBegin(GL_LINES);
172		    glVertex2f(x0, y0);
173		    glVertex2f(x1, y1);
174		glEnd();
175	    }
176	} else {
177	    width = MAXPOS / 10.0 / stars[n].z[0] + 1.0;
178	    glColor3f(1.0, 0.0, 0.0);
179	    glBegin(GL_POLYGON);
180		for (i = 0; i < 8; i++) {
181		    float x = x0 + width * Cos((float)i*MAXANGLES/8.0);
182		    float y = y0 + width * Sin((float)i*MAXANGLES/8.0);
183		    glVertex2f(x, y);
184		};
185	    glEnd();
186	}
187	return GL_TRUE;
188    } else {
189	return GL_FALSE;
190    }
191}
192
193static void ShowStars(void)
194{
195    GLint n;
196
197    glClear(GL_COLOR_BUFFER_BIT);
198
199    for (n = 0; n < starCount; n++) {
200	if (stars[n].z[0] > speed || (stars[n].z[0] > 0.0 && speed < MAXWARP)) {
201	    if (StarPoint(n) == GL_FALSE) {
202		NewStar(n, MAXPOS);
203	    }
204	} else {
205	    NewStar(n, MAXPOS);
206	}
207    }
208}
209
210static void Init(void)
211{
212    float angle;
213    GLint n;
214
215    srand((unsigned int) glutGet(GLUT_ELAPSED_TIME) );
216
217    for (n = 0; n < MAXSTARS; n++) {
218	NewStar(n, 100);
219    }
220
221    angle = 0.0;
222    for (n = 0; n < MAXANGLES ; n++) {
223	sinTable[n] = sin(angle);
224        angle += PI / (MAXANGLES / 2.0);
225    }
226
227    glClearColor(0.0, 0.0, 0.0, 0.0);
228
229    glDisable(GL_DITHER);
230}
231
232static void Reshape(int width, int height)
233{
234
235    windW = (GLint)width;
236    windH = (GLint)height;
237
238    glViewport(0, 0, windW, windH);
239
240    glMatrixMode(GL_PROJECTION);
241    glLoadIdentity();
242    gluOrtho2D(-0.5, windW+0.5, -0.5, windH+0.5);
243    glMatrixMode(GL_MODELVIEW);
244}
245
246static void Key(unsigned char key, int x, int y)
247{
248
249    switch (key) {
250      case 27:
251	exit(1);
252      case 32:
253	flag = (flag == NORMAL) ? WEIRD : NORMAL;
254	break;
255      case 't':
256	nitro = 1;
257	break;
258      default:
259	return;
260    }
261}
262
263static void Draw(void)
264{
265
266    MoveStars();
267    ShowStars();
268    if (nitro > 0) {
269	speed = (float)(nitro / 10) + 1.0;
270	if (speed > MAXWARP) {
271	    speed = MAXWARP;
272	}
273	if (++nitro > MAXWARP*10) {
274	    nitro = -nitro;
275	}
276    } else if (nitro < 0) {
277	nitro++;
278	speed = (float)(-nitro / 10) + 1.0;
279	if (speed > MAXWARP) {
280	    speed = MAXWARP;
281	}
282    }
283
284    glFlush();
285    if (doubleBuffer) {
286	glutSwapBuffers();
287    }
288}
289
290static GLenum Args(int argc, char **argv)
291{
292    GLint i;
293
294    doubleBuffer = GL_TRUE;
295
296    for (i = 1; i < argc; i++) {
297	if (strcmp(argv[i], "-sb") == 0) {
298	    doubleBuffer = GL_FALSE;
299	} else if (strcmp(argv[i], "-db") == 0) {
300	    doubleBuffer = GL_TRUE;
301	}
302    }
303    return GL_TRUE;
304}
305
306#if !defined(GLUTCALLBACK)
307#define GLUTCALLBACK
308#endif
309
310static void GLUTCALLBACK glut_post_redisplay_p(void)
311{
312      glutPostRedisplay();
313}
314
315int main(int argc, char **argv)
316{
317    GLenum type;
318
319    glutInit(&argc, argv);
320
321    if (Args(argc, argv) == GL_FALSE) {
322	exit(1);
323    }
324
325    windW = 300;
326    windH = 300;
327    glutInitWindowPosition(0, 0); glutInitWindowSize( 300, 300);
328
329    type = GLUT_RGB;
330    type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
331    glutInitDisplayMode(type);
332
333    if (glutCreateWindow("Stars") == GL_FALSE) {
334	exit(1);
335    }
336
337    Init();
338
339    glutReshapeFunc(Reshape);
340    glutKeyboardFunc(Key);
341    glutDisplayFunc(Draw);
342    glutIdleFunc(glut_post_redisplay_p);
343    glutMainLoop();
344	return 0;
345}
346