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 <time.h>
30#include "glut_wrap.h"
31
32
33#ifndef PI
34#define PI 3.141592657
35#endif
36
37
38enum {
39    NORMAL = 0,
40    WEIRD = 1
41};
42
43enum {
44    STREAK = 0,
45    CIRCLE = 1
46};
47
48#define MAXSTARS 400
49#define MAXPOS 10000
50#define MAXWARP 10
51#define MAXANGLES 6000
52
53
54typedef struct _starRec {
55    GLint type;
56    float x[2], y[2], z[2];
57    float offsetX, offsetY, offsetR, rotation;
58} starRec;
59
60
61GLenum doubleBuffer;
62GLint windW, windH;
63
64GLenum flag = NORMAL, overlayInit = GL_FALSE;
65GLint starCount = MAXSTARS / 2;
66float speed = 1.0;
67GLint nitro = 0;
68starRec stars[MAXSTARS];
69float sinTable[MAXANGLES];
70
71
72static float Sin(float angle)
73{
74
75    return (sinTable[(GLint)angle]);
76}
77
78static float Cos(float angle)
79{
80
81    return (sinTable[((GLint)angle+(MAXANGLES/4))%MAXANGLES]);
82}
83
84static void NewStar(GLint n, GLint d)
85{
86
87    if (rand()%4 == 0) {
88	stars[n].type = CIRCLE;
89    } else {
90	stars[n].type = STREAK;
91    }
92    stars[n].x[0] = (float)(rand() % MAXPOS - MAXPOS / 2);
93    stars[n].y[0] = (float)(rand() % MAXPOS - MAXPOS / 2);
94    stars[n].z[0] = (float)(rand() % MAXPOS + d);
95    if (rand()%4 == 0 && flag == WEIRD) {
96	stars[n].offsetX = (float)(rand() % 100 - 100 / 2);
97	stars[n].offsetY = (float)(rand() % 100 - 100 / 2);
98	stars[n].offsetR = (float)(rand() % 25 - 25 / 2);
99    } else {
100	stars[n].offsetX = 0.0;
101	stars[n].offsetY = 0.0;
102	stars[n].offsetR = 0.0;
103    }
104}
105
106static void RotatePoint(float *x, float *y, float rotation)
107{
108    float tmpX, tmpY;
109
110    tmpX = *x * Cos(rotation) - *y * Sin(rotation);
111    tmpY = *y * Cos(rotation) + *x * Sin(rotation);
112    *x = tmpX;
113    *y = tmpY;
114}
115
116static void MoveStars(void)
117{
118    float offset;
119    GLint n;
120
121    offset = speed * 60.0;
122
123    for (n = 0; n < starCount; n++) {
124	stars[n].x[1] = stars[n].x[0];
125	stars[n].y[1] = stars[n].y[0];
126	stars[n].z[1] = stars[n].z[0];
127	stars[n].x[0] += stars[n].offsetX;
128	stars[n].y[0] += stars[n].offsetY;
129	stars[n].z[0] -= offset;
130        stars[n].rotation += stars[n].offsetR;
131        if (stars[n].rotation > MAXANGLES) {
132            stars[n].rotation = 0.0;
133	}
134    }
135}
136
137static GLenum StarPoint(GLint n)
138{
139    float x0, y0, x1, y1, width;
140    GLint i;
141
142    x0 = stars[n].x[0] * windW / stars[n].z[0];
143    y0 = stars[n].y[0] * windH / stars[n].z[0];
144    RotatePoint(&x0, &y0, stars[n].rotation);
145    x0 += windW / 2.0;
146    y0 += windH / 2.0;
147
148    if (x0 >= 0.0 && x0 < windW && y0 >= 0.0 && y0 < windH) {
149	if (stars[n].type == STREAK) {
150	    x1 = stars[n].x[1] * windW / stars[n].z[1];
151	    y1 = stars[n].y[1] * windH / stars[n].z[1];
152	    RotatePoint(&x1, &y1, stars[n].rotation);
153	    x1 += windW / 2.0;
154	    y1 += windH / 2.0;
155
156	    glLineWidth(MAXPOS/100.0/stars[n].z[0]+1.0);
157	    glColor3f(1.0, (MAXWARP-speed)/MAXWARP, (MAXWARP-speed)/MAXWARP);
158	    if (fabs(x0-x1) < 1.0 && fabs(y0-y1) < 1.0) {
159		glBegin(GL_POINTS);
160		    glVertex2f(x0, y0);
161		glEnd();
162	    } else {
163		glBegin(GL_LINES);
164		    glVertex2f(x0, y0);
165		    glVertex2f(x1, y1);
166		glEnd();
167	    }
168	} else {
169	    width = MAXPOS / 10.0 / stars[n].z[0] + 1.0;
170	    glColor3f(1.0, 0.0, 0.0);
171	    glBegin(GL_POLYGON);
172		for (i = 0; i < 8; i++) {
173		    float x = x0 + width * Cos((float)i*MAXANGLES/8.0);
174		    float y = y0 + width * Sin((float)i*MAXANGLES/8.0);
175		    glVertex2f(x, y);
176		};
177	    glEnd();
178	}
179	return GL_TRUE;
180    } else {
181	return GL_FALSE;
182    }
183}
184
185static void ShowStars(void)
186{
187    GLint n;
188
189    glClear(GL_COLOR_BUFFER_BIT);
190
191    for (n = 0; n < starCount; n++) {
192	if (stars[n].z[0] > speed || (stars[n].z[0] > 0.0 && speed < MAXWARP)) {
193	    if (StarPoint(n) == GL_FALSE) {
194		NewStar(n, MAXPOS);
195	    }
196	} else {
197	    NewStar(n, MAXPOS);
198	}
199    }
200}
201
202static void Init(void)
203{
204    float angle;
205    GLint n;
206
207    srand((unsigned int)time(NULL));
208
209    for (n = 0; n < MAXSTARS; n++) {
210	NewStar(n, 100);
211    }
212
213    angle = 0.0;
214    for (n = 0; n < MAXANGLES ; n++) {
215	sinTable[n] = sin(angle);
216        angle += PI / (MAXANGLES / 2.0);
217    }
218
219    glClearColor(0.0, 0.0, 0.0, 0.0);
220
221    glDisable(GL_DITHER);
222}
223
224static void Reshape(int width, int height)
225{
226
227    windW = (GLint)width;
228    windH = (GLint)height;
229
230    glutUseLayer(GLUT_OVERLAY);
231
232    glViewport(0, 0, windW, windH);
233    glMatrixMode(GL_PROJECTION);
234    glLoadIdentity();
235    gluOrtho2D(-0.5, windW+0.5, -0.5, windH+0.5);
236    glMatrixMode(GL_MODELVIEW);
237    overlayInit = GL_FALSE;
238
239    glutUseLayer(GLUT_NORMAL);
240
241    glViewport(0, 0, windW, windH);
242    glMatrixMode(GL_PROJECTION);
243    glLoadIdentity();
244    gluOrtho2D(-0.5, windW+0.5, -0.5, windH+0.5);
245    glMatrixMode(GL_MODELVIEW);
246}
247
248static void Key(unsigned char key, int x, int y)
249{
250
251    switch (key) {
252      case 27:
253	exit(1);
254      case 32:
255	flag = (flag == NORMAL) ? WEIRD : NORMAL;
256	break;
257      case 't':
258	nitro = 1;
259	break;
260      default:
261	return;
262    }
263}
264
265static void Idle(void)
266{
267
268    if (overlayInit == GL_FALSE) {
269	glutUseLayer(GLUT_OVERLAY);
270	glClear(GL_COLOR_BUFFER_BIT);
271/*	    glColor3f(1.0, 0.0, 0.0);*/
272
273	glIndexf( 2.0 );
274	glBegin(GL_POLYGON);
275	    glVertex2i(windW/4-10, windH/4-10);
276	    glVertex2i(windW/2-10, windH/4-10);
277	    glVertex2i(windW/2-10, windH/2-10);
278	    glVertex2i(windW/4-10, windH/2-10);
279	glEnd();
280
281        glIndexf( 0.0 );
282	glBegin(GL_POLYGON);
283	    glVertex2i(windW/4, windH/4);
284	    glVertex2i(windW/2, windH/4);
285	    glVertex2i(windW/2, windH/2);
286	    glVertex2i(windW/4, windH/2);
287	glEnd();
288
289        glIndexf( 1.0 );
290	glBegin(GL_POLYGON);
291	    glVertex2i(windW/4+10, windH/4+10);
292	    glVertex2i(windW/2+10, windH/4+10);
293	    glVertex2i(windW/2+10, windH/2+10);
294	    glVertex2i(windW/4+10, windH/2+10);
295	glEnd();
296
297	glutUseLayer(GLUT_NORMAL);
298	overlayInit = GL_TRUE;
299    }
300
301    MoveStars();
302    ShowStars();
303    if (nitro > 0) {
304	speed = (float)(nitro / 10) + 1.0;
305	if (speed > MAXWARP) {
306	    speed = MAXWARP;
307	}
308	if (++nitro > MAXWARP*10) {
309	    nitro = -nitro;
310	}
311    } else if (nitro < 0) {
312	nitro++;
313	speed = (float)(-nitro / 10) + 1.0;
314	if (speed > MAXWARP) {
315	    speed = MAXWARP;
316	}
317    }
318
319    glFlush();
320    if (doubleBuffer) {
321	glutSwapBuffers();
322    }
323}
324
325static GLenum Args(int argc, char **argv)
326{
327    GLint i;
328
329    doubleBuffer = GL_TRUE;
330
331    for (i = 1; i < argc; i++) {
332	if (strcmp(argv[i], "-sb") == 0) {
333	    doubleBuffer = GL_FALSE;
334	} else if (strcmp(argv[i], "-db") == 0) {
335	    doubleBuffer = GL_TRUE;
336	}
337    }
338    return GL_TRUE;
339}
340
341int main(int argc, char **argv)
342{
343    GLenum type;
344
345    glutInit(&argc, argv);
346
347    if (!glutLayerGet(GLUT_OVERLAY_POSSIBLE))
348    {
349	fprintf(stderr, "Overlay not available\n");
350	return(1);
351    }
352
353    if (Args(argc, argv) == GL_FALSE) {
354	return(1);
355    }
356
357    windW = 300;
358    windH = 300;
359    glutInitWindowPosition(0, 0); glutInitWindowSize( 300, 300);
360
361    type = GLUT_RGB;
362    type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
363    glutInitDisplayMode(type);
364
365    if (glutCreateWindow("Overlay Test") == GL_FALSE) {
366	return(1);
367    }
368
369    glutEstablishOverlay();
370
371    Init();
372
373    glutReshapeFunc(Reshape);
374    glutKeyboardFunc(Key);
375    glutIdleFunc(Idle);
376    glutMainLoop();
377	return 0;
378}
379