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 <stdlib.h>
27#include <math.h>
28#include <string.h>
29#include <time.h>
30#include "glut_wrap.h"
31
32
33#define MAXOBJS 10000
34#define MAXSELECT 100
35#define MAXFEED 300
36#define	SOLID 1
37#define	LINE 2
38#define	POINT 3
39
40
41GLint windW, windH;
42
43GLuint selectBuf[MAXSELECT];
44GLfloat feedBuf[MAXFEED];
45GLint vp[4];
46float zRotation = 90.0;
47float zoom = 1.0;
48GLint objectCount;
49GLint numObjects;
50struct object {
51    float v1[2];
52    float v2[2];
53    float v3[2];
54    float color[3];
55} objects[MAXOBJS];
56GLenum linePoly = GL_FALSE;
57
58
59static void InitObjects(GLint num)
60{
61    GLint i;
62    float x, y;
63
64    if (num > MAXOBJS) {
65	num = MAXOBJS;
66    }
67    if (num < 1) {
68	num = 1;
69    }
70    objectCount = num;
71
72    srand((unsigned int)time(NULL));
73    for (i = 0; i < num; i++) {
74	x = (rand() % 300) - 150;
75	y = (rand() % 300) - 150;
76
77	objects[i].v1[0] = x + (rand() % 50) - 25;
78	objects[i].v2[0] = x + (rand() % 50) - 25;
79	objects[i].v3[0] = x + (rand() % 50) - 25;
80	objects[i].v1[1] = y + (rand() % 50) - 25;
81	objects[i].v2[1] = y + (rand() % 50) - 25;
82	objects[i].v3[1] = y + (rand() % 50) - 25;
83	objects[i].color[0] = ((rand() % 100) + 50) / 150.0;
84	objects[i].color[1] = ((rand() % 100) + 50) / 150.0;
85	objects[i].color[2] = ((rand() % 100) + 50) / 150.0;
86    }
87}
88
89static void Init(void)
90{
91
92    numObjects = 10;
93    InitObjects(numObjects);
94    glGetIntegerv(GL_VIEWPORT, vp);
95
96#if 0 /* debug - test culling */
97    glCullFace(GL_BACK);
98    glFrontFace(GL_CW);
99    glEnable(GL_CULL_FACE);
100#endif
101}
102
103static void Reshape(int width, int height)
104{
105
106    windW = (GLint)width;
107    windH = (GLint)height;
108}
109
110static void Render(GLenum mode)
111{
112    GLint i;
113
114    for (i = 0; i < objectCount; i++) {
115	if (mode == GL_SELECT) {
116	    glLoadName(i);
117	}
118	glColor3fv(objects[i].color);
119	glBegin(GL_POLYGON);
120	    glVertex2fv(objects[i].v1);
121	    glVertex2fv(objects[i].v2);
122	    glVertex2fv(objects[i].v3);
123	glEnd();
124    }
125}
126
127static GLint DoSelect(GLint x, GLint y)
128{
129    GLint hits;
130
131    glSelectBuffer(MAXSELECT, selectBuf);
132    (void)glRenderMode(GL_SELECT);
133    glInitNames();
134    glPushName(~0);
135
136    glPushMatrix();
137
138    glViewport(0, 0, windW, windH);
139    glGetIntegerv(GL_VIEWPORT, vp);
140
141    glMatrixMode(GL_PROJECTION);
142    glLoadIdentity();
143    gluPickMatrix(x, windH-y, 4, 4, vp);
144    gluOrtho2D(-175, 175, -175, 175);
145    glMatrixMode(GL_MODELVIEW);
146
147    glClearColor(0.0, 0.0, 0.0, 0.0);
148    glClear(GL_COLOR_BUFFER_BIT);
149
150    glScalef(zoom, zoom, zoom);
151    glRotatef(zRotation, 0, 0, 1);
152
153    Render(GL_SELECT);
154
155    glPopMatrix();
156
157    hits = glRenderMode(GL_RENDER);
158    if (hits <= 0) {
159	return -1;
160    }
161
162    return selectBuf[(hits-1)*4+3];
163}
164
165static void RecolorTri(GLint h)
166{
167
168    objects[h].color[0] = ((rand() % 100) + 50) / 150.0;
169    objects[h].color[1] = ((rand() % 100) + 50) / 150.0;
170    objects[h].color[2] = ((rand() % 100) + 50) / 150.0;
171}
172
173static void DeleteTri(GLint h)
174{
175
176    objects[h] = objects[objectCount-1];
177    objectCount--;
178}
179
180static void GrowTri(GLint h)
181{
182    float v[2];
183    float *oldV = NULL;
184    GLint i;
185
186    v[0] = objects[h].v1[0] + objects[h].v2[0] + objects[h].v3[0];
187    v[1] = objects[h].v1[1] + objects[h].v2[1] + objects[h].v3[1];
188    v[0] /= 3;
189    v[1] /= 3;
190
191    for (i = 0; i < 3; i++) {
192	switch (i) {
193	  case 0:
194	    oldV = objects[h].v1;
195	    break;
196	  case 1:
197	    oldV = objects[h].v2;
198	    break;
199	  case 2:
200	    oldV = objects[h].v3;
201	    break;
202	}
203	oldV[0] = 1.5 * (oldV[0] - v[0]) + v[0];
204	oldV[1] = 1.5 * (oldV[1] - v[1]) + v[1];
205    }
206}
207
208static void Mouse(int button, int state, int mouseX, int mouseY)
209{
210    GLint hit;
211
212    if (state != GLUT_DOWN)
213	return;
214
215    hit = DoSelect((GLint)mouseX, (GLint)mouseY);
216    if (hit != -1) {
217	if (button == GLUT_LEFT_BUTTON) {
218	    RecolorTri(hit);
219	}
220	if (button == GLUT_MIDDLE_BUTTON) {
221	    GrowTri(hit);
222	}
223	if (button == GLUT_RIGHT_BUTTON) {
224	    DeleteTri(hit);
225	}
226    }
227
228    glutPostRedisplay();
229}
230
231static void Draw(void)
232{
233
234    glPushMatrix();
235
236    glViewport(0, 0, windW, windH);
237    glGetIntegerv(GL_VIEWPORT, vp);
238
239    glMatrixMode(GL_PROJECTION);
240    glLoadIdentity();
241    gluOrtho2D(-175, 175, -175, 175);
242    glMatrixMode(GL_MODELVIEW);
243
244    glClearColor(0.0, 0.0, 0.0, 0.0);
245    glClear(GL_COLOR_BUFFER_BIT);
246
247    glScalef(zoom, zoom, zoom);
248    glRotatef(zRotation, 0, 0, 1);
249
250    Render(GL_RENDER);
251
252    glPopMatrix();
253
254    glFlush();
255}
256
257static void DrawZoom(GLint x, GLint y)
258{
259
260    glPushMatrix();
261
262    glViewport(0, 0, windW, windH);
263    glGetIntegerv(GL_VIEWPORT, vp);
264
265    glMatrixMode(GL_PROJECTION);
266    glLoadIdentity();
267    gluPickMatrix(x, windH-y, 4, 4, vp);
268    gluOrtho2D(-175, 175, -175, 175);
269    glMatrixMode(GL_MODELVIEW);
270
271    glClearColor(0.0, 0.0, 0.0, 0.0);
272    glClear(GL_COLOR_BUFFER_BIT);
273
274    glScalef(zoom, zoom, zoom);
275    glRotatef(zRotation, 0, 0, 1);
276
277    Render(GL_RENDER);
278
279    glPopMatrix();
280}
281
282static void DumpFeedbackVert(GLint *i, GLint n)
283{
284    GLint index;
285
286    index = *i;
287    if (index+7 > n) {
288	*i = n;
289	printf("  ???\n");
290	return;
291    }
292    printf("  (%g %g %g), color = (%4.2f %4.2f %4.2f)\n",
293	   feedBuf[index],
294	   feedBuf[index+1],
295	   feedBuf[index+2],
296	   feedBuf[index+3],
297	   feedBuf[index+4],
298	   feedBuf[index+5]);
299    index += 7;
300    *i = index;
301}
302
303static void DrawFeedback(GLint n)
304{
305    GLint i;
306    GLint verts;
307
308    printf("Feedback results (%d floats):\n", n);
309    for (i = 0; i < n; i++) {
310	switch ((GLint)feedBuf[i]) {
311	  case GL_POLYGON_TOKEN:
312	    printf("Polygon");
313	    i++;
314	    if (i < n) {
315		verts = (GLint)feedBuf[i];
316		i++;
317		printf(": %d vertices", verts);
318	    } else {
319		verts = 0;
320	    }
321	    printf("\n");
322	    while (verts) {
323		DumpFeedbackVert(&i, n);
324		verts--;
325	    }
326	    i--;
327	    break;
328	  case GL_LINE_TOKEN:
329	    printf("Line:\n");
330	    i++;
331	    DumpFeedbackVert(&i, n);
332	    DumpFeedbackVert(&i, n);
333	    i--;
334	    break;
335	  case GL_LINE_RESET_TOKEN:
336	    printf("Line Reset:\n");
337	    i++;
338	    DumpFeedbackVert(&i, n);
339	    DumpFeedbackVert(&i, n);
340	    i--;
341	    break;
342	  default:
343	    printf("%9.2f\n", feedBuf[i]);
344	    break;
345	}
346    }
347    if (i == MAXFEED) {
348	printf("...\n");
349    }
350    printf("\n");
351}
352
353static void DoFeedback(void)
354{
355    GLint x;
356
357    glFeedbackBuffer(MAXFEED, GL_3D_COLOR, feedBuf);
358    (void)glRenderMode(GL_FEEDBACK);
359
360    glPushMatrix();
361
362    glViewport(0, 0, windW, windH);
363    glGetIntegerv(GL_VIEWPORT, vp);
364
365    glMatrixMode(GL_PROJECTION);
366    glLoadIdentity();
367    gluOrtho2D(-175, 175, -175, 175);
368    glMatrixMode(GL_MODELVIEW);
369
370    glClearColor(0.0, 0.0, 0.0, 0.0);
371    glClear(GL_COLOR_BUFFER_BIT);
372
373    glScalef(zoom, zoom, zoom);
374    glRotatef(zRotation, 0, 0, 1);
375
376    Render(GL_FEEDBACK);
377
378    glPopMatrix();
379
380    x = glRenderMode(GL_RENDER);
381    if (x == -1) {
382	x = MAXFEED;
383    }
384
385    DrawFeedback((GLint)x);
386}
387
388static void Key2(int key, int x, int y)
389{
390    switch (key) {
391      case GLUT_KEY_LEFT:
392	zRotation += 0.5;
393	break;
394      case GLUT_KEY_RIGHT:
395	zRotation -= 0.5;
396	break;
397      default:
398	return;
399    }
400
401    glutPostRedisplay();
402}
403
404static void Key(unsigned char key, int x, int y)
405{
406    switch (key) {
407      case 27:
408	exit(1);
409      case 'Z':
410	zoom /= 0.75;
411	break;
412      case 'z':
413	zoom *= 0.75;
414	break;
415      case 'f':
416	DoFeedback();
417	break;
418      case 'd':
419	DrawZoom(x, y);
420	break;
421      case 'l':
422	linePoly = !linePoly;
423	if (linePoly) {
424	    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
425	} else {
426	    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
427	}
428	break;
429      default:
430	return;
431    }
432
433    glutPostRedisplay();
434}
435
436int main(int argc, char **argv)
437{
438    GLenum type;
439
440    glutInit(&argc, argv);
441
442    windW = 300;
443    windH = 300;
444    glutInitWindowPosition(0, 0); glutInitWindowSize( windW, windH);
445
446    type = GLUT_RGB | GLUT_SINGLE;
447    glutInitDisplayMode(type);
448
449    if (glutCreateWindow("Select Test") == GL_FALSE) {
450	exit(1);
451    }
452
453    Init();
454
455    glutReshapeFunc(Reshape);
456    glutKeyboardFunc(Key);
457    glutSpecialFunc(Key2);
458    glutMouseFunc(Mouse);
459    glutDisplayFunc(Draw);
460    glutMainLoop();
461	return 0;
462}
463